Decodificar una entrada de directorio FAT de Microsoft MS-DOS 5.0

27

El sistema de archivos FAT de Microsoft tiene una tabla de directorio para representar qué "archivos" están en qué "carpetas" en el disco. Por el momento, estas entradas concentraron mucha información en una pequeña cantidad de bits. Hay un montón de especificaciones técnicas en Wiki para los curiosos, pero el desafío aquí se centrará en una decodificación "simple" de una entrada.

Cada entrada consta de una palabra binaria de 32 bytes, dividida en varias secciones. Para mantener la coherencia en este desafío, utilizaremos la versión 5.0 de MS-DOS, los bytes se ordenan como big endian y llamamos byte 0x00como el más a la izquierda y byte 0x1Fcomo el más a la derecha.

A continuación se muestra un breve esquema de las secciones relevantes y cuál debería ser el resultado de cada sección (en negrita ).

  • Los primeros 11 bytes son el nombre del archivo en formato ASCII (de aquí proviene el famoso nombre de archivo 8.3: 8 bytes para el nombre del archivo, 3 bytes para la extensión). Estas son codificaciones ASCII directas y deben enviarse como ASCII con un punto (.) Entre ellas .
    • Nota: tanto las partes 8 como las 3 están acolchadas con espacios para hacer una entrada de longitud completa. El resultado debe ignorar los espacios (es decir, no generarlos).
    • La extensión del archivo puede estar vacía (es decir, todos los espacios), en cuyo caso la salida no debería mostrar el punto .
    • Dado que ASCII solo usa los 7 bits inferiores, todos los bytes tendrán un inicio 0.
  • El siguiente byte (0x0b) es una máscara de bits de lo siguiente:
    • 0x01 Solo lectura - salida RO
    • 0x02 Oculto - salida H
    • Sistema 0x04 - salida S
    • 0x08 Etiqueta de volumen - salida VL . El tamaño del archivo (a continuación) debe aparecer como 0 , independientemente de su entrada real.
    • Subdirectorio 0x10 - salida SD . El tamaño del archivo (a continuación) debe aparecer como 0 , independientemente de su entrada real.
    • Archivo 0x20 - salida A
    • Dispositivo 0x40: ignorado para este desafío.
    • 0x80 reservado: ignorado para este desafío.
    • Como se trata de una máscara de bits, son posibles varios indicadores: todas las salidas aplicables se deben concatenar juntas en cualquier orden. Por ejemplo, 0xffpodría ser ROHSVLSDA(o cualquier otra combinación).
  • Los siguientes dos bytes (0x0c y 0x0d) no se utilizan en MS-DOS 5.0.
  • Los siguientes dos bytes (0x0e y 0x0f) son el tiempo de creación de la siguiente manera:
    • Los bits 15 a 11 son las horas en formato de 24 horas - salida 00 a 23
    • Los bits 10 a 5 son los minutos: salida 00 a 59
    • Los bits 4 a 0 son los segundos / 2 - salida 00 a 58 (tenga en cuenta que los segundos son solo en resolución de dos segundos)
    • Para aclarar: hhhhhmmmmmmssssscuando se escribe big-endian.
  • Los siguientes dos bytes (0x10 y 0x11) son la fecha de creación de la siguiente manera:
    • Los bits 15 a 9 son el año: salida 1980 para 0hasta 2107 para127
    • Los bits 8 a 5 son los meses: salida 1 a 12 (con o sin cero a la izquierda)
    • Los bits 4 a 0 son el día - salida 0 a 31 (con o sin cero a la izquierda)
    • Para aclarar: yyyyyyymmmmdddddcuando se escribe big-endian.
  • Los siguientes dos bytes (0x12 y 0x13) son la última fecha de acceso. Si bien se usa en MS-DOS 5.0, ignoramos esta parte para este desafío.
  • MS-DOS 5.0 no utiliza los siguientes dos bytes (0x14 y 0x15).
  • Los siguientes dos bytes (0x16 y 0x17) son la última hora modificada, siguiendo el mismo formato que la hora de creación, arriba.
  • Los siguientes dos bytes (0x18 y 0x19) son la última fecha de modificación, siguiendo el mismo formato que la fecha de creación, arriba.
  • Los siguientes dos bytes (0x1a y 0x1b) son la ubicación del clúster del archivo en el disco. Estamos ignorando esta porción para este desafío.
  • Los cuatro bytes finales (0x1c, 0x1d, 0x1e y 0x1f) son el tamaño del archivo, que se genera como un entero sin signo , a menos que se establezcan los indicadores VL o SD (arriba), en cuyo caso se generará 0.

