Decodificar uma entrada de diretório do Microsoft MS-DOS 5.0 FAT

27

O sistema de arquivos Microsoft FAT possui uma tabela de diretórios para representar quais "arquivos" estão em quais "pastas" no disco. Por enquanto, essas entradas colocavam muitas informações em uma pequena quantidade de bits. Há um monte de especificações técnicas no Wiki para os curiosos, mas o desafio aqui será focar na decodificação "simples" de uma entrada.

Cada entrada consiste em uma palavra binária de 32 bytes, dividida em várias seções. Para maior consistência nesse desafio, usaremos a versão MS-DOS 5.0, os bytes são ordenados como big endian e chamamos byte 0x00como o mais à esquerda e byte 0x1Fcomo o mais à direita.

Abaixo está um breve esquema das seções relevantes e qual deve ser o resultado de cada seção (em negrito ).

  • Os primeiros 11 bytes são o nome do arquivo no formato ASCII (é daí que o famoso nome do arquivo 8.3 vem - 8 bytes para o nome do arquivo, 3 bytes para a extensão). Elas são codificação ASCII direta e devem ser exibidas como ASCII com um período (.) Entre .
    • Nota: as partes 8 e 3 são preenchidas com espaços para fazer uma entrada completa. A saída deve ignorar os espaços (por exemplo, não os gera).
    • A extensão do arquivo pode estar vazia (ou seja, todos os espaços); nesse caso, a saída não deve gerar o ponto .
    • Como o ASCII usa apenas os 7 bits inferiores, todos os bytes terão uma vantagem 0.
  • O próximo byte (0x0b) é uma máscara de bits do seguinte:
    • 0x01 somente leitura - saída RO
    • 0x02 Oculto - saída H
    • Sistema 0x04 - saída S
    • Etiqueta de volume 0x08 - saída VL . O tamanho do arquivo (abaixo) deve ser exibido como 0 , independentemente de sua entrada real.
    • 0x10 Subdiretório - saída SD . O tamanho do arquivo (abaixo) deve ser exibido como 0 , independentemente de sua entrada real.
    • Arquivo 0x20 - saída A
    • Dispositivo 0x40 - ignorado para este desafio.
    • 0x80 Reservado - ignorado para este desafio.
    • Como se trata de uma máscara de bits, vários sinalizadores são possíveis - todas as saídas aplicáveis ​​devem ser concatenadas juntas em qualquer ordem. Por exemplo, 0xffpoderia ser ROHSVLSDA(ou qualquer outra combinação).
  • Os próximos dois bytes (0x0c e 0x0d) não são usados ​​no MS-DOS 5.0.
  • Os próximos dois bytes (0x0e e 0x0f) são o horário de criação da seguinte maneira:
    • Os bits 15 a 11 são as horas no formato de 24 horas - saída 00 a 23
    • Os bits 10 a 5 são os minutos - saída 00 a 59
    • Os bits 4 a 0 são os segundos / 2 - saída de 00 a 58 (observe que os segundos estão apenas na resolução de dois segundos)
    • Para esclarecimento: hhhhhmmmmmmsssssquando escrito big-endian.
  • Os próximos dois bytes (0x10 e 0x11) são a data de criação da seguinte maneira:
    • Os bits 15 a 9 são o ano - produção em 1980 para 0até 2107 para127
    • Os bits 8 a 5 são os meses - saída 1 a 12 (com ou sem zero inicial)
    • Os bits 4 a 0 são o dia - saída 0 a 31 (com ou sem zero inicial)
    • Para esclarecimento: yyyyyyymmmmdddddquando escrito big-endian.
  • Os próximos dois bytes (0x12 e 0x13) são a última data de acesso. Enquanto usado no MS-DOS 5.0, estamos ignorando esta parte desse desafio.
  • Os próximos dois bytes (0x14 e 0x15) não são usados ​​pelo MS-DOS 5.0.
  • Os próximos dois bytes (0x16 e 0x17) são a hora da última modificação, seguindo o mesmo formato da hora de criação, acima.
  • Os próximos dois bytes (0x18 e 0x19) são a data da última modificação, seguindo o mesmo formato da data de criação acima.
  • Os próximos dois bytes (0x1a e 0x1b) são o local do cluster do arquivo no disco. Estamos ignorando esta parte deste desafio.
  • Os quatro bytes finais (0x1c, 0x1d, 0x1e e 0x1f) são o tamanho do arquivo - produzido como um número inteiro não assinado , a menos que os sinalizadores VL ou SD estejam definidos (acima), nesse caso, saída 0.

