解码Microsoft MS-DOS 5.0 FAT目录项


27

Microsoft FAT文件系统具有一个目录表,用于表示磁盘上哪些“文件”位于哪个“文件夹”中。暂时,这些条目将大量信息塞满了少量比特。出于好奇,Wiki上有很多技术规范,但是这里的挑战将集中在条目的“简单”解码上。

每个条目由一个32字节的二进制字组成,分为几个部分。为了在此挑战中保持一致,我们将使用MS-DOS 5.0版本,字节顺序为big endian,并且将byte 0x00称为最左边,将byte 0x1F称为最右边。

以下是相关部分的简要示意图,以及每个部分的输出(以粗体显示)。

  • 前11个字节是ASCII格式的文件名(这是著名的8.3文件名的来源-文件名8个字节,扩展名3个字节)。这些是直接的ASCII编码,应以ASCII(。)之间的形式输出
    • 注意:第8部分和第3部分都用空格填充,以进行全长输入。输出应忽略空格(即,不输出空格)。
    • 文件扩展名可能为空(即所有空格),在这种情况下,输出不应输出点
    • 由于ASCII仅使用低7位,因此所有字节均具有前导0
  • 下一个字节(0x0b)是以下内容的位掩码:
    • 0x01只读-输出RO
    • 0x02隐藏-输出H
    • 0x04系统-输出S
    • 0x08音量标签输出VL。文件大小(以下)应输出为0,无论其实际输入如何。
    • 0x10子目录-输出SD。文件大小(以下)应输出为0,无论其实际输入如何。
    • 0x20存档-输出A
    • 0x40设备-此挑战被忽略。
    • 0x80保留-对于此挑战被忽略。
    • 由于这是位掩码,因此可能有多个标志-所有适用的输出应以任意顺序串联在一起。例如,0xff可以是ROHSVLSDA(或任何其他组合)。
  • 在MS-DOS 5.0下不使用接下来的两个字节(0x0c和0x0d)。
  • 接下来的两个字节(0x0e和0x0f)是创建时间,如下所示:
    • 位15到11是24小时格式的小时-输出0023
    • 位10到5是分钟-输出0059
    • 位4到0是秒数/ 2-输出0058(请注意,秒仅是两秒的分辨率)
    • 为了澄清:hhhhhmmmmmmsssss写大端时。
  • 接下来的两个字节(0x10和0x11)是创建日期,如下所示:
    • 位15至9年-输出1980年0高达2107127
    • 位8到5是月份-输出112(带或不带前导零)
    • 位4至0是日期-输出031(带或不带前导零)
    • 为了澄清:yyyyyyymmmmddddd写大端时。
  • 接下来的两个字节(0x12和0x13)是最后访问日期。在MS-DOS 5.0中使用时,我们将忽略此部分的挑战。
  • MS-DOS 5.0不使用接下来的两个字节(0x14和0x15)。
  • 接下来的两个字节(0x16和0x17)是最后修改的时间,遵循与上面创建时间相同的格式。
  • 接下来的两个字节(0x18和0x19)是最后修改日期,其格式与上面的创建日期相同。
  • 接下来的两个字节(0x1a和0x1b)是文件在磁盘上的群集位置。对于这一挑战,我们将忽略这一部分。
  • 最后四个字节(0x1c,0x1d,0x1e和0x1f)是文件大小-输出为 无符号整数,除非设置了VLSD标志(在上面),否则输出0

视觉表现

0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
\______________________________FILENAME________________________________________________/\_ATTR_/\___NOTUSED____/\_CREATIONTIME_/\_CREATIONDATE_/\__LASTACCESS__/\___NOTUSED____/\_MODIFIEDTIME_/\_MODIFIEDDATE_/\___NOTUSED____/\___________FILESIZE___________/

输入项

  • 单个32字节字(即256位),采用任何方便的格式。
    • 这可能是作为一个串10作为几个无符号intS,布尔值的阵列等
    • 请在您的答案中指定您使用的输入格式。
    • 不能接受多个输入(即,将数组预分解为相关的字节大小),除非是您的语言接受输入唯一方法,。解析输入是挑战的一部分。
  • 您可以假定输入是有效的(例如,您不需要执行日期检查来验证日期是否有效)。
  • 只要存在,未使用的字节就可以是all 0,all 1等。在以下示例中,我使用了所有0用于未使用的字节。

输出量

