Skip to content

Commit 6d228df

Browse files
committed
express: Add ZipArchive class, support mounting zips to VFS
1 parent 54b9311 commit 6d228df

17 files changed

+3064
-32
lines changed

dtool/src/dtoolutil/textEncoder.cxx

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,42 @@ using std::ostream;
2121
using std::string;
2222
using std::wstring;
2323

24+
// Maps cp437 characters to Unicode codepoints.
25+
static char16_t cp437_table[256] = {
26+
0x0000, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022,
27+
0x25d8, 0x25cb, 0x25d9, 0x2642, 0x2640, 0x266a, 0x266b, 0x263c,
28+
0x25ba, 0x25c4, 0x2195, 0x203c, 0x00b6, 0x00a7, 0x25ac, 0x21a8,
29+
0x2191, 0x2193, 0x2192, 0x2190, 0x221f, 0x2194, 0x25b2, 0x25bc,
30+
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
31+
0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
32+
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
33+
0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
34+
0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
35+
0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
36+
0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
37+
0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
38+
0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
39+
0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
40+
0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
41+
0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302,
42+
0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7,
43+
0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
44+
0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,
45+
0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192,
46+
0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba,
47+
0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,
48+
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
49+
0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
50+
0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,
51+
0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
52+
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b,
53+
0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580,
54+
0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4,
55+
0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229,
56+
0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248,
57+
0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0,
58+
};
59+
2460
TextEncoder::Encoding TextEncoder::_default_encoding = TextEncoder::E_utf8;
2561