Representação visual

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

Entrada

  • Uma única palavra de 32 bytes (ou seja, 256 bits), em qualquer formato que seja conveniente.
    • Pode ser uma string 1e 0, como vários ints não assinados , uma matriz de valores booleanos, etc.
    • Especifique na sua resposta qual formato você está usando para entrada.
    • Você não pode receber várias entradas (ou seja, uma matriz pré-dividida nos tamanhos de bytes relevantes), a menos que seja a única maneira de o seu idioma receber entradas. Analisar a entrada faz parte do desafio.
  • Você pode assumir que a entrada é válida (por exemplo, não é necessário executar a verificação da data para verificar se a data é válida).
  • Os bytes não utilizados podem ser todos 0, todos 1etc., desde que estejam presentes. Nos exemplos abaixo, usei tudo 0para os bytes não utilizados.

Saída

Impresso em tela ou retornado, o seguinte:

  • O nome do arquivo como uma sequência ASCII
  • O arquivo atribui como uma sequência ASCII
  • O horário e a data de criação, com separadores apropriados (dois pontos, barras, algo para distinguir os componentes)
  • A hora e data da modificação, novamente com separadores apropriados
  • O tamanho do arquivo

A saída pode ser uma cadeia única separada por espaço ou nova linha, elementos separados em uma matriz, etc. Especifique na sua resposta como a saída é formatada.

Regras

  • Formatos de E / S padrão são aceitáveis.
  • Um programa completo ou uma função são aceitáveis.
  • As brechas padrão são proibidas.
  • Isso é , então todas as regras usuais de golfe se aplicam e o código mais curto vence.
  • Os internos que executam exatamente essa função são proibidos.

Exemplos

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
AdmBorkBork
fonte
Tudo bem se houver excesso de espaço em branco ao redor das bandeiras? Por exemplo, seria SD Sum conjunto de sinalizadores válido?
Morgan Thrapp
@MorganThrapp Claro, isso deve ficar bem.
AdmBorkBork
Por curiosidade, você teve muita experiência em interagir com o MS-DOS 5.0 naquela época ou estava realmente entediado na Wikipedia um dia?
cat
3
@cat Alguns dos dois. Eu tenho um grande interesse em computadores desde os 5 anos de idade e recebi um Commodore VIC-20. Um dos meus projetos de ciências da computação em nível de graduação há cerca de 10 anos era construir nosso próprio sistema de arquivos, então pesquisei bastante sobre isso. Por isso, peguei um monte do Wiki e reduzi-o a algo que poderia ser um desafio.
AdmBorkBork

Respostas:

6

Verilog, 513 670 617 bytes

Executa usando IVerilog. Não são necessários sinalizadores especiais de compilação.

Este é um monstro de definições aninhadas, manipulação de bits e o incômodo de ter que inverter a ordem dos bits devido à persistência (caso contrário, a sequência não será impressa ou a ordem dos bits numéricos estará incorreta). A entrada é feita através da iporta, que é a maneira usual de levar a entrada para um módulo Verilog. $displayé usado para imprimir na saída padrão. 6 bytes poderiam ser salvos se zeros à esquerda não fossem necessários para o registro de data e hora.

`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

Demo

Testbench (Não pontuado):

`timescale 1ns / 1ps

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

endmodule

Exemplo de execução:

$ 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
ζ--
fonte
5