打印到屏幕或返回以下内容:

  • 文件名作为ASCII字符串
  • 文件属性为ASCII字符串
  • 创建时间和创建日期,并带有适当的分隔符(冒号,斜杠,用于区分组件的内容)
  • 修改的时间和修改的日期,再次使用适当的分隔符
  • 档案大小

输出可以是用空格或换行符分隔的单个字符串,数组中的单独元素等。请在答案中指定输出的格式。

规则

  • 标准I / O格式是可以接受的。
  • 完整的程序或功能都是可以接受的。
  • 禁止出现标准漏洞
  • 这是,因此所有常见的打高尔夫球规则均适用,最短的代码获胜。
  • 禁止完全执行此功能的内置程序。

例子

0111000001110010011011110110011101110010011000010110110101101101011010010110111001100111000001100000000000000000101000100100010001001000110101000000000000000000000000000000000010100010010001000100100011010100000000000000000000000000000000001101000000000000

programm.ing HS 20:18:08 2016/06/20 20:18:08 2016/06/20 53248

0010000000100000001000000010000001110000011100000110001101100111001000000010000000100000000101000000000000000000010111010110110000111101100111110000000000000000000000000000000010100010010001000100100011010100000000000000000011110000000100111111001011100001

ppcg SDS 11:43:24 2010/12/31 20:18:08 2016/06/20 0

标记周围是否有多余的空格可以吗?例如,将SD S设置有效的标志吗?
Morgan Thrapp '16

@MorganThrapp当然,那应该没问题。
AdmBorkBork

出于好奇,您是否有一天回到了与MS-DOS 5.0进行交互的丰富经验,或者您一天真的对Wikipedia感到无聊?

3
@cat两者都有。我从5岁起就对计算机产生了浓厚的兴趣,并收到了Commodore VIC-20。大约10年前,我的研究生计算机科学项目之一是构建自己的文件系统,因此我为此进行了大量研究。为此,我从Wiki中抽了很多钱,将其削减为可能带来挑战的内容。
AdmBorkBork

Answers:


6

的Verilog,513个 670 617字节

使用IVerilog运行。无需特殊的编译标志。

这是一个嵌套定义,位纠结以及由于字节顺序而不得不翻转位顺序的烦恼的怪兽(否则字符串不打印或数字位顺序错误)。输入是通过i端口获取的,这是将输入输入Verilog模块的常用方法。$display用于打印到标准输出。如果时间戳不需要前导零,则可以节省6个字节。

`define r(o,b)wire[3:0]o;assign o={i[b],i[b+1],i[b+2],i[b+3]}; 
`define R(t,a,b,c,d,s)`r(a,s)`r(b,s+4)`r(c,s+8)`r(d,s+12)wire[15:0]t;assign t={a,b,c,d};
`define p(m,k)i[90+m]?"k":"",
`define F(a,b)"a a a b\t b%d"
module f(input[0:255]i);`R(d,q,w,e,r,112)`R(D,Q,W,E,R,128)`R(s,z,x,c,v,224)`R(S,Z,X,C,V,240)`R(p,t,y,u,o,176)`R (A,b,n,m,l,192)always@(i)$display(`F(%s%s%s,%02d:%02d:%02d%d/%d/%d),i[0:63],i[64:87]=="   "?" ":".",i[64:87],`p(5,RO)`p(4,H)`p(3,S)`p(2,VL)`p(1,SD)`p(0,A)d[15:11],d[10:5],d[4:0]*2,D[15:9]+1980,D[8:5],D[4:0],p[15:11],p[10:5],p[4:0]*2,A[15:9]+1980,A[8:5],A[4:0],|i[91:92]?0:{s,S});endmodule

演示版

测试平台(未评分):

`timescale 1ns / 1ps

module ftest;
reg [0:255] i;
f uut (
.i(i)
);
initial begin
    i=256'b0111000001110010011011110110011101110010011000010110110101101101011010010110111001100111000001100000000000000000101000100100010001001000110101000000000000000000000000000000000010100010010001000100100011010100000000000000000000000000000000001101000000000000;
    #100;
i=256'b0010000000100000001000000010000001110000011100000110001101100111001000000010000000100000000101000000000000000000010111010110110000111101100111110000000000000000000000000000000010100010010001000100100011010100000000000000000011110000000100111111001011100001;     
end

endmodule

示例运行:

$ iverilog design.sv testbench.sv  && vvp a.out  
programm.ing   HS      20:18:08       2016/ 6/20      53248
    ppcg        S  SD  11:43:24       2010/12/31          0

5

Python,485、479、442、438、431、429、418、402、395、391和370个字节。

保存了19个字节,感谢CᴏɴᴏʀO'Bʀɪᴇɴ提醒我可以为字母分配功能。

由于FryAmTheEggman建议清理位掩码过滤器,因此节省了6个字节。

由于W0lf出色的Ruby回答,我节省了21个字节,这迫使我进一步降低了这一点。;)

