Decodificare una voce della directory FAT di Microsoft MS-DOS 5.0


27

Il file system Microsoft FAT ha una tabella di directory per rappresentare quali "file" si trovano in quali "cartelle" sul disco. Per il momento, queste voci hanno riempito molte informazioni in una piccola quantità di bit. Ci sono un sacco di specifiche tecniche su Wiki per i curiosi, ma la sfida qui si concentrerà su una "semplice" decodifica di una voce.

Ogni voce è composta da una parola binaria a 32 byte, suddivisa in più sezioni. Per coerenza in questa sfida, utilizzeremo la versione 5.0 di MS-DOS, i byte sono ordinati come big endian e chiameremo byte 0x00come l'estrema sinistra e byte0x1F come il più a destra.

Di seguito è riportato un breve schema delle sezioni pertinenti e quale dovrebbe essere l'output per ciascuna sezione (in grassetto ).

  • I primi 11 byte sono il nome del file in formato ASCII (da qui deriva il famoso nome di file 8.3 - 8 byte per il nome del file, 3 byte per l'estensione). Questi sono codifica ASCII diretta e devono essere emessi come ASCII con un punto (.) Tra .
    • Nota: entrambe le parti 8 e 3 sono riempite con spazi per fare una voce a lunghezza intera. L'output dovrebbe ignorare gli spazi (ovvero non emetterli).
    • L'estensione del file potrebbe essere vuota (ovvero tutti gli spazi), nel qual caso l'output non dovrebbe generare il punto .
    • Poiché ASCII utilizza solo i 7 bit inferiori, i byte avranno tutti un vantaggio 0.
  • Il byte successivo (0x0b) è una maschera di bit di quanto segue:
    • 0x01 Sola lettura - uscita RO
    • 0x02 Nascosto - uscita H
    • Sistema 0x04 - uscita S
    • Etichetta volume 0x08 - uscita VL . Le dimensioni del file (in basso) devono essere visualizzate come 0 , indipendentemente dalla voce effettiva.
    • Sottodirectory 0x10 - output SD . Le dimensioni del file (in basso) devono essere visualizzate come 0 , indipendentemente dalla voce effettiva.
    • 0x20 Archive - output A
    • Dispositivo 0x40: ignorato per questa sfida.
    • 0x80 riservato - ignorato per questa sfida.
    • Poiché si tratta di una maschera di bit, sono possibili più flag: tutti gli output applicabili devono essere concatenati insieme in qualsiasi ordine. Ad esempio, 0xffpotrebbe essere ROHSVLSDA(o qualsiasi altra combinazione).
  • I successivi due byte (0x0c e 0x0d) non vengono utilizzati in MS-DOS 5.0.
  • I successivi due byte (0x0e e 0x0f) sono i tempi di creazione come segue:
    • I bit da 15 a 11 sono le ore nel formato 24 ore - output da 00 a 23
    • I bit da 10 a 5 sono i minuti - uscita da 00 a 59
    • I bit da 4 a 0 sono i secondi / 2 - uscita da 00 a 58 (notare che i secondi sono solo con una risoluzione di due secondi)
    • Per chiarimenti: hhhhhmmmmmmsssssquando scritto big-endian.
  • I successivi due byte (0x10 e 0x11) sono la data di creazione come segue:
    • I bit da 15 a 9 sono l'anno - uscita 1980 per 0un massimo di 2107 per127
    • I bit da 8 a 5 sono i mesi - output da 1 a 12 (con o senza zero iniziale)
    • I bit da 4 a 0 sono il giorno - output da 0 a 31 (con o senza zero iniziale)
    • Per chiarimenti: yyyyyyymmmmdddddquando scritto big-endian.
  • I successivi due byte (0x12 e 0x13) sono la data dell'ultimo accesso. Mentre utilizzato in MS-DOS 5.0, ignoriamo questa parte per questa sfida.
  • I successivi due byte (0x14 e 0x15) non vengono utilizzati da MS-DOS 5.0.
  • I successivi due byte (0x16 e 0x17) sono l'ora dell'ultima modifica, seguendo lo stesso formato dell'ora di creazione, sopra.
  • I successivi due byte (0x18 e 0x19) sono l'ultima data modificata, seguendo lo stesso formato della data di creazione sopra.
  • I successivi due byte (0x1a e 0x1b) sono la posizione del cluster del file sul disco. Stiamo ignorando questa parte per questa sfida.
  • Gli ultimi quattro byte (0x1c, 0x1d, 0x1e e 0x1f) sono le dimensioni del file - output come numero intero senza segno , a meno che non siano impostati (sopra) i flag VL o SD , nel qual caso output 0.

Rappresentazione visiva

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

Ingresso

  • Una sola parola da 32 byte (ovvero 256 bit), in qualsiasi formato sia conveniente.
    • Questo potrebbe essere una stringa di 1e 0, come molti ints non firmati , una matrice di valori booleani, ecc.
    • Si prega di specificare nella risposta quale formato si sta utilizzando per l'input.
    • Non è possibile accettare input multipli (ad es. Un array pre-suddiviso nelle relative dimensioni di byte) a meno che non sia l' unico modo per la propria lingua di ricevere input. L'analisi dell'input fa parte della sfida.
  • Puoi presumere che l'input sia valido (ad esempio, non è necessario eseguire il controllo della data per verificare che la data sia valida).
  • I byte non utilizzati possono essere tutti 0, tutti 1, ecc., Purché siano presenti. Negli esempi seguenti, ho usato tutto 0per i byte non utilizzati.

Produzione

O stampato sullo schermo o restituito, il seguente:

  • Il nome file come stringa ASCII
  • Il file viene attribuito come stringa ASCII
  • L'ora di creazione e la data di creazione, con i separatori appropriati (due punti, barre, qualcosa per distinguere i componenti)
  • L'ora e la data modificate, sempre con i separatori appropriati
  • La dimensione del file

L'output può essere una stringa singola separata da spazio o newline, elementi separati in un array, ecc. Specificare nella risposta come viene formattato l'output.

Regole

  • I formati I / O standard sono accettabili.
  • È accettabile un programma completo o una funzione.
  • Sono vietate le scappatoie standard .
  • Questo è , quindi si applicano tutte le normali regole del golf e vince il codice più corto.
  • Gli built-in che svolgono esattamente questa funzione sono vietati.

Esempi

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

Va bene se c'è spazio in eccesso attorno alle bandiere? Ad esempio, sarebbe SD Sun set di flag valido?
Morgan Thrapp,

@MorganThrapp Certo, dovrebbe andare bene.
AdmBorkBork,

Per curiosità, hai avuto molta esperienza di interazione con MS-DOS 5.0 in passato, o ti sei davvero annoiato su Wikipedia un giorno?
gatto,

3
@cat Alcuni di entrambi. Sono molto interessato ai computer da quando avevo circa 5 anni e ho ricevuto un Commodore VIC-20. Uno dei miei progetti informatici di livello superiore circa 10 anni fa era quello di costruire il nostro filesystem, quindi ho fatto molte ricerche. Per questo, ho estratto un gruppo da Wiki e l'ho ridotto a qualcosa che potrebbe essere una sfida.
AdmBorkBork,

Risposte:


6

Verilog, 513 670 617 byte

Funziona con IVerilog. Non sono necessari flag di compilazione speciali.

Questo è un mostro di definizioni nidificate, manipolazione dei bit e fastidio di dover invertire l'ordine dei bit a causa dell'endianness (altrimenti la stringa non viene stampata o l'ordine dei bit numerici è errato). L'input viene acquisito attraverso la iporta, che è il solito modo di ricevere input in un modulo Verilog. $displayviene utilizzato per stampare in modo standard. 6 byte potrebbero essere salvati se non fossero richiesti zeri iniziali per il timestamp.

`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

dimostrazione

Banco di prova (non segnato):

`timescale 1ns / 1ps

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

endmodule

Esempio di esecuzione:

$ 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 byte.

Salvato 19 byte grazie a Cᴏɴᴏʀ O'Bʀɪᴇɴ che mi ricorda che posso assegnare funzioni a una lettera.

6 byte salvati grazie al suggerimento di FryAmTheEggman per ripulire il filtro maschera di bit.

Ho risparmiato 21 byte grazie alla straordinaria risposta di Ruby di W0lf che mi ha costretto a giocare ancora un po '. ;)

Questo è un mostro assoluto. Abbastanza sicuro di poterlo ridurre un po 'di più, ma si sta avvicinando molto al golf.

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

forse potresti assegnare inta un personaggio? o forse fare una funzione che esegue str int.
Conor O'Brien,

@ CᴏɴᴏʀO'Bʀɪᴇɴ Buona idea!
Morgan Thrapp,

Lo spazio in mezzo or 'SD'può essere rimosso, credo
Conor O'Brien,

@ CᴏɴᴏʀO'Bʀɪᴇɴ Sì, l'ho appena fatto.
Morgan Thrapp,

Wow. Abbastanza un po 'più corto di quanto mi aspettassi le risposte.
AdmBorkBork,

4

Haskell, 781 710 byte

Grazie a BlackCap per la semplificazione

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

Ciò consente inoltre all'immondizia (come un carattere di nuova riga) di apparire dopo l'input.


Ti ho
procurato un

3

Java, 1721 1587 1573 1560 1511 byte:

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()));}}

