1 // streaming file system (virtual)
2 {$MODE DELPHI}
3 {$R+}
4 {.$DEFINE SFS_VOLDEBUG}
7 interface
9 uses
13 type
19 public
21 fPath: AnsiString; // ðàçäåëèòåëè êàòàëîãîâ -- "/"; êîðåíü íèêàê íå îáîçíà÷åí, åñëè íå ïóñòîå, îáÿçàíî çàâåðøàòüñÿ "/"
34 // âèðòóàëüíàÿ ôàéëîâàÿ ñèñòåìà. ÒÎËÜÊÎ ÄËß ×ÒÅÍÈß!
35 // òîì ÍÅ ÄÎËÆÅÍ óáèâàòüñÿ íèêàê èíà÷å, ÷åì ïðè ïîìîùè ôàáðèêè!
37 protected
42 // ïðèøèáèòü âñå ñòðóêòóðû.
43 // íå äîëæíà ïàäàòü, åñëè å¸ âûçûâàþò íåñêîëüêî ðàç.
46 // âûçûâàåòñÿ èç DoDirectoryRead() äëÿ çàïîëíåíèÿ ñïèñêà ôàéëîâ.
47 // ñ÷èòàåòñÿ, ÷òî âñå ìàãèêè óæå ïðîâåðåíû è ôàéë òî÷íî íàø.
48 // fFileName, fFileStream óæå óñòàíîâëåíû, fFiles ñîçäàí,
49 // â í¸ì, ñêîðåå âñåãî, íèêîãî íåò.
50 // ïîçèöèÿ ïîòîêà -- òà, ÷òî îñòàâèëà ôàáðèêà.
51 // ïðè îøèáêàõ êèäàòü èñêëþ÷åíèå, òîãäà òîì áóäåò ïðèáèò ôàáðèêîé.
52 // ðàçäåëèòåëè ïóòåé äîëæíû áûòü òîëüêî "/", êîðíåâîé "/" äîëæåí
53 // áûòü îïóùåí, ïóòè (åñëè íå ïóñòûå) äîëæíû çàâåðøàòüñÿ "/"!
54 // fName äîëæíî ñîäåðæàòü òîëüêî èìÿ, fPath -- òîëüêî ïóòü.
55 // â ïðèíöèïå, îá ýòîì ïîçàáîòèòñÿ DoDirectoryRead(), íî çà÷åì
56 // äàâàòü åìó ëèøíþþ ðàáîòó?
59 // íàéòè ôàéë, âåðíóòü åãî èíäåêñ â fFiles.
60 // ýòà ïðîöåäóðà ìîæåò ìåíÿòü fFiles!
61 // fPath -- â ïðàâèëüíîé ôîðìå, ñ "/", êîðíåâîé "/" óáèò, ôèíàëüíûé äîáàâëåí.
62 // åñëè ôàéë íå íàéäåí, âåðíóòü -1.
65 // âîçâðàùàåò êîëè÷åñòâî ôàéëîâ â fFiles
68 // âîçâðàùàåò ôàéë ñ èíäåêñîì index.
69 // ìîæåò âîçâðàùàòü NIL.
70 // íèêàêèõ ïàäåíèé íà íåïðàâèëüíûå èíäåêñû!
73 public
74 // pSt íå îáÿçàòåëüíî çàïîìèíàòü, åñëè îí íå íóæåí.
76 // fFileStream óíè÷òîæàòü íåëüçÿ, åñëè îí ðàâåí ïàðàìåòðó pSt êîíñòðóêòîðà.
79 // âûçûâàåò ReadDirectory().
80 // ýòà ïðîöåäóðà ñàìà ðàçáåð¸òñÿ ñ äóáëèêàòàìè èì¸í: ïîäîáàâëÿåò â
81 // êîíåö èì¸í-äóáëèêàòîâ ïîä÷¸ðêèâàíèå è äåñÿòè÷íûé íîìåð.
82 // òàêæå îíà íîðìàëèçóåò âèä èì¸í.
85 // ïðè îøèáêàõ êèäàòüñÿ èñêëþ÷åíèÿìè.
88 // åñëè íå ñìîãëî îòêóïîðèòü ôàéëî (èëè åù¸ ãäå îøèáëîñü), çàøâûðí¸ò èñêëþ÷åíèå.
92 // ìîæåò âîçâðàùàòü NIL.
93 // íèêàêèõ ïàäåíèé íà íåïðàâèëüíûå èíäåêñû!
97 // ôàáðèêà òîìîâ. âñå SFS ïðè ñòàðòå äîáàâëÿþò ñâîè ôàáðèêè.
98 // áëàãîäàðÿ ýòîìó ìîæíî ñîçäàâàòü ðàçíûå âñÿêèå SFS ñòàíäàðòíûì
99 // âûçîâîì ñòàíäàðòíîé ïðîöåäóðû.
100 // ôàáðèêà ÍÅ ÄÎËÆÍÀ óáèâàòüñÿ íèêàê èíà÷å, ÷åì ïðè ïîìîùè âûçîâà
101 // SFSUnregisterVolumeFactory()! ýòî ãàðàíòèðóåò, ÷òî äâèæîê
102 // ïåðåä ðàññòðåëîì îòäàñò åé âñå å¸ òîìà.
104 public
105 // åñëè äîáàâëÿåì ôàéë äàííûõ ôàéë ñ èìåíåì òèïà "zip:....", òî
106 // SFS èçâëå÷¸ò ýòî "zip" è ïåðåäàñò â ñèþ ôóíêöèþ.
107 // åæåëè ôóíêöèÿ âåðí¸ò ïðàâäó, òî SFS âûçîâåò Produce äëÿ äàííîãî
108 // ôàéëà. åñëè íè îäíà ôàáðèêà ïðåôèêñ íå ïðèçíàåò, òî ôàéë íå îòêðîþò.
109 // èñïîëüçóåòñÿ äëÿ ñêèïàíèÿ àâòîäåòåêòà.
110 // SFS ÍÅ Ñ×ÈÒÀÅÒ ÏÐÅÔÈÊÑÎÌ ÑÒÐÎÊÓ ÊÎÐÎ×Å ÒÐ¨Õ ÑÈÌÂÎËÎÂ!
112 // ïðîâåðÿåò, ìîæåò ëè ôàáðèêà ñäåëàòü òîì äëÿ äàííîãî ôàéëà.
113 // st -- îòêðûòûé äëÿ ÷òåíèÿ ôàéëîâé ïîòîê. óêàçàòåëü ÷òåíèÿ ñòîèò â íà÷àëå.
114 // ýòîò ïîòîê íåëüçÿ çàêðûâàòü!
115 // prefix: òî, ÷òî áûëî ïåðåäàíî â IsMyVolumePrefix() èëè ''.
116 // èñêëþ÷åíèå ñ÷èòàåòñÿ îøèáêîé, âîçâðàò NIL ñ÷èòàåòñÿ îøèáêîé.
117 function Produce (const prefix, fileName: AnsiString; st: TStream): TSFSVolume; virtual; abstract;
118 // êîãäà òîì áîëüøå íå íóæåí, îí áóäåò îòäàí ôàáðèêå íà ïåðåðàáîòêó.
119 // äàëåå äâèæîê íå áóäåò þçàòü ñåé òîì.
123 // "èòåðàòîð", âîçâðàùàåìûé SFSFileList()
125 protected
131 public
137 // ïðè íåïðàâèëüíîì èíäåêñå ìîë÷à âåðí¸ò NIL.
138 // ïðè ïðàâèëüíîì òîæå ìîæåò âåðíóòü NIL!
139 // î÷åíü íå ñîâåòóþ ìåíÿòü ñîäåðæèìîå ïîëó÷åííîãî êëàññà.
140 // êîíå÷íî, ÿ ìîã áû âîçâðàùàòü íîâóþ ñòðóêòóðó èëè íå÷òî ïîõîæåå,
141 // íî áëèí, åñëè òû èäèîò è íå óìååøü äàæå êîììåíòû ÷èòàòü, òî
142 // êàêîãî òû âîîáùå â ïðîãðàììèíã ïîëåç?
148 // ýòà ôóíêöèÿ àâòîìàòè÷åñêè ïðèáü¸ò factory.
151 // äîáàâèòü ñáîðíèê â ïîñòîÿííûé ñïèñîê.
152 // åñëè ñáîðíèê ñ òàêèì èìåíåì óæå îòêðûò, òî íå îòêðûâàåò åãî ïîâòîðíî.
153 // íèêîãäà íå êèäàåò èñêëþ÷åíèé.
154 // top: äîáàâèòü â íà÷àëî ñïèñêà ïîèñêà.
155 // âåðí¸ò ëîæü ïðè îøèáêå.
156 // ñïîñîáíî îòêðûâàòü ñáîðíèêè â ñáîðíèêàõ ïðè ïîìîùè êðóòûõ èì¸í a-la:
157 // "zip:pack0::pack:pack1::wad2:pack2".
158 // â äàëüíåéøåì ñëåäóåò îáðàùàòüñÿ ê ñáîðíèêó êàê "pack2::xxx".
159 // èëè ìîæíî íàïèñàòü:
160 // "zip:pack0::pack:pack1::wad2:pack2|datafile".
161 // è îáðàùàòüñÿ êàê "datafile::xxx".
162 // "||" ïðåîáðàçóþòñÿ â ïðîñòîé "|" è ðàçäåëèòåëåì íå ñ÷èòàþòñÿ.
163 // ïðèíèìàåòñÿ âî âíèìàíèå òîëüêî ïîñëåäíÿÿ òðóáà.
166 // äîáàâèòü ñáîðíèê âðåìåííî
169 // äîáàâèòü â ïîñòîÿííûé ñïèñîê ñáîðíèê èç ïîòîêà ds.
170 // åñëè âîçâðàùàåò èñòèíó, òî SFS ñòàíîâèòñÿ âëÿäåëüöåì ïîòîêà ds è ñàìà
171 // óãðîáèò ñåé ïîòîê ïî íåîáõîäèìîñòè.
172 // virtualName ñòàíîâèòñÿ èìåíåì ñáîðíèêà äëÿ îïåðàöèè îòêðûòèÿ ôàéëà òèïà
173 // "packfile:file.ext".
174 // åñëè êàêîé-íèáóäü ñáîðíèê ñ èìåíåì virtualName óæå îòêðûò, âåðí¸ò false.
175 // íèêîãäà íå êèäàåò èñêëþ÷åíèé.
176 // top: äîáàâèòü â íà÷àëî ñïèñêà ïîèñêà.
177 // âåðí¸ò ëîæü ïðè îøèáêå.
178 // îòêðûâàåò ñáîðíèê èç ïîòîêà. dataFileName -- ÂÈÐÒÓÀËÜÍÎÅ èìÿ.
179 // ò.å. íà ñàìîì äåëå òàêîãî ôàéëà ìîæåò è íå áûòü íà äèñêå.
180 function SFSAddSubDataFile (const virtualName: AnsiString; ds: TStream; top: Boolean=false): Boolean;
182 // øâûðÿåòñÿ èñêëþ÷åíèÿìè.
183 // åñëè fName íå èìååò óêàçàíèÿ íà ôàéë äàííûõ (ýòî òî, ÷òî îòäåëåíî îò
184 // îñòàëüíîãî èìåíè äâîåòî÷èåì), òî èùåì ñíà÷àëà ïî âñåì çàðåãèñòðèðîâàííûì
185 // ôàéëàì äàííûõ, ïîòîì â òåêóùåì êàòàëîãå, ïîòîì â êàòàëîãå, îòêóäà ñòàðòîâàëè.
186 // åñëè íè÷åãî íå íàøëè, êèäàåì èñêëþ÷åíèå.
189 // ïðè îøèáêå -- NIL, è íèêàêèõ èñêëþ÷åíèé.
192 // âîçâðàùàåò NIL ïðè îøèáêå.
193 // ïîñëå èñïîëüçîâàíèÿ, íàòóðàëüíî, èòåðàòîð íàäî ãðîõíóòü %-)
196 // çàïðåòèòü îñâîáîæäåíèå âðåìåííûõ òîìîâ (ìîæíî âûçûâàòü ðåêóðñèâíî)
199 // ðàçðåøèòü îñâîáîæäåíèå âðåìåííûõ òîìîâ (ìîæíî âûçûâàòü ðåêóðñèâíî)
202 // for completeness sake
207 // ðàçîáðàòü òîëñòîå èìÿ ôàéëà, âåðíóòü âèðòóàëüíîå èìÿ ïîñëåäíåãî ñïèñêà
208 // èëè ïóñòóþ ñòîðîêó, åñëè ñïèñêîâ íå áûëî.
211 // Wildcard matching
212 // this code is meant to allow wildcard pattern matches. tt is VERY useful
213 // for matching filename wildcard patterns. tt allows unix grep-like pattern
214 // comparisons, for instance:
215 //
216 // ? Matches any single characer
217 // + Matches any single characer or nothing
218 // * Matches any number of contiguous characters
219 // [abc] Matches a or b or c at that position
220 // [!abc] Matches anything but a or b or c at that position
221 // [a-e] Matches a through e at that position
222 //
223 // 'ma?ch.*' -Would match match.exe, mavch.dat, march.on, etc
224 // 'this [e-n]s a [!zy]est' -Would match 'this is a test', but would
225 // not match 'this as a yest'
226 //
232 var
233 // ïðàâäà: ðàçðåøåíî èñêàòü ôàéëî íå òîëüêî â ôàéëàõ äàííûõ, íî è íà äèñêå.
235 // ïðàâäà: åñëè ôàéë íå ïðåôèêñîâàí, òî ñíà÷àëà èùåì ôàéëî íà äèñêå,
236 // ïîòîì â ôàéëàõ äàííûõ.
238 // ïðàâäà: äàæå äëÿ ïðåôèêñîâàíûõ ôàéëîâ ñíà÷àëà ïðîñìîòðèì äèñê
239 // (åñëè óñòàíîâëåí ôëàæîê sfsDiskFirst è sfsDiskEnabled).
241 // ñïèñîê äèñêîâûõ êàòàëîãîâ äëÿ ïîèñêà ôàéëà. åñëè ïóñò -- èùåì òîëüêî â
242 // òåêóùåì. êàòàëîãè ðàçäåëÿþòñÿ òðóáîé ("|").
243 // <currentdir> çàìåíÿåòñÿ íà òåêóùèé êàòàëîã (ñ çàâåðøàþùèì "/"),
244 // <exedir> çàìåíÿåòñÿ íà êàòàëîã, ãäå ñèäèò .EXE (ñ çàâåðøàþùèì "/").
248 implementation
250 uses
254 const
255 // character defines
267 begin
268 result :=
276 function MatchMask (const pattern: AnsiString; p, pend: Integer; const text: AnsiString; t, tend: Integer): Boolean;
277 var
281 begin
282 // sanity checks
288 begin
290 begin
291 // no more text. check if there's no more chars in pattern (except "*" & "+")
296 exit;
299 WILD_CHAR_SINGLE: ;
300 WILD_CHAR_ESCAPE:
301 begin
306 WILD_CHAR_RANGE_OPEN:
307 begin
315 repeat
321 begin
325 begin
327 end
329 end
334 // skip the rest or the range
338 WILD_CHAR_SINGLE_OR_NONE:
339 begin
343 exit;
345 WILD_CHAR_MULTI:
346 begin
350 begin
354 exit;
365 begin
372 var
374 begin
380 begin
382 begin
384 begin
391 begin
401 type
407 fPermanent: Boolean; // èñòèíà -- íå áóäåò óãðîáëåíà, åñëè íå îñòàíåòñÿ íè îäíîãî îòêðûòîãî òîìà
408 // èñòèíà -- ýòîò òîì áûë ñîçäàí èç ïîòîêà è íå èìååò äèñêîâîãî ôàéëà, ïîòîìó ôàáðèêå áóäåò ïåðåäàíî íå èìÿ ñáîðíèêà, à ïóñòàÿ ñòðîêà
416 protected
419 public
425 var
432 var
436 begin
437 // collect garbage
440 begin
444 begin
445 // this volume probably can be removed
449 begin
451 begin
459 begin
460 {$IFDEF SFS_VOLDEBUG}writeln('000: destroying volume "', TVolumeInfo(volumes[f]).fPackName, '"');{$ENDIF}
464 continue;
472 begin
477 begin
480 begin
487 // ðàçáèòü èìÿ ôàéëà íà ÷àñòè: ïðåôèêñ ôàéëîâîé ñèñòåìû, èìÿ ôàéëà äàííûõ,
488 // ñîáñòâåííî èìÿ ôàéëà
489 // èìÿ âûãëÿäèò êàê:
490 // (("sfspfx:")?"datafile::")*"filename"
492 var
494 begin
497 begin
502 else
503 begin
509 // ñàéäýôôåêò: âûðåçàåò âèðòóàëüíîå èìÿ èç dataFile.
511 var
513 begin
516 begin
519 begin
521 else
522 begin
525 break;
532 // ðàçáèòü èìÿ ñáîðíèêà íà ÷àñòè: ïðåôèêñ ôàéëîâîé ñèñòåìû, èìÿ ôàéëà äàííûõ,
533 // âèðòóàëüíîå èìÿ. åñëè âèðòóàëüíîãî èìåíè íå äàíî, îíî áóäåò ðàâíî dataFile.
534 // èìÿ âûãëÿäèò êàê:
535 // [sfspfx:]datafile[|virtname]
536 // åñëè ïåðåä äâîåòî÷èåì ìåíüøå òð¸õ áóêâ, òî ýòî ñ÷èòàåòñÿ íå ïðåôèêñîì,
537 // à èìåíåì äèñêà.
539 var
541 begin
544 else
545 begin
552 // íàéòè ïðîèçâîäèòåëÿ äëÿ ýòîãî ôàéëà (åñëè ôàéë óæå îòêðûò).
553 // onlyPerm: òîëüêî "ïîñòîÿííûå" ïðîèçâîäèòåëè.
555 var
558 begin
561 begin
563 begin
566 begin
568 begin
570 exit;
579 // íàéòè èíôó äëÿ ýòîãî òîìà.
580 // õîðîøåå èìÿ, ïðàâäà? %-)
582 begin
585 begin
587 begin
595 // adds '/' too
597 var
599 begin
603 begin
605 begin
607 continue;
610 begin
612 end
613 else
614 begin
623 var
625 begin
628 begin
630 begin
631 // avoid unnecessary string changes
638 var
641 begin
643 repeat
651 { TVolumeInfo }
653 var
656 begin
663 // òèïà ìóñîðîñáîðíèê: åñëè íàø ïîòîê áîëåå íèêåì íå þçàåòñÿ, òî óãðîáèòü åãî íàôèã
665 begin
669 begin
671 begin
674 begin
687 { TOwnedPartialStream }
690 begin
697 var
699 begin
702 begin
705 begin
708 begin
709 {$IFDEF SFS_VOLDEBUG}writeln('001: destroying volume "', TVolumeInfo(volumes[f]).fPackName, '"');{$ENDIF}
717 { TSFSFileInfo }
719 begin
730 begin
736 { TSFSVolume }
738 begin
746 var
750 begin
757 begin
759 // normalize name & path
766 begin
767 // split path and name
779 begin
786 begin
791 begin
793 else
794 begin
797 begin
800 begin
810 begin
815 begin
817 else
818 begin
825 var
828 begin
830 // normalize name, find split position
834 begin
847 { TSFSFileList }
849 var
851 begin
861 var
863 begin
867 // óáü¸ì çàïèñü, åñëè îíà âðåìåííàÿ, è â íåé íåò áîëüøå íè÷åãî îòêðûòîãî
868 if (gcdisabled = 0) and not TVolumeInfo(volumes[f]).fPermanent and (TVolumeInfo(volumes[f]).fOpenedFilesCount < 1) then
869 begin
870 {$IFDEF SFS_VOLDEBUG}writeln('002: destroying volume "', TVolumeInfo(volumes[f]).fPackName, '"');{$ENDIF}
877 begin
882 begin
889 var
891 begin
900 var
903 begin
908 begin
916 function SFSAddDataFileEx (dataFileName: AnsiString; ds: TStream; top, permanent: Integer): Integer;
917 // dataFileName ìîæåò èìåòü ïðåôèêñ òèïà "zip:" (ñì. âûøå: IsMyPrefix).
918 // ìîæåò âûêèíóòü èñêëþ÷åíèå!
919 // top:
920 // <0: äîáàâèòü â íà÷àëî ñïèñêà ïîèñêà.
921 // =0: íå ìåíÿòü.
922 // >0: äîáàâèòü â êîíåö ñïèñêà ïîèñêà.
923 // permanent:
924 // <0: ñîçäàòü "âðåìåííûé" òîì.
925 // =0: íå ìåíÿòü ôëàæîê ïîñòîÿíñòâà.
926 // >0: ñîçäàòü "ïîñòîÿííûé" òîì.
927 // åñëè ds <> nil, òî ñîçäà¸ò ñáîðíèê èç ïîòîêà. åñëè ñáîðíèê ñ èìåíåì
928 // dataFileName óæå çàðåãèñòðèðîâàí, òî ïàäàåò íàôèã.
929 // âîçâðàùàåò èíäåêñ â volumes.
930 // óìååò äåëàòü ðåêóðñèþ.
931 var
939 begin
942 begin
943 // ðåêóðñèâíîå îòêðûòèå.
944 // ðàçîáü¸ì dataFileName íà èìÿ ñáîðíèêà è îñòàòîê.
945 // pfx áóäåò èìåíåì ñáîðíèêà, dataFileName -- îñòàòêîì.
947 // ñíà÷àëà îòêðîåì ïåðâûé ñïèñîê...
949 // ...òåïåðü ïðîäîëæèì ñ îñòàòêîì.
950 // óçíàåì, êàêîå ôàéëî îòêðûâàòü.
951 // âûêîâûðÿåì ïåðâûé "::" ïðåôèêñ (ýòî áóäåò èìÿ ôàéëà).
954 // dataFileName õðàíèò îñòàòîê.
955 // èçâëå÷¸ì èìÿ ôàéëà:
957 // îòêðîåì ýòîò ôàéë
959 try
962 except
964 // óäàëèì íåèñïîëüçóåìûé âðåìåííûé òîì.
965 if (gcdisabled = 0) and not vi.fPermanent and (vi.fOpenedFilesCount < 1) then volumes[result] := nil;
968 // óðà. îòêðûëè ôàéë. êèäàåì â âîçäóõ ÷åï÷èêè, ïðîäîëæàåì ðàçâëå÷åíèå.
970 try
973 except
977 exit;
980 // îáûêíîâåííîå íåðåêóðñèâíîå îòêðûòèå.
985 begin
992 exit;
1002 try
1004 begin
1009 try
1012 except
1018 except
1024 try
1026 begin
1029 end
1031 except
1047 function SFSAddSubDataFile (const virtualName: AnsiString; ds: TStream; top: Boolean=false): Boolean;
1048 var
1050 begin
1052 try
1056 except
1062 var
1064 begin
1065 try
1069 except
1075 var
1077 begin
1078 try
1082 except
1090 var
1093 begin
1096 begin
1107 begin
1112 end
1118 var
1126 // ïðîâåðèì, åñòü ëè ôàëî fn ãäå-òî íà äèñêàõ.
1127 var
1130 begin
1137 begin
1143 try
1145 exit;
1146 except
1151 begin
1158 begin
1159 // ïðåôèêñîâàíûé ôàéë
1161 begin
1169 try
1172 except
1174 if (gcdisabled = 0) and not vi.fPermanent and (vi.fOpenedFilesCount < 1) then volumes[f] := nil;
1177 exit;
1179 //Inc(vi.fOpenedFilesCount);
1181 exit;
1184 // íåïðåôèêñîâàíûé ôàéë
1186 begin
1190 // èùåì ïî âñåì ïåðìàíåíòíûì ïðåôèêñàì
1193 begin
1196 begin
1198 begin
1201 begin
1202 try
1205 //Inc(vi.fOpenedFilesCount);
1206 except
1220 begin
1221 try
1223 except
1229 var
1232 begin
1236 try
1238 except
1239 exit;
1243 try
1245 except
1246 if (gcdisabled = 0) and not vi.fPermanent and (vi.fOpenedFilesCount < 1) then volumes[f] := nil;
1251 initialization
1254 //finalization
1255 //volumes.Free(); // it fails for some reason... Runtime 217 (^C hit). wtf?!
1256 //factories.Free(); // not need to be done actually...