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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy