| 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 | |