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 // ïîñëå èñïîëüçîâàíèÿ, íàòóðàëüíî, èòåðàòîð íàäî ãðîõíóòü %-)
203 // èãíîðèðóåò ðåãèñòð ñèìâîëîâ
206 // ðàçîáðàòü òîëñòîå èìÿ ôàéëà, âåðíóòü âèðòóàëüíîå èìÿ ïîñëåäíåãî ñïèñêà
207 // èëè ïóñòóþ ñòîðîêó, åñëè ñïèñêîâ íå áûëî.
210 // ïðåîáðàçîâàòü ÷èñëî â ñòðîêó, êðàñèâî ðàçáàâëÿÿ çàïÿòûìè
213 // `name` will be modified
214 // return `true` if file was found
217 // Wildcard matching
218 // this code is meant to allow wildcard pattern matches. tt is VERY useful
219 // for matching filename wildcard patterns. tt allows unix grep-like pattern
220 // comparisons, for instance:
221 //
222 // ? Matches any single characer
223 // + Matches any single characer or nothing
224 // * Matches any number of contiguous characters
225 // [abc] Matches a or b or c at that position
226 // [!abc] Matches anything but a or b or c at that position
227 // [a-e] Matches a through e at that position
228 //
229 // 'ma?ch.*' -Would match match.exe, mavch.dat, march.on, etc
230 // 'this [e-n]s a [!zy]est' -Would match 'this is a test', but would
231 // not match 'this as a yest'
232 //
237 // this will compare only last path element from sfspath
245 var
246 // ïðàâäà: ðàçðåøåíî èñêàòü ôàéëî íå òîëüêî â ôàéëàõ äàííûõ, íî è íà äèñêå.
248 // ïðàâäà: åñëè ôàéë íå ïðåôèêñîâàí, òî ñíà÷àëà èùåì ôàéëî íà äèñêå,
249 // ïîòîì â ôàéëàõ äàííûõ.
251 // ïðàâäà: äàæå äëÿ ïðåôèêñîâàíûõ ôàéëîâ ñíà÷àëà ïðîñìîòðèì äèñê
252 // (åñëè óñòàíîâëåí ôëàæîê sfsDiskFirst è sfsDiskEnabled).
254 // ñïèñîê äèñêîâûõ êàòàëîãîâ äëÿ ïîèñêà ôàéëà. åñëè ïóñò -- èùåì òîëüêî â
255 // òåêóùåì. êàòàëîãè ðàçäåëÿþòñÿ òðóáîé ("|").
256 // <currentdir> çàìåíÿåòñÿ íà òåêóùèé êàòàëîã (ñ çàâåðøàþùèì "/"),
257 // <exedir> çàìåíÿåòñÿ íà êàòàëîã, ãäå ñèäèò .EXE (ñ çàâåðøàþùèì "/").
261 implementation
263 uses
264 xstreams;
268 var
270 begin
274 begin
280 // `name` will be modified
282 var
285 begin
291 repeat
295 begin
298 exit;
307 const
308 // character defines
320 begin
321 result :=
329 function MatchMask (const pattern: TSFSString; p, pend: Integer; const text: TSFSString; t, tend: Integer): Boolean;
330 var
334 begin
335 // sanity checks
341 begin
343 begin
344 // no more text. check if there's no more chars in pattern (except "*" & "+")
349 exit;
352 WILD_CHAR_SINGLE: ;
353 WILD_CHAR_ESCAPE:
354 begin
359 WILD_CHAR_RANGE_OPEN:
360 begin
368 repeat
374 begin
378 begin
380 end
382 end
387 // skip the rest or the range
391 WILD_CHAR_SINGLE_OR_NONE:
392 begin
396 exit;
398 WILD_CHAR_MULTI:
399 begin
403 begin
407 exit;
418 begin
425 var
427 begin
433 begin
435 begin
437 begin
444 begin
454 type
460 fPermanent: Boolean; // èñòèíà -- íå áóäåò óãðîáëåíà, åñëè íå îñòàíåòñÿ íè îäíîãî îòêðûòîãî òîìà
461 // èñòèíà -- ýòîò òîì áûë ñîçäàí èç ïîòîêà è íå èìååò äèñêîâîãî ôàéëà, ïîòîìó ôàáðèêå áóäåò ïåðåäàíî íå èìÿ ñáîðíèêà, à ïóñòàÿ ñòðîêà
469 protected
472 public
478 var
483 // ðàçáèòü èìÿ ôàéëà íà ÷àñòè: ïðåôèêñ ôàéëîâîé ñèñòåìû, èìÿ ôàéëà äàííûõ,
484 // ñîáñòâåííî èìÿ ôàéëà
485 // èìÿ âûãëÿäèò êàê:
486 // (("sfspfx:")?"datafile::")*"filename"
488 var
490 begin
493 begin
498 else
499 begin
505 // ñàéäýôôåêò: âûðåçàåò âèðòóàëüíîå èìÿ èç dataFile.
507 var
509 begin
512 begin
515 begin
517 else
518 begin
521 break;
528 // ðàçáèòü èìÿ ñáîðíèêà íà ÷àñòè: ïðåôèêñ ôàéëîâîé ñèñòåìû, èìÿ ôàéëà äàííûõ,
529 // âèðòóàëüíîå èìÿ. åñëè âèðòóàëüíîãî èìåíè íå äàíî, îíî áóäåò ðàâíî dataFile.
530 // èìÿ âûãëÿäèò êàê:
531 // [sfspfx:]datafile[|virtname]
532 // åñëè ïåðåä äâîåòî÷èåì ìåíüøå òð¸õ áóêâ, òî ýòî ñ÷èòàåòñÿ íå ïðåôèêñîì,
533 // à èìåíåì äèñêà.
535 var
537 begin
540 else
541 begin
548 // íàéòè ïðîèçâîäèòåëÿ äëÿ ýòîãî ôàéëà (åñëè ôàéë óæå îòêðûò).
549 // onlyPerm: òîëüêî "ïîñòîÿííûå" ïðîèçâîäèòåëè.
551 var
554 begin
557 begin
559 begin
562 begin
564 begin
566 exit;
575 // íàéòè èíôó äëÿ ýòîãî òîìà.
576 // õîðîøåå èìÿ, ïðàâäà? %-)
578 begin
581 begin
583 begin
591 begin
593 begin
595 end
596 else
597 begin
599 begin
601 end
602 else
603 begin
614 var
616 begin
617 //result := (AnsiCompareText(s0, s1) == 0);
621 begin
627 // this will compare only last path element from sfspath
629 {var
630 i: Integer;}
631 begin
633 (*
634 if not result and (length(sfspath) > 1) then
635 begin
636 i := length(sfspath);
637 while i > 1 do
638 begin
639 while (i > 1) and (sfspath[i-1] <> '/') do Dec(i);
640 if i <= 1 then exit;
641 writeln('{', sfspath, '} [', Copy(sfspath, i, length(sfspath)), '] : [', path, ']');
642 result := SFSStrEqu(Copy(sfspath, i, length(sfspath)), path);
643 end;
644 end;
645 *)
648 // adds '/' too
650 var
652 begin
656 begin
658 begin
660 continue;
663 begin
665 end
666 else
667 begin
676 var
678 begin
681 begin
683 begin
684 // avoid unnecessary string changes
691 var
694 begin
696 repeat
704 { TVolumeInfo }
706 var
709 begin
716 // òèïà ìóñîðîñáîðíèê: åñëè íàø ïîòîê áîëåå íèêåì íå þçàåòñÿ, òî óãðîáèòü åãî íàôèã
718 begin
722 begin
724 begin
727 begin
740 { TOwnedPartialStream }
743 begin
750 var
752 begin
755 begin
758 begin
761 begin
762 {$IFDEF SFS_VOLDEBUG}writeln('destroying volume "', TVolumeInfo(volumes[f]).fPackName, '"');{$ENDIF}
770 { TSFSFileInfo }
772 begin
783 begin
789 { TSFSVolume }
791 begin
800 begin
804 var
808 begin
815 begin
817 // normalize name & path
824 begin
825 // split path and name
838 begin
845 begin
851 begin
853 else
854 begin
857 begin
860 begin
870 begin
875 begin
877 else
878 begin
885 var
888 begin
890 // normalize name, find split position
894 begin
907 { TSFSFileList }
909 var
911 begin
921 var
923 begin
928 // óáü¸ì çàïèñü, åñëè îíà âðåìåííàÿ, è â íåé íåò áîëüøå íè÷åãî îòêðûòîãî
929 if not TVolumeInfo(volumes[f]).fPermanent and (TVolumeInfo(volumes[f]).fOpenedFilesCount < 1) then
930 begin
931 {$IFDEF SFS_VOLDEBUG}writeln('destroying volume "', TVolumeInfo(volumes[f]).fPackName, '"');{$ENDIF}
938 begin
943 begin
950 var
952 begin
961 var
964 begin
969 begin
977 function SFSAddDataFileEx (dataFileName: TSFSString; ds: TStream; top, permanent: Integer): Integer;
978 // dataFileName ìîæåò èìåòü ïðåôèêñ òèïà "zip:" (ñì. âûøå: IsMyPrefix).
979 // ìîæåò âûêèíóòü èñêëþ÷åíèå!
980 // top:
981 // <0: äîáàâèòü â íà÷àëî ñïèñêà ïîèñêà.
982 // =0: íå ìåíÿòü.
983 // >0: äîáàâèòü â êîíåö ñïèñêà ïîèñêà.
984 // permanent:
985 // <0: ñîçäàòü "âðåìåííûé" òîì.
986 // =0: íå ìåíÿòü ôëàæîê ïîñòîÿíñòâà.
987 // >0: ñîçäàòü "ïîñòîÿííûé" òîì.
988 // åñëè ds <> nil, òî ñîçäà¸ò ñáîðíèê èç ïîòîêà. åñëè ñáîðíèê ñ èìåíåì
989 // dataFileName óæå çàðåãèñòðèðîâàí, òî ïàäàåò íàôèã.
990 // âîçâðàùàåò èíäåêñ â volumes.
991 // óìååò äåëàòü ðåêóðñèþ.
992 var
1000 begin
1003 begin
1004 // ðåêóðñèâíîå îòêðûòèå.
1005 // ðàçîáü¸ì dataFileName íà èìÿ ñáîðíèêà è îñòàòîê.
1006 // pfx áóäåò èìåíåì ñáîðíèêà, dataFileName -- îñòàòêîì.
1008 // ñíà÷àëà îòêðîåì ïåðâûé ñïèñîê...
1010 // ...òåïåðü ïðîäîëæèì ñ îñòàòêîì.
1011 // óçíàåì, êàêîå ôàéëî îòêðûâàòü.
1012 // âûêîâûðÿåì ïåðâûé "::" ïðåôèêñ (ýòî áóäåò èìÿ ôàéëà).
1015 // dataFileName õðàíèò îñòàòîê.
1016 // èçâëå÷¸ì èìÿ ôàéëà:
1018 // îòêðîåì ýòîò ôàéë
1020 try
1023 except
1025 // óäàëèì íåèñïîëüçóåìûé âðåìåííûé òîì.
1029 // óðà. îòêðûëè ôàéë. êèäàåì â âîçäóõ ÷åï÷èêè, ïðîäîëæàåì ðàçâëå÷åíèå.
1031 try
1034 except
1038 exit;
1041 // îáûêíîâåííîå íåðåêóðñèâíîå îòêðûòèå.
1046 begin
1053 exit;
1063 try
1065 begin
1070 try
1073 except
1079 except
1085 try
1087 begin
1090 end
1092 except
1108 function SFSAddSubDataFile (const virtualName: TSFSString; ds: TStream; top: Boolean=false): Boolean;
1109 var
1111 begin
1113 try
1117 except
1123 var
1125 begin
1126 try
1130 except
1136 var
1138 begin
1139 try
1143 except
1151 var
1154 begin
1157 begin
1168 begin
1173 end
1179 var
1187 // ïðîâåðèì, åñòü ëè ôàëî fn ãäå-òî íà äèñêàõ.
1188 var
1191 begin
1198 begin
1204 try
1206 exit;
1207 except
1212 begin
1219 begin
1220 // ïðåôèêñîâàíûé ôàéë
1222 begin
1230 try
1233 except
1238 exit;
1240 //Inc(vi.fOpenedFilesCount);
1242 exit;
1245 // íåïðåôèêñîâàíûé ôàéë
1247 begin
1251 // èùåì ïî âñåì ïåðìàíåíòíûì ïðåôèêñàì
1254 begin
1257 begin
1259 begin
1262 begin
1263 try
1266 //Inc(vi.fOpenedFilesCount);
1267 except
1281 begin
1282 try
1284 except
1290 var
1293 begin
1297 try
1299 except
1300 exit;
1304 try
1307 except
1313 // ////////////////////////////////////////////////////////////////////////// //
1314 // utils
1315 // `ch`: utf8 start
1316 // -1: invalid utf8
1318 begin
1330 var
1332 begin
1336 begin
1342 // check other sequence bytes
1344 begin
1354 // ////////////////////////////////////////////////////////////////////////// //
1355 const
1356 // TODO: move this to a separate file
1358 $0402,$0403,$201A,$0453,$201E,$2026,$2020,$2021,$20AC,$2030,$0409,$2039,$040A,$040C,$040B,$040F,
1359 $0452,$2018,$2019,$201C,$201D,$2022,$2013,$2014,$003F,$2122,$0459,$203A,$045A,$045C,$045B,$045F,
1360 $00A0,$040E,$045E,$0408,$00A4,$0490,$00A6,$00A7,$0401,$00A9,$0404,$00AB,$00AC,$00AD,$00AE,$0407,
1361 $00B0,$00B1,$0406,$0456,$0491,$00B5,$00B6,$00B7,$0451,$2116,$0454,$00BB,$0458,$0405,$0455,$0457,
1362 $0410,$0411,$0412,$0413,$0414,$0415,$0416,$0417,$0418,$0419,$041A,$041B,$041C,$041D,$041E,$041F,
1363 $0420,$0421,$0422,$0423,$0424,$0425,$0426,$0427,$0428,$0429,$042A,$042B,$042C,$042D,$042E,$042F,
1364 $0430,$0431,$0432,$0433,$0434,$0435,$0436,$0437,$0438,$0439,$043A,$043B,$043C,$043D,$043E,$043F,
1365 $0440,$0441,$0442,$0443,$0444,$0445,$0446,$0447,$0448,$0449,$044A,$044B,$044C,$044D,$044E,$044F
1366 );
1370 var
1372 begin
1373 (* The following encodings are valid, except for the 5 and 6 byte
1374 * combinations:
1375 * 0xxxxxxx
1376 * 110xxxxx 10xxxxxx
1377 * 1110xxxx 10xxxxxx 10xxxxxx
1378 * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
1379 * 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
1380 * 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
1381 *)
1389 // mask out unused bits
1397 // now continue
1399 begin
1407 // done, try 1251
1409 // alas
1414 var
1416 begin
1420 begin
1431 initialization
1434 //finalization
1435 //volumes.Free(); // it fails for some reason... Runtime 217 (^C hit). wtf?!
1436 //factories.Free(); // not need to be done actually...