#include <cstdio>
#include <cstdlib>
#include "pcencoder.h"
#include "rcqsmodel.h"
#include "front.h"
#include "fpzip.h"
#include "codec.h"
#include "write.h"
struct FPZoutput : public FPZ {
RCencoder* re;
};
static FPZoutput*
allocate_output()
{
FPZoutput* stream = new FPZoutput;
stream->type = FPZIP_TYPE_FLOAT;
stream->prec = 0;
stream->nx = stream->ny = stream->nz = stream->nf = 1;
stream->re = 0;
return stream;
}
#if FPZIP_FP == FPZIP_FP_FAST || FPZIP_FP == FPZIP_FP_SAFE
template <typename T, uint bits>
static void
compress3d(
RCencoder* re, const T* data, uint nx, uint ny, uint nz )
{
typedef PCmap<T, bits> Map;
RCmodel* rm = new RCqsmodel(true, PCencoder<T, Map>::symbols);
PCencoder<T, Map>* fe = new PCencoder<T, Map>(re, &rm);
Front<T> f(nx, ny);
uint x, y, z;
for (z = 0, f.advance(0, 0, 1); z < nz; z++)
for (y = 0, f.advance(0, 1, 0); y < ny; y++)
for (x = 0, f.advance(1, 0, 0); x < nx; x++) {
#if FPZIP_FP == FPZIP_FP_SAFE
volatile T p = f(1, 1, 1);
p += f(1, 0, 0);
p -= f(0, 1, 1);
p += f(0, 1, 0);
p -= f(1, 0, 1);
p += f(0, 0, 1);
p -= f(1, 1, 0);
#else
T p = f(1, 0, 0) - f(0, 1, 1) +
f(0, 1, 0) - f(1, 0, 1) +
f(0, 0, 1) - f(1, 1, 0) +
f(1, 1, 1);
#endif
T a = *data++;
a = fe->encode(a, p);
f.push(a);
}
delete fe;
delete rm;
}
#elif FPZIP_FP == FPZIP_FP_EMUL
#include "fpe.h"
template <typename T, uint bits>
static void
compress3d(
RCencoder* re, const T* data, uint nx, uint ny, uint nz )
{
typedef PCmap<T, bits> Map;
typedef FPE<T> Float;
RCmodel* rm = new RCqsmodel(true, PCencoder<T, Map>::symbols);
PCencoder<T, Map>* fe = new PCencoder<T, Map>(re, &rm);
Front<Float> f(nx, ny);
uint x, y, z;
for (z = 0, f.advance(0, 0, 1); z < nz; z++)
for (y = 0, f.advance(0, 1, 0); y < ny; y++)
for (x = 0, f.advance(1, 0, 0); x < nx; x++) {
Float p = f(1, 0, 0) - f(0, 1, 1) +
f(0, 1, 0) - f(1, 0, 1) +
f(0, 0, 1) - f(1, 1, 0) +
f(1, 1, 1);
T a = *data++;
a = fe->encode(a, T(p));
f.push(a);
}
delete fe;
delete rm;
}
#else
template <typename T, uint bits>
static void
compress3d(
RCencoder* re, const T* data, uint nx, uint ny, uint nz )
{
typedef PCmap<T, bits> TMap;
typedef typename TMap::Range U;
typedef PCmap<U, bits, U> UMap;
RCmodel* rm = new RCqsmodel(true, PCencoder<U, UMap>::symbols);
PCencoder<U, UMap>* fe = new PCencoder<U, UMap>(re, &rm);
TMap map;
Front<U> f(nx, ny, map.forward(0));
uint x, y, z;
for (z = 0, f.advance(0, 0, 1); z < nz; z++)
for (y = 0, f.advance(0, 1, 0); y < ny; y++)
for (x = 0, f.advance(1, 0, 0); x < nx; x++) {
U p = f(1, 0, 0) - f(0, 1, 1) +
f(0, 1, 0) - f(1, 0, 1) +
f(0, 0, 1) - f(1, 1, 0) +
f(1, 1, 1);
U a = map.forward(*data++);
a = fe->encode(a, p);
f.push(a);
}
delete fe;
delete rm;
}
#endif
#define compress_case(p)\
case subsize(T, p):\
compress3d<T, subsize(T, p)>(stream->re, data, stream->nx, stream->ny, stream->nz);\
break
template <typename T>
static bool
compress4d(
FPZoutput* stream, const T* data )
{
for (int i = 0; i < stream->nf; i++) {
int bits = stream->prec ? stream->prec : (int)(CHAR_BIT * sizeof(T));
switch (bits) {
compress_case( 2);
compress_case( 3);
compress_case( 4);
compress_case( 5);
compress_case( 6);
compress_case( 7);
compress_case( 8);
compress_case( 9);
compress_case(10);
compress_case(11);
compress_case(12);
compress_case(13);
compress_case(14);
compress_case(15);
compress_case(16);
compress_case(17);
compress_case(18);
compress_case(19);
compress_case(20);
compress_case(21);
compress_case(22);
compress_case(23);
compress_case(24);
compress_case(25);
compress_case(26);
compress_case(27);
compress_case(28);
compress_case(29);
compress_case(30);
compress_case(31);
compress_case(32);
default:
fpzip_errno = fpzipErrorBadPrecision;
return false;
}
data += stream->nx * stream->ny * stream->nz;
}
return true;
}
FPZ*
fpzip_write_to_file(
FILE* file )
{
fpzip_errno = fpzipSuccess;
FPZoutput* stream = allocate_output();
stream->re = new RCfileencoder(file);
return static_cast<FPZ*>(stream);
}
FPZ*
fpzip_write_to_buffer(
void* buffer, size_t size )
{
fpzip_errno = fpzipSuccess;
FPZoutput* stream = allocate_output();
stream->re = new RCmemencoder(buffer, size);
return static_cast<FPZ*>(stream);
}
void
fpzip_write_close(
FPZ* fpz )
{
FPZoutput* stream = static_cast<FPZoutput*>(fpz);
delete stream->re;
delete stream;
}
int
fpzip_write_header(
FPZ* fpz )
{
fpzip_errno = fpzipSuccess;
FPZoutput* stream = static_cast<FPZoutput*>(fpz);
RCencoder* re = stream->re;
re->encode<uint>('f', 8);
re->encode<uint>('p', 8);
re->encode<uint>('z', 8);
re->encode<uint>('\0', 8);
re->encode<uint>(FPZ_MAJ_VERSION, 16);
re->encode<uint>(FPZ_MIN_VERSION, 8);
re->encode<uint>(stream->type, 1);
re->encode<uint>(stream->prec, 7);
re->encode<uint>(stream->nx, 32);
re->encode<uint>(stream->ny, 32);
re->encode<uint>(stream->nz, 32);
re->encode<uint>(stream->nf, 32);
if (re->error) {
fpzip_errno = fpzipErrorWriteStream;
return 0;
}
return 1;
}
size_t
fpzip_write(
FPZ* fpz, const void* data )
{
fpzip_errno = fpzipSuccess;
size_t bytes = 0;
try {
FPZoutput* stream = static_cast<FPZoutput*>(fpz);
bool success = (stream->type == FPZIP_TYPE_FLOAT
? compress4d(stream, static_cast<const float*>(data))
: compress4d(stream, static_cast<const double*>(data)));
if (success) {
RCencoder* re = stream->re;
re->finish();
if (re->error) {
if (fpzip_errno == fpzipSuccess)
fpzip_errno = fpzipErrorWriteStream;
}
else
bytes = re->bytes();
}
}
catch (...) {
fpzip_errno = fpzipErrorInternal;
}
return bytes;
}