示例#1
0
	void ZipWriter::begin_file(const std::string &filename, bool compress)
	{
		if (impl->file_begun)
			throw Exception("ZipWriter already writing a file");
		impl->file_begun = true;

		impl->uncompressed_length = 0;
		impl->compressed_length = 0;
		impl->compress = compress;
		impl->crc32 = ZIP_CRC_START_VALUE;

		impl->local_header_offset = impl->output.get_position();
		impl->local_header = ZipLocalFileHeader();
		impl->local_header.version_needed_to_extract = 20;
		if (impl->storeFilenamesAsUTF8)
			impl->local_header.general_purpose_bit_flag = ZIP_USE_UTF8;
		else
			impl->local_header.general_purpose_bit_flag = 0;
		impl->local_header.compression_method = compress ? zip_compress_deflate : zip_compress_store;
		ZipArchive_Impl::calc_time_and_date(
			impl->local_header.last_mod_file_date,
			impl->local_header.last_mod_file_time);
		impl->local_header.crc32 = 0;
		impl->local_header.uncompressed_size = 0;
		impl->local_header.compressed_size = 0;
		impl->local_header.file_name_length = filename.length();
		impl->local_header.filename = filename;

		if (!impl->storeFilenamesAsUTF8) // Add UTF-8 as extra field if we aren't storing normal UTF-8 filenames
		{
			// -Info-ZIP Unicode Path Extra Field (0x7075)
			std::string filename_cp437 = StringHelp::text_to_cp437(filename);
			std::string filename_utf8 = StringHelp::text_to_utf8(filename);
			DataBuffer unicode_path(9 + filename_utf8.length());
			uint16_t *extra_id = (uint16_t *)(unicode_path.get_data());
			uint16_t *extra_len = (uint16_t *)(unicode_path.get_data() + 2);
			uint8_t *extra_version = (uint8_t *)(unicode_path.get_data() + 4);
			uint32_t *extra_crc32 = (uint32_t *)(unicode_path.get_data() + 5);
			*extra_id = 0x7075;
			*extra_len = 5 + filename_utf8.length();
			*extra_version = 1;
			*extra_crc32 = ZipArchive_Impl::calc_crc32(filename_cp437.data(), filename_cp437.size());
			memcpy(unicode_path.get_data() + 9, filename_utf8.data(), filename_utf8.length());
			impl->local_header.extra_field_length = unicode_path.get_size();
			impl->local_header.extra_field = unicode_path;
		}

		impl->local_header.save(impl->output);

		if (compress)
		{
			memset(&impl->zs, 0, sizeof(mz_stream));
			int result = mz_deflateInit2(&impl->zs, MZ_DEFAULT_COMPRESSION, MZ_DEFLATED, -15, 8, MZ_DEFAULT_STRATEGY); // Undocumented: if wbits is negative, zlib skips header check
			if (result != MZ_OK)
				throw Exception("Zlib deflateInit failed for zip index!");
		}
	}
示例#2
0
DataBuffer ZLibCompression::compress(const DataBuffer &data, bool raw, int compression_level, CompressionMode mode)
{
	const int window_bits = 15;

	DataBuffer zbuffer(1024*1024);
	IODevice_Memory output;

	int strategy = MZ_DEFAULT_STRATEGY;
	switch (mode)
	{
	case default_strategy: strategy = MZ_DEFAULT_STRATEGY; break;
	case filtered: strategy = MZ_FILTERED; break;
	case huffman_only: strategy = MZ_HUFFMAN_ONLY; break;
	case rle: strategy = MZ_RLE; break;
	case fixed: strategy = MZ_FIXED; break;
	}

	mz_stream zs = { nullptr };
	int result = mz_deflateInit2(&zs, compression_level, MZ_DEFLATED, raw ? -window_bits : window_bits, 8, strategy); // Undocumented: if wbits is negative, zlib skips header check
	if (result != MZ_OK)
		throw Exception("Zlib deflateInit failed");

	try
	{
		zs.next_in = (unsigned char *) data.get_data();
		zs.avail_in = data.get_size();
		while (true)
		{
			zs.next_out = (unsigned char *) zbuffer.get_data();
			zs.avail_out = zbuffer.get_size();

			int result = mz_deflate(&zs, MZ_FINISH);
			if (result == MZ_NEED_DICT) throw Exception("Zlib deflate wants a dictionary!");
			if (result == MZ_DATA_ERROR) throw Exception("Zip data stream is corrupted");
			if (result == MZ_STREAM_ERROR) throw Exception("Zip stream structure was inconsistent!");
			if (result == MZ_MEM_ERROR) throw Exception("Zlib did not have enough memory to compress file!");
			if (result == MZ_BUF_ERROR) throw Exception("Not enough data in buffer when Z_FINISH was used");
			if (result != MZ_OK && result != MZ_STREAM_END) throw Exception("Zlib deflate failed while compressing zip file!");
			int zsize = zbuffer.get_size() - zs.avail_out;
			if (zsize == 0)
				break;
			output.write(zbuffer.get_data(), zsize);
			if (result == MZ_STREAM_END)
				break;
		}
		mz_deflateEnd(&zs);
	}
	catch (...)
	{
		mz_deflateEnd(&zs);
		throw;
	}

	return output.get_data();
}