1 // streaming file system (virtual)
2 {$MODE DELPHI}
3 {.$R-}
6 interface
8 uses
12 type
21 public
23 fPath: TSFSString; // ðàçäåëèòåëè êàòàëîãîâ -- "/"; êîðåíü íèêàê íå îáîçíà÷åí, åñëè íå ïóñòîå, îáÿçàíî çàâåðøàåòñÿ "/"
36 // âèðòóàëüíàÿ ôàéëîâàÿ ñèñòåìà. ÒÎËÜÊÎ ÄËß ×ÒÅÍÈß!
37 // òîì ÍÅ ÄÎËÆÅÍ óáèâàòüñÿ íèêàê èíà÷å, ÷åì ïðè ïîìîùè ôàáðèêè!
39 protected
45 // ïðèøèáèòü âñå ñòðóêòóðû.
46 // íå äîëæíà ïàäàòü, åñëè å¸ âûçûâàþò íåñêîëüêî ðàç.
49 // âûçûâàåòñÿ èç DoDirectoryRead() äëÿ çàïîëíåíèÿ ñïèñêà ôàéëîâ.
50 // ñ÷èòàåòñÿ, ÷òî âñå ìàãèêè óæå ïðîâåðåíû è ôàéë òî÷íî íàø.
51 // fFileName, fFileStream óæå óñòàíîâëåíû, fFiles ñîçäàí,
52 // â í¸ì, ñêîðåå âñåãî, íèêîãî íåò.
53 // ïîçèöèÿ ïîòîêà -- òà, ÷òî îñòàâèëà ôàáðèêà.
54 // ïðè îøèáêàõ êèäàòü èñêëþ÷åíèå, òîãäà òîì áóäåò ïðèáèò ôàáðèêîé.
55 // ðàçäåëèòåëè ïóòåé äîëæíû áûòü òîëüêî "/", êîðíåâîé "/" äîëæåí
56 // áûòü îïóùåí, ïóòè (åñëè íå ïóñòûå) äîëæíû çàâåðøàòüñÿ "/"!
57 // fName äîëæíî ñîäåðæàòü òîëüêî èìÿ, fPath -- òîëüêî ïóòü.
58 // â ïðèíöèïå, îá ýòîì ïîçàáîòèòñÿ DoDirectoryRead(), íî çà÷åì
59 // äàâàòü åìó ëèøíþþ ðàáîòó?
62 // íàéòè ôàéë, âåðíóòü åãî èíäåêñ â fFiles.
63 // ýòà ïðîöåäóðà ìîæåò ìåíÿòü fFiles!
64 // fPath -- â ïðàâèëüíîé ôîðìå, ñ "/", êîðíåâîé "/" óáèò, ôèíàëüíûé äîáàâëåí.
65 // åñëè ôàéë íå íàéäåí, âåðíóòü -1.
68 // âîçâðàùàåò êîëè÷åñòâî ôàéëîâ â fFiles
71 // âîçâðàùàåò ôàéë ñ èíäåêñîì index.
72 // ìîæåò âîçâðàùàòü NIL.
73 // íèêàêèõ ïàäåíèé íà íåïðàâèëüíûå èíäåêñû!
78 public
79 // pSt íå îáÿçàòåëüíî çàïîìèíàòü, åñëè îí íå íóæåí.
81 // fFileStream óíè÷òîæàòü íåëüçÿ, åñëè îí ðàâåí ïàðàìåòðó pSt êîíñòðóêòîðà.
84 // âûçûâàåò ReadDirectory().
85 // ýòà ïðîöåäóðà ñàìà ðàçáåð¸òñÿ ñ äóáëèêàòàìè èì¸í: ïîäîáàâëÿåò â
86 // êîíåö èì¸í-äóáëèêàòîâ ïîä÷¸ðêèâàíèå è äåñÿòè÷íûé íîìåð.
87 // òàêæå îíà íîðìàëèçóåò âèä èì¸í.
90 // ïðè îøèáêàõ êèäàòüñÿ èñêëþ÷åíèÿìè.
93 // åñëè íå ñìîãëî îòêóïîðèòü ôàéëî (èëè åù¸ ãäå îøèáëîñü), çàøâûðí¸ò èñêëþ÷åíèå.
97 // ìîæåò âîçâðàùàòü NIL.
98 // íèêàêèõ ïàäåíèé íà íåïðàâèëüíûå èíäåêñû!
102 // ôàáðèêà òîìîâ. âñå SFS ïðè ñòàðòå äîáàâëÿþò ñâîè ôàáðèêè.
103 // áëàãîäàðÿ ýòîìó ìîæíî ñîçäàâàòü ðàçíûå âñÿêèå SFS ñòàíäàðòíûì
104 // âûçîâîì ñòàíäàðòíîé ïðîöåäóðû.
105 // ôàáðèêà ÍÅ ÄÎËÆÍÀ óáèâàòüñÿ íèêàê èíà÷å, ÷åì ïðè ïîìîùè âûçîâà
106 // SFSUnregisterVolumeFactory()! ýòî ãàðàíòèðóåò, ÷òî äâèæîê
107 // ïåðåä ðàññòðåëîì îòäàñò åé âñå å¸ òîìà.
109 public
110 // åñëè äîáàâëÿåì ôàéë äàííûõ ôàéë ñ èìåíåì òèïà "zip:....", òî
111 // SFS èçâëå÷¸ò ýòî "zip" è ïåðåäàñò â ñèþ ôóíêöèþ.
112 // åæåëè ôóíêöèÿ âåðí¸ò ïðàâäó, òî SFS âûçîâåò Produce äëÿ äàííîãî
113 // ôàéëà. åñëè íè îäíà ôàáðèêà ïðåôèêñ íå ïðèçíàåò, òî ôàéë íå îòêðîþò.
114 // èñïîëüçóåòñÿ äëÿ ñêèïàíèÿ àâòîäåòåêòà.
115 // SFS ÍÅ Ñ×ÈÒÀÅÒ ÏÐÅÔÈÊÑÎÌ ÑÒÐÎÊÓ ÊÎÐÎ×Å ÒÐ¨Õ ÑÈÌÂÎËÎÂ!
117 // ïðîâåðÿåò, ìîæåò ëè ôàáðèêà ñäåëàòü òîì äëÿ äàííîãî ôàéëà.
118 // st -- îòêðûòûé äëÿ ÷òåíèÿ ôàéëîâé ïîòîê. óêàçàòåëü ÷òåíèÿ ñòîèò â íà÷àëå.
119 // ýòîò ïîòîê íåëüçÿ çàêðûâàòü!
120 // prefix: òî, ÷òî áûëî ïåðåäàíî â IsMyVolumePrefix() èëè ''.
121 // èñêëþ÷åíèå ñ÷èòàåòñÿ îøèáêîé, âîçâðàò NIL ñ÷èòàåòñÿ îøèáêîé.
122 function Produce (const prefix, fileName: TSFSString; st: TStream): TSFSVolume; virtual; abstract;
123 // êîãäà òîì áîëüøå íå íóæåí, îí áóäåò îòäàí ôàáðèêå íà ïåðåðàáîòêó.
124 // äàëåå äâèæîê íå áóäåò þçàòü ñåé òîì.
128 // "èòåðàòîð", âîçâðàùàåìûé SFSFileList()
130 protected
136 public
142 // ïðè íåïðàâèëüíîì èíäåêñå ìîë÷à âåðí¸ò NIL.
143 // ïðè ïðàâèëüíîì òîæå ìîæåò âåðíóòü NIL!
144 // î÷åíü íå ñîâåòóþ ìåíÿòü ñîäåðæèìîå ïîëó÷åííîãî êëàññà.
145 // êîíå÷íî, ÿ ìîã áû âîçâðàùàòü íîâóþ ñòðóêòóðó èëè íå÷òî ïîõîæåå,
146 // íî áëèí, åñëè òû èäèîò è íå óìååøü äàæå êîììåíòû ÷èòàòü, òî
147 // êàêîãî òû âîîáùå â ïðîãðàììèíã ïîëåç?
153 // ýòà ôóíêöèÿ àâòîìàòè÷åñêè ïðèáü¸ò factory.
156 // äîáàâèòü ñáîðíèê â ïîñòîÿííûé ñïèñîê.
157 // åñëè ñáîðíèê ñ òàêèì èìåíåì óæå îòêðûò, òî íå îòêðûâàåò åãî ïîâòîðíî.
158 // íèêîãäà íå êèäàåò èñêëþ÷åíèé.
159 // top: äîáàâèòü â íà÷àëî ñïèñêà ïîèñêà.
160 // âåðí¸ò ëîæü ïðè îøèáêå.
161 // ñïîñîáíî îòêðûâàòü ñáîðíèêè â ñáîðíèêàõ ïðè ïîìîùè êðóòûõ èì¸í a-la:
162 // "zip:pack0::pack:pack1::wad2:pack2".
163 // â äàëüíåéøåì ñëåäóåò îáðàùàòüñÿ ê ñáîðíèêó êàê "pack2::xxx".
164 // èëè ìîæíî íàïèñàòü:
165 // "zip:pack0::pack:pack1::wad2:pack2|datafile".
166 // è îáðàùàòüñÿ êàê "datafile::xxx".
167 // "||" ïðåîáðàçóþòñÿ â ïðîñòîé "|" è ðàçäåëèòåëåì íå ñ÷èòàþòñÿ.
168 // ïðèíèìàåòñÿ âî âíèìàíèå òîëüêî ïîñëåäíÿÿ òðóáà.
171 // äîáàâèòü â ïîñòîÿííûé ñïèñîê ñáîðíèê èç ïîòîêà ds.
172 // åñëè âîçâðàùàåò èñòèíó, òî SFS ñòàíîâèòñÿ âëÿäåëüöåì ïîòîêà ds è ñàìà
173 // óãðîáèò ñåé ïîòîê ïî íåîáõîäèìîñòè.
174 // virtualName ñòàíîâèòñÿ èìåíåì ñáîðíèêà äëÿ îïåðàöèè îòêðûòèÿ ôàéëà òèïà
175 // "packfile:file.ext".
176 // åñëè êàêîé-íèáóäü ñáîðíèê ñ èìåíåì virtualName óæå îòêðûò, âåðí¸ò false.
177 // íèêîãäà íå êèäàåò èñêëþ÷åíèé.
178 // top: äîáàâèòü â íà÷àëî ñïèñêà ïîèñêà.
179 // âåðí¸ò ëîæü ïðè îøèáêå.
180 // îòêðûâàåò ñáîðíèê èç ïîòîêà. dataFileName -- ÂÈÐÒÓÀËÜÍÎÅ èìÿ.
181 // ò.å. íà ñàìîì äåëå òàêîãî ôàéëà ìîæåò è íå áûòü íà äèñêå.
182 function SFSAddSubDataFile (const virtualName: TSFSString; ds: TStream; top: Boolean=false): Boolean;
184 // øâûðÿåòñÿ èñêëþ÷åíèÿìè.
185 // åñëè fName íå èìååò óêàçàíèÿ íà ôàéë äàííûõ (ýòî òî, ÷òî îòäåëåíî îò
186 // îñòàëüíîãî èìåíè äâîåòî÷èåì), òî èùåì ñíà÷àëà ïî âñåì çàðåãèñòðèðîâàííûì
187 // ôàéëàì äàííûõ, ïîòîì â òåêóùåì êàòàëîãå, ïîòîì â êàòàëîãå, îòêóäà ñòàðòîâàëè.
188 // åñëè íè÷åãî íå íàøëè, êèäàåì èñêëþ÷åíèå.
191 // ïðè îøèáêå -- NIL, è íèêàêèõ èñêëþ÷åíèé.
194 // âîçâðàùàåò NIL ïðè îøèáêå.
195 // ïîñëå èñïîëüçîâàíèÿ, íàòóðàëüíî, èòåðàòîð íàäî ãðîõíóòü %-)
199 // èãíîðèðóåò ðåãèñòð ñèìâîëîâ
202 // ðàçîáðàòü òîëñòîå èìÿ ôàéëà, âåðíóòü âèðòóàëüíîå èìÿ ïîñëåäíåãî ñïèñêà
203 // èëè ïóñòóþ ñòîðîêó, åñëè ñïèñêîâ íå áûëî.
206 // ïðåîáðàçîâàòü ÷èñëî â ñòðîêó, êðàñèâî ðàçáàâëÿÿ çàïÿòûìè
209 // `name` will be modified
210 // return `true` if file was found
213 // Wildcard matching
214 // this code is meant to allow wildcard pattern matches. tt is VERY useful
215 // for matching filename wildcard patterns. tt allows unix grep-like pattern
216 // comparisons, for instance:
217 //
218 // ? Matches any single characer
219 // + Matches any single characer or nothing
220 // * Matches any number of contiguous characters
221 // [abc] Matches a or b or c at that position
222 // [!abc] Matches anything but a or b or c at that position
223 // [a-e] Matches a through e at that position
224 //
225 // 'ma?ch.*' -Would match match.exe, mavch.dat, march.on, etc
226 // 'this [e-n]s a [!zy]est' -Would match 'this is a test', but would
227 // not match 'this as a yest'
228 //
233 // this will compare only last path element from sfspath
239 var
240 // ïðàâäà: ðàçðåøåíî èñêàòü ôàéëî íå òîëüêî â ôàéëàõ äàííûõ, íî è íà äèñêå.
242 // ïðàâäà: åñëè ôàéë íå ïðåôèêñîâàí, òî ñíà÷àëà èùåì ôàéëî íà äèñêå,
243 // ïîòîì â ôàéëàõ äàííûõ.
245 // ïðàâäà: äàæå äëÿ ïðåôèêñîâàíûõ ôàéëîâ ñíà÷àëà ïðîñìîòðèì äèñê
246 // (åñëè óñòàíîâëåí ôëàæîê sfsDiskFirst è sfsDiskEnabled).
248 // ñïèñîê äèñêîâûõ êàòàëîãîâ äëÿ ïîèñêà ôàéëà. åñëè ïóñò -- èùåì òîëüêî â
249 // òåêóùåì. êàòàëîãè ðàçäåëÿþòñÿ òðóáîé ("|").
250 // <currentdir> çàìåíÿåòñÿ íà òåêóùèé êàòàëîã (ñ çàâåðøàþùèì "/"),
251 // <exedir> çàìåíÿåòñÿ íà êàòàëîã, ãäå ñèäèò .EXE (ñ çàâåðøàþùèì "/").
255 implementation
257 uses
258 xstreams;
262 var
264 begin
268 begin
274 // `name` will be modified
276 var
279 begin
285 repeat
289 begin
292 exit;
301 const
302 // character defines
314 begin
315 result :=
323 function MatchMask (const pattern: TSFSString; p, pend: Integer; const text: TSFSString; t, tend: Integer): Boolean;
324 var
328 begin
329 // sanity checks
335 begin
337 begin
338 // no more text. check if there's no more chars in pattern (except "*" & "+")
343 exit;
346 WILD_CHAR_SINGLE: ;
347 WILD_CHAR_ESCAPE:
348 begin
353 WILD_CHAR_RANGE_OPEN:
354 begin
362 repeat
368 begin
372 begin
374 end
376 end
381 // skip the rest or the range
385 WILD_CHAR_SINGLE_OR_NONE:
386 begin
390 exit;
392 WILD_CHAR_MULTI:
393 begin
397 begin
401 exit;
412 begin
419 var
421 begin
427 begin
429 begin
431 begin
438 begin
448 type
454 fPermanent: Boolean; // èñòèíà -- íå áóäåò óãðîáëåíà, åñëè íå îñòàíåòñÿ íè îäíîãî îòêðûòîãî òîìà
455 // èñòèíà -- ýòîò òîì áûë ñîçäàí èç ïîòîêà è íå èìååò äèñêîâîãî ôàéëà, ïîòîìó ôàáðèêå áóäåò ïåðåäàíî íå èìÿ ñáîðíèêà, à ïóñòàÿ ñòðîêà
463 protected
466 public
472 var
477 // ðàçáèòü èìÿ ôàéëà íà ÷àñòè: ïðåôèêñ ôàéëîâîé ñèñòåìû, èìÿ ôàéëà äàííûõ,
478 // ñîáñòâåííî èìÿ ôàéëà
479 // èìÿ âûãëÿäèò êàê:
480 // (("sfspfx:")?"datafile::")*"filename"
482 var
484 begin
487 begin
492 else
493 begin
499 // ñàéäýôôåêò: âûðåçàåò âèðòóàëüíîå èìÿ èç dataFile.
501 var
503 begin
506 begin
509 begin
511 else
512 begin
515 break;
522 // ðàçáèòü èìÿ ñáîðíèêà íà ÷àñòè: ïðåôèêñ ôàéëîâîé ñèñòåìû, èìÿ ôàéëà äàííûõ,
523 // âèðòóàëüíîå èìÿ. åñëè âèðòóàëüíîãî èìåíè íå äàíî, îíî áóäåò ðàâíî dataFile.
524 // èìÿ âûãëÿäèò êàê:
525 // [sfspfx:]datafile[|virtname]
526 // åñëè ïåðåä äâîåòî÷èåì ìåíüøå òð¸õ áóêâ, òî ýòî ñ÷èòàåòñÿ íå ïðåôèêñîì,
527 // à èìåíåì äèñêà.
529 var
531 begin
534 else
535 begin
542 // íàéòè ïðîèçâîäèòåëÿ äëÿ ýòîãî ôàéëà (åñëè ôàéë óæå îòêðûò).
543 // onlyPerm: òîëüêî "ïîñòîÿííûå" ïðîèçâîäèòåëè.
545 var
548 begin
551 begin
553 begin
556 begin
558 begin
560 exit;
569 // íàéòè èíôó äëÿ ýòîãî òîìà.
570 // õîðîøåå èìÿ, ïðàâäà? %-)
572 begin
575 begin
577 begin
585 begin
587 begin
589 end
590 else
591 begin
593 begin
595 end
596 else
597 begin
608 var
610 begin
611 //result := (AnsiCompareText(s0, s1) == 0);
615 begin
621 // this will compare only last path element from sfspath
623 {var
624 i: Integer;}
625 begin
627 (*
628 if not result and (length(sfspath) > 1) then
629 begin
630 i := length(sfspath);
631 while i > 1 do
632 begin
633 while (i > 1) and (sfspath[i-1] <> '/') do Dec(i);
634 if i <= 1 then exit;
635 writeln('{', sfspath, '} [', Copy(sfspath, i, length(sfspath)), '] : [', path, ']');
636 result := SFSStrEqu(Copy(sfspath, i, length(sfspath)), path);
637 end;
638 end;
639 *)
642 // adds '/' too
644 var
646 begin
650 begin
652 begin
654 continue;
657 begin
659 end
660 else
661 begin
670 var
672 begin
675 begin
677 begin
678 // avoid unnecessary string changes
685 var
688 begin
690 repeat
698 { TVolumeInfo }
700 var
703 begin
710 // òèïà ìóñîðîñáîðíèê: åñëè íàø ïîòîê áîëåå íèêåì íå þçàåòñÿ, òî óãðîáèòü åãî íàôèã
712 begin
716 begin
718 begin
721 begin
734 { TOwnedPartialStream }
737 begin
744 var
746 begin
749 begin
752 begin
760 { TSFSFileInfo }
762 begin
773 begin
779 { TSFSVolume }
781 begin
790 begin
794 var
798 begin
804 begin
806 // normalize name & path
813 begin
814 // split path and name
826 begin
833 begin
839 begin
841 else
842 begin
845 begin
848 begin
858 begin
863 begin
865 else
866 begin
873 var
876 begin
878 // normalize name, find split position
882 begin
895 { TSFSFileList }
897 var
899 begin
909 var
911 begin
916 // óáü¸ì çàïèñü, åñëè îíà âðåìåííàÿ, è â íåé íåò áîëüøå íè÷åãî îòêðûòîãî
923 begin
928 begin
935 var
937 begin
946 var
949 begin
954 begin
962 function SFSAddDataFileEx (dataFileName: TSFSString; ds: TStream; top, permanent: Integer): Integer;
963 // dataFileName ìîæåò èìåòü ïðåôèêñ òèïà "zip:" (ñì. âûøå: IsMyPrefix).
964 // ìîæåò âûêèíóòü èñêëþ÷åíèå!
965 // top:
966 // <0: äîáàâèòü â íà÷àëî ñïèñêà ïîèñêà.
967 // =0: íå ìåíÿòü.
968 // >0: äîáàâèòü â êîíåö ñïèñêà ïîèñêà.
969 // permanent:
970 // <0: ñîçäàòü "âðåìåííûé" òîì.
971 // =0: íå ìåíÿòü ôëàæîê ïîñòîÿíñòâà.
972 // >0: ñîçäàòü "ïîñòîÿííûé" òîì.
973 // åñëè ds <> nil, òî ñîçäà¸ò ñáîðíèê èç ïîòîêà. åñëè ñáîðíèê ñ èìåíåì
974 // dataFileName óæå çàðåãèñòðèðîâàí, òî ïàäàåò íàôèã.
975 // âîçâðàùàåò èíäåêñ â volumes.
976 // óìååò äåëàòü ðåêóðñèþ.
977 var
985 begin
988 begin
989 // ðåêóðñèâíîå îòêðûòèå.
990 // ðàçîáü¸ì dataFileName íà èìÿ ñáîðíèêà è îñòàòîê.
991 // pfx áóäåò èìåíåì ñáîðíèêà, dataFileName -- îñòàòêîì.
993 // ñíà÷àëà îòêðîåì ïåðâûé ñïèñîê...
995 // ...òåïåðü ïðîäîëæèì ñ îñòàòêîì.
996 // óçíàåì, êàêîå ôàéëî îòêðûâàòü.
997 // âûêîâûðÿåì ïåðâûé "::" ïðåôèêñ (ýòî áóäåò èìÿ ôàéëà).
1000 // dataFileName õðàíèò îñòàòîê.
1001 // èçâëå÷¸ì èìÿ ôàéëà:
1003 // îòêðîåì ýòîò ôàéë
1005 try
1008 except
1010 // óäàëèì íåèñïîëüçóåìûé âðåìåííûé òîì.
1014 // óðà. îòêðûëè ôàéë. êèäàåì â âîçäóõ ÷åï÷èêè, ïðîäîëæàåì ðàçâëå÷åíèå.
1016 try
1019 except
1023 exit;
1026 // îáûêíîâåííîå íåðåêóðñèâíîå îòêðûòèå.
1031 begin
1038 exit;
1048 try
1050 begin
1055 try
1058 except
1064 except
1070 try
1072 begin
1075 end
1077 except
1095 var
1097 begin
1099 try
1103 except
1109 var
1111 begin
1112 try
1116 except
1123 var
1126 begin
1129 begin
1140 begin
1145 end
1151 var
1159 // ïðîâåðèì, åñòü ëè ôàëî fn ãäå-òî íà äèñêàõ.
1160 var
1163 begin
1170 begin
1176 try
1178 exit;
1179 except
1184 begin
1191 begin
1192 // ïðåôèêñîâàíûé ôàéë
1194 begin
1202 try
1205 except
1210 exit;
1212 //Inc(vi.fOpenedFilesCount);
1214 exit;
1217 // íåïðåôèêñîâàíûé ôàéë
1219 begin
1223 // èùåì ïî âñåì ïåðìàíåíòíûì ïðåôèêñàì
1226 begin
1229 begin
1231 begin
1234 begin
1235 try
1238 //Inc(vi.fOpenedFilesCount);
1239 except
1253 begin
1254 try
1256 except
1262 var
1265 begin
1269 try
1271 except
1272 exit;
1276 try
1279 except
1285 initialization
1288 //finalization
1289 //volumes.Free(); // it fails for some reason... Runtime 217 (^C hit). wtf?!
1290 //factories.Free(); // not need to be done actually...