这是绝对的怪物。可以肯定,我可以再减少一点,但它已经接近打高尔夫球了。

a=input()
j=''.join
n=lambda v:int(v,2)
f=j('RO H S VL SD A'.split()[i]for i in range(6)if n(a[88:96])&2**i)
print(j(chr(n(a[x:x+8])).strip()+'.'*(x==56)for x in range(0,88,8)).strip('.'),f,j('%02d:%02d:%02d'%(n(a[b-11:b-6]),n(a[b-6:b]),n(a[b:b+6]))+' %d/%d/%d '%(n(a[b+6:b+12])+1980,n(a[b+12:b+16]),n(a[b+16:b+21]))for b in[123,187]),n(a[208:])*(1-('V'in f or'D'in f)))

也许您可以分配int给一个字符?或者做一个执行的功能str int
Conor O'Brien

@CᴏɴᴏʀO'Bʀɪᴇɴ好主意!
Morgan Thrapp

or 'SD'我认为,两者之间的空间可以删除
Conor O'Brien

@CᴏɴᴏʀO'Bʀɪᴇɴ是的,就是那样。
Morgan Thrapp

哇。比我预期的要短很多。
AdmBorkBork

4

Haskell,781 710字节

感谢BlackCap的简化

w n=('0'<$[1..2-length a])++a where a=show n
x s=tail.foldr(\a b->s:a++b)""
t=snd.span(==' ')
y a|all(==' ')a=""|0<1='.':t a
nm=(\(a,b)->t a++y b).splitAt 8
ms n(r,s)|n`mod`2^(r+1)`div`2^r>0=s|0<1=""
tm n=x ':'[w$n`div`2^11,w$n`mod`2^11`div`32,w$2*n`mod`64]
dt n=x '/'[w$1980+n`div`2^9,w$n`mod`2^9`div`32,w$n`mod`32]
pa s=x ' '[nm.map(toEnum.v.take 8).takeWhile(not.null)$iterate(drop 8)a,t,dt$v i,tm$v g,dt$v o,tm$v m,show u,"\n"]where{z n=splitAt(8*n);(a,b)=z 11 s;(c,d)=z 1 b;(e,f)=z 2 d;(g,h)=z 2 f;(i,j)=z 2 h;(k,l)=z 4 j;(m,n)=z 2 l;(o,p)=z 2 n;(q,r)=z 2 p;t=(zip [0..](words"RO H S VL SD A")>>=).ms$v c;u|any(`elem`t)"LD"=0|0<1=v r;v=foldl((+).(2*))0.map(read.pure).filter(`elem`"01")}
main=interact pa

另外,这还允许在输入之后出现垃圾(例如换行符)。


得到了一些低挂的水果:pastebin.com/X69jH75f
BlackCap,2016年

3

Java,1721 1587 1573 1560 1511字节:

