// distribution boxbackup-0.10 (svn version: 494)
//
// Copyright (c) 2003 - 2006
// Ben Summers and contributors. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided 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.
// 3. All use of this software and associated advertising materials must
// display the following acknowledgment:
// This product includes software developed by Ben Summers.
// 4. The names of the Authors may not be used to endorse or promote
// products derived from this software without specific prior written
// permission.
//
// [Where legally impermissible the Authors do not disclaim liability for
// direct physical injury or death caused solely by defects in the software
// unless it is modified by a third party.]
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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.
//
//
//
// --------------------------------------------------------------------------
//
// File
// Name: testcompress.cpp
// Purpose: Test lib/compress
// Created: 5/12/03
//
// --------------------------------------------------------------------------
#include "Box.h"
#include <stdio.h>
#include <string.h>
#include "Test.h"
#include "Compress.h"
#include "CompressStream.h"
#include "CollectInBufferStream.h"
#include "MemLeakFindOn.h"
#define DATA_SIZE (1024*128+103)
#define CHUNK_SIZE 2561
#define DECOMP_CHUNK_SIZE 3
// Stream for testing
class CopyInToOutStream : public IOStream
{
public:
CopyInToOutStream() : currentBuffer(0) {buffers[currentBuffer].SetForReading();}
~CopyInToOutStream() {}
int Read(void *pBuffer, int NBytes, int Timeout = IOStream::TimeOutInfinite)
{
if(buffers[currentBuffer].StreamDataLeft())
{
return buffers[currentBuffer].Read(pBuffer, NBytes, Timeout);
}
// Swap buffers?
if(buffers[(currentBuffer + 1) & 1].GetSize() > 0)
{
buffers[currentBuffer].Reset();
currentBuffer = (currentBuffer + 1) & 1;
buffers[currentBuffer].SetForReading();
return buffers[currentBuffer].Read(pBuffer, NBytes, Timeout);
}
return 0;
}
void Write(const void *pBuffer, int NBytes)
{
buffers[(currentBuffer + 1) & 1].Write(pBuffer, NBytes);
}
bool StreamDataLeft()
{
return buffers[currentBuffer].StreamDataLeft() || buffers[(currentBuffer + 1) % 1].GetSize() > 0;
}
bool StreamClosed()
{
return false;
}
int currentBuffer;
CollectInBufferStream buffers[2];
};
// Test stream based interface
int test_stream()
{
// Make a load of compressible data to compress
CollectInBufferStream source;
uint16_t data[1024];
for(int x = 0; x < 1024; ++x)
{
data[x] = x;
}
for(int x = 0; x < (32*1024); ++x)
{
source.Write(data, (x % 1024) * 2);
}
source.SetForReading();
// Straight compress from one stream to another
{
CollectInBufferStream *poutput = new CollectInBufferStream;
CompressStream compress(poutput, true /* take ownership */, false /* read */, true /* write */);
source.CopyStreamTo(compress);
compress.Close();
poutput->SetForReading();
// Check sizes
TEST_THAT(poutput->GetSize() < source.GetSize());
TRACE2("compressed size = %d, source size = %d\n", poutput->GetSize(), source.GetSize());
// Decompress the data
{
CollectInBufferStream decompressed;
CompressStream decompress(poutput, false /* don't take ownership */, true /* read */, false /* write */);
decompress.CopyStreamTo(decompressed);
decompress.Close();
TEST_THAT(decompressed.GetSize() == source.GetSize());
TEST_THAT(::memcmp(decompressed.GetBuffer(), source.GetBuffer(), decompressed.GetSize()) == 0);
}
// Don't delete poutput, let mem leak testing ensure it's deleted.
}
// Set source to the beginning
source.Seek(0, IOStream::SeekType_Absolute);
// Test where the same stream compresses and decompresses, should be fun!
{
CollectInBufferStream output;
CopyInToOutStream copyer;
CompressStream compress(©er, false /* no ownership */, true, true);
bool done = false;
int count = 0;
int written = 0;
while(!done)
{
++count;
bool do_sync = (count % 256) == 0;
uint8_t buffer[4096];
int r = source.Read(buffer, sizeof(buffer), IOStream::TimeOutInfinite);
if(r == 0)
{
done = true;
compress.Close();
}
else
{
compress.Write(buffer, r);
written += r;
if(do_sync)
{
compress.WriteAllBuffered();
}
}
int r2 = 0;
do
{
r2 = compress.Read(buffer, sizeof(buffer), IOStream::TimeOutInfinite);
if(r2 > 0)
{
output.Write(buffer, r2);
}
} while(r2 > 0);
if(do_sync && r != 0)
{
// Check that everything is synced
TEST_THAT(output.GetSize() == written);
TEST_THAT(::memcmp(output.GetBuffer(), source.GetBuffer(), output.GetSize()) == 0);
}
}
output.SetForReading();
// Test that it's the same
TEST_THAT(output.GetSize() == source.GetSize());
TEST_THAT(::memcmp(output.GetBuffer(), source.GetBuffer(), output.GetSize()) == 0);
}
return 0;
}
// Test basic interface
int test(int argc, const char *argv[])
{
// Bad data to compress!
char *data = (char *)malloc(DATA_SIZE);
for(int l = 0; l < DATA_SIZE; ++l)
{
data[l] = l*23;
}
// parameters about compression
int maxOutput = Compress_MaxSizeForCompressedData(DATA_SIZE);
TEST_THAT(maxOutput >= DATA_SIZE);
char *compressed = (char *)malloc(maxOutput);
int compressedSize = 0;
// Do compression, in small chunks
{
Compress<true> compress;
int in_loc = 0;
while(!compress.OutputHasFinished())
{
int ins = DATA_SIZE - in_loc;
if(ins > CHUNK_SIZE) ins = CHUNK_SIZE;
if(ins == 0)
{
compress.FinishInput();
}
else
{
compress.Input(data + in_loc, ins);
}
in_loc += ins;
// Get output data
int s = 0;
do
{
TEST_THAT(compressedSize < maxOutput);
s = compress.Output(compressed + compressedSize, maxOutput - compressedSize);
compressedSize += s;
} while(s > 0);
}
}
// a reasonable test, especially given the compressability of the input data.
TEST_THAT(compressedSize < DATA_SIZE);
// decompression
char *decompressed = (char*)malloc(DATA_SIZE * 2);
int decomp_size = 0;
{
Compress<false> decompress;
int in_loc = 0;
while(!decompress.OutputHasFinished())
{
int ins = compressedSize - in_loc;
if(ins > DECOMP_CHUNK_SIZE) ins = DECOMP_CHUNK_SIZE;
if(ins == 0)
{
decompress.FinishInput();
}
else
{
decompress.Input(compressed + in_loc, ins);
}
in_loc += ins;
// Get output data
int s = 0;
do
{
TEST_THAT(decomp_size <= DATA_SIZE);
s = decompress.Output(decompressed + decomp_size, (DATA_SIZE*2) - decomp_size);
decomp_size += s;
} while(s > 0);
}
}
TEST_THAT(decomp_size == DATA_SIZE);
TEST_THAT(::memcmp(data, decompressed, DATA_SIZE) == 0);
::free(data);
::free(compressed);
::free(decompressed);
return test_stream();
}
syntax highlighted by Code2HTML, v. 0.9.1