Representación visual

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

Entrada

  • Una sola palabra de 32 bytes (es decir, 256 bits), en cualquier formato que sea conveniente.
    • Esto podría ser como una cadena de 1y 0, como varios ints sin signo , una matriz de valores booleanos, etc.
    • Especifique en su respuesta qué formato está utilizando para la entrada.
    • No puede tomar entradas múltiples (es decir, una matriz previamente dividida en los tamaños de bytes relevantes) a menos que esa sea la única forma en que su idioma pueda ingresar. Analizar la entrada es parte del desafío.
  • Puede suponer que la entrada es válida (por ejemplo, no necesita realizar una verificación de fecha para verificar que la fecha sea válida).
  • Los bytes que no se usan pueden ser todos 0, todos 1, etc., siempre que estén presentes. En los ejemplos a continuación, utilicé todo 0para los bytes no utilizados.

Salida

Ya sea impreso en pantalla o devuelto, lo siguiente:

  • El nombre del archivo como una cadena ASCII
  • El archivo se atribuye como una cadena ASCII
  • El tiempo de creación y la fecha de creación, con separadores apropiados (dos puntos, barras, algo para distinguir los componentes)
  • La hora modificada y la fecha modificada, nuevamente con los separadores apropiados
  • El tamaño del archivo

La salida puede ser una cadena individual separada por espacios o por líneas nuevas, elementos separados en una matriz, etc. Especifique en su respuesta cómo se formatea su salida.

Reglas

  • Los formatos estándar de E / S son aceptables.
  • Un programa completo o una función son aceptables.
  • Las lagunas estándar están prohibidas.
  • Este es el , por lo que se aplican todas las reglas habituales de golf y gana el código más corto.
  • Las incorporaciones que realizan exactamente esta función están prohibidas.

Ejemplos

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
fuente
¿Está bien si hay un exceso de espacio en blanco alrededor de las banderas? Por ejemplo, ¿ SD Ssería un conjunto de banderas válido?
Morgan Thrapp
@MorganThrapp Claro, eso debería estar bien.
AdmBorkBork
Por curiosidad, ¿tuviste mucha experiencia interactuando con MS-DOS 5.0 en el pasado, o un día estabas realmente aburrido en Wikipedia?
gato
3
@cat Algunos de los dos. He estado muy interesado en las computadoras desde que tenía 5 años y recibí un Commodore VIC-20. Uno de mis proyectos de informática de nivel de posgrado hace unos 10 años fue construir nuestro propio sistema de archivos, así que investigué mucho para eso. Para esto, saqué un montón de Wiki y lo reduje a algo que podría ser un desafío.
AdmBorkBork

Respuestas:

6

Verilog, 513 670 617 bytes

Se ejecuta con IVerilog. No se necesitan banderas especiales de compilación.

Este es un monstruo de definiciones anidadas, cambios de bits y la molestia de tener que cambiar el orden de los bits debido a la endianidad (de lo contrario, la cadena no se imprime o el orden de los números es incorrecto). La entrada se toma a través del ipuerto, que es la forma habitual de llevar la entrada a un módulo Verilog. $displayse utiliza para imprimir a la salida estándar. Se podrían guardar 6 bytes si los ceros iniciales no fueran necesarios para la marca de tiempo.

