1 /*
2  *  The ManaPlus Client
3  *  Copyright (C) 2016-2019  The ManaPlus Developers
4  *  Copyright (C) 2019-2021  Andrei Karas
5  *
6  *  This file is part of The ManaPlus Client.
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include "unittests/unittests.h"
23 
24 #include "fs/files.h"
25 
26 #include "fs/virtfs/fs.h"
27 #include "fs/virtfs/rwops.h"
28 
29 #include "utils/checkutils.h"
30 #include "utils/foreach.h"
31 #include "utils/stringutils.h"
32 
33 PRAGMA48(GCC diagnostic push)
34 PRAGMA48(GCC diagnostic ignored "-Wshadow")
35 #include <SDL_rwops.h>
PRAGMA48(GCC diagnostic pop)36 PRAGMA48(GCC diagnostic pop)
37 
38 #ifndef UNITTESTS_CATCH
39 #include <algorithm>
40 #endif  // UNITTESTS_CATCH
41 
42 #include "debug.h"
43 
44 static bool inList(StringVect list,
45                    const std::string &name)
46 {
47     FOR_EACH (StringVectCIter, it, list)
48     {
49         if (*it == name)
50             return true;
51     }
52     return false;
53 }
54 
inList(StringVect list,const std::string & dir,const std::string & name)55 static bool inList(StringVect list,
56                    const std::string &dir,
57                    const std::string &name)
58 {
59     const std::string path = pathJoin(dir, name);
60     FOR_EACH (StringVectCIter, it, list)
61     {
62         if (*it == path)
63             return true;
64     }
65     return false;
66 }
67 
removeTemp(StringVect & restrict list)68 static void removeTemp(StringVect &restrict list)
69 {
70     int cnt = 0;
71     std::sort(list.begin(), list.end());
72 
73     FOR_EACH (StringVectIter, it, list)
74     {
75         if (*it != "serverlistplus.xml.part")
76         {
77             logger->log("file: %d %s",
78                 cnt,
79                 (*it).c_str());
80             cnt ++;
81         }
82     }
83 
84     FOR_EACH (StringVectIter, it, list)
85     {
86         if (*it == "serverlistplus.xml.part")
87         {
88             list.erase(it);
89             return;
90         }
91     }
92 }
93 
94 TEST_CASE("VirtFs2 isDirectory1", "")
95 {
96     VirtFs::init(".");
97     std::string name("data/test/test.zip");
98     std::string prefix;
99     if (Files::existsLocal(name) == false)
100         prefix = "../" + prefix;
101 
102     VirtFs::mountDir(prefix + "data",
103         Append_false);
104 
105     REQUIRE(VirtFs::isDirectory("test/units.xml") == false);
106     REQUIRE(VirtFs::isDirectory("test/units.xml/") == false);
107     REQUIRE(VirtFs::isDirectory("test//units.xml") == false);
108     REQUIRE(VirtFs::isDirectory("test/units123.xml") == false);
109     REQUIRE(VirtFs::isDirectory("test//units123.xml") == false);
110     REQUIRE(VirtFs::isDirectory("tesQ/units.xml") == false);
111     REQUIRE(VirtFs::isDirectory("tesQ//units.xml") == false);
112     REQUIRE(VirtFs::isDirectory("units.xml") == false);
113     REQUIRE(VirtFs::isDirectory("test") == true);
114     REQUIRE(VirtFs::isDirectory("test/") == true);
115     REQUIRE(VirtFs::isDirectory("test//") == true);
116     REQUIRE(VirtFs::isDirectory("test/dir1") == true);
117     REQUIRE(VirtFs::isDirectory("test//dir1") == true);
118     REQUIRE(VirtFs::isDirectory("test//dir1/") == true);
119     REQUIRE(VirtFs::isDirectory("test//dir1//") == true);
120     REQUIRE(VirtFs::isDirectory("test\\dir1/") == true);
121     REQUIRE(VirtFs::isDirectory("test/dir1//") == true);
122     REQUIRE(VirtFs::isDirectory("testQ") == false);
123     REQUIRE(VirtFs::isDirectory("testQ/") == false);
124     REQUIRE(VirtFs::isDirectory("testQ//") == false);
125 
126     VirtFs::mountDir(prefix + "data/test",
127         Append_false);
128 
129     REQUIRE(VirtFs::isDirectory("test/units.xml") == false);
130     REQUIRE(VirtFs::isDirectory("test/units.xml/") == false);
131     REQUIRE(VirtFs::isDirectory("test//units.xml") == false);
132     REQUIRE(VirtFs::isDirectory("test/units123.xml") == false);
133     REQUIRE(VirtFs::isDirectory("tesQ/units.xml") == false);
134     REQUIRE(VirtFs::isDirectory("units.xml") == false);
135     REQUIRE(VirtFs::isDirectory("test") == true);
136     REQUIRE(VirtFs::isDirectory("testQ") == false);
137     REQUIRE(VirtFs::isDirectory("test/dir1") == true);
138     REQUIRE(VirtFs::isDirectory("test\\dir1") == true);
139 
140     VirtFs::unmountDir(prefix + "data/test");
141 
142     REQUIRE(VirtFs::isDirectory("test/units.xml") == false);
143     REQUIRE(VirtFs::isDirectory("test/units123.xml") == false);
144     REQUIRE(VirtFs::isDirectory("tesQ/units.xml") == false);
145     REQUIRE(VirtFs::isDirectory("units.xml") == false);
146     REQUIRE(VirtFs::isDirectory("units.xml/") == false);
147     REQUIRE(VirtFs::isDirectory("test") == true);
148     REQUIRE(VirtFs::isDirectory("test/") == true);
149     REQUIRE(VirtFs::isDirectory("testQ") == false);
150     REQUIRE(VirtFs::isDirectory("test/dir1") == true);
151 
152     VirtFs::unmountDirSilent(prefix + "data");
153     VirtFs::deinit();
154 }
155 
156 TEST_CASE("VirtFs2 isDirectory2", "")
157 {
158     VirtFs::init(".");
159     std::string name("data/test/test.zip");
160     std::string prefix;
161     if (Files::existsLocal(name) == false)
162         prefix = "../" + prefix;
163 
164     VirtFs::mountZip(prefix + "data/test/test2.zip",
165         Append_false);
166 
167     REQUIRE(VirtFs::isDirectory("dir2/units.xml") == false);
168     REQUIRE(VirtFs::isDirectory("dir2/units.xml/") == false);
169     REQUIRE(VirtFs::isDirectory("dir2//units.xml") == false);
170     REQUIRE(VirtFs::isDirectory("dir2/units123.xml") == false);
171     REQUIRE(VirtFs::isDirectory("dir2//units123.xml") == false);
172     REQUIRE(VirtFs::isDirectory("tesQ/units.xml") == false);
173     REQUIRE(VirtFs::isDirectory("tesQ//units.xml") == false);
174     REQUIRE(VirtFs::isDirectory("units.xml") == false);
175     REQUIRE(VirtFs::isDirectory("dir") == true);
176     REQUIRE(VirtFs::isDirectory("dir2/") == true);
177     REQUIRE(VirtFs::isDirectory("dir2//") == true);
178     REQUIRE(VirtFs::isDirectory("dir/1") == true);
179     REQUIRE(VirtFs::isDirectory("dir//1") == true);
180     REQUIRE(VirtFs::isDirectory("dir\\1/") == true);
181     REQUIRE(VirtFs::isDirectory("dir/1") == true);
182     REQUIRE(VirtFs::isDirectory("dir/1/zzz") == false);
183     REQUIRE(VirtFs::isDirectory("test/dir1\\") == false);
184     REQUIRE(VirtFs::isDirectory("testQ") == false);
185     REQUIRE(VirtFs::isDirectory("testQ/") == false);
186     REQUIRE(VirtFs::isDirectory("testQ//") == false);
187 
188     VirtFs::mountZip(prefix + "data/test/test.zip",
189         Append_false);
190 
191     REQUIRE(VirtFs::isDirectory("dir2/units.xml") == false);
192     REQUIRE(VirtFs::isDirectory("dir2/units.xml/") == false);
193     REQUIRE(VirtFs::isDirectory("dir2\\units.xml") == false);
194     REQUIRE(VirtFs::isDirectory("dir2/units123.xml") == false);
195     REQUIRE(VirtFs::isDirectory("dir2//units123.xml") == false);
196     REQUIRE(VirtFs::isDirectory("tesQ/units.xml") == false);
197     REQUIRE(VirtFs::isDirectory("tesQ//units.xml") == false);
198     REQUIRE(VirtFs::isDirectory("units.xml") == false);
199     REQUIRE(VirtFs::isDirectory("dir") == true);
200     REQUIRE(VirtFs::isDirectory("dir2/") == true);
201     REQUIRE(VirtFs::isDirectory("dir2\\") == true);
202     REQUIRE(VirtFs::isDirectory("dir/1") == true);
203     REQUIRE(VirtFs::isDirectory("dir//1") == true);
204     REQUIRE(VirtFs::isDirectory("dir//1/") == true);
205     REQUIRE(VirtFs::isDirectory("dir/1") == true);
206     REQUIRE(VirtFs::isDirectory("dir/1/zzz") == false);
207     REQUIRE(VirtFs::isDirectory("test/dir1//") == false);
208     REQUIRE(VirtFs::isDirectory("testQ") == false);
209     REQUIRE(VirtFs::isDirectory("testQ/") == false);
210     REQUIRE(VirtFs::isDirectory("testQ//") == false);
211 
212     VirtFs::unmountZip(prefix + "data/test/test2.zip");
213 
214     REQUIRE(VirtFs::isDirectory("dir2/units.xml") == false);
215     REQUIRE(VirtFs::isDirectory("dir2/units.xml/") == false);
216     REQUIRE(VirtFs::isDirectory("dir2//units.xml") == false);
217     REQUIRE(VirtFs::isDirectory("dir2/units123.xml") == false);
218     REQUIRE(VirtFs::isDirectory("dir2//units123.xml") == false);
219     REQUIRE(VirtFs::isDirectory("tesQ/units.xml") == false);
220     REQUIRE(VirtFs::isDirectory("tesQ//units.xml") == false);
221     REQUIRE(VirtFs::isDirectory("units.xml") == false);
222     REQUIRE(VirtFs::isDirectory("dir") == true);
223     REQUIRE(VirtFs::isDirectory("dir2/") == false);
224     REQUIRE(VirtFs::isDirectory("dir2//") == false);
225     REQUIRE(VirtFs::isDirectory("dir/1") == false);
226     REQUIRE(VirtFs::isDirectory("dir\\1") == false);
227     REQUIRE(VirtFs::isDirectory("dir//1/") == false);
228     REQUIRE(VirtFs::isDirectory("dir/1") == false);
229     REQUIRE(VirtFs::isDirectory("dir/1/zzz") == false);
230     REQUIRE(VirtFs::isDirectory("test/dir1//") == false);
231     REQUIRE(VirtFs::isDirectory("testQ") == false);
232     REQUIRE(VirtFs::isDirectory("testQ/") == false);
233     REQUIRE(VirtFs::isDirectory("testQ//") == false);
234 
235     VirtFs::unmountZip(prefix + "data/test/test.zip");
236     VirtFs::deinit();
237 }
238 
239 TEST_CASE("VirtFs2 isDirectory3", "")
240 {
241     VirtFs::init(".");
242     std::string name("data/test/test.zip");
243     std::string prefix;
244     if (Files::existsLocal(name) == false)
245         prefix = "../" + prefix;
246 
247     VirtFs::mountDir2(prefix + "data",
248         "test",
249         Append_false);
250 
251     REQUIRE(VirtFs::isDirectory("units.xml") == false);
252     REQUIRE(VirtFs::isDirectory("units.xml/") == false);
253     REQUIRE(VirtFs::isDirectory("units123.xml") == false);
254     REQUIRE(VirtFs::isDirectory("tesQ/units.xml") == false);
255     REQUIRE(VirtFs::isDirectory("tesQ//units.xml") == false);
256     REQUIRE(VirtFs::isDirectory("test") == false);
257     REQUIRE(VirtFs::isDirectory("dir1") == true);
258     REQUIRE(VirtFs::isDirectory("dir2//") == true);
259     REQUIRE(VirtFs::isDirectory("test/dir1") == false);
260     REQUIRE(VirtFs::isDirectory("testQ") == false);
261     REQUIRE(VirtFs::isDirectory("testQ/") == false);
262     REQUIRE(VirtFs::isDirectory("testQ//") == false);
263 
264     VirtFs::unmountDirSilent2(prefix + "data",
265         "test");
266     VirtFs::deinit();
267 }
268 
269 TEST_CASE("VirtFs2 isDirectory4", "")
270 {
271     VirtFs::init(".");
272     std::string name("data/test/test.zip");
273     std::string prefix;
274     if (Files::existsLocal(name) == false)
275         prefix = "../" + prefix;
276 
277     VirtFs::mountZip2(prefix + "data/test/test2.zip",
278         "dir",
279         Append_false);
280 
281     REQUIRE(VirtFs::isDirectory("dir2/units.xml") == false);
282     REQUIRE(VirtFs::isDirectory("dir2/units.xml/") == false);
283     REQUIRE(VirtFs::isDirectory("dir2//units.xml") == false);
284     REQUIRE(VirtFs::isDirectory("dir2/units123.xml") == false);
285     REQUIRE(VirtFs::isDirectory("dir2//units123.xml") == false);
286     REQUIRE(VirtFs::isDirectory("tesQ/units.xml") == false);
287     REQUIRE(VirtFs::isDirectory("tesQ//units.xml") == false);
288     REQUIRE(VirtFs::isDirectory("units.xml") == false);
289     REQUIRE(VirtFs::isDirectory("1") == true);
290     REQUIRE(VirtFs::isDirectory("gpl") == true);
291     REQUIRE(VirtFs::isDirectory("dir2/") == false);
292     REQUIRE(VirtFs::isDirectory("dir/1") == false);
293     REQUIRE(VirtFs::isDirectory("dir/1/zzz") == false);
294     REQUIRE(VirtFs::isDirectory("test/dir1\\") == false);
295     REQUIRE(VirtFs::isDirectory("testQ") == false);
296     REQUIRE(VirtFs::isDirectory("testQ/") == false);
297     REQUIRE(VirtFs::isDirectory("testQ//") == false);
298 
299     VirtFs::unmountZip2(prefix + "data/test/test2.zip",
300         "dir");
301     VirtFs::deinit();
302 }
303 
304 TEST_CASE("VirtFs2 openRead1", "")
305 {
306     VirtFs::init(".");
307     std::string name("data/test/test.zip");
308     std::string prefix;
309     if (Files::existsLocal(name) == false)
310         prefix = "../" + prefix;
311 
312     VirtFs::mountDir(prefix + "data",
313         Append_false);
314 
315     VirtFs::File *file = nullptr;
316 
317     file = VirtFs::openRead("test/units.xml");
318     REQUIRE(file != nullptr);
319     VirtFs::close(file);
320     file = VirtFs::openRead("test\\units.xml");
321     REQUIRE(file != nullptr);
322     VirtFs::close(file);
323     file = VirtFs::openRead("test/units123.xml");
324     REQUIRE(file == nullptr);
325     file = VirtFs::openRead("tesQ/units.xml");
326     REQUIRE(file == nullptr);
327     file = VirtFs::openRead("units.xml");
328     REQUIRE(file == nullptr);
329     file = VirtFs::openRead("testQ");
330     REQUIRE(file == nullptr);
331 
332     VirtFs::mountDir(prefix + "data/test",
333         Append_false);
334 
335     file = VirtFs::openRead("test/units.xml");
336     REQUIRE(file != nullptr);
337     VirtFs::close(file);
338     file = VirtFs::openRead("test/units123.xml");
339     REQUIRE(file == nullptr);
340     file = VirtFs::openRead("tesQ/units.xml");
341     REQUIRE(file == nullptr);
342     file = VirtFs::openRead("units.xml");
343     REQUIRE(file != nullptr);
344     VirtFs::close(file);
345     file = VirtFs::openRead("testQ");
346     REQUIRE(file == nullptr);
347 
348     VirtFs::unmountDir(prefix + "data/test");
349 
350     file = VirtFs::openRead("test/units.xml");
351     REQUIRE(file != nullptr);
352     VirtFs::close(file);
353     file = VirtFs::openRead("test/units123.xml");
354     REQUIRE(file == nullptr);
355     file = VirtFs::openRead("tesQ/units.xml");
356     REQUIRE(file == nullptr);
357     file = VirtFs::openRead("units.xml");
358     REQUIRE(file == nullptr);
359     file = VirtFs::openRead("testQ");
360     REQUIRE(file == nullptr);
361 
362     VirtFs::unmountDir(prefix + "data");
363     VirtFs::deinit();
364 }
365 
366 TEST_CASE("VirtFs2 openRead2", "")
367 {
368     VirtFs::init(".");
369     std::string name("data/test/test.zip");
370     std::string prefix("data/test/");
371     if (Files::existsLocal(name) == false)
372         prefix = "../" + prefix;
373 
374     VirtFs::mountZip(prefix + "test2.zip",
375         Append_false);
376 
377     VirtFs::File *file = nullptr;
378 
379     file = VirtFs::openRead("dir2/units.xml");
380     REQUIRE(file != nullptr);
381     VirtFs::close(file);
382     file = VirtFs::openRead("dir2\\units.xml");
383     REQUIRE(file != nullptr);
384     VirtFs::close(file);
385     file = VirtFs::openRead("dir2/units123.xml");
386     REQUIRE(file == nullptr);
387     file = VirtFs::openRead("tesQ/units.xml");
388     REQUIRE(file == nullptr);
389     file = VirtFs::openRead("units.xml1");
390     REQUIRE(file == nullptr);
391     file = VirtFs::openRead("testQ");
392     REQUIRE(file == nullptr);
393     file = VirtFs::openRead("dir/brimmedhat.png");
394     REQUIRE(file == nullptr);
395     file = VirtFs::openRead("dir//brimmedhat.png");
396     REQUIRE(file == nullptr);
397 
398     VirtFs::mountZip(prefix + "test.zip",
399         Append_false);
400 
401     file = VirtFs::openRead("dir2/units.xml");
402     REQUIRE(file != nullptr);
403     VirtFs::close(file);
404     file = VirtFs::openRead("dir2//units.xml");
405     REQUIRE(file != nullptr);
406     VirtFs::close(file);
407     file = VirtFs::openRead("dir2/units123.xml");
408     REQUIRE(file == nullptr);
409     file = VirtFs::openRead("tesQ/units.xml");
410     REQUIRE(file == nullptr);
411     file = VirtFs::openRead("units.xml1");
412     REQUIRE(file == nullptr);
413     file = VirtFs::openRead("testQ");
414     REQUIRE(file == nullptr);
415     file = VirtFs::openRead("dir/brimmedhat.png");
416     REQUIRE(file != nullptr);
417     VirtFs::close(file);
418 
419     VirtFs::unmountZip(prefix + "test.zip");
420 
421     file = VirtFs::openRead("dir2/units.xml");
422     REQUIRE(file != nullptr);
423     VirtFs::close(file);
424     file = VirtFs::openRead("dir2\\/\\units.xml");
425     REQUIRE(file != nullptr);
426     VirtFs::close(file);
427     file = VirtFs::openRead("dir2/units123.xml");
428     REQUIRE(file == nullptr);
429     file = VirtFs::openRead("tesQ/units.xml");
430     REQUIRE(file == nullptr);
431     file = VirtFs::openRead("units.xml1");
432     REQUIRE(file == nullptr);
433     file = VirtFs::openRead("testQ");
434     REQUIRE(file == nullptr);
435     file = VirtFs::openRead("dir/brimmedhat.png");
436     REQUIRE(file == nullptr);
437 
438     VirtFs::unmountZip(prefix + "test2.zip");
439 
440     VirtFs::deinit();
441 }
442 
443 TEST_CASE("VirtFs2 openRead3", "")
444 {
445     VirtFs::init(".");
446     std::string name("data/test/test.zip");
447     std::string prefix;
448     if (Files::existsLocal(name) == false)
449         prefix = "../" + prefix;
450 
451     VirtFs::mountDir2(prefix + "data",
452         "test",
453         Append_false);
454 
455     VirtFs::File *file = nullptr;
456 
457     file = VirtFs::openRead("units.xml");
458     REQUIRE(file != nullptr);
459     VirtFs::close(file);
460     file = VirtFs::openRead("test/units.xml");
461     REQUIRE(file == nullptr);
462     file = VirtFs::openRead("units123.xml");
463     REQUIRE(file == nullptr);
464     file = VirtFs::openRead("tesQ/units.xml");
465     REQUIRE(file == nullptr);
466     file = VirtFs::openRead("testQ");
467     REQUIRE(file == nullptr);
468     file = VirtFs::openRead("file1.txt");
469     REQUIRE(file == nullptr);
470     file = VirtFs::openRead("file2.txt");
471     REQUIRE(file == nullptr);
472 
473     VirtFs::mountDir2(prefix + "data/test",
474         "dir2",
475         Append_false);
476 
477     file = VirtFs::openRead("units.xml");
478     REQUIRE(file != nullptr);
479     VirtFs::close(file);
480     file = VirtFs::openRead("test/units.xml");
481     REQUIRE(file == nullptr);
482     file = VirtFs::openRead("units123.xml");
483     REQUIRE(file == nullptr);
484     file = VirtFs::openRead("tesQ/units.xml");
485     REQUIRE(file == nullptr);
486     file = VirtFs::openRead("testQ");
487     REQUIRE(file == nullptr);
488     file = VirtFs::openRead("file1.txt");
489     REQUIRE(file != nullptr);
490     VirtFs::close(file);
491     file = VirtFs::openRead("file2.txt");
492     REQUIRE(file != nullptr);
493     VirtFs::close(file);
494 
495     VirtFs::unmountDir2(prefix + "data/test",
496         "dir2");
497 
498     file = VirtFs::openRead("units.xml");
499     REQUIRE(file != nullptr);
500     VirtFs::close(file);
501     file = VirtFs::openRead("test/units.xml");
502     REQUIRE(file == nullptr);
503     file = VirtFs::openRead("units123.xml");
504     REQUIRE(file == nullptr);
505     file = VirtFs::openRead("tesQ/units.xml");
506     REQUIRE(file == nullptr);
507     file = VirtFs::openRead("testQ");
508     REQUIRE(file == nullptr);
509     file = VirtFs::openRead("file1.txt");
510     REQUIRE(file == nullptr);
511     file = VirtFs::openRead("file2.txt");
512     REQUIRE(file == nullptr);
513 
514     VirtFs::unmountDir2(prefix + "data",
515         "test");
516     VirtFs::deinit();
517 }
518 
519 TEST_CASE("VirtFs2 openRead4", "")
520 {
521     VirtFs::init(".");
522     std::string name("data/test/test.zip");
523     std::string prefix("data/test/");
524     if (Files::existsLocal(name) == false)
525         prefix = "../" + prefix;
526 
527     VirtFs::mountZip2(prefix + "test2.zip",
528         "dir",
529         Append_false);
530 
531     VirtFs::File *file = nullptr;
532 
533     file = VirtFs::openRead("dye.png");
534     REQUIRE(file != nullptr);
535     VirtFs::close(file);
536     file = VirtFs::openRead("1\\test.txt");
537     REQUIRE(file != nullptr);
538     VirtFs::close(file);
539     file = VirtFs::openRead("dir/dye.png");
540     REQUIRE(file == nullptr);
541     file = VirtFs::openRead("tesQ/units.xml");
542     REQUIRE(file == nullptr);
543     file = VirtFs::openRead("dye.png1");
544     REQUIRE(file == nullptr);
545     file = VirtFs::openRead("testQ");
546     REQUIRE(file == nullptr);
547     file = VirtFs::openRead("brimmedhat.png");
548     REQUIRE(file == nullptr);
549 
550     VirtFs::mountZip2(prefix + "test.zip",
551         "dir",
552         Append_false);
553 
554     file = VirtFs::openRead("dye.png");
555     REQUIRE(file != nullptr);
556     VirtFs::close(file);
557     file = VirtFs::openRead("1\\test.txt");
558     REQUIRE(file != nullptr);
559     VirtFs::close(file);
560     file = VirtFs::openRead("dir/dye.png");
561     REQUIRE(file == nullptr);
562     file = VirtFs::openRead("tesQ/units.xml");
563     REQUIRE(file == nullptr);
564     file = VirtFs::openRead("dye.png1");
565     REQUIRE(file == nullptr);
566     file = VirtFs::openRead("testQ");
567     REQUIRE(file == nullptr);
568     file = VirtFs::openRead("brimmedhat.png");
569     REQUIRE(file != nullptr);
570     VirtFs::close(file);
571 
572     VirtFs::unmountZip2(prefix + "test.zip",
573         "dir");
574 
575     file = VirtFs::openRead("dye.png");
576     REQUIRE(file != nullptr);
577     VirtFs::close(file);
578     file = VirtFs::openRead("1\\test.txt");
579     REQUIRE(file != nullptr);
580     VirtFs::close(file);
581     file = VirtFs::openRead("dir/dye.png");
582     REQUIRE(file == nullptr);
583     file = VirtFs::openRead("tesQ/units.xml");
584     REQUIRE(file == nullptr);
585     file = VirtFs::openRead("dye.png1");
586     REQUIRE(file == nullptr);
587     file = VirtFs::openRead("testQ");
588     REQUIRE(file == nullptr);
589     file = VirtFs::openRead("brimmedhat.png");
590     REQUIRE(file == nullptr);
591 
592     VirtFs::unmountZip2(prefix + "test2.zip",
593         "dir");
594 
595     VirtFs::deinit();
596 }
597 
598 TEST_CASE("VirtFs2 permitLinks", "")
599 {
600     VirtFs::init(".");
601     std::string name("data/test/test.zip");
602     std::string prefix;
603     if (Files::existsLocal(name) == false)
604         prefix = "../" + prefix;
605 
606     VirtFs::mountDir(prefix + "data",
607         Append_false);
608 
609     const int cnt1 = VirtFs::exists("test/test2.txt") ? 27 : 26;
610     const int cnt2 = 27;
611 
612     StringVect list;
613     VirtFs::permitLinks(false);
614     VirtFs::getFiles("test", list);
615     removeTemp(list);
616     const size_t sz = list.size();
617     REQUIRE(sz == cnt1);
618 
619     list.clear();
620     VirtFs::permitLinks(true);
621     VirtFs::getFiles("test", list);
622     removeTemp(list);
623     REQUIRE(list.size() == cnt2);
624 
625     list.clear();
626     VirtFs::permitLinks(false);
627     VirtFs::getFiles("test", list);
628     removeTemp(list);
629     REQUIRE(list.size() == cnt1);
630 
631     VirtFs::unmountDirSilent(prefix + "data");
632     VirtFs::deinit();
633 }
634 
635 TEST_CASE("VirtFs2 read1", "")
636 {
637     VirtFs::init(".");
638     std::string name("data/test/test.zip");
639     std::string prefix;
640     if (Files::existsLocal(name) == false)
641         prefix = "../" + prefix;
642 
643     VirtFs::mountDir(prefix + "data",
644         Append_false);
645 
646     VirtFs::File *file = VirtFs::openRead("test/test.txt");
647     REQUIRE(file != nullptr);
648     REQUIRE(VirtFs::fileLength(file) == 23);
649     const int fileSize = VirtFs::fileLength(file);
650 
651     void *restrict buffer = calloc(fileSize + 1, 1);
652     REQUIRE(VirtFs::read(file, buffer, 1, fileSize) == fileSize);
653     REQUIRE(strcmp(static_cast<char*>(buffer),
654         "test line 1\ntest line 2") == 0);
655     REQUIRE(VirtFs::tell(file) == fileSize);
656     REQUIRE(VirtFs::eof(file) != 0);
657 
658     free(buffer);
659     buffer = calloc(fileSize + 1, 1);
660     REQUIRE(VirtFs::seek(file, 12) != 0);
661     REQUIRE(VirtFs::eof(file) == 0);
662     REQUIRE(VirtFs::tell(file) == 12);
663     REQUIRE(VirtFs::read(file, buffer, 1, 11) == 11);
664     REQUIRE(strcmp(static_cast<char*>(buffer),
665         "test line 2") == 0);
666     REQUIRE(VirtFs::eof(file) != 0);
667 
668     VirtFs::close(file);
669     free(buffer);
670 
671     VirtFs::unmountDir(prefix + "data");
672     VirtFs::deinit();
673 }
674 
675 TEST_CASE("VirtFs2 read2", "")
676 {
677     VirtFs::init(".");
678     std::string name("data/test/test.zip");
679     std::string prefix("data/test/");
680     if (Files::existsLocal(name) == false)
681         prefix = "../" + prefix;
682 
683     VirtFs::mountZip(prefix + "test2.zip",
684         Append_false);
685     VirtFs::File *file = nullptr;
686     void *restrict buffer = nullptr;
687 
688     SECTION("test 1")
689     {
690         file = VirtFs::openRead("dir2//test.txt");
691         REQUIRE(file != nullptr);
692         REQUIRE(VirtFs::fileLength(file) == 23);
693         const int fileSize = VirtFs::fileLength(file);
694 
695         buffer = calloc(fileSize + 1, 1);
696         REQUIRE(VirtFs::read(file, buffer, 1, fileSize) == fileSize);
697         REQUIRE(strcmp(static_cast<char*>(buffer),
698             "test line 1\ntest line 2") == 0);
699         REQUIRE(VirtFs::tell(file) == fileSize);
700         REQUIRE(VirtFs::eof(file) != 0);
701     }
702 
703     SECTION("test 2")
704     {
705         file = VirtFs::openRead("dir2\\/test.txt");
706         REQUIRE(file != nullptr);
707         REQUIRE(VirtFs::fileLength(file) == 23);
708         const int fileSize = VirtFs::fileLength(file);
709 
710         buffer = calloc(fileSize + 1, 1);
711         REQUIRE(VirtFs::seek(file, 12) != 0);
712         REQUIRE(VirtFs::eof(file) == 0);
713         REQUIRE(VirtFs::tell(file) == 12);
714         REQUIRE(VirtFs::read(file, buffer, 1, 11) == 11);
715         REQUIRE(strcmp(static_cast<char*>(buffer),
716             "test line 2") == 0);
717         REQUIRE(VirtFs::eof(file) != 0);
718     }
719 
720     SECTION("test 3")
721     {
722         file = VirtFs::openRead("dir2//test.txt");
723         REQUIRE(file != nullptr);
724         const int fileSize = VirtFs::fileLength(file);
725 
726         buffer = calloc(fileSize + 1, 1);
727         for (int f = 0; f < fileSize; f ++)
728         {
729             REQUIRE(VirtFs::seek(file, f) != 0);
730             REQUIRE(VirtFs::eof(file) == 0);
731             REQUIRE(VirtFs::tell(file) == f);
732         }
733     }
734 
735     SECTION("test 4")
736     {
737         file = VirtFs::openRead("dir2/test.txt");
738         REQUIRE(file != nullptr);
739         const int fileSize = VirtFs::fileLength(file);
740         const char *restrict const str = "test line 1\ntest line 2";
741         buffer = calloc(fileSize + 1, 1);
742         for (int f = 0; f < fileSize - 1; f ++)
743         {
744             REQUIRE(VirtFs::read(file, buffer, 1, 1) == 1);
745             REQUIRE(static_cast<char*>(buffer)[0] == str[f]);
746             REQUIRE(VirtFs::eof(file) == 0);
747             REQUIRE(VirtFs::tell(file) == f + 1);
748         }
749         REQUIRE(VirtFs::read(file, buffer, 1, 1) == 1);
750         REQUIRE(static_cast<char*>(buffer)[0] == str[22]);
751         REQUIRE(VirtFs::eof(file) != 0);
752         REQUIRE(VirtFs::tell(file) == fileSize);
753     }
754 
755     SECTION("test 5")
756     {
757         file = VirtFs::openRead("dir2\\\\test.txt");
758         REQUIRE(file != nullptr);
759         const int fileSize = VirtFs::fileLength(file);
760         const char *restrict const str = "test line 1\ntest line 2";
761         buffer = calloc(fileSize + 1, 1);
762         for (int f = 0; f < fileSize - 1; f += 2)
763         {
764             REQUIRE(VirtFs::read(file, buffer, 2, 1) == 1);
765             REQUIRE(static_cast<char*>(buffer)[0] == str[f]);
766             REQUIRE(static_cast<char*>(buffer)[1] == str[f + 1]);
767             REQUIRE(VirtFs::eof(file) == 0);
768             REQUIRE(VirtFs::tell(file) == f + 2);
769         }
770         REQUIRE(VirtFs::eof(file) == 0);
771         REQUIRE(VirtFs::tell(file) == 22);
772         REQUIRE(VirtFs::read(file, buffer, 2, 1) == 0);
773         REQUIRE(VirtFs::eof(file) == 0);
774     }
775 
776     SECTION("test 6")
777     {
778         file = VirtFs::openRead("dir2//test.txt");
779         REQUIRE(file != nullptr);
780         const int fileSize = VirtFs::fileLength(file);
781         const char *restrict const str = "test line 1\ntest line 2";
782         buffer = calloc(fileSize + 1, 1);
783         for (int f = 0; f < fileSize - 1; f += 2)
784         {
785             REQUIRE(VirtFs::read(file, buffer, 1, 2) == 2);
786             REQUIRE(static_cast<char*>(buffer)[0] == str[f]);
787             REQUIRE(static_cast<char*>(buffer)[1] == str[f + 1]);
788             REQUIRE(VirtFs::eof(file) == 0);
789             REQUIRE(VirtFs::tell(file) == f + 2);
790         }
791         REQUIRE(VirtFs::eof(file) == 0);
792         REQUIRE(VirtFs::tell(file) == 22);
793         REQUIRE(VirtFs::read(file, buffer, 1, 2) == 1);
794         REQUIRE(static_cast<char*>(buffer)[0] == str[22]);
795         REQUIRE(VirtFs::eof(file) != 0);
796     }
797 
798     VirtFs::close(file);
799     free(buffer);
800     VirtFs::unmountZip(prefix + "test2.zip");
801     VirtFs::deinit();
802 }
803 
804 TEST_CASE("VirtFs2 loadFile1", "")
805 {
806     VirtFs::init(".");
807     int fileSize = 0;
808     std::string name("data/test/test.zip");
809     std::string prefix;
810     if (Files::existsLocal(name) == false)
811         prefix = "../" + prefix;
812 
813     VirtFs::mountDir(prefix + "data",
814         Append_false);
815 
816     const char *const buffer = VirtFs::loadFile("test/test.txt", fileSize);
817     REQUIRE(static_cast<const void*>(buffer) != nullptr);
818     REQUIRE(fileSize == 23);
819     REQUIRE(strncmp(buffer, "test line 1\ntest line 2", 23) == 0);
820     delete [] buffer;
821 
822     VirtFs::unmountDir(prefix + "data");
823     VirtFs::deinit();
824 }
825 
826 TEST_CASE("VirtFs2 loadFile2", "")
827 {
828     VirtFs::init(".");
829     int fileSize = 0;
830     std::string name("data/test/test.zip");
831     std::string prefix;
832     if (Files::existsLocal(name) == false)
833         prefix = "../" + prefix;
834 
835     VirtFs::mountZip(prefix + "data/test/test2.zip",
836         Append_false);
837 
838     SECTION("test 1")
839     {
840         const char *restrict buffer = VirtFs::loadFile("dir2//test.txt",
841             fileSize);
842         REQUIRE(static_cast<const void*>(buffer) != nullptr);
843         REQUIRE(fileSize == 23);
844         REQUIRE(strncmp(buffer, "test line 1\ntest line 2", 23) == 0);
845         delete [] buffer;
846     }
847 
848     SECTION("test 2")
849     {
850         const char *restrict buffer = VirtFs::loadFile("dir2\\/test.txt",
851             fileSize);
852         REQUIRE(static_cast<const void*>(buffer) != nullptr);
853         REQUIRE(fileSize == 23);
854         REQUIRE(strncmp(buffer, "test line 1\ntest line 2", 23) == 0);
855         delete [] buffer;
856     }
857 
858     VirtFs::unmountZip(prefix + "data/test/test2.zip");
859     VirtFs::deinit();
860 }
861 
862 TEST_CASE("VirtFs2 loadFile3", "")
863 {
864     VirtFs::init(".");
865     int fileSize = 0;
866     std::string name("data/test/test.zip");
867     std::string prefix;
868     if (Files::existsLocal(name) == false)
869         prefix = "../" + prefix;
870 
871     VirtFs::mountDir2(prefix + "data",
872         "test",
873         Append_false);
874 
875     const char *const buffer = VirtFs::loadFile("test.txt", fileSize);
876     REQUIRE(static_cast<const void*>(buffer) != nullptr);
877     REQUIRE(fileSize == 23);
878     REQUIRE(strncmp(buffer, "test line 1\ntest line 2", 23) == 0);
879     delete [] buffer;
880 
881     VirtFs::unmountDir2(prefix + "data",
882         "test");
883     VirtFs::deinit();
884 }
885 
886 TEST_CASE("VirtFs2 loadFile4", "")
887 {
888     VirtFs::init(".");
889     int fileSize = 0;
890     std::string name("data/test/test.zip");
891     std::string prefix;
892     if (Files::existsLocal(name) == false)
893         prefix = "../" + prefix;
894 
895     VirtFs::mountZip2(prefix + "data/test/test2.zip",
896         "dir2",
897         Append_false);
898 
899     SECTION("test 1")
900     {
901         const char *restrict buffer = VirtFs::loadFile("test.txt",
902             fileSize);
903         REQUIRE(static_cast<const void*>(buffer) != nullptr);
904         REQUIRE(fileSize == 23);
905         REQUIRE(strncmp(buffer, "test line 1\ntest line 2", 23) == 0);
906         delete [] buffer;
907     }
908 
909     SECTION("test 2")
910     {
911         const char *restrict buffer = VirtFs::loadFile("test.txt",
912             fileSize);
913         REQUIRE(static_cast<const void*>(buffer) != nullptr);
914         REQUIRE(fileSize == 23);
915         REQUIRE(strncmp(buffer, "test line 1\ntest line 2", 23) == 0);
916         delete [] buffer;
917     }
918 
919     VirtFs::unmountZip2(prefix + "data/test/test2.zip",
920         "dir2");
921     VirtFs::deinit();
922 }
923 
924 TEST_CASE("VirtFs2 rwops_read1", "")
925 {
926     VirtFs::init(".");
927     std::string name("data/test/test.zip");
928     std::string prefix;
929     if (Files::existsLocal(name) == false)
930         prefix = "../" + prefix;
931 
932     VirtFs::mountDir(prefix + "data",
933         Append_false);
934 
935     SDL_RWops *file = VirtFs::rwopsOpenRead("test/test.txt");
936     REQUIRE(file != nullptr);
937 #ifdef USE_SDL2
938     REQUIRE(file->size(file) == 23);
939 #endif  // USE_SDL2
940 
941     const int fileSize = 23;
942 
943     void *restrict buffer = calloc(fileSize + 1, 1);
944     REQUIRE(file->read(file, buffer, 1, fileSize) == fileSize);
945     REQUIRE(strcmp(static_cast<char*>(buffer),
946         "test line 1\ntest line 2") == 0);
947     REQUIRE(file->seek(file, 0, SEEK_CUR) == fileSize);
948 
949     free(buffer);
950     buffer = calloc(fileSize + 1, 1);
951     REQUIRE(file->seek(file, 12, SEEK_SET) != 0);
952     REQUIRE(file->seek(file, 0, SEEK_CUR) == 12);
953     REQUIRE(file->read(file, buffer, 1, 11) == 11);
954     REQUIRE(strcmp(static_cast<char*>(buffer),
955         "test line 2") == 0);
956 
957     file->close(file);
958     free(buffer);
959 
960     VirtFs::unmountDir(prefix + "data");
961     VirtFs::deinit();
962 }
963 
964 TEST_CASE("VirtFs2 rwops_read2", "")
965 {
966     VirtFs::init(".");
967     std::string name("data/test/test.zip");
968     std::string prefix("data/test/");
969     if (Files::existsLocal(name) == false)
970         prefix = "../" + prefix;
971 
972     VirtFs::mountZip(prefix + "test2.zip",
973         Append_false);
974     SDL_RWops *file = nullptr;
975     void *restrict buffer = nullptr;
976 
977     SECTION("test 1")
978     {
979         file = VirtFs::rwopsOpenRead("dir2//test.txt");
980         REQUIRE(file != nullptr);
981 #ifdef USE_SDL2
982         REQUIRE(file->size(file) == 23);
983 #endif  // USE_SDL2
984         const int fileSize = 23;
985 
986         buffer = calloc(fileSize + 1, 1);
987         REQUIRE(file->read(file, buffer, 1, fileSize) == fileSize);
988         REQUIRE(strcmp(static_cast<char*>(buffer),
989             "test line 1\ntest line 2") == 0);
990         REQUIRE(file->seek(file, 0, SEEK_CUR) == fileSize);
991     }
992 
993     SECTION("test 2")
994     {
995         file = VirtFs::rwopsOpenRead("dir2\\/test.txt");
996         REQUIRE(file != nullptr);
997 #ifdef USE_SDL2
998         REQUIRE(file->size(file) == 23);
999 #endif  // USE_SDL2
1000         const int fileSize = 23;
1001 
1002         buffer = calloc(fileSize + 1, 1);
1003         REQUIRE(file->seek(file, 12, SEEK_SET) != 0);
1004         REQUIRE(file->seek(file, 0, SEEK_CUR) == 12);
1005         REQUIRE(file->read(file, buffer, 1, 11) == 11);
1006         REQUIRE(strcmp(static_cast<char*>(buffer),
1007             "test line 2") == 0);
1008     }
1009 
1010     SECTION("test 3")
1011     {
1012         file = VirtFs::rwopsOpenRead("dir2//test.txt");
1013         REQUIRE(file != nullptr);
1014         const int fileSize = 23;
1015 
1016         buffer = calloc(fileSize + 1, 1);
1017         for (int f = 0; f < fileSize; f ++)
1018         {
1019             REQUIRE(file->seek(file, f, SEEK_SET) == f);
1020             REQUIRE(file->seek(file, 0, SEEK_CUR) == f);
1021         }
1022     }
1023 
1024     SECTION("test 4")
1025     {
1026         file = VirtFs::rwopsOpenRead("dir2/test.txt");
1027         REQUIRE(file != nullptr);
1028         const int fileSize = 23;
1029         const char *restrict const str = "test line 1\ntest line 2";
1030         buffer = calloc(fileSize + 1, 1);
1031         for (int f = 0; f < fileSize - 1; f ++)
1032         {
1033             REQUIRE(file->read(file, buffer, 1, 1) == 1);
1034             REQUIRE(static_cast<char*>(buffer)[0] == str[f]);
1035             REQUIRE(file->seek(file, 0, SEEK_CUR) == f + 1);
1036         }
1037         REQUIRE(file->read(file, buffer, 1, 1) == 1);
1038         REQUIRE(static_cast<char*>(buffer)[0] == str[22]);
1039         REQUIRE(file->seek(file, 0, SEEK_CUR) == fileSize);
1040     }
1041 
1042     SECTION("test 5")
1043     {
1044         file = VirtFs::rwopsOpenRead("dir2\\\\test.txt");
1045         REQUIRE(file != nullptr);
1046         const int fileSize = 23;
1047         const char *restrict const str = "test line 1\ntest line 2";
1048         buffer = calloc(fileSize + 1, 1);
1049         for (int f = 0; f < fileSize - 1; f += 2)
1050         {
1051             REQUIRE(file->read(file, buffer, 2, 1) == 1);
1052             REQUIRE(static_cast<char*>(buffer)[0] == str[f]);
1053             REQUIRE(static_cast<char*>(buffer)[1] == str[f + 1]);
1054             REQUIRE(file->seek(file, 0, SEEK_CUR) == f + 2);
1055         }
1056         REQUIRE(file->seek(file, 0, SEEK_CUR) == 22);
1057         REQUIRE(file->read(file, buffer, 2, 1) == 0);
1058     }
1059 
1060     SECTION("test 6")
1061     {
1062         file = VirtFs::rwopsOpenRead("dir2//test.txt");
1063         REQUIRE(file != nullptr);
1064         const int fileSize = 23;
1065         const char *restrict const str = "test line 1\ntest line 2";
1066         buffer = calloc(fileSize + 1, 1);
1067         for (int f = 0; f < fileSize - 1; f += 2)
1068         {
1069             REQUIRE(file->read(file, buffer, 1, 2) == 2);
1070             REQUIRE(static_cast<char*>(buffer)[0] == str[f]);
1071             REQUIRE(static_cast<char*>(buffer)[1] == str[f + 1]);
1072             REQUIRE(file->seek(file, 0, SEEK_CUR) == f + 2);
1073         }
1074         REQUIRE(file->seek(file, 0, SEEK_CUR) == 22);
1075         REQUIRE(file->read(file, buffer, 1, 2) == 1);
1076         REQUIRE(static_cast<char*>(buffer)[0] == str[22]);
1077     }
1078 
1079     SECTION("test 7")
1080     {
1081         file = VirtFs::rwopsOpenRead("dir2//test.txt");
1082         REQUIRE(file != nullptr);
1083         const int fileSize = 23;
1084         const char *restrict const str = "test line 1\ntest line 2";
1085         buffer = calloc(fileSize + 1, 1);
1086         for (int f = 0; f < fileSize - 1; f += 2)
1087         {
1088             REQUIRE(file->read(file, buffer, 1, 2) == 2);
1089             REQUIRE(file->seek(file, -2, SEEK_CUR) == f);
1090             REQUIRE(file->seek(file, 0, SEEK_CUR) == f);
1091             REQUIRE(file->seek(file, 2, SEEK_CUR) == f + 2);
1092             REQUIRE(static_cast<char*>(buffer)[0] == str[f]);
1093             REQUIRE(static_cast<char*>(buffer)[1] == str[f + 1]);
1094             REQUIRE(file->seek(file, 0, SEEK_CUR) == f + 2);
1095         }
1096         REQUIRE(file->seek(file, 0, SEEK_CUR) == 22);
1097         REQUIRE(file->read(file, buffer, 1, 2) == 1);
1098         REQUIRE(static_cast<char*>(buffer)[0] == str[22]);
1099     }
1100 
1101     SECTION("test 8")
1102     {
1103         file = VirtFs::rwopsOpenRead("dir2//test.txt");
1104         REQUIRE(file != nullptr);
1105         const int fileSize = 23;
1106         const char *restrict const str = "test line 1\ntest line 2";
1107         buffer = calloc(fileSize + 1, 1);
1108         for (int f = 0; f < fileSize - 1; f += 2)
1109         {
1110             REQUIRE(file->seek(file, -f - 2, SEEK_END) == 23 - f - 2);
1111             REQUIRE(file->read(file, buffer, 1, 2) == 2);
1112             REQUIRE(static_cast<char*>(buffer)[0] == str[23 - f - 2]);
1113             REQUIRE(static_cast<char*>(buffer)[1] == str[23 - f - 2 + 1]);
1114             REQUIRE(file->seek(file, 0, SEEK_CUR) == 23 - f);
1115         }
1116         // 3
1117         REQUIRE(file->seek(file, 1, SEEK_CUR) == 4);
1118         // 4
1119         REQUIRE(file->read(file, buffer, 1, 2) == 2);
1120         // 6
1121         REQUIRE(static_cast<char*>(buffer)[0] == str[4]);
1122         REQUIRE(static_cast<char*>(buffer)[1] == str[5]);
1123         REQUIRE(file->seek(file, -7, SEEK_CUR) == -1);
1124         REQUIRE(file->seek(file, 6, SEEK_SET) == 6);
1125         REQUIRE(file->seek(file, -6, SEEK_CUR) == 0);
1126     }
1127 
1128     if (file != nullptr)
1129         file->close(file);
1130     free(buffer);
1131     VirtFs::unmountZip(prefix + "test2.zip");
1132     VirtFs::deinit();
1133 }
1134 
1135 TEST_CASE("VirtFs2 rwops_read3", "")
1136 {
1137     VirtFs::init(".");
1138     std::string name("data/test/test.zip");
1139     std::string prefix;
1140     if (Files::existsLocal(name) == false)
1141         prefix = "../" + prefix;
1142 
1143     VirtFs::mountDir(prefix + "data",
1144         Append_false);
1145     SDL_RWops *file = nullptr;
1146     void *restrict buffer = nullptr;
1147 
1148     SECTION("test 1")
1149     {
1150         file = VirtFs::rwopsOpenRead("test/test.txt");
1151         REQUIRE(file != nullptr);
1152 #ifdef USE_SDL2
1153         REQUIRE(file->size(file) == 23);
1154 #endif  // USE_SDL2
1155         const int fileSize = 23;
1156 
1157         buffer = calloc(fileSize + 1, 1);
1158         REQUIRE(file->read(file, buffer, 1, fileSize) == fileSize);
1159         REQUIRE(strcmp(static_cast<char*>(buffer),
1160             "test line 1\ntest line 2") == 0);
1161         REQUIRE(file->seek(file, 0, SEEK_CUR) == fileSize);
1162     }
1163 
1164     SECTION("test 2")
1165     {
1166         file = VirtFs::rwopsOpenRead("test\\test.txt");
1167         REQUIRE(file != nullptr);
1168 #ifdef USE_SDL2
1169         REQUIRE(file->size(file) == 23);
1170 #endif  // USE_SDL2
1171         const int fileSize = 23;
1172 
1173         buffer = calloc(fileSize + 1, 1);
1174         REQUIRE(file->seek(file, 12, SEEK_SET) != 0);
1175         REQUIRE(file->seek(file, 0, SEEK_CUR) == 12);
1176         REQUIRE(file->read(file, buffer, 1, 11) == 11);
1177         REQUIRE(strcmp(static_cast<char*>(buffer),
1178             "test line 2") == 0);
1179     }
1180 
1181     SECTION("test 3")
1182     {
1183         file = VirtFs::rwopsOpenRead("test\\/test.txt");
1184         REQUIRE(file != nullptr);
1185         const int fileSize = 23;
1186 
1187         buffer = calloc(fileSize + 1, 1);
1188         for (int f = 0; f < fileSize; f ++)
1189         {
1190             REQUIRE(file->seek(file, f, SEEK_SET) == f);
1191             REQUIRE(file->seek(file, 0, SEEK_CUR) == f);
1192         }
1193     }
1194 
1195     SECTION("test 4")
1196     {
1197         file = VirtFs::rwopsOpenRead("test/test.txt");
1198         REQUIRE(file != nullptr);
1199         const int fileSize = 23;
1200         const char *restrict const str = "test line 1\ntest line 2";
1201         buffer = calloc(fileSize + 1, 1);
1202         for (int f = 0; f < fileSize - 1; f ++)
1203         {
1204             REQUIRE(file->read(file, buffer, 1, 1) == 1);
1205             REQUIRE(static_cast<char*>(buffer)[0] == str[f]);
1206             REQUIRE(file->seek(file, 0, SEEK_CUR) == f + 1);
1207         }
1208         REQUIRE(file->read(file, buffer, 1, 1) == 1);
1209         REQUIRE(static_cast<char*>(buffer)[0] == str[22]);
1210         REQUIRE(file->seek(file, 0, SEEK_CUR) == fileSize);
1211     }
1212 
1213     SECTION("test 5")
1214     {
1215         file = VirtFs::rwopsOpenRead("test///test.txt");
1216         REQUIRE(file != nullptr);
1217         const int fileSize = 23;
1218         const char *restrict const str = "test line 1\ntest line 2";
1219         buffer = calloc(fileSize + 1, 1);
1220         for (int f = 0; f < fileSize - 1; f += 2)
1221         {
1222             REQUIRE(file->read(file, buffer, 2, 1) == 1);
1223             REQUIRE(static_cast<char*>(buffer)[0] == str[f]);
1224             REQUIRE(static_cast<char*>(buffer)[1] == str[f + 1]);
1225             REQUIRE(file->seek(file, 0, SEEK_CUR) == f + 2);
1226         }
1227         REQUIRE(file->seek(file, 0, SEEK_CUR) == 22);
1228         REQUIRE(file->read(file, buffer, 2, 1) == 0);
1229     }
1230 
1231     SECTION("test 6")
1232     {
1233         file = VirtFs::rwopsOpenRead("test\\\\test.txt");
1234         REQUIRE(file != nullptr);
1235         const int fileSize = 23;
1236         const char *restrict const str = "test line 1\ntest line 2";
1237         buffer = calloc(fileSize + 1, 1);
1238         for (int f = 0; f < fileSize - 1; f += 2)
1239         {
1240             REQUIRE(file->read(file, buffer, 1, 2) == 2);
1241             REQUIRE(static_cast<char*>(buffer)[0] == str[f]);
1242             REQUIRE(static_cast<char*>(buffer)[1] == str[f + 1]);
1243             REQUIRE(file->seek(file, 0, SEEK_CUR) == f + 2);
1244         }
1245         REQUIRE(file->seek(file, 0, SEEK_CUR) == 22);
1246         REQUIRE(file->read(file, buffer, 1, 2) == 1);
1247         REQUIRE(static_cast<char*>(buffer)[0] == str[22]);
1248     }
1249 
1250     SECTION("test 7")
1251     {
1252         file = VirtFs::rwopsOpenRead("test//test.txt");
1253         REQUIRE(file != nullptr);
1254         const int fileSize = 23;
1255         const char *restrict const str = "test line 1\ntest line 2";
1256         buffer = calloc(fileSize + 1, 1);
1257         for (int f = 0; f < fileSize - 1; f += 2)
1258         {
1259             REQUIRE(file->read(file, buffer, 1, 2) == 2);
1260             REQUIRE(file->seek(file, -2, SEEK_CUR) == f);
1261             REQUIRE(file->seek(file, 0, SEEK_CUR) == f);
1262             REQUIRE(file->seek(file, 2, SEEK_CUR) == f + 2);
1263             REQUIRE(static_cast<char*>(buffer)[0] == str[f]);
1264             REQUIRE(static_cast<char*>(buffer)[1] == str[f + 1]);
1265             REQUIRE(file->seek(file, 0, SEEK_CUR) == f + 2);
1266         }
1267         REQUIRE(file->seek(file, 0, SEEK_CUR) == 22);
1268         REQUIRE(file->read(file, buffer, 1, 2) == 1);
1269         REQUIRE(static_cast<char*>(buffer)[0] == str[22]);
1270     }
1271 
1272     SECTION("test 8")
1273     {
1274         file = VirtFs::rwopsOpenRead("test/test.txt");
1275         REQUIRE(file != nullptr);
1276         const int fileSize = 23;
1277         const char *restrict const str = "test line 1\ntest line 2";
1278         buffer = calloc(fileSize + 1, 1);
1279         for (int f = 0; f < fileSize - 1; f += 2)
1280         {
1281             REQUIRE(file->seek(file, -f - 2, SEEK_END) == 23 - f - 2);
1282             REQUIRE(file->read(file, buffer, 1, 2) == 2);
1283             REQUIRE(static_cast<char*>(buffer)[0] == str[23 - f - 2]);
1284             REQUIRE(static_cast<char*>(buffer)[1] == str[23 - f - 2 + 1]);
1285             REQUIRE(file->seek(file, 0, SEEK_CUR) == 23 - f);
1286         }
1287         // 3
1288         REQUIRE(file->seek(file, 1, SEEK_CUR) == 4);
1289         // 4
1290         REQUIRE(file->read(file, buffer, 1, 2) == 2);
1291         // 6
1292         REQUIRE(static_cast<char*>(buffer)[0] == str[4]);
1293         REQUIRE(static_cast<char*>(buffer)[1] == str[5]);
1294         REQUIRE(file->seek(file, -7, SEEK_CUR) == -1);
1295         REQUIRE(file->seek(file, 6, SEEK_SET) == 6);
1296         REQUIRE(file->seek(file, -6, SEEK_CUR) == 0);
1297     }
1298 
1299     if (file != nullptr)
1300         file->close(file);
1301     free(buffer);
1302     VirtFs::unmountDir(prefix + "data");
1303     VirtFs::deinit();
1304 }
1305 
1306 TEST_CASE("VirtFs2 getFiles zip1", "")
1307 {
1308     VirtFs::init(".");
1309     std::string name("data/test/test.zip");
1310     std::string prefix;
1311     if (Files::existsLocal(name) == false)
1312         prefix = "../" + prefix;
1313 
1314     VirtFs::mountZip(prefix + "data/test/test2.zip",
1315         Append_false);
1316 
1317     StringVect list;
1318     VirtFs::getFiles("dir", list);
1319     REQUIRE(list.size() == 2);
1320     REQUIRE(inList(list, "dye.png"));
1321     REQUIRE(inList(list, "hide.png"));
1322 
1323     list.clear();
1324     VirtFs::getFiles("dir2", list);
1325     REQUIRE(list.size() == 4);
1326     REQUIRE(inList(list, "hide.png"));
1327     REQUIRE(inList(list, "paths.xml"));
1328     REQUIRE(inList(list, "test.txt"));
1329     REQUIRE(inList(list, "units.xml"));
1330 
1331     VirtFs::unmountZip(prefix + "data/test/test2.zip");
1332     VirtFs::deinit();
1333 }
1334 
1335 TEST_CASE("VirtFs2 getFiles zip2", "")
1336 {
1337     VirtFs::init(".");
1338     std::string name("data/test/test.zip");
1339     std::string prefix;
1340     if (Files::existsLocal(name) == false)
1341         prefix = "../" + prefix;
1342 
1343     VirtFs::mountZip2(prefix + "data/test/test2.zip",
1344         "dir",
1345         Append_false);
1346 
1347     StringVect list;
1348     VirtFs::getFiles(dirSeparator, list);
1349     REQUIRE(list.size() == 2);
1350     REQUIRE(inList(list, "dye.png"));
1351     REQUIRE(inList(list, "hide.png"));
1352 
1353     list.clear();
1354     VirtFs::getFiles("1", list);
1355     REQUIRE(list.size() == 2);
1356     REQUIRE(inList(list, "file1.txt"));
1357     REQUIRE(inList(list, "test.txt"));
1358 
1359     VirtFs::unmountZip2(prefix + "data/test/test2.zip",
1360         "dir");
1361     VirtFs::deinit();
1362 }
1363 
1364 TEST_CASE("VirtFs2 getDirs1", "")
1365 {
1366     VirtFs::init(".");
1367     std::string name("data/test/test.zip");
1368     std::string prefix;
1369     if (Files::existsLocal(name) == false)
1370         prefix = "../" + prefix;
1371 
1372     VirtFs::mountZip(prefix + "data/test/test2.zip",
1373         Append_false);
1374 
1375     StringVect list;
1376     VirtFs::getDirs("dir", list);
1377     REQUIRE(list.size() == 2);
1378     REQUIRE(inList(list, "1"));
1379     REQUIRE(inList(list, "gpl"));
1380     list.clear();
1381 
1382     VirtFs::getDirs("dir2", list);
1383     REQUIRE(list.empty());
1384 
1385     VirtFs::unmountZip(prefix + "data/test/test2.zip");
1386     VirtFs::deinit();
1387 }
1388 
1389 TEST_CASE("VirtFs2 getDirs2", "")
1390 {
1391     VirtFs::init(".");
1392     std::string name("data/test/test.zip");
1393     std::string prefix;
1394     if (Files::existsLocal(name) == false)
1395         prefix = "../" + prefix;
1396     StringVect list;
1397 
1398     SECTION("dir1")
1399     {
1400         VirtFs::mountDir(prefix + "data/test",
1401             Append_false);
1402 
1403         VirtFs::getDirs("/", list);
1404 //        REQUIRE(list.size() == 2);
1405         REQUIRE(inList(list, "dir1"));
1406         REQUIRE(inList(list, "dir2"));
1407         list.clear();
1408 
1409         VirtFs::getDirs("dir1", list);
1410         REQUIRE(list.empty());
1411 
1412         VirtFs::unmountDir(prefix + "data/test");
1413     }
1414 
1415     SECTION("dir2")
1416     {
1417         VirtFs::mountDir(prefix + "data",
1418             Append_false);
1419 
1420         VirtFs::getDirs("sfx", list);
1421         REQUIRE(inList(list, "system"));
1422         list.clear();
1423 
1424         VirtFs::getDirs("evol", list);
1425         REQUIRE(list.size() == 2);
1426         REQUIRE(inList(list, "icons"));
1427         REQUIRE(inList(list, "images"));
1428 
1429         VirtFs::unmountDir(prefix + "data");
1430     }
1431 
1432     VirtFs::deinit();
1433 }
1434 
1435 TEST_CASE("VirtFs2 getDirs3", "")
1436 {
1437     VirtFs::init(".");
1438     std::string name("data/test/test.zip");
1439     std::string prefix;
1440     if (Files::existsLocal(name) == false)
1441         prefix = "../" + prefix;
1442 
1443     VirtFs::mountZip2(prefix + "data/test/test2.zip",
1444         "dir",
1445         Append_false);
1446 
1447     StringVect list;
1448     VirtFs::getDirs(dirSeparator, list);
1449     REQUIRE(list.size() == 2);
1450     REQUIRE(inList(list, "1"));
1451     REQUIRE(inList(list, "gpl"));
1452     list.clear();
1453 
1454     VirtFs::getDirs("1", list);
1455     REQUIRE(list.empty());
1456 
1457     VirtFs::unmountZip2(prefix + "data/test/test2.zip",
1458         "dir");
1459     VirtFs::deinit();
1460 }
1461 
1462 TEST_CASE("VirtFs2 getDirs4", "")
1463 {
1464     VirtFs::init(".");
1465     std::string name("data/test/test.zip");
1466     std::string prefix;
1467     if (Files::existsLocal(name) == false)
1468         prefix = "../" + prefix;
1469     StringVect list;
1470 
1471     SECTION("dir1")
1472     {
1473         VirtFs::mountDir2(prefix + "data",
1474             "test",
1475             Append_false);
1476 
1477         VirtFs::getDirs("/", list);
1478         REQUIRE(inList(list, "dir1"));
1479         REQUIRE(inList(list, "dir2"));
1480         list.clear();
1481 
1482         VirtFs::getDirs("dir1", list);
1483         REQUIRE(list.empty());
1484 
1485         VirtFs::unmountDir2(prefix + "data",
1486             "test");
1487     }
1488 
1489     VirtFs::deinit();
1490 }
1491 
1492 TEST_CASE("VirtFs2 getFilesWithDir1", "")
1493 {
1494     VirtFs::init(".");
1495     std::string name("data/test/test.zip");
1496     std::string prefix;
1497     if (Files::existsLocal(name) == false)
1498         prefix = "../" + prefix;
1499 
1500     VirtFs::mountZip(prefix + "data/test/test2.zip",
1501         Append_false);
1502 
1503     StringVect list;
1504     VirtFs::getFilesWithDir("dir", list);
1505     REQUIRE(list.size() == 2);
1506     REQUIRE(inList(list, "dir", "dye.png"));
1507     REQUIRE(inList(list, "dir", "hide.png"));
1508     list.clear();
1509 
1510     VirtFs::getFilesWithDir("dir2", list);
1511     REQUIRE(list.size() == 4);
1512     REQUIRE(inList(list, "dir2", "hide.png"));
1513     REQUIRE(inList(list, "dir2", "paths.xml"));
1514     REQUIRE(inList(list, "dir2", "test.txt"));
1515     REQUIRE(inList(list, "dir2", "units.xml"));
1516     list.clear();
1517 
1518     VirtFs::getFilesWithDir(dirSeparator, list);
1519     REQUIRE(list.size() > 2);
1520     REQUIRE(inList(list, dirSeparator, "test.txt"));
1521     REQUIRE(inList(list, dirSeparator, "units.xml"));
1522     list.clear();
1523 
1524     VirtFs::unmountZip(prefix + "data/test/test2.zip");
1525     VirtFs::deinit();
1526 }
1527 
1528 TEST_CASE("VirtFs2 getFilesWithDir2", "")
1529 {
1530     VirtFs::init(".");
1531     std::string name("data/test/test.zip");
1532     std::string prefix;
1533     if (Files::existsLocal(name) == false)
1534         prefix = "../" + prefix;
1535     StringVect list;
1536 
1537     SECTION("dir1")
1538     {
1539         VirtFs::mountDir(prefix + "data/graphics",
1540             Append_false);
1541 
1542         VirtFs::getFilesWithDir("/", list);
1543         REQUIRE(list.size() <= 5);
1544         VirtFs::unmountDir(prefix + "data/graphics");
1545     }
1546 
1547     SECTION("dir2")
1548     {
1549         VirtFs::mountDir(prefix + "data",
1550             Append_false);
1551 
1552         VirtFs::getFilesWithDir("music", list);
1553         REQUIRE(list.size() <= 5);
1554         REQUIRE(!list.empty());
1555         REQUIRE(inList(list, "music", "keprohm.ogg"));
1556         list.clear();
1557 
1558         VirtFs::getFilesWithDir(pathJoin("evol", "icons"), list);
1559         REQUIRE(list.size() == 3);
1560         REQUIRE(inList(list, pathJoin("evol", "icons"), "evol-client.ico"));
1561         REQUIRE(inList(list, pathJoin("evol", "icons"), "evol-client.png"));
1562         REQUIRE(inList(list, pathJoin("evol", "icons"), "evol-client.xpm"));
1563 
1564         VirtFs::unmountDir(prefix + "data");
1565     }
1566 
1567     VirtFs::deinit();
1568 }
1569 
1570 TEST_CASE("VirtFs2 getFilesWithDir3", "")
1571 {
1572     VirtFs::init(".");
1573     std::string name("data/test/test.zip");
1574     std::string prefix;
1575     if (Files::existsLocal(name) == false)
1576         prefix = "../" + prefix;
1577 
1578     VirtFs::mountZip2(prefix + "data/test/test2.zip",
1579         "dir",
1580         Append_false);
1581 
1582     StringVect list;
1583     VirtFs::getFilesWithDir("1", list);
1584     REQUIRE(list.size() == 2);
1585     REQUIRE(inList(list, "1", "file1.txt"));
1586     REQUIRE(inList(list, "1", "test.txt"));
1587     list.clear();
1588 
1589     VirtFs::getFilesWithDir(dirSeparator, list);
1590     REQUIRE(list.size() == 2);
1591     REQUIRE(inList(list, dirSeparator, "dye.png"));
1592     REQUIRE(inList(list, dirSeparator, "hide.png"));
1593     list.clear();
1594 
1595     VirtFs::unmountZip2(prefix + "data/test/test2.zip",
1596         "dir");
1597     VirtFs::deinit();
1598 }
1599 
1600 TEST_CASE("VirtFs2 getFilesWithDir4", "")
1601 {
1602     VirtFs::init(".");
1603     std::string name("data/test/test.zip");
1604     std::string prefix;
1605     if (Files::existsLocal(name) == false)
1606         prefix = "../" + prefix;
1607     StringVect list;
1608 
1609     SECTION("dir1")
1610     {
1611         VirtFs::mountDir2(prefix + "data/graphics",
1612             "sprites",
1613             Append_false);
1614 
1615         VirtFs::getFilesWithDir("/", list);
1616         REQUIRE(list.size() <= 16);
1617         VirtFs::unmountDir2(prefix + "data/graphics",
1618             "sprites");
1619     }
1620 
1621     SECTION("dir2")
1622     {
1623         VirtFs::mountDir2(prefix + "data",
1624             "test",
1625             Append_false);
1626 
1627         VirtFs::getFilesWithDir("dir1", list);
1628         REQUIRE(list.size() <= 6);
1629         REQUIRE(!list.empty());
1630         REQUIRE(inList(list, "dir1", "file1.txt"));
1631         list.clear();
1632 
1633         VirtFs::unmountDir2(prefix + "data",
1634             "test");
1635     }
1636 
1637     VirtFs::deinit();
1638 }
1639