2662
/**
@@ -177,6 +213,20 @@ encode_wchar(char32_t ch, TextEncoder::Encoding encoding) {
177213
};
178214
return string(encoded, 4);
179215
}
216+
217+
case E_cp437:
218+
if ((ch & ~0x7f) == 0) {
219+
return string(1, (char)ch);
220+
}
221+
else if (ch >= 0 && ch < 0x266b) {
222+
// This case is not optimized, because we don't really need it right now.
223+
for (int i = 0; i < 256; ++i) {
224+
if (cp437_table[i] == ch) {
225+
return std::string(1, (char)i);
226+
}
227+
}
228+
}
229+
return ".";
180230
}
181231

182232
return "";
@@ -233,6 +283,15 @@ decode_text(const string &text, TextEncoder::Encoding encoding) {
233283
return decode_text_impl(decoder);
234284
}
235285

286+
case E_cp437:
287+
{
288+
std::wstring result(text.size(), 0);
289+
for (size_t i = 0; i < result.size(); ++i) {
290+
result[i] = cp437_table[(uint8_t)text[i]];
291+
}
292+
return result;
293+
}
294+
236295
case E_iso8859:
237296
default:
238297
{
@@ -382,6 +441,9 @@ operator << (ostream &out, TextEncoder::Encoding encoding) {
382441

383442
case TextEncoder::E_utf16be:
384443
return out << "utf16be";
444+
445+
case TextEncoder::E_cp437:
446+
return out << "cp437";
385447
};
386448

387449
return out << "**invalid TextEncoder::Encoding(" << (int)encoding << ")**";
@@ -402,6 +464,8 @@ operator >> (istream &in, TextEncoder::Encoding &encoding) {
402464
} else if (word == "unicode" || word == "utf16be" || word == "utf-16be" ||
403465
word == "utf16-be" || word == "utf-16-be") {
404466
encoding = TextEncoder::E_utf16be;
467+
} else if (word == "cp437") {
468+
encoding = TextEncoder::E_cp437;
405469
} else {
406470
ostream *notify_ptr = StringDecoder::get_notify_ptr();
407471
if (notify_ptr != nullptr) {

dtool/src/dtoolutil/textEncoder.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ class EXPCL_DTOOL_DTOOLUTIL TextEncoder {
3636
E_iso8859,
3737
E_utf8,
3838
E_utf16be,
39+
E_cp437,
3940

4041
// Deprecated alias for E_utf16be
4142
E_unicode = E_utf16be,

panda/src/express/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ set(P3EXPRESS_HEADERS
5656
virtualFileMountMultifile.h virtualFileMountMultifile.I
5757
virtualFileMountRamdisk.h virtualFileMountRamdisk.I
5858
virtualFileMountSystem.h virtualFileMountSystem.I
59+
virtualFileMountZip.h virtualFileMountZip.I
5960
virtualFileSimple.h virtualFileSimple.I
6061
virtualFileSystem.h virtualFileSystem.I
6162
weakPointerCallback.I weakPointerCallback.h
@@ -64,6 +65,7 @@ set(P3EXPRESS_HEADERS
6465
weakPointerToVoid.I weakPointerToVoid.h
6566
weakReferenceList.I weakReferenceList.h
6667
windowsRegistry.h
68+
zipArchive.I zipArchive.h
6769
zStream.I zStream.h zStreamBuf.h
6870
)
6971

@@ -110,13 +112,15 @@ set(P3EXPRESS_SOURCES
110112
virtualFileMountMultifile.cxx
111113
virtualFileMountRamdisk.cxx
112114
virtualFileMountSystem.cxx
115+
virtualFileMountZip.cxx
113116
virtualFileSimple.cxx virtualFileSystem.cxx
114117
weakPointerCallback.cxx
115118
weakPointerTo.cxx
116119
weakPointerToBase.cxx
117120
weakPointerToVoid.cxx
118121
weakReferenceList.cxx
119122
windowsRegistry.cxx
123+
zipArchive.cxx
120124
zStream.cxx zStreamBuf.cxx
121125
)
122126

panda/src/express/p3express_composite2.cxx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "virtualFileMountMultifile.cxx"
2121
#include "virtualFileMountRamdisk.cxx"
2222
#include "virtualFileMountSystem.cxx"
23+
#include "virtualFileMountZip.cxx"
2324
#include "virtualFileSimple.cxx"
2425
#include "virtualFileSystem.cxx"
2526
#include "weakPointerCallback.cxx"
@@ -30,3 +31,4 @@
3031
#include "windowsRegistry.cxx"
3132
#include "zStream.cxx"
3233
#include "zStreamBuf.cxx"
34+
#include "zipArchive.cxx"
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/**
2+
* PANDA 3D SOFTWARE
3+
* Copyright (c) Carnegie Mellon University. All rights reserved.
4+
*
5+
* All use of this software is subject to the terms of the revised BSD
6+
* license. You should have received a copy of this license along
7+
* with this source code in a file named "LICENSE."
8+
*
9+
* @file virtualFileMountZip.I
10+
* @author rdb
11+
* @date 2019-11-07
12+
*/
13+
14+
/**
15+
*
16+
*/
17+
INLINE VirtualFileMountZip::
18+
VirtualFileMountZip(ZipArchive *archive, const Filename &directory) :
19+
_archive(archive),
20+
_directory(directory)
21+
{
22+
}
23+
24+
/**
25+
* Returns the ZipArchive pointer that this mount object is based on.
26+
*/
27+
INLINE ZipArchive *VirtualFileMountZip::
28+
get_archive() const {
29+
return _archive;
30+
}
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
/**
2+
* PANDA 3D SOFTWARE
3+
* Copyright (c) Carnegie Mellon University. All rights reserved.
4+
*
5+
* All use of this software is subject to the terms of the revised BSD
6+
* license. You should have received a copy of this license along
7+
* with this source code in a file named "LICENSE."
8+
*
9+
* @file virtualFileMountZip.cxx
10+
* @author drose
11+
* @date 2002-08-03
12+
*/
13+
14+
#include "virtualFileMountZip.h"
15+
#include "virtualFileSystem.h"
16+
17+
TypeHandle VirtualFileMountZip::_type_handle;
18+
19+
20+
/**
21+
*
22+
*/
23+
VirtualFileMountZip::
24+
~VirtualFileMountZip() {
25+
}
26+
27+
28+
/**
29+
* Returns true if the indicated file exists within the mount system.
30+
*/
31+
bool VirtualFileMountZip::
32+
has_file(const Filename &file) const {
33+
Filename path(_directory, file);
34+
return (path.empty() ||
35+
_archive->find_subfile(path) >= 0 ||
36+
_archive->has_directory(path));
37+
}
38+
39+
/**
40+
* Returns true if the indicated file exists within the mount system and is a
41+
* directory.
42+
*/
43+
bool VirtualFileMountZip::
44+
is_directory(const Filename &file) const {
45+
Filename path(_directory, file);
46+
return (path.empty() || _archive->has_directory(file));
47+
}
48+
49+
/**
50+
* Returns true if the indicated file exists within the mount system and is a
51+
* regular file.
52+
*/
53+
bool VirtualFileMountZip::
54+
is_regular_file(const Filename &file) const {
55+
Filename path(_directory, file);
56+
return (_archive->find_subfile(path) >= 0);
57+
}
58+
59+
/**
60+
* Fills up the indicated pvector with the contents of the file, if it is a
61+
* regular file. Returns true on success, false otherwise.
62+
*/
63+
bool VirtualFileMountZip::
64+
read_file(const Filename &file, bool do_uncompress,
65+
vector_uchar &result) const {
66+
67+
Filename path(_directory, file);
68+
if (do_uncompress) {
69+
// If the file is to be decompressed, we'd better just use the higher-
70+
// level implementation, which includes support for on-the-fly
71+
// decompression.
72+
return VirtualFileMount::read_file(path, do_uncompress, result);
73+
}
74+
75+
// But if we're just reading a straight file, let the Multifile do the
76+
// reading, which avoids a few levels of buffer copies.
77+
78+
int subfile_index = _archive->find_subfile(path);
79+
if (subfile_index < 0) {
80+
express_cat.info()
81+
<< "Unable to read " << path << "\n";
82+
return false;
83+
}
84+
85+
return _archive->read_subfile(subfile_index, result);
86+
}
87+
88+
/**
89+
* Opens the file for reading, if it exists. Returns a newly allocated
90+
* istream on success (which you should eventually delete when you are done
91+
* reading). Returns NULL on failure.
92+
*/
93+
std::istream *VirtualFileMountZip::
94+
open_read_file(const Filename &file) const {
95+
Filename path(_directory, file);
96+
int subfile_index = _archive->find_subfile(path);
97+
if (subfile_index < 0) {
98+
return nullptr;
99+
}
100+
101+
// The caller will eventually pass this pointer to
102+
// VirtualFileSystem::close_read_file(), not to
103+
// Multifile::close_read_subfile(). Fortunately, these two methods do the
104+
// same thing, so that doesn't matter.
105+
return _archive->open_read_subfile(subfile_index);
106+
}
107+
108+
/**
109+
* Returns the current size on disk (or wherever it is) of the already-open
110+
* file. Pass in the stream that was returned by open_read_file(); some
111+
* implementations may require this stream to determine the size.
112+
*/
113+
std::streamsize VirtualFileMountZip::
114+
get_file_size(const Filename &file, std::istream *) const {
115+
Filename path(_directory, file);
116+
int subfile_index = _archive->find_subfile(path);
117+
if (subfile_index < 0) {
118+
return 0;
119+
}
120+
return _archive->get_subfile_length(subfile_index);
121+
}
122+
123+
/**
124+
* Returns the current size on disk (or wherever it is) of the file before it
125+
* has been opened.
126+
*/
127+
std::streamsize VirtualFileMountZip::
128+
get_file_size(const Filename &file) const {
129+
Filename path(_directory, file);
130+
int subfile_index = _archive->find_subfile(path);
131+
if (subfile_index < 0) {
132+
return 0;
133+
}
134+
return _archive->get_subfile_length(subfile_index);
135+
}
136+
137+
/**
138+
* Returns a time_t value that represents the time the file was last modified,
139+
* to within whatever precision the operating system records this information
140+
* (on a Windows95 system, for instance, this may only be accurate to within 2
141+
* seconds).
142+
*
143+
* If the timestamp cannot be determined, either because it is not supported
144+
* by the operating system or because there is some error (such as file not
145+
* found), returns 0.
146+
*/
147+
time_t VirtualFileMountZip::
148+
get_timestamp(const Filename &file) const {
149+
Filename path(_directory, file);
150+
int subfile_index = _archive->find_subfile(path);
151+
if (subfile_index < 0) {
152+
return 0;
153+
}
154+
return _archive->get_subfile_timestamp(subfile_index);
155+
}
156+
157+
/**
158+
* Populates the SubfileInfo structure with the data representing where the
159+
* file actually resides on disk, if this is knowable. Returns true if the
160+
* file might reside on disk, and the info is populated, or false if it might
161+
* not (or it is not known where the file resides), in which case the info is
162+
* meaningless.
163+
*/
164+
bool VirtualFileMountZip::
165+
get_system_info(const Filename &file, SubfileInfo &info) {
166+
Filename path(_directory, file);
167+
Filename filename = _archive->get_filename();
168+
if (filename.empty()) {
169+
return false;
170+
}
171+
int subfile_index = _archive->find_subfile(path);
172+
if (subfile_index < 0) {
173+
return false;
174+
}
175+
if (_archive->is_subfile_compressed(subfile_index) ||
176+
_archive->is_subfile_encrypted(subfile_index)) {
177+
return false;
178+
}
179+
180+
std::streampos start = _archive->get_subfile_internal_start(subfile_index);
181+
size_t length = _archive->get_subfile_internal_length(subfile_index);
182+
183+
info = SubfileInfo(filename, start, length);
184+
return true;
185+
}
186+
187+
/**
188+
* Fills the given vector up with the list of filenames that are local to this
189+
* directory, if the filename is a directory. Returns true if successful, or
190+
* false if the file is not a directory or cannot be read.
191+
*/
192+
bool VirtualFileMountZip::
193+
scan_directory(vector_string &contents, const Filename &dir) const {
194+
Filename path(_directory, dir);
195+
return _archive->scan_directory(contents, path);
196+
}
197+
198+
/**
199+
*
200+
*/
201+
void VirtualFileMountZip::
202+
output(std::ostream &out) const {
203+
out << _archive->get_filename();
204+
}

0 commit comments

Comments
 (0)