PWIZ_API_DECL string SHA1Calculator::hash(istream& is) { CSHA1 sha1; is.clear(); is.seekg(0); unsigned char buffer[65535]; size_t bytesRead; while (is && (bytesRead = is.readsome(reinterpret_cast<char*>(buffer), 65535)) > 0) sha1.Update(buffer, static_cast<UINT_32>(bytesRead)); sha1.Final(); return formatHash(sha1); }
static inline int readChar(istream& is) { char b[1]; return (is.readsome(b, 1) == 1) ? b[0] : -1; }
bool read_next_file(istream& s, ZIPLocalFileHeader& fh) { char b[30]; if (s.readsome(b, 4) != 4) THROW(("Truncated ePub file")); if (b[0] != 'P' or b[1] != 'K') THROW(("Invalid ePub file")); if (b[2] == '0' and b[3] == '0') // split THROW(("Split ePub archives are not supported")); if ((b[2] == '\001' and b[3] == '\002') or // central directory (b[2] == '\005' and b[3] == '\006')) // end of archive record { return false; } // now it must be a regular file entry, otherwise we bail out if (not (b[2] == '\003' and b[3] == '\004')) THROW(("Invalid ePub file, perhaps it is damaged")); if (s.readsome(b + 4, sizeof(b) - 4) != sizeof(b) - 4) THROW(("Truncated ePub file")); uint16 versionNeededToExtract, bitFlag, compressionMethod, fileNameLength, extraFieldLength; char* p = read(versionNeededToExtract, b + 4); p = read(bitFlag, p); p = read(compressionMethod, p); p = read(fh.file_mod_time, p); p = read(fh.file_mod_date, p); p = read(fh.crc, p); p = read(fh.compressed_size, p); p = read(fh.uncompressed_size, p); p = read(fileNameLength, p); p = read(extraFieldLength, p); // sanity checks if (compressionMethod != 0 and compressionMethod != 8) THROW(("Unsupported compression method used in ePub file")); assert(p == b + sizeof(b)); // read file name vector<char> fn(fileNameLength); if (s.readsome(&fn[0], fileNameLength) != fileNameLength) THROW(("Truncated ePub file")); fh.filename.assign(&fn[0], fileNameLength); // skip over the extra data s.seekg(extraFieldLength, ios::cur); // OK, now read in the data and inflate if required fh.data.clear(); // save the offset in the stream to be able to seek back if needed std::streamsize offset = s.tellg(); if (compressionMethod == 0) // no compression { if (fh.compressed_size > 0) { vector<char> b(fh.compressed_size); if (s.readsome(&b[0], fh.compressed_size) != fh.compressed_size) THROW(("Truncated ePub file")); fh.data.assign(&b[0], fh.compressed_size); } } else // inflate { if (fh.compressed_size == 0 and not (bitFlag & kZipLengthAtEndMask)) THROW(("Invalid ePub file, missing compressed size")); // setup a boost::iostreams pair to read the compressed data io::zlib_params params; params.noheader = true; // don't read header, i.e. true deflate compression params.calculate_crc = true; io::zlib_decompressor z_stream(params); io::filtering_streambuf<io::input> in; in.push(z_stream); in.push(s); io::filtering_ostream out(io::back_inserter(fh.data)); io::copy(in, out); s.seekg(offset + z_stream.filter().total_in(), ios::beg); // now read the trailing length if needed if (bitFlag & kZipLengthAtEndMask) { char b2[16]; if (s.readsome(b2, sizeof(b2)) != sizeof(b2)) THROW(("Truncated ePub file")); uint32 signature; char* p = read(signature, b2); if (signature == 0x08074b50UL) p = read(fh.crc, p); else { fh.crc = signature; s.seekg(-4, ios::cur); } p = read(fh.compressed_size, p); p = read(fh.uncompressed_size, p); } // OK, so decompression succeeded, now validate the data // if (compressed_size != fh.compressed_size) // THROW(("ePub data, compressed data is wrong size")); if (static_cast<uint32>(z_stream.total_out()) != fh.uncompressed_size) THROW(("ePub data, uncompressed data is wrong size")); if (z_stream.crc() != fh.crc) THROW(("ePub data, bad crc")); } return true; }