import java.util.*;class A{int Q(String a,int b){return Integer.parseInt(a,b);}String P(int a){return Integer.toString(a);}ArrayList<String>B=new ArrayList<String>();void J(String O){B.add(O);}String TD(String l,String p,int a,int c,int d){String X,Y,Z;X=Y=Z=new String();int i=0;for(char F:l.toCharArray()){if(i<a){X+=F;}if(a<=i&i<c){Y+=F;}if(c<=i){Z+=F;}i++;}String[]H=new String[3];H[0]=P(d+Q(X,2));H[1]=P(Q(Y,2));H[2]=(p==":")?P(Q(Z,2)*2):P(Q(Z,2));int T=0;for(String A:H){H[T]=(A.length()<2)?"0"+A:A;T++;}return H[0]+p+H[1]+p+H[2];}String D(String i){String K=new String();int L=0;for(char Y:i.toCharArray()){if(L%8<1){K+=" ";}K+=Y;L++;}String[]C=K.split(" ");String[]z={"RO","H","S","VL","SD","A"};int[]l={1,2,4,8,16,32};Map<Integer,String>U=new HashMap<Integer,String>();for (int e=0;e<l.length;e++){U.put(l[e],z[e]);}String[]N={":","/",":","/"};int[]M={15,17,23,25};int[]O={5,7,5,7};int[]P={0,1980,0,1980};for(int y=1;y<9;y++){if((char)Q(C[y],2)!=' '){J(Character.toString((char)Q(C[y],2)));}}for(int v=9;v<12;v++){if((char)Q(C[v],2)!=' '){if(!B.contains(".")){J(".");}J(Character.toString((char)Q(C[v],2)));}}J(" ");int T=(char)Q(C[12],2);while(T>0){int H=l[0];for(int V:l){if(V<=T){H=V;}}J(U.get(H));T-=H;}for(int w=0;w<4;w++){J(" ");J(TD(C[M[w]]+C[M[w]+1],N[w],O[w],11,P[w]));}J(" ");if(B.contains("SD")||B.contains("VL")){J("0");}else{J(P(Q(C[29]+C[30]+C[31]+C[32],2)));}return String.join("",B);}public static void main(String[]a){A H=new A();System.out.print(H.D(new Scanner(System.in).next()));}}

接受32字节二进制字符串格式的输入。以空格分隔的字符串格式输出。这可能是一个非常非常长的答案,但我仍然没有失望。我很高兴能够用Java实现此功能。不过,我仍然会尽力去打高尔夫球。

在线尝试!(爱迪生)


1
+1是因为使用Java解决低级问题令人感到讽刺(就像我的Haskell一样)
Fox

2

Ruby,344字节

m=gets
s=->b,l{b.slice!(0,l).to_i 2}
t=->b{'%02d:%02d:%02d %d/%d/%d'%[s[b,5],s[b,6],2*s[b,5],s[b,7]+1980,s[b,4],s[b,5],]}
i=(0..q=32).map{|i|m[i*8,8].to_i 2}
c=i.map(&:chr).join
n=c[0,8].strip
e=c[8,3].strip
e>?!&&n<<?.+e
f=''
6.times{|j|i[11][j]>0&&f<<%w(RO H S VL SD A)[j]}
$><<[n,f,t[m[112,q]],t[m[176,q]],(f[/VL|SD/]?0:m[-q,q].to_i(2))]*' '

可读性更高的版本可在此处获得

在线测试:http//ideone.com/Fww1Rw


1
好东西!看来我需要再打27个字节。;)
Morgan Thrapp

2

JavaScript(ES6),369

(b,Z=n=>n>9?n:'0'+n,W=n=>s[n]<<8|s[n+1],U=n=>[Z((t=W(n))>>11)+`:${Z(t>>5&63)}:`+Z(t%32*2),((t=W(n+2))>>9)+1980+`/${t>>5&15}/`+t%32],X=l=>String.fromCharCode(...s.slice(p,p+=l)).trim(),s=b.match(/.{8}/g).map(x=>+('0b'+x)),p=0)=>[X(8)+((x=X(3))?'.'+x:x),[...b].map((b,i)=>'A,SD,VL,S,H,RO'.split`,`[z=(2*z|b)%4294967296,i*b-90]||'',z=0).join``,U(14),U(22),b[92]|b[91]?0:z]

少打高尔夫球

(b,
  Z=n=>n>9?n:'0'+n, // zero pad
  W=n=>s[n]<<8|s[n+1], // get word
  U=n=>[
   Z((t=W(n))>>11)+`:${Z((t>>5&63)}:`+Z(t%32*2),  // decode time
   ((t=W(n+2))>>9)+1980+`/${t>>5&15}/`+t%32 // decode date
  ],
  X=l=>String.fromCharCode(...s.slice(p,p+=l)).trim(), // extract space padded string
  s=b.match(/.{8}/g).map(x=>+('0b'+x)), // convert bits to bytes
  p=0
)=>
  [ X(8)+((x=X(3))?'.'+x:x),
    [...b].map((b,i)=>'A,SD,VL,S,H,RO'.split`,`[i*b-90]||'').join``,
    [...b].slice(-32).map((b,i)=>z=2*z|b,z=0), // this line merged with the preceding one in the golfed code
    U(14),U(22),
    b[92]|b[91]?0:z
  ]

测试

