/* ** DeltaRowCompression.cpp ** Copyright 2005, Michael Pfeiffer, laplace@users.sourceforge.net. ** All rights reserved. ** Distributed under the terms of the MIT License. */ #include "DeltaRowCompression.h" #include #include AbstractDeltaRowCompressor::AbstractDeltaRowCompressor(int rowSize, uchar initialSeed) : fSeedRow(new uchar[rowSize]), fSize(rowSize), fInitialSeed(initialSeed) { Reset(); } AbstractDeltaRowCompressor::~AbstractDeltaRowCompressor() { delete[] fSeedRow; fSeedRow = NULL; } status_t AbstractDeltaRowCompressor::InitCheck() { if (fSeedRow != NULL) return B_OK; else return B_NO_MEMORY; } void AbstractDeltaRowCompressor::Reset() { if (fSeedRow != NULL) memset(fSeedRow, fInitialSeed, fSize); } int AbstractDeltaRowCompressor::CompressRaw(const uchar* row, bool updateSeedRow, bool updateDeltaRow) { int index = DiffersIndex(row, 0); if (index == -1) { // no differences return 0; } fUpdateDeltaRow = updateDeltaRow; fDeltaRowIndex = 0; int seedRowIndex = 0; do { int length = DiffersLength(row, index); // delta starts at index and contains length bytes do { // control byte limits data bytes to 8 bytes int deltaBytes = length; if (length > 8) deltaBytes = 8; // calculate offset int totalOffset = index - seedRowIndex; bool needsOffsetBytes = totalOffset > 30; int offset = totalOffset; // control byte limits offset value to 31 if (needsOffsetBytes) offset = 31; // write control byte (delta bytes bits 5-7; offset bits 0-4) Put(((deltaBytes - 1) << 5) | offset); if (needsOffsetBytes) { // write additional offset bytes after control byte // the last offset byte must be less than 255 totalOffset -= offset; while (totalOffset >= 255) { Put(255); totalOffset -= 255; } Put(totalOffset); } // write data bytes for (int i = 0; i < deltaBytes; i ++) { // copy row to seed row and delta row uchar byte = row[index]; if (updateSeedRow) { ASSERT (index < fSize); fSeedRow[index] = byte; } Put(byte); index ++; } seedRowIndex = index; length -= deltaBytes; } while (length > 0); index = DiffersIndex(row, index); } while (index != -1); return fDeltaRowIndex; } int AbstractDeltaRowCompressor::CalculateSize(const uchar* row, bool updateSeedRow) { return CompressRaw(row, updateSeedRow, false); } void AbstractDeltaRowCompressor::Compress(const uchar* row) { CompressRaw(row, true, true); } #ifdef TEST_DELTA_ROW_COMPRESSION void test(AbstractDeltaRowCompressor* compressor, uchar* row) { int size = compressor->CalculateSize(row); printf("size %d\n", size); if (size > 0) { uchar* buffer = new uchar[size]; compressor->Compress(row, buffer, size); for (int i = 0; i < size; i ++) { printf("%2.2x ", (int)buffer[i]); } printf("\n"); delete buffer; } printf("\n"); } int main(int argc, char* argv[]) { int n = 5; uchar row1[] = {0, 0, 0, 0, 0}; uchar row2[] = {0, 1, 0, 0, 0}; uchar row3[] = {1, 1, 0, 2, 2}; DeltaRowCompressor compressor(n, 0); test(&compressor, row1); test(&compressor, row2); test(&compressor, row3); } #endif // TEST_DELTA_ROW_COMPRESSION