Accetta input nel formato di stringa binaria a 32 byte. Output nel formato di una stringa separata da spazio. Questa potrebbe essere una risposta molto lunga, ma non sono ancora deluso. Sono solo felice di essere riuscito a implementarlo in Java. Cercherò comunque di giocare a golf il più possibile, però.

Provalo online! (Ideone)


1
+1 perché usare Java per problemi di basso livello è piacevolmente ironico (proprio come il mio Haskell)
Fox

2

Rubino, 344 byte

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))]*' '

La versione leggermente più leggibile è disponibile qui .

Test online: http://ideone.com/Fww1Rw


1
Ben fatto! Sembra che debba golf altri 27 byte. ;)
Morgan Thrapp il

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]

Meno golf

(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
  ]

Test

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>


Ok, l'ho appena eseguito su Safari e ho capito Script error.. Ma per qualche motivo in Firefox sembra funzionare perfettamente. Mi chiedo perché ...
R. Kap il

@ R.Kap probabilmente Safari è meno compatibile ES6 di Firefox. kangax.github.io/compat-table/es6
edc65,

2

PHP ,301 288 byte

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];

Provalo online!

L'input è una stringa di parole da 32 byte via STDIN, output a STDOUT.

-13 byte come programma autonomo.


2

Stax , 111 byte

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

Esegui ed esegui il debug


Oops, errore mio. Farò una correzione.
ricorsivo il

1
Ora funziona correttamente al costo di 3 byte.
ricorsivo il

1

Perl, 249 byte

Prende 32 byte come input, l'output è separato da newline. unpackè perfetto per questo tipo di analisi della struttura binaria.

($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

Alcuni punti salienti:

  • Il suddetto unpack.
  • L'operatore tartaruga @{[]}consente di interpolare il codice in una stringa. In realtà, crea un riferimento di matrice che viene quindi deferenziato.
  • "$str1"x!!$str2è un buon modo per restituire $str1solo se $str2è una stringa non vuota.

Di seguito è una versione che funziona su voci di directory reali, con campi little-endian, e ignorando solo il riempimento corretto sul nome file e sull'estensione (quindi, ad esempio, " ppcg"non viene rimosso il suo spazio bianco iniziale) (254 byte)

($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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.