1 | // |
2 | // ZipFileInfo.cpp |
3 | // |
4 | // Library: Zip |
5 | // Package: Zip |
6 | // Module: ZipFileInfo |
7 | // |
8 | // Copyright (c) 2007, Applied Informatics Software Engineering GmbH. |
9 | // and Contributors. |
10 | // |
11 | // SPDX-License-Identifier: BSL-1.0 |
12 | // |
13 | |
14 | |
15 | #include "Poco/Zip/ZipFileInfo.h" |
16 | #include "Poco/Zip/ZipLocalFileHeader.h" |
17 | #include "Poco/Buffer.h" |
18 | #include <istream> |
19 | #include <cstring> |
20 | |
21 | |
22 | namespace Poco { |
23 | namespace Zip { |
24 | |
25 | |
26 | const char ZipFileInfo::[ZipCommon::HEADER_SIZE] = {'\x50', '\x4b', '\x01', '\x02'}; |
27 | |
28 | |
29 | ZipFileInfo::(const ZipLocalFileHeader& ): |
30 | _rawInfo(), |
31 | _crc32(0), |
32 | _compressedSize(0), |
33 | _uncompressedSize(0), |
34 | _localHeaderOffset(0), |
35 | _fileName(), |
36 | _lastModifiedAt(), |
37 | _extraField() |
38 | { |
39 | std::memset(_rawInfo, 0, FULLHEADER_SIZE); |
40 | std::memcpy(_rawInfo, HEADER, ZipCommon::HEADER_SIZE); |
41 | setCompressedSize(header.getCompressedSize()); |
42 | setUncompressedSize(header.getUncompressedSize()); |
43 | setCRC(header.getCRC()); |
44 | setCompressionMethod(header.getCompressionMethod()); |
45 | setCompressionLevel(header.getCompressionLevel()); |
46 | setRequiredVersion(header.getMajorVersionNumber(), header.getMinorVersionNumber()); |
47 | setHostSystem(header.getHostSystem()); |
48 | setLastModifiedAt(header.lastModifiedAt()); |
49 | setEncryption(false); |
50 | setFileName(header.getFileName()); |
51 | |
52 | if (getHostSystem() == ZipCommon::HS_UNIX) |
53 | setUnixAttributes(); |
54 | |
55 | _rawInfo[GENERAL_PURPOSE_POS+1] |= 0x08; // Set "language encoding flag" to indicate that filenames and paths are in UTF-8. |
56 | |
57 | if (header.searchCRCAndSizesAfterData()) |
58 | _rawInfo[GENERAL_PURPOSE_POS] |= 0x08; |
59 | } |
60 | |
61 | |
62 | ZipFileInfo::ZipFileInfo(std::istream& in, bool ): |
63 | _rawInfo(), |
64 | _crc32(0), |
65 | _compressedSize(0), |
66 | _uncompressedSize(0), |
67 | _localHeaderOffset(0), |
68 | _fileName(), |
69 | _lastModifiedAt(), |
70 | _extraField() |
71 | { |
72 | // sanity check |
73 | poco_assert_dbg (RELATIVEOFFSETLOCALHEADER_POS + RELATIVEOFFSETLOCALHEADER_SIZE == FULLHEADER_SIZE); |
74 | parse(in, assumeHeaderRead); |
75 | } |
76 | |
77 | |
78 | ZipFileInfo::~ZipFileInfo() |
79 | { |
80 | } |
81 | |
82 | |
83 | void ZipFileInfo::parse(std::istream& inp, bool ) |
84 | { |
85 | if (!assumeHeaderRead) |
86 | { |
87 | inp.read(_rawInfo, ZipCommon::HEADER_SIZE); |
88 | if (inp.gcount() != ZipCommon::HEADER_SIZE) |
89 | throw Poco::IOException("Failed to read file info header" ); |
90 | if (std::memcmp(_rawInfo, HEADER, ZipCommon::HEADER_SIZE) != 0) |
91 | throw Poco::DataFormatException("Bad file info header" ); |
92 | } |
93 | else |
94 | { |
95 | std::memcpy(_rawInfo, HEADER, ZipCommon::HEADER_SIZE); |
96 | } |
97 | |
98 | // read the rest of the header |
99 | inp.read(_rawInfo + ZipCommon::HEADER_SIZE, FULLHEADER_SIZE - ZipCommon::HEADER_SIZE); |
100 | _crc32 = getCRCFromHeader(); |
101 | _compressedSize = getCompressedSizeFromHeader(); |
102 | _uncompressedSize = getUncompressedSizeFromHeader(); |
103 | _localHeaderOffset = getOffsetFromHeader(); |
104 | parseDateTime(); |
105 | Poco::UInt16 len = getFileNameLength(); |
106 | if (len > 0) |
107 | { |
108 | Poco::Buffer<char> buf(len); |
109 | inp.read(buf.begin(), len); |
110 | _fileName = std::string(buf.begin(), len); |
111 | } |
112 | if (hasExtraField()) |
113 | { |
114 | len = getExtraFieldLength(); |
115 | if (len > 0) |
116 | { |
117 | Poco::Buffer<char> xtra(len); |
118 | inp.read(xtra.begin(), len); |
119 | _extraField = std::string(xtra.begin(), len); |
120 | char* ptr = xtra.begin(); |
121 | while (ptr <= xtra.begin() + len - 4) |
122 | { |
123 | Poco::UInt16 id = ZipUtil::get16BitValue(ptr, 0); |
124 | ptr += 2; |
125 | Poco::UInt16 size = ZipUtil::get16BitValue(ptr, 0); |
126 | ptr += 2; |
127 | if (id == ZipCommon::ZIP64_EXTRA_ID) |
128 | { |
129 | if (size >= 8 && getUncompressedSizeFromHeader() == ZipCommon::ZIP64_MAGIC) |
130 | { |
131 | setUncompressedSize(ZipUtil::get64BitValue(ptr, 0)); |
132 | size -= 8; |
133 | ptr += 8; |
134 | } |
135 | if (size >= 8 && getCompressedSizeFromHeader() == ZipCommon::ZIP64_MAGIC) |
136 | { |
137 | setCompressedSize(ZipUtil::get64BitValue(ptr, 0)); |
138 | size -= 8; |
139 | ptr += 8; |
140 | } |
141 | if (size >= 8 && getOffsetFromHeader() == ZipCommon::ZIP64_MAGIC) |
142 | { |
143 | setOffset(ZipUtil::get64BitValue(ptr, 0)); |
144 | size -= 8; |
145 | ptr += 8; |
146 | } |
147 | } |
148 | else |
149 | { |
150 | ptr += size; |
151 | } |
152 | } |
153 | } |
154 | } |
155 | len = getFileCommentLength(); |
156 | if (len > 0) |
157 | { |
158 | Poco::Buffer<char> buf2(len); |
159 | inp.read(buf2.begin(), len); |
160 | _fileComment = std::string(buf2.begin(), len); |
161 | } |
162 | } |
163 | |
164 | |
165 | std::string ZipFileInfo::() const |
166 | { |
167 | std::string result(_rawInfo, FULLHEADER_SIZE); |
168 | result.append(_fileName); |
169 | result.append(_extraField); |
170 | result.append(_fileComment); |
171 | return result; |
172 | } |
173 | |
174 | |
175 | void ZipFileInfo::setUnixAttributes() |
176 | { |
177 | bool isDir = isDirectory(); |
178 | int mode; |
179 | if (isDir) |
180 | mode = DEFAULT_UNIX_DIR_MODE; |
181 | else |
182 | mode = DEFAULT_UNIX_FILE_MODE; |
183 | Poco::UInt32 attrs = (mode << 16) | (isDir ? 0x10 : 0); |
184 | setExternalFileAttributes(attrs); |
185 | } |
186 | |
187 | |
188 | } } // namespace Poco::Zip |
189 | |