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
22namespace Poco {
23namespace Zip {
24
25
26const char ZipFileInfo::HEADER[ZipCommon::HEADER_SIZE] = {'\x50', '\x4b', '\x01', '\x02'};
27
28
29ZipFileInfo::ZipFileInfo(const ZipLocalFileHeader& header):
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
62ZipFileInfo::ZipFileInfo(std::istream& in, bool assumeHeaderRead):
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
78ZipFileInfo::~ZipFileInfo()
79{
80}
81
82
83void ZipFileInfo::parse(std::istream& inp, bool assumeHeaderRead)
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
165std::string ZipFileInfo::createHeader() 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
175void 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