diff --git a/czi-format/czi-parser/CMakeLists.txt b/czi-format/czi-parser/CMakeLists.txt index 10703476e5ab74e285b6079a830e344ce9777b9a..4d8b5312434658ba235269cf4359b100b091a278 100644 --- a/czi-format/czi-parser/CMakeLists.txt +++ b/czi-format/czi-parser/CMakeLists.txt @@ -49,7 +49,11 @@ if (OPENMP_FOUND) message("ENABLED OpenMP") endif() -include_directories("utilities/bsdiff") +# add_library(BSDIFF "utilities/bsdiff/bsdiff.h" "utilities/bsdiff/bsdiff.c") +# include_directories("utilities/bsdiff/") +# target_link_libraries(czi-parser BSDIFF) + +# include_directories() set(CPACK_PROJECT_NAME ${PROJECT_NAME}) set(CPACK_PROJECT_VERSION ${PROJECT_VERSION}) diff --git a/czi-format/czi-parser/compression/benchmark.cpp b/czi-format/czi-parser/compression/benchmark.cpp index 2df8ae3d2e153d5c1fe25ae13f21f833a0171d63..e5aacca739ceee5949282a8b0faef3a2b7870e24 100644 --- a/czi-format/czi-parser/compression/benchmark.cpp +++ b/czi-format/czi-parser/compression/benchmark.cpp @@ -250,7 +250,7 @@ static void _diff_from_frame_gray16(const ByteArray &pfData, const ByteArray &cf } auto minMax = vecUtil::find_min_max(delta); - long maxRequiredValue = (minMax.first < 0) ? (abs(minMax.first) + minMax.second) : (minMax.second); + long maxRequiredValue = (minMax.min < 0) ? (abs(minMax.min) + minMax.max) : (minMax.max); bool canBeMappedToUShort = maxRequiredValue < USHORT_MAX; always_assert(canBeMappedToUShort && "Value can not be mapped into ushort."); @@ -269,10 +269,56 @@ static void _diff_from_frame_gray16(const ByteArray &pfData, const ByteArray &cf cr = test_compression_method(ushortMappedDeltaBytes, cm, compLevel); } -void value_diff_by_prev_frame_benchmark(CziFile &cziFile, const std::string &reportFile, bool verbose, int level, CompressionMethod cm) +static void _diff_from_frame_gray16_va_bit_count(const ByteArray &pfData, const ByteArray &cfData, + const CompressionMethod cm, const int compLevel, CompressionResult &cr, size_t &bitsUsed) +{ + + always_assert(pfData.size() == cfData.size()); + + std::vector<int> delta; + + { + std::vector<ushort> pfUshortValues = bytes_to_ushort_array(pfData); + std::vector<ushort> cfUshortValues = bytes_to_ushort_array(cfData); + always_assert(pfUshortValues.size() == cfUshortValues.size()); + + delta = vecUtil::diff_vectors<ushort, int>(pfUshortValues, cfUshortValues); + } + + auto minMax = vecUtil::find_min_max(delta); + long maxRequiredValue = (minMax.min < 0) ? (abs(minMax.min) + minMax.max) : (minMax.max); + bool canBeMappedToUShort = maxRequiredValue < USHORT_MAX; + always_assert(canBeMappedToUShort && "Value can not be mapped into ushort."); + + // Here we map integers into ushort. + ByteArray diffBytes; + { + TypeMapper<int, ushort> typeMapper; + std::vector<ushort> ushortMappedDelta = typeMapper.map(delta); + + ushort ushortMappedDeltaMax = vecUtil::find_max(ushortMappedDelta); + bitsUsed = bits_required(ushortMappedDeltaMax); + + OutMemoryBitStream outMemoryBitStream(bitsUsed); + size_t requiredBitCount = bitsUsed * ushortMappedDelta.size(); + size_t requiredSize = (requiredBitCount + 8 - 1) / 8; + outMemoryBitStream.resize_for_raw_write(requiredSize); + + for (size_t i = 0; i < ushortMappedDelta.size(); i++) + { + outMemoryBitStream.write_value_no_alloc(ushortMappedDelta[i]); + } + diffBytes = outMemoryBitStream.get_flushed_buffer(); + } + + cr = test_compression_method(diffBytes, cm, compLevel); +} + +void value_diff_by_prev_frame_benchmark(CziFile &cziFile, const std::string &reportFile, bool verbose, int level, CompressionMethod cm, bool variableBitCount) { // NOTE: This benchmark works only for 16 bit pixels! printf("Compression method %s with compression level %i\n", compression_method_str(cm), level); + printf_if(variableBitCount, "Using variable bit count.\n"); std::string fName = fs_wrapper::get_filename(cziFile.fileName); auto framesByChannels = cziFile.get_subblocks_grouped_by_channels(); @@ -296,10 +342,6 @@ void value_diff_by_prev_frame_benchmark(CziFile &cziFile, const std::string &rep always_assert(prevEntry.pixelType == PixelType_Gray16); always_assert(currEntry.pixelType == PixelType_Gray16); - record.set_metadata(fName.c_str(), currFrameId, prevFrameId, - cziFile.pixel_type_str(currEntry.pixelType), currEntry.width, currEntry.height, - compression_method_str(cm), level, "PrevFrameDiff", 16, channelGroup.first); - DimensionEntryDV1 prevDim = prevEntry.get_dimension(Dimension_Z); DimensionEntryDV1 currDim = currEntry.get_dimension(Dimension_Z); always_assert(!prevDim.isEmpty && !currDim.isEmpty); @@ -311,21 +353,37 @@ void value_diff_by_prev_frame_benchmark(CziFile &cziFile, const std::string &rep // pf => previous frame, cf => current frame. size_t originalSize = 0; - //std::thread(pfData,cfData, benchmarkRecord); + size_t bitsUsed = 16; { auto pfData = cziFile.get_image_data(prevFrameId, false); auto cfData = cziFile.get_image_data(currFrameId, false); - _diff_from_frame_gray16(pfData, cfData, cm, level, crN); + + if (variableBitCount) + _diff_from_frame_gray16_va_bit_count(pfData, cfData, cm, level, crN, bitsUsed); + else + _diff_from_frame_gray16(pfData, cfData, cm, level, crN); + originalSize = pfData.size(); } // Z order { auto pfDataZ = cziFile.get_image_data(prevFrameId, true); auto cfDataZ = cziFile.get_image_data(currFrameId, true); - _diff_from_frame_gray16(pfDataZ, cfDataZ, cm, level, crZ); + + if (variableBitCount) + _diff_from_frame_gray16_va_bit_count(pfDataZ, cfDataZ, cm, level, crZ, bitsUsed); + else + _diff_from_frame_gray16(pfDataZ, cfDataZ, cm, level, crZ); + always_assert(pfDataZ.size() == originalSize); } + record.set_metadata(fName.c_str(), currFrameId, prevFrameId, + cziFile.pixel_type_str(currEntry.pixelType), currEntry.width, currEntry.height, + compression_method_str(cm), level, "PrevFrameDiff", bitsUsed, channelGroup.first); + + //printf_if((variableBitCount && verbose), "Bits used for encoding: %lu\n", bitsUsed); + record.originalSize = originalSize; record.compressedSize = crN.compressedSize; record.zOrderCompressedSize = crZ.compressedSize; @@ -351,6 +409,8 @@ void value_diff_by_prev_frame_benchmark(CziFile &cziFile, const std::string &rep void bsdiff_by_prev_frame_benchmark(CziFile &cziFile, const std::string &reportFile, bool verbose) { + always_assert(NOT_IMPLEMENTED_YET && "This has to fixed with proper version of bsdiff."); + /* std::string fName = fs_wrapper::get_filename(cziFile.fileName); printf("Difference from previuos frame by bsdiff unix tool.\n"); auto framesByChannels = cziFile.get_subblocks_grouped_by_channels(); @@ -394,11 +454,13 @@ void bsdiff_by_prev_frame_benchmark(CziFile &cziFile, const std::string &reportF auto cfData = cziFile.get_image_data(currFrameId, false); originalSize = pfData.size(); - size_t maxPatchSize = lib_bsdiff::bsdiff_patchsize_max(pfData.size(), cfData.size()); + size_t maxPatchSize = 0; //lib_bsdiff::bsdiff_patchsize_max(pfData.size(), cfData.size()); ByteArray patchBuffer; - patchBuffer.resize(maxPatchSize); + //patchBuffer.resize(maxPatchSize); + + lib_bsdiff::bsdiff_helper(pfData.data(), pfData.size(), cfData.data(), cfData.size(), patchBuffer); - off_t actualBufferSize = lib_bsdiff::bsdiff(pfData.data(), pfData.size(), cfData.data(), cfData.size(), patchBuffer.data(), maxPatchSize); + off_t actualBufferSize = patchBuffer.size(); //lib_bsdiff::bsdiff(pfData.data(), pfData.size(), cfData.data(), cfData.size(), patchBuffer.data(), maxPatchSize); always_assert(actualBufferSize != -1 && "bsdiff error."); patchSizeN = actualBufferSize; } @@ -408,11 +470,11 @@ void bsdiff_by_prev_frame_benchmark(CziFile &cziFile, const std::string &reportF auto cfDataZ = cziFile.get_image_data(currFrameId, true); always_assert(pfDataZ.size() == originalSize); - size_t maxPatchSize = lib_bsdiff::bsdiff_patchsize_max(pfDataZ.size(), cfDataZ.size()); + size_t maxPatchSize = 0; //lib_bsdiff::bsdiff_patchsize_max(pfDataZ.size(), cfDataZ.size()); ByteArray patchBuffer; patchBuffer.resize(maxPatchSize); - off_t actualBufferSize = lib_bsdiff::bsdiff(pfDataZ.data(), pfDataZ.size(), cfDataZ.data(), cfDataZ.size(), patchBuffer.data(), maxPatchSize); + off_t actualBufferSize = 0; //lib_bsdiff::bsdiff(pfDataZ.data(), pfDataZ.size(), cfDataZ.data(), cfDataZ.size(), patchBuffer.data(), maxPatchSize); always_assert(actualBufferSize != -1 && "bsdiff error."); patchSizeZ = actualBufferSize; } @@ -438,4 +500,5 @@ void bsdiff_by_prev_frame_benchmark(CziFile &cziFile, const std::string &reportF write_diff_report(benchmarkRecords, reportFile); printf("\rFinished %u/%u\n", iterCount, iterCount); printf("Report saved in %s\n", reportFile.c_str()); + */ } \ No newline at end of file diff --git a/czi-format/czi-parser/compression/benchmark.h b/czi-format/czi-parser/compression/benchmark.h index c45fe338469926d09d58f44e87dff6ea0104a19a..64ce63198fe1658302506a023e42cdf0e353e6c1 100644 --- a/czi-format/czi-parser/compression/benchmark.h +++ b/czi-format/czi-parser/compression/benchmark.h @@ -2,31 +2,53 @@ #include "compressors.h" #include "../czi_file.h" #include "../file_system.h" +#include "../stream/memory_bit_stream.h" #include <iomanip> #include <thread> namespace lib_bsdiff { -#include "../utilities/bsdiff/bsdiff.h" -#include "../utilities/bsdiff/bsdiff.c" +// #include "../utilities/bsdiff/bsdiff.h" + +// static int bs_write_imp(struct bsdiff_stream *stream, const void *buffer, int size) +// { +// auto vectorBuffer = ((std::vector<unsigned char> *)stream->opaque); +// unsigned char *binDataToWrite = (unsigned char *)buffer; +// for (int i = 0; i < size; i++) +// { +// vectorBuffer->push_back(binDataToWrite[i]); +// } +// return 0; +// } + +// static int bsdiff_helper(const uint8_t *old, int64_t oldsize, const uint8_t *_new, int64_t newsize, std::vector<unsigned char> &buffer) +// { +// struct bsdiff_stream diff_stream; +// diff_stream.opaque = (void *)&buffer; +// diff_stream.malloc = malloc; +// diff_stream.free = free; +// diff_stream.write = bs_write_imp; + +// return bsdiff(old, oldsize, _new, newsize, &diff_stream); +// } }; // namespace lib_bsdiff struct BaseBenchmarkRecord { - const char *fileName; - size_t subblockId; - const char *pixelType; - size_t width; - size_t height; - const char *compressionMethod; - int compressionLevel; - size_t originalSize; - size_t compressedSize; - size_t zOrderCompressedSize; - float compressionRatio; - float zOrderCompressionRatio; - double compressionTime; - double zOrderCompressionTime; + const char *fileName = nullptr; + size_t subblockId = 0; + const char *pixelType = nullptr; + size_t width = 0; + size_t height = 0; + const char *compressionMethod = nullptr; + int compressionLevel = 0; + size_t originalSize = 0; + size_t compressedSize = 0; + size_t zOrderCompressedSize = 0; + float compressionRatio = 0.0f; + float zOrderCompressionRatio = 0.0f; + double compressionTime = 0.0; + double zOrderCompressionTime = 0.0; BaseBenchmarkRecord() {} BaseBenchmarkRecord(const CompressionResult &dataResult, const CompressionResult &dataZOrderResult) @@ -66,10 +88,10 @@ struct BaseBenchmarkRecord struct DiffBenchmarkRecord : BaseBenchmarkRecord { - size_t refSubblockId; - uint channel; - const char *diffType; - uint bitsUsedForEncoding; + size_t refSubblockId = 0; + uint channel = 0; + const char *diffType = nullptr; + uint bitsUsedForEncoding = 0; void set_metadata(const char *fName, size_t subBlockId, size_t refSlubblockId, const char *pixelType, size_t width, size_t height, const char *cMethod, int cLevel, const char *diffType, const uint bitsUsed, const uint channel) @@ -100,8 +122,11 @@ void benchmark_continuos_compression(CziFile &cziFile, const std::string &report void benchmark_compression(CziFile &cziFile, const std::string &reportFile, bool verbose, int level = -1); // Frame difference benchmark stuff -void value_diff_by_prev_frame_benchmark(CziFile &cziFile, const std::string &reportFile, bool verbose, int level, CompressionMethod cm); -void bsdiff_by_prev_frame_benchmark(CziFile &cziFile, const std::string &reportFile, bool verbose); +void value_diff_by_prev_frame_benchmark(CziFile &cziFile, const std::string &reportFile, + bool verbose, int level, CompressionMethod cm, bool variableBitCount); + +// void bsdiff_by_prev_frame_benchmark(CziFile &cziFile, const std::string &reportFile, bool verbose); + static void write_diff_report(const std::vector<DiffBenchmarkRecord> &results, const std::string &reportFile); #include "benchmark.cpp" \ No newline at end of file diff --git a/czi-format/czi-parser/main.cpp b/czi-format/czi-parser/main.cpp index 38278099c19b233a4b6587026b626149bdfbbc4a..06091f0414c1b589e4798e819f59847b5ec1248c 100644 --- a/czi-format/czi-parser/main.cpp +++ b/czi-format/czi-parser/main.cpp @@ -44,9 +44,12 @@ int main(int argc, char **argv) // Options args::Flag dontParseMetadataOption(optionsGroup, "no metadata", "Dont read metadata byte", {"no-metadata"}); args::Flag verboseOption(optionsGroup, "verbose", "Extend output of method", {'v', "verbose"}); + args::Flag variableBitCount(optionsGroup, "Variable bit count", "Use variable bit count for encoding difference value.", {"variable"}); + args::ValueFlag<int> compressionLevelOption(optionsGroup, "Compression level", "Compression level", {'l', "level"}); args::ValueFlag<std::string> folderOption(optionsGroup, "Folder", "Folder to which save exported items.", {'f', "folder"}); args::ValueFlag<std::string> reportFileOption(optionsGroup, "Report file", "File where to write report.", {'r', "report"}); + args::Flag gzipCompressionOption(compressionGroup, "GZIP", "gzip (zlib) compression", {"gzip"}); args::Flag lzmaCompressionOption(compressionGroup, "LZMA", "lzma compression", {"lzma"}); args::Flag bzip2CompressionOption(compressionGroup, "BZIP2", "bzip2 compression", {"bzip2"}); @@ -122,7 +125,7 @@ int main(int argc, char **argv) CompressionMethod cm = get_chosen_compression_method(gzipCompressionOption, lzmaCompressionOption, bzip2CompressionOption); - value_diff_by_prev_frame_benchmark(parsedFile, reportFileOption.Get(), verboseOption.Matched(), level, cm); + value_diff_by_prev_frame_benchmark(parsedFile, reportFileOption.Get(), verboseOption.Matched(), level, cm, variableBitCount.Matched()); return 0; } diff --git a/czi-format/czi-parser/stream/memory_bit_stream.cpp b/czi-format/czi-parser/stream/memory_bit_stream.cpp index 4db2043e07e334816b00cd53b322db7ef391867d..04e2c5d20ae0590f49a5c3cfba86a6829f2f8889 100644 --- a/czi-format/czi-parser/stream/memory_bit_stream.cpp +++ b/czi-format/czi-parser/stream/memory_bit_stream.cpp @@ -3,24 +3,32 @@ /****************************************************************************************************************************** * OutMemoryBitStream implementation ****************************************************************************************************************************/ -OutMemoryBitStream::OutMemoryBitStream() +OutMemoryBitStream::OutMemoryBitStream(size_t valueEncodeBitCount) { bitBuffer = 0; bitBufferSize = 0; + memoryBufferIndex = 0; + this->valueEncodeBitCount = valueEncodeBitCount; } OutMemoryBitStream::~OutMemoryBitStream() { flush_bit_buffer(); bitBuffer = 0; + memoryBufferIndex = 0; bitBufferSize = 0; } +void OutMemoryBitStream::resize_for_raw_write(const size_t size) +{ + buffer.resize(size); +} + void OutMemoryBitStream::operator<<(const bool &bit) { - write_bit(bit); + internal_write_bit(bit, true); } -void OutMemoryBitStream::write_bit(const bool &bit) +void OutMemoryBitStream::internal_write_bit(const bool &bit, const bool &alloc) { ++bitBufferSize; if (bit) @@ -30,15 +38,39 @@ void OutMemoryBitStream::write_bit(const bool &bit) if (bitBufferSize == 8) { - flush_bit_buffer(); + internal_flush_bit_buffer(alloc); } } +void OutMemoryBitStream::write_bit(const bool &bit) +{ + internal_write_bit(bit, true); +} + +void OutMemoryBitStream::write_bit_no_alloc(const bool &bit) +{ + internal_write_bit(bit, false); +} + void OutMemoryBitStream::flush_bit_buffer() +{ + internal_flush_bit_buffer(true); +} + +void OutMemoryBitStream::internal_flush_bit_buffer(const bool &alloc) { if (bitBufferSize > 0) { - buffer.push_back(bitBuffer); + if (alloc) + { + buffer.push_back(bitBuffer); + ++memoryBufferIndex; + } + else + { + buffer[memoryBufferIndex++] = bitBuffer; + } + bitBuffer = 0; bitBufferSize = 0; } @@ -51,7 +83,13 @@ ByteArray OutMemoryBitStream::get_buffer() const ByteArray OutMemoryBitStream::get_flushed_buffer() { - flush_bit_buffer(); + internal_flush_bit_buffer(true); + return buffer; +} + +ByteArray OutMemoryBitStream::get_flushed_buffer_no_alloc() +{ + internal_flush_bit_buffer(false); return buffer; } @@ -59,12 +97,13 @@ ByteArray OutMemoryBitStream::get_flushed_buffer() * InMemoryBitStream implementation ****************************************************************************************************************************/ -InMemoryBitStream::InMemoryBitStream(const ByteArray *buffer, size_t bufferPosition) +InMemoryBitStream::InMemoryBitStream(const ByteArray *buffer, size_t bufferPosition, size_t valueEncodeBitCount) { memoryBuffer = buffer; memoryBufferPosition = bufferPosition; bitBufferSize = 0; bitBuffer = 0; + this->valueEncodeBitCount = valueEncodeBitCount; } InMemoryBitStream::~InMemoryBitStream() diff --git a/czi-format/czi-parser/stream/memory_bit_stream.h b/czi-format/czi-parser/stream/memory_bit_stream.h index d4741cf82c73e040c1c279729bad24cf41560c5a..6ae92693c05315dc2d50a093177f708ae4fce65a 100644 --- a/czi-format/czi-parser/stream/memory_bit_stream.h +++ b/czi-format/czi-parser/stream/memory_bit_stream.h @@ -1,60 +1,134 @@ #pragma once #include "../custom_types.h" +constexpr size_t MAX_BIT_COUNT = 255; + // Class allowing to write invidual bits to memory buffer. class OutMemoryBitStream { -private: - // Memory buffer. - ByteArray buffer; - // Bit buffer. - byte bitBuffer; - // Actual size of bit buffer. - byte bitBufferSize = 0; - -public: - OutMemoryBitStream(); - ~OutMemoryBitStream(); - - // Write bit to memory stream. - void write_bit(const bool &bit); - // Write bit to memory stream. - void operator<<(const bool &bit); - - // If flush buffer is not flushed, flush it to main buffer and clear it. - void flush_bit_buffer(); - // Get buffer of written bits, which may not be flushed. - ByteArray get_buffer() const; - // Get buffer of written bits, which is flushed. - ByteArray get_flushed_buffer(); + private: + // Memory buffer. + ByteArray buffer; + // Index to the next write in memory buffer. + size_t memoryBufferIndex = 0; + // Bit buffer. + byte bitBuffer; + // Actual size of bit buffer. + byte bitBufferSize = 0; + // Number of bits to which value will be encoded when `write_value` is called. + size_t valueEncodeBitCount = 0; + + void internal_write_bit(const bool &bit, const bool &alloc); + void internal_flush_bit_buffer(const bool &alloc); + + public: + OutMemoryBitStream(size_t valueEncodeBitCount = 1); + ~OutMemoryBitStream(); + // Resize the memory buffer for `write_value_no_alloc` and `write_bit_no_alloc` + void resize_for_raw_write(const size_t size); + + // Write bit to memory stream. + void write_bit(const bool &bit); + // Write bit without resizing buffer. Buffer must be allocated using `resize_for_raw_write` ! + void write_bit_no_alloc(const bool &bit); + // Write bit to memory stream. + void operator<<(const bool &bit); + + // If flush buffer is not flushed, flush it to main buffer and clear it. + void flush_bit_buffer(); + // Get buffer of written bits, which may not be flushed. + ByteArray get_buffer() const; + // Get buffer of written bits, which is flushed. + ByteArray get_flushed_buffer(); + // Get buffer of written bits, which is flushed. For allocated buffer. + ByteArray get_flushed_buffer_no_alloc(); + + template <typename T> + void write_value(const T &value) + { + // Lets do it Little-Endian way, start with LSB and move to MSB. + bool bit; + for (size_t bitPos = 0; bitPos < valueEncodeBitCount; bitPos++) + { + bit = value & (1 << bitPos); + write_bit(bit); + } + } + + // Write value without resizing buffer. Buffer must be allocated using `resize_for_raw_write` ! + template <typename T> + void write_value_no_alloc(const T &value) + { + // Lets do it Little-Endian way, start with LSB and move to MSB. + bool bit; + for (size_t bitPos = 0; bitPos < valueEncodeBitCount; bitPos++) + { + bit = value & (1 << bitPos); + write_bit_no_alloc(bit); + } + } }; // Class alowing to read invidual bits from memory buffer. class InMemoryBitStream { -private: - // Memory buffer. - const ByteArray *memoryBuffer = nullptr; - // Position in memory buffer. - size_t memoryBufferPosition = 0; - // Bit buffer. - byte bitBuffer = 0; - // Current bit buffer size. - byte bitBufferSize = 0; - - // Read byte into bit buffer. - void read_byte_to_bit_buffer(); - -public: - InMemoryBitStream(const ByteArray *buffer, size_t bufferPosition = 0); - ~InMemoryBitStream(); - - // Read one bit from memory buffer. - bool read_bit(); - // Read one bit from memory buffer. - void operator>>(bool &bit); - // Check wheter atleast one bit can be read. - bool can_read() const; + private: + // Memory buffer. + const ByteArray *memoryBuffer = nullptr; + // Position in memory buffer. + size_t memoryBufferPosition = 0; + // Bit buffer. + byte bitBuffer = 0; + // Current bit buffer size. + byte bitBufferSize = 0; + // Number of bits to consume when reading value by `read_value`. + size_t valueEncodeBitCount; + + // Read byte into bit buffer. + void read_byte_to_bit_buffer(); + + public: + InMemoryBitStream(const ByteArray *buffer, size_t bufferPosition = 0, size_t valueEncodeBitCount = 1); + ~InMemoryBitStream(); + + // Read one bit from memory buffer. + bool read_bit(); + // Read one bit from memory buffer. + void operator>>(bool &bit); + // Check wheter atleast one bit can be read. + bool can_read() const; + + template <typename T> + T read_value() + { + bool bit; + T result = 0; + for (size_t bitPos = 0; bitPos < valueEncodeBitCount; bitPos++) + { + bit = read_bit(); + result |= (bit << bitPos); + } + return result; + } }; +// Find number of bits required to encode value of `maxValue`. +size_t bits_required(size_t maxValue) +{ + size_t maxValueForBitCount = 0; + for (size_t bitCount = 2; bitCount < MAX_BIT_COUNT; bitCount++) + { + maxValueForBitCount = 0; + for (size_t i = 0; i < bitCount; i++) + { + maxValueForBitCount |= 1 << i; + } + if (maxValue <= maxValueForBitCount) + return bitCount; + } + + always_assert(false && "Max value is too large"); + return 0; +} + #include "memory_bit_stream.cpp" \ No newline at end of file diff --git a/czi-format/czi-parser/utilities/bsdiff/bsdiff.c b/czi-format/czi-parser/utilities/bsdiff/bsdiff.c index b90ebbf36a8d4187f22884ba45e301f3c8871e18..628f1c1a05b470e167d025e9fa99f379a81e67e2 100644 --- a/czi-format/czi-parser/utilities/bsdiff/bsdiff.c +++ b/czi-format/czi-parser/utilities/bsdiff/bsdiff.c @@ -1,10 +1,10 @@ /*- - * Copyright 2012-2013 Austin Seipp * Copyright 2003-2005 Colin Percival + * Copyright 2012 Matthew Endsley * All rights reserved * * Redistribution and use in source and binary forms, with or without - * modification, are permitted providing that the following conditions + * modification, are permitted providing that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. @@ -25,474 +25,421 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#if 0 -__FBSDID("$FreeBSD: src/usr.bin/bsdiff/bsdiff/bsdiff.c,v 1.1 2005/08/06 01:59:05 cperciva Exp $"); -#endif +#include "bsdiff.h" -#include <stdlib.h> -#include <stdio.h> +#include <limits.h> #include <string.h> -#include <sys/types.h> -#include "bsdiff.h" +#define MIN(x,y) (((x)<(y)) ? (x) : (y)) -#define MIN(x, y) (((x) < (y)) ? (x) : (y)) - -/* Header is - 0 8 BSDIFF_CONFIG_MAGIC (see minibsdiff-config.h) - 8 8 length of bzip2ed ctrl block - 16 8 length of bzip2ed diff block - 24 8 length of new file */ -/* File is - 0 32 Header - 32 ?? ctrl block - ?? ?? diff block - ?? ?? extra block */ - -static void -split(off_t *I, off_t *V, off_t start, off_t len, off_t h) +static void split(int64_t *I,int64_t *V,int64_t start,int64_t len,int64_t h) { - off_t i, j, k, x, tmp, jj, kk; - - if (len < 16) - { - for (k = start; k < start + len; k += j) - { - j = 1; - x = V[I[k] + h]; - for (i = 1; k + i < start + len; i++) - { - if (V[I[k + i] + h] < x) - { - x = V[I[k + i] + h]; - j = 0; - }; - if (V[I[k + i] + h] == x) - { - tmp = I[k + j]; - I[k + j] = I[k + i]; - I[k + i] = tmp; - j++; - }; - }; - for (i = 0; i < j; i++) - V[I[k + i]] = k + j - 1; - if (j == 1) - I[k] = -1; - }; - return; - }; - - x = V[I[start + len / 2] + h]; - jj = 0; - kk = 0; - for (i = start; i < start + len; i++) - { - if (V[I[i] + h] < x) - jj++; - if (V[I[i] + h] == x) - kk++; - }; - jj += start; - kk += jj; - - i = start; - j = 0; - k = 0; - while (i < jj) - { - if (V[I[i] + h] < x) - { - i++; - } - else if (V[I[i] + h] == x) - { - tmp = I[i]; - I[i] = I[jj + j]; - I[jj + j] = tmp; - j++; - } - else - { - tmp = I[i]; - I[i] = I[kk + k]; - I[kk + k] = tmp; - k++; - }; - }; - - while (jj + j < kk) - { - if (V[I[jj + j] + h] == x) - { - j++; - } - else - { - tmp = I[jj + j]; - I[jj + j] = I[kk + k]; - I[kk + k] = tmp; - k++; - }; - }; - - if (jj > start) - split(I, V, start, jj - start, h); - - for (i = 0; i < kk - jj; i++) - V[I[jj + i]] = kk - 1; - if (jj == kk - 1) - I[jj] = -1; - - if (start + len > kk) - split(I, V, kk, start + len - kk, h); + int64_t i,j,k,x,tmp,jj,kk; + + if(len<16) { + for(k=start;k<start+len;k+=j) { + j=1;x=V[I[k]+h]; + for(i=1;k+i<start+len;i++) { + if(V[I[k+i]+h]<x) { + x=V[I[k+i]+h]; + j=0; + }; + if(V[I[k+i]+h]==x) { + tmp=I[k+j];I[k+j]=I[k+i];I[k+i]=tmp; + j++; + }; + }; + for(i=0;i<j;i++) V[I[k+i]]=k+j-1; + if(j==1) I[k]=-1; + }; + return; + }; + + x=V[I[start+len/2]+h]; + jj=0;kk=0; + for(i=start;i<start+len;i++) { + if(V[I[i]+h]<x) jj++; + if(V[I[i]+h]==x) kk++; + }; + jj+=start;kk+=jj; + + i=start;j=0;k=0; + while(i<jj) { + if(V[I[i]+h]<x) { + i++; + } else if(V[I[i]+h]==x) { + tmp=I[i];I[i]=I[jj+j];I[jj+j]=tmp; + j++; + } else { + tmp=I[i];I[i]=I[kk+k];I[kk+k]=tmp; + k++; + }; + }; + + while(jj+j<kk) { + if(V[I[jj+j]+h]==x) { + j++; + } else { + tmp=I[jj+j];I[jj+j]=I[kk+k];I[kk+k]=tmp; + k++; + }; + }; + + if(jj>start) split(I,V,start,jj-start,h); + + for(i=0;i<kk-jj;i++) V[I[jj+i]]=kk-1; + if(jj==kk-1) I[jj]=-1; + + if(start+len>kk) split(I,V,kk,start+len-kk,h); } -static void -qsufsort(off_t *I, off_t *V, u_char *old, off_t oldsize) +static void qsufsort(int64_t *I,int64_t *V,const uint8_t *old,int64_t oldsize) { - off_t buckets[256]; - off_t i, h, len; - - for (i = 0; i < 256; i++) - buckets[i] = 0; - for (i = 0; i < oldsize; i++) - buckets[old[i]]++; - for (i = 1; i < 256; i++) - buckets[i] += buckets[i - 1]; - for (i = 255; i > 0; i--) - buckets[i] = buckets[i - 1]; - buckets[0] = 0; - - for (i = 0; i < oldsize; i++) - I[++buckets[old[i]]] = i; - I[0] = oldsize; - for (i = 0; i < oldsize; i++) - V[i] = buckets[old[i]]; - V[oldsize] = 0; - for (i = 1; i < 256; i++) - if (buckets[i] == buckets[i - 1] + 1) - I[buckets[i]] = -1; - I[0] = -1; - - for (h = 1; I[0] != -(oldsize + 1); h += h) - { - len = 0; - for (i = 0; i < oldsize + 1;) - { - if (I[i] < 0) - { - len -= I[i]; - i -= I[i]; - } - else - { - if (len) - I[i - len] = -len; - len = V[I[i]] + 1 - i; - split(I, V, i, len, h); - i += len; - len = 0; - }; - }; - if (len) - I[i - len] = -len; - }; - - for (i = 0; i < oldsize + 1; i++) - I[V[i]] = i; + int64_t buckets[256]; + int64_t i,h,len; + + for(i=0;i<256;i++) buckets[i]=0; + for(i=0;i<oldsize;i++) buckets[old[i]]++; + for(i=1;i<256;i++) buckets[i]+=buckets[i-1]; + for(i=255;i>0;i--) buckets[i]=buckets[i-1]; + buckets[0]=0; + + for(i=0;i<oldsize;i++) I[++buckets[old[i]]]=i; + I[0]=oldsize; + for(i=0;i<oldsize;i++) V[i]=buckets[old[i]]; + V[oldsize]=0; + for(i=1;i<256;i++) if(buckets[i]==buckets[i-1]+1) I[buckets[i]]=-1; + I[0]=-1; + + for(h=1;I[0]!=-(oldsize+1);h+=h) { + len=0; + for(i=0;i<oldsize+1;) { + if(I[i]<0) { + len-=I[i]; + i-=I[i]; + } else { + if(len) I[i-len]=-len; + len=V[I[i]]+1-i; + split(I,V,i,len,h); + i+=len; + len=0; + }; + }; + if(len) I[i-len]=-len; + }; + + for(i=0;i<oldsize+1;i++) I[V[i]]=i; } -static off_t -matchlen(u_char *oldp, off_t oldsize, u_char *newp, off_t newsize) +static int64_t matchlen(const uint8_t *old,int64_t oldsize,const uint8_t *new,int64_t newsize) { - off_t i; + int64_t i; - for (i = 0; (i < oldsize) && (i < newsize); i++) - if (oldp[i] != newp[i]) - break; + for(i=0;(i<oldsize)&&(i<newsize);i++) + if(old[i]!=new[i]) break; - return i; + return i; } -static off_t -search(off_t *I, u_char *oldp, off_t oldsize, - u_char *newp, off_t newsize, off_t st, off_t en, off_t *pos) +static int64_t search(const int64_t *I,const uint8_t *old,int64_t oldsize, + const uint8_t *new,int64_t newsize,int64_t st,int64_t en,int64_t *pos) { - off_t x, y; - - if (en - st < 2) - { - x = matchlen(oldp + I[st], oldsize - I[st], newp, newsize); - y = matchlen(oldp + I[en], oldsize - I[en], newp, newsize); - - if (x > y) - { - *pos = I[st]; - return x; - } - else - { - *pos = I[en]; - return y; - } - }; - - x = st + (en - st) / 2; - if (memcmp(oldp + I[x], newp, MIN(oldsize - I[x], newsize)) < 0) - { - return search(I, oldp, oldsize, newp, newsize, x, en, pos); - } - else - { - return search(I, oldp, oldsize, newp, newsize, st, x, pos); - }; + int64_t x,y; + + if(en-st<2) { + x=matchlen(old+I[st],oldsize-I[st],new,newsize); + y=matchlen(old+I[en],oldsize-I[en],new,newsize); + + if(x>y) { + *pos=I[st]; + return x; + } else { + *pos=I[en]; + return y; + } + }; + + x=st+(en-st)/2; + if(memcmp(old+I[x],new,MIN(oldsize-I[x],newsize))<0) { + return search(I,old,oldsize,new,newsize,x,en,pos); + } else { + return search(I,old,oldsize,new,newsize,st,x,pos); + }; } -static void -offtout(off_t x, u_char *buf) +static void offtout(int64_t x,uint8_t *buf) { - off_t y; - - if (x < 0) - y = -x; - else - y = x; - - buf[0] = y % 256; - y -= buf[0]; - y = y / 256; - buf[1] = y % 256; - y -= buf[1]; - y = y / 256; - buf[2] = y % 256; - y -= buf[2]; - y = y / 256; - buf[3] = y % 256; - y -= buf[3]; - y = y / 256; - buf[4] = y % 256; - y -= buf[4]; - y = y / 256; - buf[5] = y % 256; - y -= buf[5]; - y = y / 256; - buf[6] = y % 256; - y -= buf[6]; - y = y / 256; - buf[7] = y % 256; - - if (x < 0) - buf[7] |= 0x80; + int64_t y; + + if(x<0) y=-x; else y=x; + + buf[0]=y%256;y-=buf[0]; + y=y/256;buf[1]=y%256;y-=buf[1]; + y=y/256;buf[2]=y%256;y-=buf[2]; + y=y/256;buf[3]=y%256;y-=buf[3]; + y=y/256;buf[4]=y%256;y-=buf[4]; + y=y/256;buf[5]=y%256;y-=buf[5]; + y=y/256;buf[6]=y%256;y-=buf[6]; + y=y/256;buf[7]=y%256; + + if(x<0) buf[7]|=0x80; } -off_t bsdiff_patchsize_max(off_t newsize, off_t oldsize) +static int64_t writedata(struct bsdiff_stream* stream, const void* buffer, int64_t length) { - return newsize + oldsize + BSDIFF_PATCH_SLOP_SIZE; + int64_t result = 0; + + while (length > 0) + { + const int smallsize = (int)MIN(length, INT_MAX); + const int writeresult = stream->write(stream, buffer, smallsize); + if (writeresult == -1) + { + return -1; + } + + result += writeresult; + length -= smallsize; + buffer = (uint8_t*)buffer + smallsize; + } + + return result; } -int bsdiff(u_char *oldp, off_t oldsize, - u_char *newp, off_t newsize, - u_char *patch, off_t patchsz) +struct bsdiff_request { - off_t *I, *V; - off_t scan, pos, len; - off_t lastscan, lastpos, lastoffset; - off_t oldscore, scsc; - off_t s, Sf, lenf, Sb, lenb; - off_t overlap, Ss, lens; - off_t i; - off_t dblen, eblen; - u_char *db, *eb; - u_char buf[8]; - u_char header[32]; - u_char *fileblock; - - off_t ctrllen; - - /* Sanity checks */ - if (oldp == NULL || newp == NULL || patch == NULL) - return -1; - if (oldsize < 0 || newsize < 0 || patchsz < 0) - return -1; - if (bsdiff_patchsize_max(oldsize, newsize) > patchsz) - return -1; - - /* Allocate oldsize+1 bytes instead of oldsize bytes to ensure - that we never try to malloc(0) and get a NULL pointer */ - if (((I = (off_t *)malloc((oldsize + 1) * sizeof(off_t))) == NULL) || - ((V = (off_t *)malloc((oldsize + 1) * sizeof(off_t))) == NULL)) - { - if (I) - free(I); - return -1; - } - - qsufsort(I, V, oldp, oldsize); - - free(V); - - /* Allocate newsize+1 bytes instead of newsize bytes to ensure - that we never try to malloc(0) and get a NULL pointer */ - if (((db = (u_char *)malloc(newsize + 1)) == NULL) || - ((eb = (u_char *)malloc(newsize + 1)) == NULL)) - { - if (db) - free(db); - free(I); - return -1; - } - dblen = 0; - eblen = 0; - - /* Write initial header */ - memcpy(header, BSDIFF_CONFIG_MAGIC, 8); - offtout(0, header + 8); - offtout(0, header + 16); - offtout(newsize, header + 24); - memcpy(patch, header, 32); - - /* Set up initial pointers */ - fileblock = patch + 32; - ctrllen = 0; - - /* Compute the differences, writing ctrl as we go */ - scan = 0; - len = 0; - pos = 0; - lastscan = 0; - lastpos = 0; - lastoffset = 0; - while (scan < newsize) - { - oldscore = 0; - - for (scsc = scan += len; scan < newsize; scan++) - { - len = search(I, oldp, oldsize, newp + scan, newsize - scan, - 0, oldsize, &pos); - - for (; scsc < scan + len; scsc++) - if ((scsc + lastoffset < oldsize) && - (oldp[scsc + lastoffset] == newp[scsc])) - oldscore++; - - if (((len == oldscore) && (len != 0)) || - (len > oldscore + 8)) - break; - - if ((scan + lastoffset < oldsize) && - (oldp[scan + lastoffset] == newp[scan])) - oldscore--; - }; - - if ((len != oldscore) || (scan == newsize)) - { - s = 0; - Sf = 0; - lenf = 0; - for (i = 0; (lastscan + i < scan) && (lastpos + i < oldsize);) - { - if (oldp[lastpos + i] == newp[lastscan + i]) - s++; - i++; - if (s * 2 - i > Sf * 2 - lenf) - { - Sf = s; - lenf = i; - }; - }; - - lenb = 0; - if (scan < newsize) - { - s = 0; - Sb = 0; - for (i = 1; (scan >= lastscan + i) && (pos >= i); i++) - { - if (oldp[pos - i] == newp[scan - i]) - s++; - if (s * 2 - i > Sb * 2 - lenb) - { - Sb = s; - lenb = i; - }; - }; - }; - - if (lastscan + lenf > scan - lenb) - { - overlap = (lastscan + lenf) - (scan - lenb); - s = 0; - Ss = 0; - lens = 0; - for (i = 0; i < overlap; i++) - { - if (newp[lastscan + lenf - overlap + i] == - oldp[lastpos + lenf - overlap + i]) - s++; - if (newp[scan - lenb + i] == - oldp[pos - lenb + i]) - s--; - if (s > Ss) - { - Ss = s; - lens = i + 1; - }; - }; - - lenf += lens - overlap; - lenb -= lens; - }; - - for (i = 0; i < lenf; i++) - db[dblen + i] = newp[lastscan + i] - oldp[lastpos + i]; - for (i = 0; i < (scan - lenb) - (lastscan + lenf); i++) - eb[eblen + i] = newp[lastscan + lenf + i]; - - dblen += lenf; - eblen += (scan - lenb) - (lastscan + lenf); - - offtout(lenf, buf); - memcpy(fileblock, buf, 8); - fileblock += 8; - ctrllen += 8; - - offtout((scan - lenb) - (lastscan + lenf), buf); - memcpy(fileblock, buf, 8); - fileblock += 8; - ctrllen += 8; - - offtout((pos - lenb) - (lastpos + lenf), buf); - memcpy(fileblock, buf, 8); - fileblock += 8; - ctrllen += 8; - - lastscan = scan - lenb; - lastpos = pos - lenb; - lastoffset = pos - scan; - }; - }; - - /* Write size of ctrl data */ - offtout(ctrllen, header + 8); - - /* Write diff data */ - memcpy(fileblock, db, dblen); - fileblock += dblen; - /* Write size of diff data */ - offtout(dblen, header + 16); - - /* Write extra data */ - memcpy(fileblock, eb, eblen); - - /* Write the final header */ - memcpy(patch, header, 32); - - /* Free the memory we used */ - free(db); - free(eb); - free(I); - - return (32 + ctrllen + dblen + eblen); + const uint8_t* old; + int64_t oldsize; + const uint8_t* new; + int64_t newsize; + struct bsdiff_stream* stream; + int64_t *I; + uint8_t *buffer; +}; + +static int bsdiff_internal(const struct bsdiff_request req) +{ + int64_t *I,*V; + int64_t scan,pos,len; + int64_t lastscan,lastpos,lastoffset; + int64_t oldscore,scsc; + int64_t s,Sf,lenf,Sb,lenb; + int64_t overlap,Ss,lens; + int64_t i; + uint8_t *buffer; + uint8_t buf[8 * 3]; + + if((V=req.stream->malloc((req.oldsize+1)*sizeof(int64_t)))==NULL) return -1; + I = req.I; + + qsufsort(I,V,req.old,req.oldsize); + req.stream->free(V); + + buffer = req.buffer; + + /* Compute the differences, writing ctrl as we go */ + scan=0;len=0;pos=0; + lastscan=0;lastpos=0;lastoffset=0; + while(scan<req.newsize) { + oldscore=0; + + for(scsc=scan+=len;scan<req.newsize;scan++) { + len=search(I,req.old,req.oldsize,req.new+scan,req.newsize-scan, + 0,req.oldsize,&pos); + + for(;scsc<scan+len;scsc++) + if((scsc+lastoffset<req.oldsize) && + (req.old[scsc+lastoffset] == req.new[scsc])) + oldscore++; + + if(((len==oldscore) && (len!=0)) || + (len>oldscore+8)) break; + + if((scan+lastoffset<req.oldsize) && + (req.old[scan+lastoffset] == req.new[scan])) + oldscore--; + }; + + if((len!=oldscore) || (scan==req.newsize)) { + s=0;Sf=0;lenf=0; + for(i=0;(lastscan+i<scan)&&(lastpos+i<req.oldsize);) { + if(req.old[lastpos+i]==req.new[lastscan+i]) s++; + i++; + if(s*2-i>Sf*2-lenf) { Sf=s; lenf=i; }; + }; + + lenb=0; + if(scan<req.newsize) { + s=0;Sb=0; + for(i=1;(scan>=lastscan+i)&&(pos>=i);i++) { + if(req.old[pos-i]==req.new[scan-i]) s++; + if(s*2-i>Sb*2-lenb) { Sb=s; lenb=i; }; + }; + }; + + if(lastscan+lenf>scan-lenb) { + overlap=(lastscan+lenf)-(scan-lenb); + s=0;Ss=0;lens=0; + for(i=0;i<overlap;i++) { + if(req.new[lastscan+lenf-overlap+i]== + req.old[lastpos+lenf-overlap+i]) s++; + if(req.new[scan-lenb+i]== + req.old[pos-lenb+i]) s--; + if(s>Ss) { Ss=s; lens=i+1; }; + }; + + lenf+=lens-overlap; + lenb-=lens; + }; + + offtout(lenf,buf); + offtout((scan-lenb)-(lastscan+lenf),buf+8); + offtout((pos-lenb)-(lastpos+lenf),buf+16); + + /* Write control data */ + if (writedata(req.stream, buf, sizeof(buf))) + return -1; + + /* Write diff data */ + for(i=0;i<lenf;i++) + buffer[i]=req.new[lastscan+i]-req.old[lastpos+i]; + if (writedata(req.stream, buffer, lenf)) + return -1; + + /* Write extra data */ + for(i=0;i<(scan-lenb)-(lastscan+lenf);i++) + buffer[i]=req.new[lastscan+lenf+i]; + if (writedata(req.stream, buffer, (scan-lenb)-(lastscan+lenf))) + return -1; + + lastscan=scan-lenb; + lastpos=pos-lenb; + lastoffset=pos-scan; + }; + }; + + return 0; } + +int bsdiff(const uint8_t* old, int64_t oldsize, const uint8_t* new, int64_t newsize, struct bsdiff_stream* stream) +{ + int result; + struct bsdiff_request req; + + if((req.I=stream->malloc((oldsize+1)*sizeof(int64_t)))==NULL) + return -1; + + if((req.buffer=stream->malloc(newsize+1))==NULL) + { + stream->free(req.I); + return -1; + } + + req.old = old; + req.oldsize = oldsize; + req.new = new; + req.newsize = newsize; + req.stream = stream; + + result = bsdiff_internal(req); + + stream->free(req.buffer); + stream->free(req.I); + + return result; +} + +#if defined(BSDIFF_EXECUTABLE) + +#include <sys/types.h> + +#include <bzlib.h> +#include <err.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +static int bz2_write(struct bsdiff_stream* stream, const void* buffer, int size) +{ + int bz2err; + BZFILE* bz2; + + bz2 = (BZFILE*)stream->opaque; + BZ2_bzWrite(&bz2err, bz2, (void*)buffer, size); + if (bz2err != BZ_STREAM_END && bz2err != BZ_OK) + return -1; + + return 0; +} + +int main(int argc,char *argv[]) +{ + int fd; + int bz2err; + uint8_t *old,*new; + off_t oldsize,newsize; + uint8_t buf[8]; + FILE * pf; + struct bsdiff_stream stream; + BZFILE* bz2; + + memset(&bz2, 0, sizeof(bz2)); + stream.malloc = malloc; + stream.free = free; + stream.write = bz2_write; + + if(argc!=4) errx(1,"usage: %s oldfile newfile patchfile\n",argv[0]); + + /* Allocate oldsize+1 bytes instead of oldsize bytes to ensure + that we never try to malloc(0) and get a NULL pointer */ + if(((fd=open(argv[1],O_RDONLY,0))<0) || + ((oldsize=lseek(fd,0,SEEK_END))==-1) || + ((old=malloc(oldsize+1))==NULL) || + (lseek(fd,0,SEEK_SET)!=0) || + (read(fd,old,oldsize)!=oldsize) || + (close(fd)==-1)) err(1,"%s",argv[1]); + + + /* Allocate newsize+1 bytes instead of newsize bytes to ensure + that we never try to malloc(0) and get a NULL pointer */ + if(((fd=open(argv[2],O_RDONLY,0))<0) || + ((newsize=lseek(fd,0,SEEK_END))==-1) || + ((new=malloc(newsize+1))==NULL) || + (lseek(fd,0,SEEK_SET)!=0) || + (read(fd,new,newsize)!=newsize) || + (close(fd)==-1)) err(1,"%s",argv[2]); + + /* Create the patch file */ + if ((pf = fopen(argv[3], "w")) == NULL) + err(1, "%s", argv[3]); + + /* Write header (signature+newsize)*/ + offtout(newsize, buf); + if (fwrite("ENDSLEY/BSDIFF43", 16, 1, pf) != 1 || + fwrite(buf, sizeof(buf), 1, pf) != 1) + err(1, "Failed to write header"); + + + if (NULL == (bz2 = BZ2_bzWriteOpen(&bz2err, pf, 9, 0, 0))) + errx(1, "BZ2_bzWriteOpen, bz2err=%d", bz2err); + + stream.opaque = bz2; + if (bsdiff(old, oldsize, new, newsize, &stream)) + err(1, "bsdiff"); + + BZ2_bzWriteClose(&bz2err, bz2, 0, NULL, NULL); + if (bz2err != BZ_OK) + err(1, "BZ2_bzWriteClose, bz2err=%d", bz2err); + + if (fclose(pf)) + err(1, "fclose"); + + /* Free the memory we used */ + free(old); + free(new); + + return 0; +} + +#endif diff --git a/czi-format/czi-parser/utilities/bsdiff/bsdiff.h b/czi-format/czi-parser/utilities/bsdiff/bsdiff.h index 84ccbc00bfbbeea032be6e074824d1b9da30faa5..ab6e880c981cb63f131c218fd3bd90bc09a2240a 100644 --- a/czi-format/czi-parser/utilities/bsdiff/bsdiff.h +++ b/czi-format/czi-parser/utilities/bsdiff/bsdiff.h @@ -1,10 +1,10 @@ /*- - * Copyright 2012-2013 Austin Seipp * Copyright 2003-2005 Colin Percival + * Copyright 2012 Matthew Endsley * All rights reserved * * Redistribution and use in source and binary forms, with or without - * modification, are permitted providing that the following conditions + * modification, are permitted providing that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. @@ -24,48 +24,28 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ -#ifndef _MINIBSDIFF_H_ -#define _MINIBSDIFF_H_ -#include "minibsdiff-config.h" +#ifndef BSDIFF_H +#define BSDIFF_H -#ifdef __cplusplus -extern "C" +#include <stddef.h> +#include <stdint.h> + +#define new _new + +struct bsdiff_stream { -#endif + void *opaque; - /* ------------------------------------------------------------------------- */ - /* -- Public API ----------------------------------------------------------- */ + void *(*malloc)(size_t size); + void (*free)(void *ptr); + int (*write)(struct bsdiff_stream *stream, const void *buffer, int size); +}; - /*- - * Determine the maximum size of a patch between two files. This function - * should be used to allocate a buffer big enough for `bsdiff` to store - * its output in. - */ - off_t bsdiff_patchsize_max(off_t oldsize, off_t newsize); +int bsdiff(const uint8_t *old, int64_t oldsize, const uint8_t *new, int64_t newsize, struct bsdiff_stream *stream); - /*- - * Create a binary patch from the buffers pointed to by oldp and newp (with - * respective sizes,) and store the result in the buffer pointed to by 'patch'. - * - * The input pointer 'patch' must not be NULL, and the size of the buffer must - * be at least 'bsdiff_patchsize_max(new,old)' in length. - * - * Returns -1 if `patch` is NULL, the 'patch' buffer is not large enough, or if - * memory cannot be allocated. - * Otherwise, the return value is the size of the patch that was put in the - * 'patch' buffer. - * - * This function is memory-intensive, and requires max(17*n,9*n+m)+O(1) bytes - * of memory, where n is the size of the new file and m is the size of the old - * file. It runs in O((n+m) log n) time. - */ - int bsdiff(u_char *oldp, off_t oldsize, - u_char *newp, off_t newsize, - u_char *patch, off_t patchsize); +//#include "bsdiff.c" -#ifdef __cplusplus -} /* extern "C" */ -#endif +#undef new -#endif /* _MINIBSDIFF_H_ */ +#endif diff --git a/czi-format/czi-parser/utilities/bsdiff/bspatch.c b/czi-format/czi-parser/utilities/bsdiff/bspatch.c index e51d85a7c48055561fd535c38ebf3045d800e6f0..b5449147f624b2fa8c53191024167a270c0822d3 100644 --- a/czi-format/czi-parser/utilities/bsdiff/bspatch.c +++ b/czi-format/czi-parser/utilities/bsdiff/bspatch.c @@ -1,10 +1,10 @@ /*- - * Copyright 2012-2013 Austin Seipp * Copyright 2003-2005 Colin Percival + * Copyright 2012 Matthew Endsley * All rights reserved * * Redistribution and use in source and binary forms, with or without - * modification, are permitted providing that the following conditions + * modification, are permitted providing that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. @@ -25,141 +25,167 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#if 0 -__FBSDID("$FreeBSD: src/usr.bin/bsdiff/bspatch/bspatch.c,v 1.1 2005/08/06 01:59:06 cperciva Exp $"); -#endif - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <sys/types.h> - #include "bspatch.h" -/* - Patch file format: - 0 8 BSDIFF_CONFIG_MAGIC (see minibsdiff-config.h) - 8 8 X - 16 8 Y - 24 8 sizeof(newfile) - 32 X control block - 32+X Y diff block - 32+X+Y ??? extra block - with control block a set of triples (x,y,z) meaning "add x bytes - from oldfile to x bytes from the diff block; copy y bytes from the - extra block; seek forwards in oldfile by z bytes". -*/ - -static off_t -offtin(u_char *buf) +static int64_t offtin(uint8_t *buf) { - off_t y; + int64_t y; - y=buf[7]&0x7F; - y=y*256;y+=buf[6]; - y=y*256;y+=buf[5]; - y=y*256;y+=buf[4]; - y=y*256;y+=buf[3]; - y=y*256;y+=buf[2]; - y=y*256;y+=buf[1]; - y=y*256;y+=buf[0]; + y=buf[7]&0x7F; + y=y*256;y+=buf[6]; + y=y*256;y+=buf[5]; + y=y*256;y+=buf[4]; + y=y*256;y+=buf[3]; + y=y*256;y+=buf[2]; + y=y*256;y+=buf[1]; + y=y*256;y+=buf[0]; - if(buf[7]&0x80) y=-y; + if(buf[7]&0x80) y=-y; - return y; + return y; } -bool -bspatch_valid_header(u_char* patch, ssize_t patchsz) +int bspatch(const uint8_t* old, int64_t oldsize, uint8_t* new, int64_t newsize, struct bspatch_stream* stream) { - ssize_t newsize, ctrllen, datalen; + uint8_t buf[8]; + int64_t oldpos,newpos; + int64_t ctrl[3]; + int64_t i; + + oldpos=0;newpos=0; + while(newpos<newsize) { + /* Read control data */ + for(i=0;i<=2;i++) { + if (stream->read(stream, buf, 8)) + return -1; + ctrl[i]=offtin(buf); + }; + + /* Sanity-check */ + if(newpos+ctrl[0]>newsize) + return -1; + + /* Read diff string */ + if (stream->read(stream, new + newpos, ctrl[0])) + return -1; + + /* Add old data to diff string */ + for(i=0;i<ctrl[0];i++) + if((oldpos+i>=0) && (oldpos+i<oldsize)) + new[newpos+i]+=old[oldpos+i]; + + /* Adjust pointers */ + newpos+=ctrl[0]; + oldpos+=ctrl[0]; + + /* Sanity-check */ + if(newpos+ctrl[1]>newsize) + return -1; + + /* Read extra string */ + if (stream->read(stream, new + newpos, ctrl[1])) + return -1; + + /* Adjust pointers */ + newpos+=ctrl[1]; + oldpos+=ctrl[2]; + }; + + return 0; +} - if (patchsz < 32) return false; +#if defined(BSPATCH_EXECUTABLE) - /* Make sure magic and header fields are valid */ - if(memcmp(patch, BSDIFF_CONFIG_MAGIC, 8) != 0) return false; +#include <bzlib.h> +#include <stdlib.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <err.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> + +static int bz2_read(const struct bspatch_stream* stream, void* buffer, int length) +{ + int n; + int bz2err; + BZFILE* bz2; - ctrllen=offtin(patch+8); - datalen=offtin(patch+16); - newsize=offtin(patch+24); - if((ctrllen<0) || (datalen<0) || (newsize<0)) - return false; + bz2 = (BZFILE*)stream->opaque; + n = BZ2_bzRead(&bz2err, bz2, buffer, length); + if (n != length) + return -1; - return true; + return 0; } -ssize_t -bspatch_newsize(u_char* patch, ssize_t patchsz) +int main(int argc,char * argv[]) { - if (!bspatch_valid_header(patch, patchsz)) return -1; - return offtin(patch+24); + FILE * f; + int fd; + int bz2err; + uint8_t header[24]; + uint8_t *old, *new; + int64_t oldsize, newsize; + BZFILE* bz2; + struct bspatch_stream stream; + struct stat sb; + + if(argc!=4) errx(1,"usage: %s oldfile newfile patchfile\n",argv[0]); + + /* Open patch file */ + if ((f = fopen(argv[3], "r")) == NULL) + err(1, "fopen(%s)", argv[3]); + + /* Read header */ + if (fread(header, 1, 24, f) != 24) { + if (feof(f)) + errx(1, "Corrupt patch\n"); + err(1, "fread(%s)", argv[3]); + } + + /* Check for appropriate magic */ + if (memcmp(header, "ENDSLEY/BSDIFF43", 16) != 0) + errx(1, "Corrupt patch\n"); + + /* Read lengths from header */ + newsize=offtin(header+16); + if(newsize<0) + errx(1,"Corrupt patch\n"); + + /* Close patch file and re-open it via libbzip2 at the right places */ + if(((fd=open(argv[1],O_RDONLY,0))<0) || + ((oldsize=lseek(fd,0,SEEK_END))==-1) || + ((old=malloc(oldsize+1))==NULL) || + (lseek(fd,0,SEEK_SET)!=0) || + (read(fd,old,oldsize)!=oldsize) || + (fstat(fd, &sb)) || + (close(fd)==-1)) err(1,"%s",argv[1]); + if((new=malloc(newsize+1))==NULL) err(1,NULL); + + if (NULL == (bz2 = BZ2_bzReadOpen(&bz2err, f, 0, 0, NULL, 0))) + errx(1, "BZ2_bzReadOpen, bz2err=%d", bz2err); + + stream.read = bz2_read; + stream.opaque = bz2; + if (bspatch(old, oldsize, new, newsize, &stream)) + errx(1, "bspatch"); + + /* Clean up the bzip2 reads */ + BZ2_bzReadClose(&bz2err, bz2); + fclose(f); + + /* Write the new file */ + if(((fd=open(argv[2],O_CREAT|O_TRUNC|O_WRONLY,sb.st_mode))<0) || + (write(fd,new,newsize)!=newsize) || (close(fd)==-1)) + err(1,"%s",argv[2]); + + free(new); + free(old); + + return 0; } -int -bspatch(u_char* oldp, ssize_t oldsz, - u_char* patch, ssize_t patchsz, - u_char* newp, ssize_t newsz) -{ - ssize_t newsize,ctrllen,datalen; - u_char *ctrlblock, *diffblock, *extrablock; - off_t oldpos,newpos; - off_t ctrl[3]; - off_t i; - - /* Sanity checks */ - if (oldp == NULL || patch == NULL || newp == NULL) return -1; - if (oldsz < 0 || patchsz < 0 || newsz < 0) return -1; - if (!bspatch_valid_header(patch, patchsz)) return -2; - - /* Read lengths from patch header */ - ctrllen=offtin(patch+8); - datalen=offtin(patch+16); - newsize=offtin(patch+24); - if (newsize > newsz) return -1; - - /* Get pointers into the header metadata */ - ctrlblock = patch+32; - diffblock = patch+32+ctrllen; - extrablock = patch+32+ctrllen+datalen; - - /* Apply patch */ - oldpos=0;newpos=0; - while(newpos<newsize) { - /* Read control block */ - ctrl[0] = offtin(ctrlblock); - ctrl[1] = offtin(ctrlblock+8); - ctrl[2] = offtin(ctrlblock+16); - ctrlblock += 24; - - /* Sanity check */ - if(newpos+ctrl[0]>newsize) - return -3; /* Corrupt patch */ - - /* Read diff string */ - memcpy(newp + newpos, diffblock, ctrl[0]); - diffblock += ctrl[0]; - - /* Add old data to diff string */ - for(i=0;i<ctrl[0];i++) - if((oldpos+i>=0) && (oldpos+i<oldsz)) - newp[newpos+i]+=oldp[oldpos+i]; - - /* Adjust pointers */ - newpos+=ctrl[0]; - oldpos+=ctrl[0]; - - /* Sanity check */ - if(newpos+ctrl[1]>newsize) - return -3; /* Corrupt patch */ - - /* Read extra string */ - memcpy(newp + newpos, extrablock, ctrl[1]); - extrablock += ctrl[1]; - - /* Adjust pointers */ - newpos+=ctrl[1]; - oldpos+=ctrl[2]; - }; - - return 0; -} +#endif diff --git a/czi-format/czi-parser/utilities/bsdiff/bspatch.h b/czi-format/czi-parser/utilities/bsdiff/bspatch.h index d55919e83a8ccfe99bccd8c9e66b4228bf0cd44c..099c36e48e118df19261d2862f56264df7f7b4a6 100644 --- a/czi-format/czi-parser/utilities/bsdiff/bspatch.h +++ b/czi-format/czi-parser/utilities/bsdiff/bspatch.h @@ -1,10 +1,10 @@ /*- - * Copyright 2012-2013 Austin Seipp * Copyright 2003-2005 Colin Percival + * Copyright 2012 Matthew Endsley * All rights reserved * * Redistribution and use in source and binary forms, with or without - * modification, are permitted providing that the following conditions + * modification, are permitted providing that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. @@ -24,55 +24,19 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ -#ifndef _MINIBSPATCH_H_ -#define _MINIBSPATCH_H_ -#include "minibsdiff-config.h" +#ifndef BSPATCH_H +# define BSPATCH_H -#ifdef __cplusplus -extern "C" { -#endif - -/* ------------------------------------------------------------------------- */ -/* -- Public API ----------------------------------------------------------- */ +# include <stdint.h> -/*- - * Determine if the buffer pointed to by `patch` of a given `size` is - * a valid patch. - */ -bool bspatch_valid_header(u_char* patch, ssize_t patchsz); - -/*- - * Determine the size of the new file that will result from applying - * a patch. Returns -1 if the patch header is invalid, otherwise returns - * the size of the new file. - */ -ssize_t bspatch_newsize(u_char* patch, ssize_t patchsize); +struct bspatch_stream +{ + void* opaque; + int (*read)(const struct bspatch_stream* stream, void* buffer, int length); +}; -/*- - * Apply a patch stored in 'patch' to 'oldp', result in 'newp', and store the - * result in 'newp'. - * - * The input pointers must not be NULL. - * - * The size of 'newp', represented by 'newsz', must be at least - * 'bspatch_newsize(oldsz,patchsz)' bytes in length. - * - * Returns -1 if memory can't be allocated, or the input pointers are NULL. - * Returns -2 if the patch header is invalid. Returns -3 if the patch itself is - * corrupt. - * Otherwise, returns 0. - * - * This function requires n+m+O(1) bytes of memory, where n is the size of the - * old file and m is the size of the new file. It does no allocations. - * It runs in O(n+m) time. - */ -int bspatch(u_char* oldp, ssize_t oldsz, - u_char* patch, ssize_t patchsz, - u_char* newp, ssize_t newsz); +int bspatch(const uint8_t* old, int64_t oldsize, uint8_t* new, int64_t newsize, struct bspatch_stream* stream); -#ifdef __cplusplus -} /* extern "C" */ #endif -#endif /* _MINIBSPATCH_H_ */ diff --git a/czi-format/czi-parser/utilities/bsdiff/minibsdiff-config.h b/czi-format/czi-parser/utilities/bsdiff/minibsdiff-config.h deleted file mode 100644 index 3bf5607a4621b53ed5a50b19e2eb24ba689b72e9..0000000000000000000000000000000000000000 --- a/czi-format/czi-parser/utilities/bsdiff/minibsdiff-config.h +++ /dev/null @@ -1,64 +0,0 @@ -/*- - * Copyright 2012-2013 Austin Seipp - * Copyright 2003-2005 Colin Percival - * All rights reserved - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted providing that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -#ifndef _MINIBSDIFF_CONFIG_H_ -#define _MINIBSDIFF_CONFIG_H_ - -#ifdef _MSC_VER -#include <Windows.h> -#include "stdint-msvc.h" -#include "stdbool-msvc.h" -#else -#include <stdint.h> -#include <stdbool.h> -#endif /* _MSC_VER */ - -/* ------------------------------------------------------------------------- */ -/* -- Patch file magic number ---------------------------------------------- */ - -/** MUST be 8 bytes long! */ -/** TODO FIXME: we should static_assert this */ -#define BSDIFF_CONFIG_MAGIC "MBSDIF43" - -/* ------------------------------------------------------------------------- */ -/* -- Slop size for temporary patch buffer --------------------------------- */ - -#define BSDIFF_PATCH_SLOP_SIZE 102400 - -/* ------------------------------------------------------------------------- */ -/* -- Type definitions ----------------------------------------------------- */ - -/* Duplicated to keep code small. Keep in sync with bspatch.h! */ -#ifndef _MINIBSDIFF_U_CHAR_T_ -#define _MINIBSDIFF_U_CHAR_T_ -typedef uint8_t u_char; -#endif /* _MINIBSDIFF_U_CHAR_T_ */ - -#ifdef _MSC_VER -typedef SSIZE_T ssize_t; -#endif /* _MSC_VER */ - -#endif /* _MINIBSDIFF_CONFIG_H_ */ diff --git a/czi-format/czi-parser/utilities/type_mapper.h b/czi-format/czi-parser/utilities/type_mapper.h index a7f40875bd0153e95b6a6fb85cd77a3fd041eb4b..4784f77f99ef8ddb9a360869ff9ad7ec594b39f7 100644 --- a/czi-format/czi-parser/utilities/type_mapper.h +++ b/czi-format/czi-parser/utilities/type_mapper.h @@ -12,8 +12,8 @@ class TypeMapper std::vector<TargetType> map(std::vector<SourceType> &data) { auto limits = vecUtil::find_min_max(data); - SourceType min = limits.first; - SourceType max = limits.second; + SourceType min = limits.min; + SourceType max = limits.max; TargetType targetMaxValue = std::numeric_limits<TargetType>::max(); always_assert(max < targetMaxValue); diff --git a/czi-format/czi-parser/utilities/vector_utilities.h b/czi-format/czi-parser/utilities/vector_utilities.h index bbc1ecd479d78a94a73bce2433a332a89f4a65c5..81edd9ef24a50819010c7ec29a8bf9d522fb1528 100644 --- a/czi-format/czi-parser/utilities/vector_utilities.h +++ b/czi-format/czi-parser/utilities/vector_utilities.h @@ -3,6 +3,14 @@ #include <algorithm> #include <limits> +template <typename T> +struct MinMax +{ // Minimum value. + T min; + // Maximum value. + T max; +}; + namespace vecUtil { @@ -89,24 +97,24 @@ T find_min(const std::vector<T> &data) } template <typename T> -std::pair<T, T> find_min_max(const std::vector<T> &data) +MinMax<T> find_min_max(const std::vector<T> &data) { - T min = std::numeric_limits<T>::max(); - T max = std::numeric_limits<T>::min(); + MinMax<T> result; + result.min = std::numeric_limits<T>::max(); + result.max = std::numeric_limits<T>::min(); for (size_t i = 0; i < data.size(); i++) { - if (data[i] < min) + if (data[i] < result.min) { - min = data[i]; + result.min = data[i]; } - if (data[i] > max) + if (data[i] > result.max) { - max = data[i]; + result.max = data[i]; } } - return std::make_pair(min, max); + return result; } - }; // namespace vecUtil