Розшифруйте запис каталогу Microsoft MS-DOS 5.0 FAT


27

Файлова система Microsoft FAT має таблицю каталогів, яка відображає, які "файли" є, в яких "папках" на диску. За цей час ці записи набивали багато інформації невеликою кількістю біт. У Вікі є купа технічних специфікацій для допитливих, але тут завдання полягає в тому, щоб зосередитись на "простому" розшифровці запису.

Кожен запис складається з 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(або будь-яка інша комбінація).
  • Наступні два байти (0x0c та 0x0d) не використовуються в MS-DOS 5.0.
  • Наступні два байти (0x0e та 0x0f) - це час створення наступним чином:
    • Біти 15 - 11 - це години у 24-годинному форматі - вихід 00 - 23
    • Біти 10 - 5 - це хвилини - вихід 00 до 59
    • Біти 4 до 0 - це секунди / 2 - вихід 00 - 58 (зауважте, що секунди є лише у двох секундах)
    • Для уточнення: hhhhhmmmmmmsssssколи пишеться біг-ендіан.
  • Наступні два байти (0x10 та 0x11) - це дата створення наступним чином:
    • Біти від 15 до 9 - це рік - вихід 1980 для 0до 2107 для127
    • Біти 8 - 5 - це місяці - вихід 1 - 12 (з нульовим нулем або без нього)
    • Біти 4 до 0 - це день - вихід 0 до 31 (з нульовим нулем або без нього)
    • Для уточнення: yyyyyyymmmmdddddколи пишеться біг-ендіан.
  • Наступні два байти (0x12 та 0x13) - остання дата доступу. Під час використання в MS-DOS 5.0 ми ігноруємо цю частину для цього завдання.
  • Наступні два байти (0x14 та 0x15) не використовуються MS-DOS 5.0.
  • Наступні два байти (0x16 та 0x17) - це останній модифікований час, що відповідає тому ж формату, що і час створення.
  • Наступні два байти (0x18 та 0x19) - це остання змінена дата, що відповідає тому ж формату, що і дата створення.
  • Наступні два байти (0x1a та 0x1b) - це розташування кластера файлу на диску. Ми ігноруємо цю частину для цього виклику.
  • Останні чотири байти (0x1c, 0x1d, 0x1e і 0x1f) - це розмір файлу - виводиться як ціле число , яке не підписується , якщо не встановлені прапори VL або SD (вище), у цьому випадку виведіть 0.

Візуальне зображення

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

Вхідні дані

  • Одне 32-байтове слово (тобто 256 біт) у будь-якому зручному форматі.
    • Це може бути рядок 1і 0, як декілька безпідписаних ints, масив булевих значень тощо.
    • Будь ласка, вкажіть у своїй відповіді, який формат ви використовуєте для введення.
    • Ви не можете приймати кілька входів (тобто масив, попередньо розбитий на відповідні розміри байтів), якщо це не єдиний спосіб для вашої мови приймати дані. Розбір вводу є частиною завдання.
  • Ви можете вважати, що дані є дійсними (наприклад, вам не потрібно проводити перевірку дати, щоб перевірити, чи дата є дійсною).
  • Невикористаними байтами можуть бути всі 0, всі 1тощо, лише до тих пір, поки вони є. У наведених нижче прикладах я використовував усі 0для невикористаних байтів.

Вихідні дані

Будь-яка надрукована на екран або повернута нижче:

  • Ім'я файлу як рядок ASCII
  • Файл приписується як рядок ASCII
  • Час створення та дата створення, з відповідними роздільниками (колонки, косої риси, щось для розрізнення компонентів)
  • Змінений час та змінена дата, знову з відповідними роздільниками
  • Розмір файлу

Вихідний сигнал може бути розділеною пробілом або розділеною новою лінією однією рядком, окремими елементами в масиві тощо. Будь ласка, вкажіть у своїй відповіді, як форматується ваш вихід.

Правила

Приклади

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 років, і я отримав Commodore VIC-20. Один з моїх проектів з інформатики на рівні міста близько 10 років тому полягав у створенні власної файлової системи, тому я багато досліджував для цього. Для цього я витягнув купу з Вікі і склав її до чогось, що може стати викликом.
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ʀɪᴇɴ, що нагадує мені, що я можу призначити функції листу.

Збережено 6 байт завдяки пропозиції FryAmTheEggman очистити фільтр біткої маски.

Збережено 21 байт завдяки дивовижній відповіді Ruby від W0lf, яка змусила мене ще трохи пограти в цей гольф. ;)

Це абсолютне чудовисько. Досить впевнений, що я можу скоротити це трохи більше, але він дуже близький до того, що гольф.

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ʀɪᴇɴ Хороша ідея!
Морган Трапп

Простір між ними or 'SD'можна прибрати, я думаю
Conor O'Brien

@ 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)
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 байт. ;)
Морган Трапп

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, ймовірно, Safari менш сумісний із ES6, ніж Firefox. kangax.github.io/compat-table/es6
edc65

2

PHP ,301 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 байт як окрема програма.


2

Стакс , 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.