1 // streaming file system (virtual)
2 {$MODE DELPHI}
3 {.$R-}
4 {.$DEFINE SFS_VOLDEBUG}
7 interface
9 uses
13 type
22 public
24 fPath: TSFSString; // ðàçäåëèòåëè êàòàëîãîâ -- "/"; êîðåíü íèêàê íå îáîçíà÷åí, åñëè íå ïóñòîå, îáÿçàíî çàâåðøàåòñÿ "/"
37 // âèðòóàëüíàÿ ôàéëîâàÿ ñèñòåìà. ÒÎËÜÊÎ ÄËß ×ÒÅÍÈß!
38 // òîì ÍÅ ÄÎËÆÅÍ óáèâàòüñÿ íèêàê èíà÷å, ÷åì ïðè ïîìîùè ôàáðèêè!
40 protected
46 // ïðèøèáèòü âñå ñòðóêòóðû.
47 // íå äîëæíà ïàäàòü, åñëè å¸ âûçûâàþò íåñêîëüêî ðàç.
50 // âûçûâàåòñÿ èç DoDirectoryRead() äëÿ çàïîëíåíèÿ ñïèñêà ôàéëîâ.
51 // ñ÷èòàåòñÿ, ÷òî âñå ìàãèêè óæå ïðîâåðåíû è ôàéë òî÷íî íàø.
52 // fFileName, fFileStream óæå óñòàíîâëåíû, fFiles ñîçäàí,
53 // â í¸ì, ñêîðåå âñåãî, íèêîãî íåò.
54 // ïîçèöèÿ ïîòîêà -- òà, ÷òî îñòàâèëà ôàáðèêà.
55 // ïðè îøèáêàõ êèäàòü èñêëþ÷åíèå, òîãäà òîì áóäåò ïðèáèò ôàáðèêîé.
56 // ðàçäåëèòåëè ïóòåé äîëæíû áûòü òîëüêî "/", êîðíåâîé "/" äîëæåí
57 // áûòü îïóùåí, ïóòè (åñëè íå ïóñòûå) äîëæíû çàâåðøàòüñÿ "/"!
58 // fName äîëæíî ñîäåðæàòü òîëüêî èìÿ, fPath -- òîëüêî ïóòü.
59 // â ïðèíöèïå, îá ýòîì ïîçàáîòèòñÿ DoDirectoryRead(), íî çà÷åì
60 // äàâàòü åìó ëèøíþþ ðàáîòó?
63 // íàéòè ôàéë, âåðíóòü åãî èíäåêñ â fFiles.
64 // ýòà ïðîöåäóðà ìîæåò ìåíÿòü fFiles!
65 // fPath -- â ïðàâèëüíîé ôîðìå, ñ "/", êîðíåâîé "/" óáèò, ôèíàëüíûé äîáàâëåí.
66 // åñëè ôàéë íå íàéäåí, âåðíóòü -1.
69 // âîçâðàùàåò êîëè÷åñòâî ôàéëîâ â fFiles
72 // âîçâðàùàåò ôàéë ñ èíäåêñîì index.
73 // ìîæåò âîçâðàùàòü NIL.
74 // íèêàêèõ ïàäåíèé íà íåïðàâèëüíûå èíäåêñû!
79 public
80 // pSt íå îáÿçàòåëüíî çàïîìèíàòü, åñëè îí íå íóæåí.
82 // fFileStream óíè÷òîæàòü íåëüçÿ, åñëè îí ðàâåí ïàðàìåòðó pSt êîíñòðóêòîðà.
85 // âûçûâàåò ReadDirectory().
86 // ýòà ïðîöåäóðà ñàìà ðàçáåð¸òñÿ ñ äóáëèêàòàìè èì¸í: ïîäîáàâëÿåò â
87 // êîíåö èì¸í-äóáëèêàòîâ ïîä÷¸ðêèâàíèå è äåñÿòè÷íûé íîìåð.
88 // òàêæå îíà íîðìàëèçóåò âèä èì¸í.
91 // ïðè îøèáêàõ êèäàòüñÿ èñêëþ÷åíèÿìè.
94 // åñëè íå ñìîãëî îòêóïîðèòü ôàéëî (èëè åù¸ ãäå îøèáëîñü), çàøâûðí¸ò èñêëþ÷åíèå.
98 // ìîæåò âîçâðàùàòü NIL.
99 // íèêàêèõ ïàäåíèé íà íåïðàâèëüíûå èíäåêñû!
103 // ôàáðèêà òîìîâ. âñå SFS ïðè ñòàðòå äîáàâëÿþò ñâîè ôàáðèêè.
104 // áëàãîäàðÿ ýòîìó ìîæíî ñîçäàâàòü ðàçíûå âñÿêèå SFS ñòàíäàðòíûì
105 // âûçîâîì ñòàíäàðòíîé ïðîöåäóðû.
106 // ôàáðèêà ÍÅ ÄÎËÆÍÀ óáèâàòüñÿ íèêàê èíà÷å, ÷åì ïðè ïîìîùè âûçîâà
107 // SFSUnregisterVolumeFactory()! ýòî ãàðàíòèðóåò, ÷òî äâèæîê
108 // ïåðåä ðàññòðåëîì îòäàñò åé âñå å¸ òîìà.
110 public
111 // åñëè äîáàâëÿåì ôàéë äàííûõ ôàéë ñ èìåíåì òèïà "zip:....", òî
112 // SFS èçâëå÷¸ò ýòî "zip" è ïåðåäàñò â ñèþ ôóíêöèþ.
113 // åæåëè ôóíêöèÿ âåðí¸ò ïðàâäó, òî SFS âûçîâåò Produce äëÿ äàííîãî
114 // ôàéëà. åñëè íè îäíà ôàáðèêà ïðåôèêñ íå ïðèçíàåò, òî ôàéë íå îòêðîþò.
115 // èñïîëüçóåòñÿ äëÿ ñêèïàíèÿ àâòîäåòåêòà.
116 // SFS ÍÅ Ñ×ÈÒÀÅÒ ÏÐÅÔÈÊÑÎÌ ÑÒÐÎÊÓ ÊÎÐÎ×Å ÒÐ¨Õ ÑÈÌÂÎËÎÂ!
118 // ïðîâåðÿåò, ìîæåò ëè ôàáðèêà ñäåëàòü òîì äëÿ äàííîãî ôàéëà.
119 // st -- îòêðûòûé äëÿ ÷òåíèÿ ôàéëîâé ïîòîê. óêàçàòåëü ÷òåíèÿ ñòîèò â íà÷àëå.
120 // ýòîò ïîòîê íåëüçÿ çàêðûâàòü!
121 // prefix: òî, ÷òî áûëî ïåðåäàíî â IsMyVolumePrefix() èëè ''.
122 // èñêëþ÷åíèå ñ÷èòàåòñÿ îøèáêîé, âîçâðàò NIL ñ÷èòàåòñÿ îøèáêîé.
123 function Produce (const prefix, fileName: TSFSString; st: TStream): TSFSVolume; virtual; abstract;
124 // êîãäà òîì áîëüøå íå íóæåí, îí áóäåò îòäàí ôàáðèêå íà ïåðåðàáîòêó.
125 // äàëåå äâèæîê íå áóäåò þçàòü ñåé òîì.
129 // "èòåðàòîð", âîçâðàùàåìûé SFSFileList()
131 protected
137 public
143 // ïðè íåïðàâèëüíîì èíäåêñå ìîë÷à âåðí¸ò NIL.
144 // ïðè ïðàâèëüíîì òîæå ìîæåò âåðíóòü NIL!
145 // î÷åíü íå ñîâåòóþ ìåíÿòü ñîäåðæèìîå ïîëó÷åííîãî êëàññà.
146 // êîíå÷íî, ÿ ìîã áû âîçâðàùàòü íîâóþ ñòðóêòóðó èëè íå÷òî ïîõîæåå,
147 // íî áëèí, åñëè òû èäèîò è íå óìååøü äàæå êîììåíòû ÷èòàòü, òî
148 // êàêîãî òû âîîáùå â ïðîãðàììèíã ïîëåç?
154 // ýòà ôóíêöèÿ àâòîìàòè÷åñêè ïðèáü¸ò factory.
157 // äîáàâèòü ñáîðíèê â ïîñòîÿííûé ñïèñîê.
158 // åñëè ñáîðíèê ñ òàêèì èìåíåì óæå îòêðûò, òî íå îòêðûâàåò åãî ïîâòîðíî.
159 // íèêîãäà íå êèäàåò èñêëþ÷åíèé.
160 // top: äîáàâèòü â íà÷àëî ñïèñêà ïîèñêà.
161 // âåðí¸ò ëîæü ïðè îøèáêå.
162 // ñïîñîáíî îòêðûâàòü ñáîðíèêè â ñáîðíèêàõ ïðè ïîìîùè êðóòûõ èì¸í a-la:
163 // "zip:pack0::pack:pack1::wad2:pack2".
164 // â äàëüíåéøåì ñëåäóåò îáðàùàòüñÿ ê ñáîðíèêó êàê "pack2::xxx".
165 // èëè ìîæíî íàïèñàòü:
166 // "zip:pack0::pack:pack1::wad2:pack2|datafile".
167 // è îáðàùàòüñÿ êàê "datafile::xxx".
168 // "||" ïðåîáðàçóþòñÿ â ïðîñòîé "|" è ðàçäåëèòåëåì íå ñ÷èòàþòñÿ.
169 // ïðèíèìàåòñÿ âî âíèìàíèå òîëüêî ïîñëåäíÿÿ òðóáà.
172 // äîáàâèòü ñáîðíèê âðåìåííî
175 // äîáàâèòü â ïîñòîÿííûé ñïèñîê ñáîðíèê èç ïîòîêà ds.
176 // åñëè âîçâðàùàåò èñòèíó, òî SFS ñòàíîâèòñÿ âëÿäåëüöåì ïîòîêà ds è ñàìà
177 // óãðîáèò ñåé ïîòîê ïî íåîáõîäèìîñòè.
178 // virtualName ñòàíîâèòñÿ èìåíåì ñáîðíèêà äëÿ îïåðàöèè îòêðûòèÿ ôàéëà òèïà
179 // "packfile:file.ext".
180 // åñëè êàêîé-íèáóäü ñáîðíèê ñ èìåíåì virtualName óæå îòêðûò, âåðí¸ò false.
181 // íèêîãäà íå êèäàåò èñêëþ÷åíèé.
182 // top: äîáàâèòü â íà÷àëî ñïèñêà ïîèñêà.
183 // âåðí¸ò ëîæü ïðè îøèáêå.
184 // îòêðûâàåò ñáîðíèê èç ïîòîêà. dataFileName -- ÂÈÐÒÓÀËÜÍÎÅ èìÿ.
185 // ò.å. íà ñàìîì äåëå òàêîãî ôàéëà ìîæåò è íå áûòü íà äèñêå.
186 function SFSAddSubDataFile (const virtualName: TSFSString; ds: TStream; top: Boolean=false): Boolean;
188 // øâûðÿåòñÿ èñêëþ÷åíèÿìè.
189 // åñëè fName íå èìååò óêàçàíèÿ íà ôàéë äàííûõ (ýòî òî, ÷òî îòäåëåíî îò
190 // îñòàëüíîãî èìåíè äâîåòî÷èåì), òî èùåì ñíà÷àëà ïî âñåì çàðåãèñòðèðîâàííûì
191 // ôàéëàì äàííûõ, ïîòîì â òåêóùåì êàòàëîãå, ïîòîì â êàòàëîãå, îòêóäà ñòàðòîâàëè.
192 // åñëè íè÷åãî íå íàøëè, êèäàåì èñêëþ÷åíèå.
195 // ïðè îøèáêå -- NIL, è íèêàêèõ èñêëþ÷åíèé.
198 // âîçâðàùàåò NIL ïðè îøèáêå.
199 // ïîñëå èñïîëüçîâàíèÿ, íàòóðàëüíî, èòåðàòîð íàäî ãðîõíóòü %-)
202 // çàïðåòèòü îñâîáîæäåíèå âðåìåííûõ òîìîâ (ìîæíî âûçûâàòü ðåêóðñèâíî)
205 // ðàçðåøèòü îñâîáîæäåíèå âðåìåííûõ òîìîâ (ìîæíî âûçûâàòü ðåêóðñèâíî)
208 // for completeness sake
213 // èãíîðèðóåò ðåãèñòð ñèìâîëîâ
216 // ðàçîáðàòü òîëñòîå èìÿ ôàéëà, âåðíóòü âèðòóàëüíîå èìÿ ïîñëåäíåãî ñïèñêà
217 // èëè ïóñòóþ ñòîðîêó, åñëè ñïèñêîâ íå áûëî.
220 // ïðåîáðàçîâàòü ÷èñëî â ñòðîêó, êðàñèâî ðàçáàâëÿÿ çàïÿòûìè
223 // `name` will be modified
224 // return `true` if file was found
227 // Wildcard matching
228 // this code is meant to allow wildcard pattern matches. tt is VERY useful
229 // for matching filename wildcard patterns. tt allows unix grep-like pattern
230 // comparisons, for instance:
231 //
232 // ? Matches any single characer
233 // + Matches any single characer or nothing
234 // * Matches any number of contiguous characters
235 // [abc] Matches a or b or c at that position
236 // [!abc] Matches anything but a or b or c at that position
237 // [a-e] Matches a through e at that position
238 //
239 // 'ma?ch.*' -Would match match.exe, mavch.dat, march.on, etc
240 // 'this [e-n]s a [!zy]est' -Would match 'this is a test', but would
241 // not match 'this as a yest'
242 //
252 var
253 // ïðàâäà: ðàçðåøåíî èñêàòü ôàéëî íå òîëüêî â ôàéëàõ äàííûõ, íî è íà äèñêå.
255 // ïðàâäà: åñëè ôàéë íå ïðåôèêñîâàí, òî ñíà÷àëà èùåì ôàéëî íà äèñêå,
256 // ïîòîì â ôàéëàõ äàííûõ.
258 // ïðàâäà: äàæå äëÿ ïðåôèêñîâàíûõ ôàéëîâ ñíà÷àëà ïðîñìîòðèì äèñê
259 // (åñëè óñòàíîâëåí ôëàæîê sfsDiskFirst è sfsDiskEnabled).
261 // ñïèñîê äèñêîâûõ êàòàëîãîâ äëÿ ïîèñêà ôàéëà. åñëè ïóñò -- èùåì òîëüêî â
262 // òåêóùåì. êàòàëîãè ðàçäåëÿþòñÿ òðóáîé ("|").
263 // <currentdir> çàìåíÿåòñÿ íà òåêóùèé êàòàëîã (ñ çàâåðøàþùèì "/"),
264 // <exedir> çàìåíÿåòñÿ íà êàòàëîã, ãäå ñèäèò .EXE (ñ çàâåðøàþùèì "/").
268 implementation
270 uses
271 xstreams;
275 var
277 begin
281 begin
287 // `name` will be modified
289 var
292 begin
298 repeat
302 begin
305 exit;
314 const
315 // character defines
327 begin
328 result :=
336 function MatchMask (const pattern: TSFSString; p, pend: Integer; const text: TSFSString; t, tend: Integer): Boolean;
337 var
341 begin
342 // sanity checks
348 begin
350 begin
351 // no more text. check if there's no more chars in pattern (except "*" & "+")
356 exit;
359 WILD_CHAR_SINGLE: ;
360 WILD_CHAR_ESCAPE:
361 begin
366 WILD_CHAR_RANGE_OPEN:
367 begin
375 repeat
381 begin
385 begin
387 end
389 end
394 // skip the rest or the range
398 WILD_CHAR_SINGLE_OR_NONE:
399 begin
403 exit;
405 WILD_CHAR_MULTI:
406 begin
410 begin
414 exit;
425 begin
432 var
434 begin
440 begin
442 begin
444 begin
451 begin
461 type
467 fPermanent: Boolean; // èñòèíà -- íå áóäåò óãðîáëåíà, åñëè íå îñòàíåòñÿ íè îäíîãî îòêðûòîãî òîìà
468 // èñòèíà -- ýòîò òîì áûë ñîçäàí èç ïîòîêà è íå èìååò äèñêîâîãî ôàéëà, ïîòîìó ôàáðèêå áóäåò ïåðåäàíî íå èìÿ ñáîðíèêà, à ïóñòàÿ ñòðîêà
476 protected
479 public
485 var
492 var
496 begin
497 // collect garbage
500 begin
504 begin
505 // this volume probably can be removed
509 begin
511 begin
519 begin
520 {$IFDEF SFS_VOLDEBUG}writeln('000: destroying volume "', TVolumeInfo(volumes[f]).fPackName, '"');{$ENDIF}
524 continue;
532 begin
537 begin
540 begin
547 // ðàçáèòü èìÿ ôàéëà íà ÷àñòè: ïðåôèêñ ôàéëîâîé ñèñòåìû, èìÿ ôàéëà äàííûõ,
548 // ñîáñòâåííî èìÿ ôàéëà
549 // èìÿ âûãëÿäèò êàê:
550 // (("sfspfx:")?"datafile::")*"filename"
552 var
554 begin
557 begin
562 else
563 begin
569 // ñàéäýôôåêò: âûðåçàåò âèðòóàëüíîå èìÿ èç dataFile.
571 var
573 begin
576 begin
579 begin
581 else
582 begin
585 break;
592 // ðàçáèòü èìÿ ñáîðíèêà íà ÷àñòè: ïðåôèêñ ôàéëîâîé ñèñòåìû, èìÿ ôàéëà äàííûõ,
593 // âèðòóàëüíîå èìÿ. åñëè âèðòóàëüíîãî èìåíè íå äàíî, îíî áóäåò ðàâíî dataFile.
594 // èìÿ âûãëÿäèò êàê:
595 // [sfspfx:]datafile[|virtname]
596 // åñëè ïåðåä äâîåòî÷èåì ìåíüøå òð¸õ áóêâ, òî ýòî ñ÷èòàåòñÿ íå ïðåôèêñîì,
597 // à èìåíåì äèñêà.
599 var
601 begin
604 else
605 begin
612 // íàéòè ïðîèçâîäèòåëÿ äëÿ ýòîãî ôàéëà (åñëè ôàéë óæå îòêðûò).
613 // onlyPerm: òîëüêî "ïîñòîÿííûå" ïðîèçâîäèòåëè.
615 var
618 begin
621 begin
623 begin
626 begin
628 begin
630 exit;
639 // íàéòè èíôó äëÿ ýòîãî òîìà.
640 // õîðîøåå èìÿ, ïðàâäà? %-)
642 begin
645 begin
647 begin
655 begin
657 begin
659 end
660 else
661 begin
663 begin
665 end
666 else
667 begin
678 var
680 begin
681 //result := (AnsiCompareText(s0, s1) == 0);
685 begin
691 // adds '/' too
693 var
695 begin
699 begin
701 begin
703 continue;
706 begin
708 end
709 else
710 begin
719 var
721 begin
724 begin
726 begin
727 // avoid unnecessary string changes
734 var
737 begin
739 repeat
747 { TVolumeInfo }
749 var
752 begin
759 // òèïà ìóñîðîñáîðíèê: åñëè íàø ïîòîê áîëåå íèêåì íå þçàåòñÿ, òî óãðîáèòü åãî íàôèã
761 begin
765 begin
767 begin
770 begin
783 { TOwnedPartialStream }
786 begin
793 var
795 begin
798 begin
801 begin
804 begin
805 {$IFDEF SFS_VOLDEBUG}writeln('001: destroying volume "', TVolumeInfo(volumes[f]).fPackName, '"');{$ENDIF}
813 { TSFSFileInfo }
815 begin
826 begin
832 { TSFSVolume }
834 begin
843 begin
847 var
851 begin
858 begin
860 // normalize name & path
867 begin
868 // split path and name
881 begin
888 begin
894 begin
896 else
897 begin
900 begin
903 begin
913 begin
918 begin
920 else
921 begin
928 var
931 begin
933 // normalize name, find split position
937 begin
950 { TSFSFileList }
952 var
954 begin
964 var
966 begin
971 // óáü¸ì çàïèñü, åñëè îíà âðåìåííàÿ, è â íåé íåò áîëüøå íè÷åãî îòêðûòîãî
972 if (gcdisabled = 0) and not TVolumeInfo(volumes[f]).fPermanent and (TVolumeInfo(volumes[f]).fOpenedFilesCount < 1) then
973 begin
974 {$IFDEF SFS_VOLDEBUG}writeln('002: destroying volume "', TVolumeInfo(volumes[f]).fPackName, '"');{$ENDIF}
981 begin
986 begin
993 var
995 begin
1004 var
1007 begin
1012 begin
1013 if (volumes[c] <> nil) and (TVolumeInfo(volumes[c]).fFactory = factory) then volumes[c] := nil;
1020 function SFSAddDataFileEx (dataFileName: TSFSString; ds: TStream; top, permanent: Integer): Integer;
1021 // dataFileName ìîæåò èìåòü ïðåôèêñ òèïà "zip:" (ñì. âûøå: IsMyPrefix).
1022 // ìîæåò âûêèíóòü èñêëþ÷åíèå!
1023 // top:
1024 // <0: äîáàâèòü â íà÷àëî ñïèñêà ïîèñêà.
1025 // =0: íå ìåíÿòü.
1026 // >0: äîáàâèòü â êîíåö ñïèñêà ïîèñêà.
1027 // permanent:
1028 // <0: ñîçäàòü "âðåìåííûé" òîì.
1029 // =0: íå ìåíÿòü ôëàæîê ïîñòîÿíñòâà.
1030 // >0: ñîçäàòü "ïîñòîÿííûé" òîì.
1031 // åñëè ds <> nil, òî ñîçäà¸ò ñáîðíèê èç ïîòîêà. åñëè ñáîðíèê ñ èìåíåì
1032 // dataFileName óæå çàðåãèñòðèðîâàí, òî ïàäàåò íàôèã.
1033 // âîçâðàùàåò èíäåêñ â volumes.
1034 // óìååò äåëàòü ðåêóðñèþ.
1035 var
1043 begin
1046 begin
1047 // ðåêóðñèâíîå îòêðûòèå.
1048 // ðàçîáü¸ì dataFileName íà èìÿ ñáîðíèêà è îñòàòîê.
1049 // pfx áóäåò èìåíåì ñáîðíèêà, dataFileName -- îñòàòêîì.
1051 // ñíà÷àëà îòêðîåì ïåðâûé ñïèñîê...
1053 // ...òåïåðü ïðîäîëæèì ñ îñòàòêîì.
1054 // óçíàåì, êàêîå ôàéëî îòêðûâàòü.
1055 // âûêîâûðÿåì ïåðâûé "::" ïðåôèêñ (ýòî áóäåò èìÿ ôàéëà).
1058 // dataFileName õðàíèò îñòàòîê.
1059 // èçâëå÷¸ì èìÿ ôàéëà:
1061 // îòêðîåì ýòîò ôàéë
1063 try
1066 except
1068 // óäàëèì íåèñïîëüçóåìûé âðåìåííûé òîì.
1069 if (gcdisabled = 0) and not vi.fPermanent and (vi.fOpenedFilesCount < 1) then volumes[result] := nil;
1072 // óðà. îòêðûëè ôàéë. êèäàåì â âîçäóõ ÷åï÷èêè, ïðîäîëæàåì ðàçâëå÷åíèå.
1074 try
1077 except
1081 exit;
1084 // îáûêíîâåííîå íåðåêóðñèâíîå îòêðûòèå.
1089 begin
1096 exit;
1106 try
1108 begin
1113 try
1116 except
1122 except
1128 try
1130 begin
1133 end
1135 except
1151 function SFSAddSubDataFile (const virtualName: TSFSString; ds: TStream; top: Boolean=false): Boolean;
1152 var
1154 begin
1156 try
1160 except
1166 var
1168 begin
1169 try
1173 except
1179 var
1181 begin
1182 try
1186 except
1194 var
1197 begin
1200 begin
1211 begin
1216 end
1222 var
1230 // ïðîâåðèì, åñòü ëè ôàëî fn ãäå-òî íà äèñêàõ.
1231 var
1234 begin
1241 begin
1247 try
1249 exit;
1250 except
1255 begin
1262 begin
1263 // ïðåôèêñîâàíûé ôàéë
1265 begin
1273 try
1276 except
1278 if (gcdisabled = 0) and not vi.fPermanent and (vi.fOpenedFilesCount < 1) then volumes[f] := nil;
1281 exit;
1283 //Inc(vi.fOpenedFilesCount);
1285 exit;
1288 // íåïðåôèêñîâàíûé ôàéë
1290 begin
1294 // èùåì ïî âñåì ïåðìàíåíòíûì ïðåôèêñàì
1297 begin
1300 begin
1302 begin
1305 begin
1306 try
1309 //Inc(vi.fOpenedFilesCount);
1310 except
1324 begin
1325 try
1327 except
1333 var
1336 begin
1340 try
1342 except
1343 exit;
1347 try
1350 except
1351 if (gcdisabled = 0) and not vi.fPermanent and (vi.fOpenedFilesCount < 1) then volumes[f] := nil;
1356 // ////////////////////////////////////////////////////////////////////////// //
1357 // utils
1358 // `ch`: utf8 start
1359 // -1: invalid utf8
1361 begin
1373 var
1375 begin
1379 begin
1385 // check other sequence bytes
1387 begin
1397 // ////////////////////////////////////////////////////////////////////////// //
1398 const
1399 // TODO: move this to a separate file
1401 $0402,$0403,$201A,$0453,$201E,$2026,$2020,$2021,$20AC,$2030,$0409,$2039,$040A,$040C,$040B,$040F,
1402 $0452,$2018,$2019,$201C,$201D,$2022,$2013,$2014,$003F,$2122,$0459,$203A,$045A,$045C,$045B,$045F,
1403 $00A0,$040E,$045E,$0408,$00A4,$0490,$00A6,$00A7,$0401,$00A9,$0404,$00AB,$00AC,$00AD,$00AE,$0407,
1404 $00B0,$00B1,$0406,$0456,$0491,$00B5,$00B6,$00B7,$0451,$2116,$0454,$00BB,$0458,$0405,$0455,$0457,
1405 $0410,$0411,$0412,$0413,$0414,$0415,$0416,$0417,$0418,$0419,$041A,$041B,$041C,$041D,$041E,$041F,
1406 $0420,$0421,$0422,$0423,$0424,$0425,$0426,$0427,$0428,$0429,$042A,$042B,$042C,$042D,$042E,$042F,
1407 $0430,$0431,$0432,$0433,$0434,$0435,$0436,$0437,$0438,$0439,$043A,$043B,$043C,$043D,$043E,$043F,
1408 $0440,$0441,$0442,$0443,$0444,$0445,$0446,$0447,$0448,$0449,$044A,$044B,$044C,$044D,$044E,$044F
1409 );
1413 var
1415 begin
1416 (* The following encodings are valid, except for the 5 and 6 byte
1417 * combinations:
1418 * 0xxxxxxx
1419 * 110xxxxx 10xxxxxx
1420 * 1110xxxx 10xxxxxx 10xxxxxx
1421 * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
1422 * 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
1423 * 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
1424 *)
1432 // mask out unused bits
1440 // now continue
1442 begin
1450 // done, try 1251
1452 // alas
1457 var
1459 begin
1463 begin
1474 initialization
1477 //finalization
1478 //volumes.Free(); // it fails for some reason... Runtime 217 (^C hit). wtf?!
1479 //factories.Free(); // not need to be done actually...