Python, 485, 479, 442, 438, 431, 429, 418, 402, 395, 391 , 370 bytes.

Economizei 19 bytes graças a Cᴏɴᴏʀ O'Bʀɪᴇɴ, lembrando-me que posso atribuir funções a uma letra.

Economizou 6 bytes graças à sugestão de FryAmTheEggman de limpar o filtro de máscaras de bits.

Economizei 21 bytes graças à incrível resposta Ruby de W0lf, forçando-me a resolver isso um pouco mais. ;)

Este é um monstro absoluto. Tenho certeza de que posso reduzi-lo um pouco mais, mas está ficando bem perto de ser jogado fora.

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)))
Morgan Thrapp
fonte
talvez você possa atribuir inta um char? ou talvez faça uma função que executa str int.
Conor O'Brien
@ CᴏɴᴏʀO'Bʀɪᴇɴ Boa ideia!
Morgan Thrapp
O espaço entre eles or 'SD'pode ser removido, eu acho #
Conor O'Brien
@ CᴏɴᴏʀO'Bʀɪᴇɴ Sim, acabou de fazer isso.
Morgan Thrapp
Uau. Um pouco mais curto do que eu esperava que as respostas fossem.
AdmBorkBork
4

Haskell, 781 710 bytes

Obrigado ao BlackCap por algumas simplificações

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

Isso também permite que o lixo (como um caractere de nova linha) apareça após a entrada.

Raposa
fonte
Tenho algumas frutas penduradas baixas: pastebin.com/X69jH75f
BlackCap 22/09/16
3

Java, 1721 1587 1573 1560 1511 bytes:

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

Recebe entrada no formato de sequência binária de 32 bytes. Saídas no formato de uma sequência separada por espaço. Esta pode ser uma resposta muito, muito longa, mas ainda não estou decepcionada. Estou feliz por poder implementar isso em Java. Ainda vou tentar jogar isso o máximo que puder.

Experimente Online! (Ideona)

R. Kap
fonte
1
+1 porque usando Java para problemas de baixo nível é agradavelmente irônico (muito parecido com o meu Haskell)
Fox
2

Ruby, 344 bytes

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

A versão um pouco mais legível está disponível aqui .

Teste on-line: http://ideone.com/Fww1Rw

Cristian Lupascu
fonte
1
Agradável! Parece que preciso jogar fora outros 27 bytes. ;)
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]

Menos golfe

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

Teste

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>

edc65
fonte
Ok, então eu apenas executei isso no Safari e consegui Script error.. Mas, por alguma razão, no Firefox, parece funcionar perfeitamente. Pergunto-me porquê ...
R. Kap
@ R.Kap provavelmente o Safari é menos compatível com ES6 que o Firefox. kangax.github.io/compat-table/es6
edc65
2

PHP ,301 288 bytes

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

Experimente online!

Input é uma cadeia de palavras de 32 bytes via STDIN, saída para STDOUT.

-13 bytes como um programa independente.

640KB
fonte
2

Stax , 111 bytes

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

Execute e depure

recursivo
fonte
Opa, meu erro. Eu vou fazer uma correção.
recursivo em
1
Está funcionando corretamente agora ao custo de 3 bytes.
recursivo em
1

Perl, 249 bytes

Toma 32 bytes como entrada, a saída é separada por novas linhas. unpacké perfeito para esse tipo de análise de estrutura binária.

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

Alguns destaques:

  • O mencionado acima unpack.
  • O operador tartaruga @{[]}permite interpolar o código em uma string. Na verdade, ele cria uma referência de matriz que é desreferenciada.
  • "$str1"x!!$str2é uma boa maneira de retornar $str1apenas se $str2for uma string não vazia.

Abaixo está uma versão que funciona em entradas de diretório real, com campos little endian, e apenas ignorando o preenchimento correto no nome do arquivo e na extensão (por exemplo " ppcg", não tem seu espaço em branco inicial removido) (254 bytes)

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