Microsoft MS-DOS 5.0 FATディレクトリエントリをデコードする


27

Microsoft FATファイルシステムには、ディスク上のどの "フォルダ"にどの "ファイル"があるかを表すディレクトリテーブルがあります。当分の間、これらのエントリは多くの情報を少量のビットに詰め込みました。好奇心the盛な人のためにWikiには多くの技術仕様がありますが、ここでの課題は、エントリの「単純な」デコードに焦点を当てることです。

各エントリは32バイトのバイナリワードで構成され、いくつかのセクションに分かれています。この課題に一貫性を持たせるために、MS-DOS 5.0バージョンを使用します。バイトはビッグエンディアンとして順序付けられ、バイト0x00を左端、バイト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(または他の任意の組み合わせ)。
  • 次の2バイト(0x0cおよび0x0d)は、MS-DOS 5.0では使用されません。
  • 次の2バイト(0x0eおよび0x0f)は、次の作成時間です。
    • ビット15〜11は、24時間形式の時間である-出力0023
    • ビット10から5は分である-出力0059
    • ビット4から0は秒/ 2です-出力00から58(秒は2秒の解像度のみであることに注意してください)
    • 明確にするために:hhhhhmmmmmmsssssビッグエンディアンで書かれたとき。
  • 次の2バイト(0x10および0x11)は、次の作成日です。
    • ビット15から9は年です- 最大21071980を出力します0127
    • ビット8から5は月です-出力1から12(先行ゼロの有無にかかわらず)
    • ビット4から0は日-出力0から31(先行ゼロの有無にかかわらず)
    • 明確にするために:yyyyyyymmmmdddddビッグエンディアンで書かれたとき。
  • 次の2バイト(0x12および0x13)は最終アクセス日です。MS-DOS 5.0で使用されていますが、この課題ではこの部分を無視しています。
  • 次の2バイト(0x14および0x15)は、MS-DOS 5.0では使用されません。
  • 次の2バイト(0x16および0x17)は最終更新時刻であり、上記の作成時刻と同じ形式に従います。
  • 次の2バイト(0x18と0x19)は最終更新日で、上記の作成日と同じ形式に従います。
  • 次の2バイト(0x1aおよび0x1b)は、ディスク上のファイルのクラスターの場所です。この課題ではこの部分を無視しています。
  • 最後の4バイト(0x1c、0x1d、0x1e、および0x1f)は、VLまたはSDフラグが設定されている(上記)場合を除き、符号なし整数として出力されるファイルサイズです。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有効なフラグが設定されますか?
モーガンスラップ

@MorganThrapp確かに、それは問題ないはずです。
AdmBorkBork

好奇心から、その日はMS-DOS 5.0とやり取りした経験が豊富でしたか、それともある日ウィキペディアに本当に飽きていましたか?

3
@cat両方の一部。私は5歳の頃からコンピューターに非常に興味があり、コモドールVIC-20を受け取りました。約10年前の私の大学院レベルのコンピューターサイエンスプロジェクトの1つは、独自のファイルシステムを構築することでした。そのため、私は多くのことを研究しました。このために、私はWikiから束を引き出して、それを挑戦になり得るものに切り詰めました。
AdmBorkBork

回答:


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)))

多分あなたはintcharに割り当てることができますか?または多分実行する機能を作成しますstr int
コナーオブライエン

@CᴏɴᴏʀO'Bʀɪᴇɴいいね!
モーガンスラップ

間のスペースはor 'SD'削除できると思う
コナーオブライエン

@CᴏɴᴏʀO'Bʀɪᴇɴうん、それをやった。
モーガンスラップ

ワオ。答えが予想よりもかなり短い。
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

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のような)愉快に皮肉であるので
フォックス

2

ルビー、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バイトをゴルフする必要があるように見えます。;)
モーガンスラップ

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.ガプス

@ R.Kapはおそらく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バイトのワード文字列でSTDIN、への出力STDOUTです。

スタンドアロンプ​​ログラムとして-13バイト



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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.