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

27

Файловая система Microsoft FAT имеет таблицу каталогов для представления, какие «файлы» находятся в каких «папках» на диске. Пока что эти записи втиснули много информации в небольшое количество битов. На 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 Hidden - выход H
    • 0x04 Система - выход S
    • 0x08 Volume Label - выходной ВЛ . Размер файла (ниже) должен быть выведен как 0 , независимо от его фактической записи.
    • Подкаталог 0x10 - вывод SD . Размер файла (ниже) должен быть выведен как 0 , независимо от его фактической записи.
    • 0x20 Архив - выход А
    • Устройство 0x40 - игнорируется для этой задачи.
    • 0x80 Reserved - игнорируется для этой задачи.
    • Поскольку это битовая маска, возможны несколько флагов - все применимые выходные данные должны объединяться вместе в любом порядке. Например, 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когда написано big-endian.
  • Следующие два байта (0x10 и 0x11) представляют собой дату создания следующим образом:
    • Биты 15 до 9 в год - выпуск 1980 для 0до 2107 для127
    • Биты с 8 по 5 - месяцы - выходные данные с 1 по 12 (с начальным нулем или без него)
    • Биты с 4 по 0 - это день - вывод от 0 до 31 (с или без нуля в начале)
    • Для пояснения: yyyyyyymmmmdddddкогда написано big-endian.
  • Следующие два байта (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, как несколько беззнаковых intс, массив значений булевых и т.д.
    • Пожалуйста, укажите в своем ответе, какой формат вы используете для ввода.
    • Вы не можете получить множественный ввод (т. Е. Массив, предварительно разбитый на соответствующие размеры в байтах), если только это не единственный способ для вашего языка принять ввод. Разбор входных данных является частью проблемы.
  • Вы можете предположить, что ввод действителен (например, вам не нужно выполнять проверку даты, чтобы убедиться, что дата действительна).
  • Неиспользуемые байты могут быть всеми 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
AdmBorkBork
источник
Это нормально, если вокруг флагов есть лишние пробелы? Например, будет SD Sли установлен правильный флаг?
Морган Трепп
@MorganThrapp Конечно, это должно быть хорошо.
AdmBorkBork
Из любопытства, у вас был большой опыт взаимодействия с MS-DOS 5.0 в тот день, или вы просто скучали по Википедии однажды?
кот
3
@cat Некоторые из них. Я был очень заинтересован в компьютерах с пяти лет и получил Commodore VIC-20. Около 10 лет назад одним из моих проектов в области компьютерных наук на уровне магистратуры было создание собственной файловой системы, поэтому я много для этого исследовал. Для этого я вытащил кучу из 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ʀɪᴇɴ, напомнившему мне, что я могу назначать функции письму.

Сохранено 6 байтов благодаря предложению FryAmTheEggman очистить фильтр битовой маски.

Сэкономили 21 байт благодаря удивительному ответу W0lf на Ruby, заставившему меня еще немного поиграть в гольф. ;)

Это абсолютный монстр. Уверен, я смогу сократить это немного больше, но это довольно близко к игре в гольф.

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.
Конор О'Брайен
@ 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

Ява, 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. Я все еще буду стараться играть в гольф столько, сколько смогу.

Попробуйте онлайн! (Ideone)

Р. Кап
источник
1
+1, потому что использование Java для задач низкого уровня приятно иронично (так же, как мой Haskell)
Fox
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>

edc65
источник
Хорошо, я просто запустил это в 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 байт как отдельная программа.

640 КБ
источник
2

Stax , 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
ninjalj
источник