1 (* Copyright (C) Doom 2D: Forever Developers
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, version 3 of the License ONLY.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 *)
15 // streaming file system (virtual)
16 {$INCLUDE ../shared/a_modes.inc}
17 {$SCOPEDENUMS OFF}
18 {.$R+}
19 {.$DEFINE SFS_VOLDEBUG}
22 interface
24 uses
28 type
34 public
36 fPath: AnsiString; // ðàçäåëèòåëè êàòàëîãîâ -- "/"; êîðåíü íèêàê íå îáîçíà÷åí, åñëè íå ïóñòîå, îáÿçàíî çàâåðøàòüñÿ "/"
49 // âèðòóàëüíàÿ ôàéëîâàÿ ñèñòåìà. ÒÎËÜÊÎ ÄËß ×ÒÅÍÈß!
50 // òîì ÍÅ ÄÎËÆÅÍ óáèâàòüñÿ íèêàê èíà÷å, ÷åì ïðè ïîìîùè ôàáðèêè!
52 protected
57 // ïðèøèáèòü âñå ñòðóêòóðû.
58 // íå äîëæíà ïàäàòü, åñëè å¸ âûçûâàþò íåñêîëüêî ðàç.
61 // âûçûâàåòñÿ èç DoDirectoryRead() äëÿ çàïîëíåíèÿ ñïèñêà ôàéëîâ.
62 // ñ÷èòàåòñÿ, ÷òî âñå ìàãèêè óæå ïðîâåðåíû è ôàéë òî÷íî íàø.
63 // fFileName, fFileStream óæå óñòàíîâëåíû, fFiles ñîçäàí,
64 // â í¸ì, ñêîðåå âñåãî, íèêîãî íåò.
65 // ïîçèöèÿ ïîòîêà -- òà, ÷òî îñòàâèëà ôàáðèêà.
66 // ïðè îøèáêàõ êèäàòü èñêëþ÷åíèå, òîãäà òîì áóäåò ïðèáèò ôàáðèêîé.
67 // ðàçäåëèòåëè ïóòåé äîëæíû áûòü òîëüêî "/", êîðíåâîé "/" äîëæåí
68 // áûòü îïóùåí, ïóòè (åñëè íå ïóñòûå) äîëæíû çàâåðøàòüñÿ "/"!
69 // fName äîëæíî ñîäåðæàòü òîëüêî èìÿ, fPath -- òîëüêî ïóòü.
70 // â ïðèíöèïå, îá ýòîì ïîçàáîòèòñÿ DoDirectoryRead(), íî çà÷åì
71 // äàâàòü åìó ëèøíþþ ðàáîòó?
74 // íàéòè ôàéë, âåðíóòü åãî èíäåêñ â fFiles.
75 // ýòà ïðîöåäóðà ìîæåò ìåíÿòü fFiles!
76 // fPath -- â ïðàâèëüíîé ôîðìå, ñ "/", êîðíåâîé "/" óáèò, ôèíàëüíûé äîáàâëåí.
77 // åñëè ôàéë íå íàéäåí, âåðíóòü -1.
80 // âîçâðàùàåò êîëè÷åñòâî ôàéëîâ â fFiles
83 // âîçâðàùàåò ôàéë ñ èíäåêñîì index.
84 // ìîæåò âîçâðàùàòü NIL.
85 // íèêàêèõ ïàäåíèé íà íåïðàâèëüíûå èíäåêñû!
88 public
89 // pSt íå îáÿçàòåëüíî çàïîìèíàòü, åñëè îí íå íóæåí.
91 // fFileStream óíè÷òîæàòü íåëüçÿ, åñëè îí ðàâåí ïàðàìåòðó pSt êîíñòðóêòîðà.
94 // âûçûâàåò ReadDirectory().
95 // ýòà ïðîöåäóðà ñàìà ðàçáåð¸òñÿ ñ äóáëèêàòàìè èì¸í: ïîäîáàâëÿåò â
96 // êîíåö èì¸í-äóáëèêàòîâ ïîä÷¸ðêèâàíèå è äåñÿòè÷íûé íîìåð.
97 // òàêæå îíà íîðìàëèçóåò âèä èì¸í.
100 // ïðè îøèáêàõ êèäàòüñÿ èñêëþ÷åíèÿìè.
103 // åñëè íå ñìîãëî îòêóïîðèòü ôàéëî (èëè åù¸ ãäå îøèáëîñü), çàøâûðí¸ò èñêëþ÷åíèå.
107 // ìîæåò âîçâðàùàòü NIL.
108 // íèêàêèõ ïàäåíèé íà íåïðàâèëüíûå èíäåêñû!
112 // ôàáðèêà òîìîâ. âñå SFS ïðè ñòàðòå äîáàâëÿþò ñâîè ôàáðèêè.
113 // áëàãîäàðÿ ýòîìó ìîæíî ñîçäàâàòü ðàçíûå âñÿêèå SFS ñòàíäàðòíûì
114 // âûçîâîì ñòàíäàðòíîé ïðîöåäóðû.
115 // ôàáðèêà ÍÅ ÄÎËÆÍÀ óáèâàòüñÿ íèêàê èíà÷å, ÷åì ïðè ïîìîùè âûçîâà
116 // SFSUnregisterVolumeFactory()! ýòî ãàðàíòèðóåò, ÷òî äâèæîê
117 // ïåðåä ðàññòðåëîì îòäàñò åé âñå å¸ òîìà.
119 public
120 // åñëè äîáàâëÿåì ôàéë äàííûõ ôàéë ñ èìåíåì òèïà "zip:....", òî
121 // SFS èçâëå÷¸ò ýòî "zip" è ïåðåäàñò â ñèþ ôóíêöèþ.
122 // åæåëè ôóíêöèÿ âåðí¸ò ïðàâäó, òî SFS âûçîâåò Produce äëÿ äàííîãî
123 // ôàéëà. åñëè íè îäíà ôàáðèêà ïðåôèêñ íå ïðèçíàåò, òî ôàéë íå îòêðîþò.
124 // èñïîëüçóåòñÿ äëÿ ñêèïàíèÿ àâòîäåòåêòà.
125 // SFS ÍÅ Ñ×ÈÒÀÅÒ ÏÐÅÔÈÊÑÎÌ ÑÒÐÎÊÓ ÊÎÐÎ×Å ÒÐ¨Õ ÑÈÌÂÎËÎÂ!
127 // ïðîâåðÿåò, ìîæåò ëè ôàáðèêà ñäåëàòü òîì äëÿ äàííîãî ôàéëà.
128 // st -- îòêðûòûé äëÿ ÷òåíèÿ ôàéëîâé ïîòîê. óêàçàòåëü ÷òåíèÿ ñòîèò â íà÷àëå.
129 // ýòîò ïîòîê íåëüçÿ çàêðûâàòü!
130 // prefix: òî, ÷òî áûëî ïåðåäàíî â IsMyVolumePrefix() èëè ''.
131 // èñêëþ÷åíèå ñ÷èòàåòñÿ îøèáêîé, âîçâðàò NIL ñ÷èòàåòñÿ îøèáêîé.
132 function Produce (const prefix, fileName: AnsiString; st: TStream): TSFSVolume; virtual; abstract;
133 // êîãäà òîì áîëüøå íå íóæåí, îí áóäåò îòäàí ôàáðèêå íà ïåðåðàáîòêó.
134 // äàëåå äâèæîê íå áóäåò þçàòü ñåé òîì.
138 // "èòåðàòîð", âîçâðàùàåìûé SFSFileList()
140 protected
146 public
152 // ïðè íåïðàâèëüíîì èíäåêñå ìîë÷à âåðí¸ò NIL.
153 // ïðè ïðàâèëüíîì òîæå ìîæåò âåðíóòü NIL!
154 // î÷åíü íå ñîâåòóþ ìåíÿòü ñîäåðæèìîå ïîëó÷åííîãî êëàññà.
155 // êîíå÷íî, ÿ ìîã áû âîçâðàùàòü íîâóþ ñòðóêòóðó èëè íå÷òî ïîõîæåå,
156 // íî áëèí, åñëè òû èäèîò è íå óìååøü äàæå êîììåíòû ÷èòàòü, òî
157 // êàêîãî òû âîîáùå â ïðîãðàììèíã ïîëåç?
163 // ýòà ôóíêöèÿ àâòîìàòè÷åñêè ïðèáü¸ò factory.
166 // äîáàâèòü ñáîðíèê â ïîñòîÿííûé ñïèñîê.
167 // åñëè ñáîðíèê ñ òàêèì èìåíåì óæå îòêðûò, òî íå îòêðûâàåò åãî ïîâòîðíî.
168 // íèêîãäà íå êèäàåò èñêëþ÷åíèé.
169 // top: äîáàâèòü â íà÷àëî ñïèñêà ïîèñêà.
170 // âåðí¸ò ëîæü ïðè îøèáêå.
171 // ñïîñîáíî îòêðûâàòü ñáîðíèêè â ñáîðíèêàõ ïðè ïîìîùè êðóòûõ èì¸í a-la:
172 // "zip:pack0::pack:pack1::wad2:pack2".
173 // â äàëüíåéøåì ñëåäóåò îáðàùàòüñÿ ê ñáîðíèêó êàê "pack2::xxx".
174 // èëè ìîæíî íàïèñàòü:
175 // "zip:pack0::pack:pack1::wad2:pack2|datafile".
176 // è îáðàùàòüñÿ êàê "datafile::xxx".
177 // "||" ïðåîáðàçóþòñÿ â ïðîñòîé "|" è ðàçäåëèòåëåì íå ñ÷èòàþòñÿ.
178 // ïðèíèìàåòñÿ âî âíèìàíèå òîëüêî ïîñëåäíÿÿ òðóáà.
181 // äîáàâèòü ñáîðíèê âðåìåííî
184 // äîáàâèòü â ïîñòîÿííûé ñïèñîê ñáîðíèê èç ïîòîêà ds.
185 // åñëè âîçâðàùàåò èñòèíó, òî SFS ñòàíîâèòñÿ âëÿäåëüöåì ïîòîêà ds è ñàìà
186 // óãðîáèò ñåé ïîòîê ïî íåîáõîäèìîñòè.
187 // virtualName ñòàíîâèòñÿ èìåíåì ñáîðíèêà äëÿ îïåðàöèè îòêðûòèÿ ôàéëà òèïà
188 // "packfile:file.ext".
189 // åñëè êàêîé-íèáóäü ñáîðíèê ñ èìåíåì virtualName óæå îòêðûò, âåðí¸ò false.
190 // íèêîãäà íå êèäàåò èñêëþ÷åíèé.
191 // top: äîáàâèòü â íà÷àëî ñïèñêà ïîèñêà.
192 // âåðí¸ò ëîæü ïðè îøèáêå.
193 // îòêðûâàåò ñáîðíèê èç ïîòîêà. dataFileName -- ÂÈÐÒÓÀËÜÍÎÅ èìÿ.
194 // ò.å. íà ñàìîì äåëå òàêîãî ôàéëà ìîæåò è íå áûòü íà äèñêå.
195 function SFSAddSubDataFile (const virtualName: AnsiString; ds: TStream; top: Boolean=false): Boolean;
197 // øâûðÿåòñÿ èñêëþ÷åíèÿìè.
198 // åñëè fName íå èìååò óêàçàíèÿ íà ôàéë äàííûõ (ýòî òî, ÷òî îòäåëåíî îò
199 // îñòàëüíîãî èìåíè äâîåòî÷èåì), òî èùåì ñíà÷àëà ïî âñåì çàðåãèñòðèðîâàííûì
200 // ôàéëàì äàííûõ, ïîòîì â òåêóùåì êàòàëîãå, ïîòîì â êàòàëîãå, îòêóäà ñòàðòîâàëè.
201 // åñëè íè÷åãî íå íàøëè, êèäàåì èñêëþ÷åíèå.
204 // ïðè îøèáêå -- NIL, è íèêàêèõ èñêëþ÷åíèé.
207 // âîçâðàùàåò NIL ïðè îøèáêå.
208 // ïîñëå èñïîëüçîâàíèÿ, íàòóðàëüíî, èòåðàòîð íàäî ãðîõíóòü %-)
211 // çàïðåòèòü îñâîáîæäåíèå âðåìåííûõ òîìîâ (ìîæíî âûçûâàòü ðåêóðñèâíî)
214 // ðàçðåøèòü îñâîáîæäåíèå âðåìåííûõ òîìîâ (ìîæíî âûçûâàòü ðåêóðñèâíî)
217 // for completeness sake
222 // ðàçîáðàòü òîëñòîå èìÿ ôàéëà, âåðíóòü âèðòóàëüíîå èìÿ ïîñëåäíåãî ñïèñêà
223 // èëè ïóñòóþ ñòîðîêó, åñëè ñïèñêîâ íå áûëî.
226 // Wildcard matching
227 // this code is meant to allow wildcard pattern matches. tt is VERY useful
228 // for matching filename wildcard patterns. tt allows unix grep-like pattern
229 // comparisons, for instance:
230 //
231 // ? Matches any single characer
232 // + Matches any single characer or nothing
233 // * Matches any number of contiguous characters
234 // [abc] Matches a or b or c at that position
235 // [!abc] Matches anything but a or b or c at that position
236 // [a-e] Matches a through e at that position
237 //
238 // 'ma?ch.*' -Would match match.exe, mavch.dat, march.on, etc
239 // 'this [e-n]s a [!zy]est' -Would match 'this is a test', but would
240 // not match 'this as a yest'
241 //
247 var
248 // ïðàâäà: ðàçðåøåíî èñêàòü ôàéëî íå òîëüêî â ôàéëàõ äàííûõ, íî è íà äèñêå.
250 // ïðàâäà: åñëè ôàéë íå ïðåôèêñîâàí, òî ñíà÷àëà èùåì ôàéëî íà äèñêå,
251 // ïîòîì â ôàéëàõ äàííûõ.
253 // ïðàâäà: äàæå äëÿ ïðåôèêñîâàíûõ ôàéëîâ ñíà÷àëà ïðîñìîòðèì äèñê
254 // (åñëè óñòàíîâëåí ôëàæîê sfsDiskFirst è sfsDiskEnabled).
256 // ñïèñîê äèñêîâûõ êàòàëîãîâ äëÿ ïîèñêà ôàéëà. åñëè ïóñò -- èùåì òîëüêî â
257 // òåêóùåì. êàòàëîãè ðàçäåëÿþòñÿ òðóáîé ("|").
258 // <currentdir> çàìåíÿåòñÿ íà òåêóùèé êàòàëîã (ñ çàâåðøàþùèì "/"),
259 // <exedir> çàìåíÿåòñÿ íà êàòàëîã, ãäå ñèäèò .EXE (ñ çàâåðøàþùèì "/").
263 implementation
265 uses
269 const
270 // character defines
282 begin
283 result :=
291 function MatchMask (const pattern: AnsiString; p, pend: Integer; const text: AnsiString; t, tend: Integer): Boolean;
292 var
296 begin
297 // sanity checks
303 begin
305 begin
306 // no more text. check if there's no more chars in pattern (except "*" & "+")
311 exit;
314 WILD_CHAR_SINGLE: ;
315 WILD_CHAR_ESCAPE:
316 begin
321 WILD_CHAR_RANGE_OPEN:
322 begin
330 repeat
336 begin
340 begin
342 end
344 end
349 // skip the rest or the range
353 WILD_CHAR_SINGLE_OR_NONE:
354 begin
358 exit;
360 WILD_CHAR_MULTI:
361 begin
365 begin
369 exit;
380 begin
387 var
389 begin
395 begin
397 begin
399 begin
406 begin
416 type
418 public
423 fPermanent: Boolean; // èñòèíà -- íå áóäåò óãðîáëåíà, åñëè íå îñòàíåòñÿ íè îäíîãî îòêðûòîãî òîìà
424 // èñòèíà -- ýòîò òîì áûë ñîçäàí èç ïîòîêà è íå èìååò äèñêîâîãî ôàéëà, ïîòîìó ôàáðèêå áóäåò ïåðåäàíî íå èìÿ ñáîðíèêà, à ïóñòàÿ ñòðîêà
432 protected
435 public
441 var
448 var
452 begin
453 // collect garbage
456 begin
459 begin
460 // this volume probably can be removed
464 begin
466 begin
474 begin
475 {$IFDEF SFS_VOLDEBUG}writeln('000: destroying volume "', TVolumeInfo(volumes[f]).fPackName, '"');{$ENDIF}
479 continue;
487 begin
492 begin
495 begin
502 // ðàçáèòü èìÿ ôàéëà íà ÷àñòè: ïðåôèêñ ôàéëîâîé ñèñòåìû, èìÿ ôàéëà äàííûõ,
503 // ñîáñòâåííî èìÿ ôàéëà
504 // èìÿ âûãëÿäèò êàê:
505 // (("sfspfx:")?"datafile::")*"filename"
507 var
509 begin
512 begin
517 else
518 begin
524 // ñàéäýôôåêò: âûðåçàåò âèðòóàëüíîå èìÿ èç dataFile.
526 var
528 begin
531 begin
534 begin
536 else
537 begin
540 break;
547 // ðàçáèòü èìÿ ñáîðíèêà íà ÷àñòè: ïðåôèêñ ôàéëîâîé ñèñòåìû, èìÿ ôàéëà äàííûõ,
548 // âèðòóàëüíîå èìÿ. åñëè âèðòóàëüíîãî èìåíè íå äàíî, îíî áóäåò ðàâíî dataFile.
549 // èìÿ âûãëÿäèò êàê:
550 // [sfspfx:]datafile[|virtname]
551 // åñëè ïåðåä äâîåòî÷èåì ìåíüøå òð¸õ áóêâ, òî ýòî ñ÷èòàåòñÿ íå ïðåôèêñîì,
552 // à èìåíåì äèñêà.
554 var
556 begin
559 else
560 begin
567 // íàéòè ïðîèçâîäèòåëÿ äëÿ ýòîãî ôàéëà (åñëè ôàéë óæå îòêðûò).
568 // onlyPerm: òîëüêî "ïîñòîÿííûå" ïðîèçâîäèòåëè.
570 var
573 begin
576 begin
578 begin
581 begin
583 begin
585 exit;
594 // íàéòè èíôó äëÿ ýòîãî òîìà.
595 // õîðîøåå èìÿ, ïðàâäà? %-)
597 begin
600 begin
602 begin
610 // adds '/' too
612 var
614 begin
618 begin
620 begin
622 continue;
625 begin
627 end
628 else
629 begin
638 var
640 begin
643 begin
645 begin
646 // avoid unnecessary string changes
653 var
656 begin
658 repeat
666 { TVolumeInfo }
668 var
671 begin
678 // òèïà ìóñîðîñáîðíèê: åñëè íàø ïîòîê áîëåå íèêåì íå þçàåòñÿ, òî óãðîáèòü åãî íàôèã
680 begin
684 begin
686 begin
689 begin
702 { TOwnedPartialStream }
705 begin
712 var
714 begin
717 begin
720 begin
723 begin
724 {$IFDEF SFS_VOLDEBUG}writeln('001: destroying volume "', TVolumeInfo(volumes[f]).fPackName, '"');{$ENDIF}
732 { TSFSFileInfo }
734 begin
745 begin
751 { TSFSVolume }
753 begin
761 var
765 begin
772 begin
774 // normalize name & path
781 begin
782 // split path and name
794 begin
801 begin
806 begin
808 else
809 begin
812 begin
815 begin
825 begin
830 begin
832 else
833 begin
840 var
843 begin
845 // normalize name, find split position
849 begin
862 { TSFSFileList }
864 var
866 begin
876 var
878 begin
882 // óáü¸ì çàïèñü, åñëè îíà âðåìåííàÿ, è â íåé íåò áîëüøå íè÷åãî îòêðûòîãî
883 if (gcdisabled = 0) and not TVolumeInfo(volumes[f]).fPermanent and (TVolumeInfo(volumes[f]).fOpenedFilesCount < 1) then
884 begin
885 {$IFDEF SFS_VOLDEBUG}writeln('002: destroying volume "', TVolumeInfo(volumes[f]).fPackName, '"');{$ENDIF}
892 begin
897 begin
904 var
906 begin
915 var
918 begin
923 begin
931 function SFSAddDataFileEx (dataFileName: AnsiString; ds: TStream; top, permanent: Integer): Integer;
932 // dataFileName ìîæåò èìåòü ïðåôèêñ òèïà "zip:" (ñì. âûøå: IsMyPrefix).
933 // ìîæåò âûêèíóòü èñêëþ÷åíèå!
934 // top:
935 // <0: äîáàâèòü â íà÷àëî ñïèñêà ïîèñêà.
936 // =0: íå ìåíÿòü.
937 // >0: äîáàâèòü â êîíåö ñïèñêà ïîèñêà.
938 // permanent:
939 // <0: ñîçäàòü "âðåìåííûé" òîì.
940 // =0: íå ìåíÿòü ôëàæîê ïîñòîÿíñòâà.
941 // >0: ñîçäàòü "ïîñòîÿííûé" òîì.
942 // åñëè ds <> nil, òî ñîçäà¸ò ñáîðíèê èç ïîòîêà. åñëè ñáîðíèê ñ èìåíåì
943 // dataFileName óæå çàðåãèñòðèðîâàí, òî ïàäàåò íàôèã.
944 // âîçâðàùàåò èíäåêñ â volumes.
945 // óìååò äåëàòü ðåêóðñèþ.
946 var
954 begin
957 begin
958 // ðåêóðñèâíîå îòêðûòèå.
959 // ðàçîáü¸ì dataFileName íà èìÿ ñáîðíèêà è îñòàòîê.
960 // pfx áóäåò èìåíåì ñáîðíèêà, dataFileName -- îñòàòêîì.
962 // ñíà÷àëà îòêðîåì ïåðâûé ñïèñîê...
964 // ...òåïåðü ïðîäîëæèì ñ îñòàòêîì.
965 // óçíàåì, êàêîå ôàéëî îòêðûâàòü.
966 // âûêîâûðÿåì ïåðâûé "::" ïðåôèêñ (ýòî áóäåò èìÿ ôàéëà).
969 // dataFileName õðàíèò îñòàòîê.
970 // èçâëå÷¸ì èìÿ ôàéëà:
972 // îòêðîåì ýòîò ôàéë
974 try
977 except
979 // óäàëèì íåèñïîëüçóåìûé âðåìåííûé òîì.
980 if (gcdisabled = 0) and not vi.fPermanent and (vi.fOpenedFilesCount < 1) then volumes[result] := nil;
983 // óðà. îòêðûëè ôàéë. êèäàåì â âîçäóõ ÷åï÷èêè, ïðîäîëæàåì ðàçâëå÷åíèå.
985 try
988 except
992 exit;
995 // îáûêíîâåííîå íåðåêóðñèâíîå îòêðûòèå.
1000 begin
1007 exit;
1017 try
1019 begin
1024 try
1027 except
1033 except
1039 try
1041 begin
1044 end
1046 except
1062 function SFSAddSubDataFile (const virtualName: AnsiString; ds: TStream; top: Boolean=false): Boolean;
1063 var
1065 begin
1067 try
1071 except
1077 var
1079 begin
1080 try
1084 except
1090 var
1092 begin
1093 try
1097 except
1105 var
1108 begin
1111 begin
1122 begin
1127 end
1133 var
1141 // ïðîâåðèì, åñòü ëè ôàëî fn ãäå-òî íà äèñêàõ.
1142 var
1145 begin
1152 begin
1158 try
1160 exit;
1161 except
1166 begin
1173 begin
1174 // ïðåôèêñîâàíûé ôàéë
1176 begin
1184 try
1187 except
1189 if (gcdisabled = 0) and not vi.fPermanent and (vi.fOpenedFilesCount < 1) then volumes[f] := nil;
1192 exit;
1194 //Inc(vi.fOpenedFilesCount);
1196 exit;
1199 // íåïðåôèêñîâàíûé ôàéë
1201 begin
1205 // èùåì ïî âñåì ïåðìàíåíòíûì ïðåôèêñàì
1208 begin
1211 begin
1213 begin
1216 begin
1217 try
1220 //Inc(vi.fOpenedFilesCount);
1221 except
1235 begin
1236 try
1238 except
1244 var
1247 begin
1251 try
1253 except
1254 exit;
1258 try
1260 except
1261 if (gcdisabled = 0) and not vi.fPermanent and (vi.fOpenedFilesCount < 1) then volumes[f] := nil;
1266 initialization
1269 //finalization
1270 //volumes.Free(); // it fails for some reason... Runtime 217 (^C hit). wtf?!
1271 //factories.Free(); // not need to be done actually...