f=(b,Z=n=>n>9?n:'0'+n,W=n=>s[n]<<8|s[n+1],U=n=>[Z((t=W(n))>>11)+`:${Z(t>>5&63)}:`+Z(t%32*2),((t=W(n+2))>>9)+1980+`/${t>>5&15}/`+t%32],X=l=>String.fromCharCode(...s.slice(p,p+=l)).trim(),s=b.match(/.{8}/g).map(x=>+('0b'+x)),p=0)=>[X(8)+((x=X(3))?'.'+x:x),[...b].map((b,i)=>'A,SD,VL,S,H,RO'.split`,`[z=(2*z|b)%4294967296,i*b-90]||'',z=0).join``,U(14),U(22),b[92]|b[91]?0:z]

O.textContent+='\n'+f('0111000001110010011011110110011101110010011000010110110101101101011010010110111001100111000001100000000000000000101000100100010001001000110101000000000000000000000000000000000010100010010001000100100011010100000000000000000000000000000000001101000000000000')
O.textContent+='\n'+f('0010000000100000001000000010000001110000011100000110001101100111001000000010000000100000000101000000000000000000010111010110110000111101100111110000000000000000000000000000000010100010010001000100100011010100000000000000000011110000000100111111001011100001')
<pre id=O></pre>


好的,所以我只是在Safari中运行了并得到了Script error.。但是由于某些原因,在Firefox中它似乎可以正常工作。我不知道为什么...
R. Kap

@ R.Kap可能是Safari与Firefox的ES6兼容性较差。kangax.github.io/compat-table/es6
edc65

2

的PHP301 288字节

for($b=unpack('A8f/A3e/Cl/n/Nc/N/Nm/n/Ns',$argn);$i<8;$f.=1<<$i++&$b[l]?[RO,H,S,VL,SD,A][$i-1]:'');echo trim($b[f].'.'.$b[e],' .')," $f ",($e=function($a){echo date('H:i:s Y/m/d ',mktime($a>>27&31,$a>>21&63,$a>>15&62,$a>>5&15,$a&31,1980+($a>>9&127)));})($b[c]),$e($b[m]),$b[l]&24?0:$b[s];

在线尝试!

输入是一个32字节的字串via STDIN,输出到STDOUT

-13字节作为独立程序。


2

Stax,111 字节

¼ΘUßU'ïMo^ø¬├▓> I¬i⌠·╥.↕¥½ßqS,=frT`d_`&&↓⌠ÉûÆiü=┌-< │∟Φ☼⌐¢3²Bu╜lJ╛§≥╪║ε┐╓ù♫╨Z░╖!¥É:╬Çß═╤às8Q←φ,ºï◘≥Ä£}èΦ╡FÉçø¶É

运行并调试


糟糕,我的错。我会解决。
递归

1
现在它可以正常工作,但需要3个字节。
递归

1

Perl,249个字节

以32个字节为输入,输出用换行符分隔。unpack非常适合这种二进制结构解析。

($f,$e,$a,$C,$M,$s)=unpack"A8A3CxxNx4Nx2N",<>;$f=~s/ //g;$e=~s/ //g;printf"%s
@{[map+(RO,H,S,VL,SD,A)[$a&1<<$_?$_:9],0..5]}
"."%02d:%02d:%02d %d/%d/%d
"x2 .$s*!($a&24),$f.".$e"x!!$e,map{$_>>27,$_>>21&63,$_>>15&62,$_/512%128+1980,$_>>5&15,$_&31}$C,$M

一些重点:

  • 之前所提 unpack
  • 乌龟运算符@{[]}允许在字符串中插入代码。它实际上创建了一个数组引用,然后将其取消引用。
  • "$str1"x!!$str2$str1仅当$str2为非空字符串时,这是一种返回的好方法。

下面是一个适用于真实目录条目的版本,具有小尾数字段,并且仅忽略文件名和扩展名的正确填充(因此,例如" ppcg",没有删除其初始空白)(254字节)

($f,$e,$a,$C,$M,$s)=unpack"A8A3CxxVx4Vx2V",<>;$f=~s/ +$//;$e=~s/ +$//;printf"%s
@{[map+(RO,H,S,VL,SD,A)[$a&1<<$_?$_:9],0..5]}
"."%02d:%02d:%02d %d/%d/%d
"x2 .$s*!($a&24),$f.".$e"x!!$e,map{$_>>11&31,$_>>5&63,2*$_&63,($_>>25)+1980,$_>>21&15,$_>>16&31}$C,$M
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.