#include <stdio.h>
#include <stdlib.h>
#include "ClockServices.h"
#include "common.h"
#if LZSS
#include "lzsscompress.h"
#define InputBufferLength BUFSIZE_COMPRESSED
#define OutputBufferLength BUFSIZE_UNCOMPRESSED
#else
#include <zlib.h>
enum {
UncompressedBufferLength = 65536,
CompressedBufferLength = (UncompressedBufferLength * 1001 + 1) / 1000 + 12,
InputBufferLength = CompressedBufferLength,
OutputBufferLength = UncompressedBufferLength + 1,
};
static void *zalloc(void *opaque, unsigned int items, unsigned int size)
{ return malloc(items * (size_t) size); }
static void zfree(void *opaque, void *address)
{ free(address); }
static const char *ErrorName(int result)
{
switch (result)
{
case Z_OK: return "Z_OK";
case Z_STREAM_END: return "Z_STREAM_END";
case Z_NEED_DICT: return "Z_NEED_DICT";
case Z_ERRNO: return "Z_ERRNO";
case Z_STREAM_ERROR: return "Z_STREAM_ERROR";
case Z_DATA_ERROR: return "Z_DATA_ERROR";
case Z_MEM_ERROR: return "Z_MEM_ERROR";
case Z_BUF_ERROR: return "Z_BUF_ERROR";
case Z_VERSION_ERROR: return "Z_VERSION_ERROR";
default: return "unknown erorr";
}
}
static void TestZlibResult(int result, const char *CalledRoutine,
const char *File, const char *Function, int Line)
{
if (result == Z_OK)
return;
fprintf(stderr, "Error, %s returned %s in file %s, function %s, line %d.\n",
CalledRoutine, ErrorName(result), File, Function, Line);
exit(EXIT_FAILURE);
}
static void TestFreadResult(size_t result, size_t expected,
const char *File, const char *Function, int Line)
{
if (result == expected)
return;
fprintf(stderr,
"Error, fread returned error in file %s, function %s, line %d.\n",
File, Function, Line);
exit(EXIT_FAILURE);
}
static void TestFwriteResult(size_t result, size_t expected,
const char *File, const char *Function, int Line)
{
if (result == expected)
return;
fprintf(stderr,
"Error, fwrite returned error in file %s, function %s, line %d.\n",
File, Function, Line);
exit(EXIT_FAILURE);
}
#endif // LZSS
typedef struct
{
#if !LZSS
z_stream *stream;
#endif
unsigned char *InputBuffer;
unsigned char *OutputBuffer;
#if LZSS
u_int32_t length;
u_int32_t *outlength;
#else
size_t length;
#endif
} Parameters;
void DecompressBlock(const Parameters *parameters)
{
#if LZSS
*(parameters->outlength) = decompress_lzss(parameters->OutputBuffer, 0, parameters->InputBuffer, parameters->length);
#else // LZSS
z_stream *stream = parameters->stream;
#if defined UseReset
int zresult = inflateReset(stream);
TestZlibResult(zresult, "inflateReset", __FILE__, __func__, __LINE__);
#endif // defined UseReset
stream->next_in = parameters->InputBuffer;
stream->avail_in = parameters->length;
stream->next_out = parameters->OutputBuffer;
stream->avail_out = OutputBufferLength;
#if defined UseReset
zresult = inflate(stream, Z_FINISH);
if (zresult != Z_STREAM_END)
if (zresult == Z_OK)
{
fprintf(stderr,
"Error, unexpected Z_OK from inflate in file %s, function %s, line %d.\n",
__FILE__, __func__, __LINE__);
exit(EXIT_FAILURE);
}
else
TestZlibResult(zresult, "inflate",
__FILE__, __func__, __LINE__);
#else // defined UseReset
fprintf(stderr, "%d.\n", __LINE__);
int zresult = inflate(stream, Z_SYNC_FLUSH);
TestZlibResult(zresult, "inflate", __FILE__, __func__, __LINE__);
#endif // defined UseReset
#endif // LZSS
}
void Driver(unsigned int iterations, void *parameters)
{
Parameters *p = (Parameters *) parameters;
while (iterations--)
DecompressBlock(p);
}
int main(int argc, char *argv[])
{
#define ShowPerformance 1|(OutStream != stdout)
FILE *fi = stdin;
FILE *OutStream = stdout;
if (argc == 3) {
if (!(fi = fopen(argv[1],"rb")))
{
fprintf(stderr,
"Error, unable to read %s at file %s, function %s, line %d.\n",
argv[1], __FILE__, __func__, __LINE__);
perror("fopen");
exit(EXIT_FAILURE);
}
if (!(OutStream = fopen(argv[2], "wb")))
{
fprintf(stderr,
"Error, unable to write to %s at file %s, function %s, line %d.\n",
argv[2], __FILE__, __func__, __LINE__);
perror("fopen");
exit(EXIT_FAILURE);
}
}
else
{
fprintf(stderr, "Usage: %s input output\n", argv[0]);
exit(EXIT_FAILURE);
}
#if LZSS
unsigned char InputBuffer[InputBufferLength];
unsigned char OutputBuffer[OutputBufferLength];
#else
unsigned char *InputBuffer = malloc(InputBufferLength);
unsigned char *OutputBuffer = malloc(OutputBufferLength);
if (InputBuffer == NULL || OutputBuffer == NULL)
{
fprintf(stderr, "Error, unable to allocate memory.\n");
return EXIT_FAILURE;
}
#endif
double TotalTime = 0;
size_t TotalCompressedBytes = 0;
size_t TotalUncompressedBytes = 0;
size_t TotalNoncompressedBlocks = 0;
size_t TotalNoncompressedBytes = 0;
size_t fresult;
#if !LZSS
int zresult;
z_stream stream = { .zalloc = zalloc, .zfree = zfree, .opaque = NULL };
zresult = inflateInit(&stream);
TestZlibResult(zresult, "inflateInit", __FILE__, __func__, __LINE__);
#endif
while (1)
{
u_int32_t length, decompressed_length;
fresult = fread(&length, sizeof length, 1, fi);
if (fresult == 0)
{
if (ferror(fi))
{
fprintf(stderr,
"Error, stream error in file %s, function %s, line %d.\n",
__FILE__, __func__, __LINE__);
exit(EXIT_FAILURE);
}
break;
}
fresult = fread(InputBuffer, 1, length, fi);
#if !LZSS
TestFreadResult(fresult, length, __FILE__, __func__, __LINE__);
if (InputBuffer[0] == (unsigned char) '\xff')
{
fprintf(stderr, "%d.\n", __LINE__);
TotalCompressedBytes += length + 4;
--length;
fresult = fwrite(InputBuffer + 1, 1, length, OutStream);
TestFwriteResult(fresult, length, __FILE__, __func__, __LINE__);
++TotalNoncompressedBlocks;
TotalNoncompressedBytes += length;
TotalUncompressedBytes += length;
}
else
#endif
{
Parameters parameters =
{
#if !LZSS
.stream = &stream,
#endif
.InputBuffer = InputBuffer,
.OutputBuffer = OutputBuffer,
#if LZSS
.length = length,
.outlength = &decompressed_length,
#else
.length = length,
#endif
};
if (ShowPerformance)
{
TotalCompressedBytes += length + 4;
double t = MeasureNetTimeInCPUCycles(Driver,
10, ¶meters, 10);
TotalTime += t;
#if LZSS
TotalUncompressedBytes += decompressed_length;
#else
TotalUncompressedBytes += stream.total_out;
#endif
}
else
DecompressBlock(¶meters);
#if LZSS
fresult = fwrite(OutputBuffer, 1, decompressed_length, stdout);
#else
fresult = fwrite(OutputBuffer, 1, stream.total_out, OutStream);
TestFwriteResult(fresult, stream.total_out,
__FILE__, __func__, __LINE__);
#endif
}
}
#if !LZSS
zresult = inflateEnd(&stream);
TestZlibResult(zresult, "deflateEnd", __FILE__, __func__, __LINE__);
#endif
if (OutStream != stdout)
if (fclose(OutStream))
{
fprintf(stderr,
"Error, stream error in output file, file %s, function %s, line %d.\n",
__FILE__, __func__, __LINE__);
exit(EXIT_FAILURE);
}
#if !LZSS
free(InputBuffer);
free(OutputBuffer);
#endif
if (ShowPerformance)
{
fprintf(stderr,"Total CPU cycles = %g.\n", TotalTime);
fprintf(stderr,"Compressed size / Uncompressed size = %zd / %zd = %g.\n",
TotalCompressedBytes, TotalUncompressedBytes,
(double) TotalCompressedBytes / TotalUncompressedBytes);
fprintf(stderr,"CPU cycles per compressed byte = %g.\n",
TotalTime / TotalCompressedBytes);
fprintf(stderr,"CPU cycles per uncompressed byte = %g.\n",
TotalTime / TotalUncompressedBytes);
fprintf(stderr,"%zd blocks %s not compressed, totaling %zd bytes.\n",
TotalNoncompressedBlocks,
TotalNoncompressedBlocks == 1 ? "was" : "were",
TotalNoncompressedBytes);
}
return 0;
}