1 /* Invisible Vector Library
2 * coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
3 * Understanding is not required. Only obedience.
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3 of the License ONLY.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 module iv
.vfs
.arc
.wad2
/*is aliced*/;
20 import iv
.vfs
.types
: Seek
;
25 import iv
.vfs
.arc
.internal
;
28 // ////////////////////////////////////////////////////////////////////////// //
29 mixin(VFSSimpleArchiveDetectorMixin
!"Wad2");
32 // ////////////////////////////////////////////////////////////////////////// //
33 public final class VFSDriverWad2
: VFSDriver
{
34 mixin VFSSimpleArchiveDriverMixin
;
37 static struct FileInfo
{
39 long ofs
; // offset in archive
40 string name
; // with path
44 /** query various file properties; driver-specific.
45 * properties of interest:
46 * "type" -- internal type
47 * "packed" -- is file packed?
48 * "pksize" -- packed file size (for archives)
49 * "offset" -- offset in wad
50 * "size" -- file size (so we can get size without opening the file)
52 public override VFSVariant
stat (usize idx
, const(char)[] propname
) {
53 if (idx
>= dir
.length
) return VFSVariant();
54 if (propname
== "arcname") return VFSVariant("wad2");
55 if (propname
== "type") return VFSVariant(dir
[idx
].type
);
56 if (propname
== "packed") return VFSVariant(false);
57 if (propname
== "pksize") return VFSVariant(dir
[idx
].size
);
58 if (propname
== "offset") return VFSVariant(dir
[idx
].ofs
);
59 if (propname
== "size") return VFSVariant(dir
[idx
].size
);
63 VFile
wrap (usize idx
) { return wrapStreamRO(st
, dir
[idx
].ofs
, dir
[idx
].size
, dir
[idx
].name
); }
65 void open (VFile fl
, const(char)[] prefixpath
) {
66 ulong flsize
= fl
.size
;
67 if (flsize
> 0xffff_ffffu
) throw new /*VFSNamedException!"Wad2Archive"*/VFSExceptionArc("file too big");
69 fl
.rawReadExact(sign
[]);
70 if (sign
!= "WAD2") throw new /*VFSNamedException!"Wad2Archive"*/VFSExceptionArc("not a PAK file");
71 auto flCount
= fl
.readNum
!uint;
72 auto dirOfs
= fl
.readNum
!uint;
73 if (flCount
> 0x3fff_ffff || dirOfs
>= flsize || dirOfs
+flCount
*32 > flsize
) throw new /*VFSNamedException!"Wad2Archive"*/VFSExceptionArc("invalid archive file");
77 while (flCount
-- > 0) {
79 fi
.ofs
= fl
.readNum
!uint;
80 fi
.size
= fl
.readNum
!uint;
81 fl
.readNum
!uint; // size of entry in memory, not used
82 ubyte type
= fl
.readNum
!ubyte;
83 ubyte origtype
= type
;
84 if (type
== '/') type
= '_'; // oops
85 auto compr
= fl
.readNum
!ubyte; // 0: none
86 fl
.readNum
!ushort; // not used
87 fl
.rawReadExact(nbuf
[0..16]);
90 name
= new char[](prefixpath
.length
+16+2);
91 usize nbpos
= prefixpath
.length
;
92 if (nbpos
) name
[0..nbpos
] = prefixpath
[];
93 foreach (char ch
; nbuf
[0..16]) {
95 if (ch
== '\\') ch
= '/';
96 if (ch
== '/' && (nbpos
== 0 || name
.ptr
[nbpos
-1] == '/')) continue;
97 name
.ptr
[nbpos
++] = ch
;
99 if (type
) { name
.ptr
[nbpos
++] = '.'; name
.ptr
[nbpos
++] = cast(char)type
; }
100 name
= name
[0..nbpos
];
101 if (name
.length
&& name
[$-1] == '/') name
= null;
103 // some sanity checks
104 if (fi
.size
> 0 && fi
.ofs
>= flsize || fi
.size
> flsize
) throw new /*VFSNamedException!"Wad2Archive"*/VFSExceptionArc("invalid archive directory");
105 if (fi
.ofs
+fi
.size
> flsize
) throw new /*VFSNamedException!"Wad2Archive"*/VFSExceptionArc("invalid archive directory");
106 if (compr
!= 0) throw new /*VFSNamedException!"Wad2Archive"*/VFSExceptionArc("invalid compression type");
108 fi
.name
= cast(string
)name
; // it's safe here
109 fi
.type
= cast(char)origtype
;
110 dir
.arrayAppendUnsafe(fi
);
113 buildNameHashTable();