`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

Manifestación

Banco de pruebas (sin puntuación):

`timescale 1ns / 1ps

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

endmodule

Ejemplo de ejecución:

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

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

Ahorré 19 bytes gracias a Cᴏɴᴏʀ O'Bʀɪᴇɴ recordándome que puedo asignar funciones a una letra.

Guardado 6 bytes gracias a la sugerencia de FryAmTheEggman de limpiar el filtro de máscara de bits.

Ahorré 21 bytes gracias a la increíble respuesta de Ruby de W0lf que me obligó a jugar un poco más. ;)

Este es un monstruo absoluto. Estoy bastante seguro de que puedo reducirlo un poco más, pero se está acercando bastante 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)))
Morgan Thrapp
fuente
tal vez podrías asignar inta un personaje? o tal vez hacer una función que realice str int.
Conor O'Brien
@ CᴏɴᴏʀO'Bʀɪᴇɴ ¡Buena idea!
Morgan Thrapp
El espacio intermedio or 'SD'se puede eliminar, creo
Conor O'Brien
@ CᴏɴᴏʀO'Bʀɪᴇɴ Sí, acabo de hacer eso.
Morgan Thrapp
Guau. Bastante más corto de lo que esperaba que fueran las respuestas.
AdmBorkBork
4

Haskell, 781710 bytes

Gracias a BlackCap por alguna simplificación

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

Esto además permite que la basura (como un carácter de nueva línea) aparezca después de la entrada.

zorro
fuente
Te conseguí un poco de fruta: pastebin.com/X69jH75f
BlackCap
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()));}}

Toma entrada en el formato de cadena binaria de 32 bytes. Salidas en el formato de una cadena separada por espacios. Esta puede ser una respuesta muy larga, pero todavía no estoy decepcionado. Estoy feliz de haber podido implementar esto en Java. Sin embargo, todavía intentaré jugar al golf tanto como pueda.

¡Pruébelo en línea! (Ideone)

R. Kap
fuente
1
+1 porque usar Java para problemas de bajo nivel es agradablemente irónico (muy parecido a mi Haskell)
Fox
2

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

La versión ligeramente más legible está disponible aquí .

Prueba en línea: http://ideone.com/Fww1Rw

Cristian Lupascu
fuente
1
¡Buena esa! Parece que necesito jugar otros 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 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
  ]

Prueba

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
fuente
Ok, solo ejecuté esto en Safari y lo obtuve Script error.. Pero por alguna razón en Firefox parece funcionar perfectamente. Me pregunto por qué ...
R. Kap
@ R.Kap probablemente Safari sea menos compatible con ES6 que 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];

Pruébalo en línea!

La entrada es una cadena de palabras de 32 bytes vía STDIN, salida a STDOUT.

-13 bytes como un programa independiente.

640 KB
fuente
2

Stax , 111 bytes

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

Ejecutar y depurarlo

recursivo
fuente
Vaya, mi error. Arreglaré
recursivo
1
Funciona correctamente ahora a un costo de 3 bytes.
recursivo
1

Perl, 249 bytes

Toma 32 bytes como entrada, la salida está separada por nuevas líneas. unpackes perfecto para este tipo de análisis de estructura 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

Algunos puntos destacados:

  • Lo anterior unpack.
  • El operador de tortuga @{[]}permite interpolar código en una cadena. Realmente crea una referencia de matriz que luego se desreferencia.
  • "$str1"x!!$str2es una buena manera de regresar $str1solo si $str2es una cadena no vacía.

A continuación se muestra una versión que funciona en entradas de directorio reales, con campos little-endian, y solo ignora el relleno derecho en el nombre de archivo y la extensión (por lo tanto, por ejemplo " ppcg", no se elimina su espacio en blanco inicial) (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
fuente