diff options
Diffstat (limited to 'conversion/vff.cc')
-rw-r--r-- | conversion/vff.cc | 797 |
1 files changed, 797 insertions, 0 deletions
diff --git a/conversion/vff.cc b/conversion/vff.cc new file mode 100644 index 0000000..25b58f7 --- /dev/null +++ b/conversion/vff.cc @@ -0,0 +1,797 @@ +/* +* This file is part of rasdaman community. +* +* Rasdaman community is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* Rasdaman community is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with rasdaman community. If not, see <http://www.gnu.org/licenses/>. +* +* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / +rasdaman GmbH. +* +* For more information please see <http://www.rasdaman.org> +* or contact Peter Baumann via <baumann@rasdaman.com>. +/ +/** + * FILE: vff.cc + * + * MODULE: conversion + * + * CLASSES: r_Conv_VFF + * + * COMMENTS: + * + * Provides interface to convert data to VFF and back. + * +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#include <iostream> +#include <strstream> + +#include "raslib/rminit.hh" +#include "raslib/endian.hh" +#include "raslib/miterd.hh" +#include "raslib/odmgtypes.hh" +#include "raslib/parseparams.hh" +#include "conversion/vff.hh" + + +// file magic +const char *r_Conv_VFF::fileMagic = "ncaa"; + +// keyword enumerators, must be kept in sync with keywords +enum vff_keyword_e { + vffkey_rank = 0, + vffkey_type, + vffkey_format, + vffkey_size, + vffkey_origin, + vffkey_extent, + vffkey_aspect, + vffkey_bands, + vffkey_bits, + vffkey_value, + vffkey_endian, + vffkey_dorder, + vffkey_NUMBER +}; + +// Keywords +const char *r_Conv_VFF::keywords[] = { + // mandatory + "rank", + "type", + "format", + "size", + "origin", + "extent", + "aspect", + "bands", + "bits", + // optional + "value", + "endianness", + "data_order" +}; + +// values +const char *r_Conv_VFF::kval_Raster = "raster"; +const char *r_Conv_VFF::kval_Slice = "slice"; +const char *r_Conv_VFF::kval_LEndian = "little_endian"; +const char *r_Conv_VFF::kval_BEndian = "big_endian"; + +// default data order +const char *r_Conv_VFF::dfltDataOrder2 = "xy"; +const char *r_Conv_VFF::dfltDataOrder3 = "yzx"; + +// default dimension order +const char *r_Conv_VFF::dfltDimOrder2 = "xy"; +const char *r_Conv_VFF::dfltDimOrder3 = "yzx"; + +// end of header +const char r_Conv_VFF::endOfHeader = 0x0c; + +// method names +const char *r_Conv_VFF::method_convTo = "r_Conv_VFF::convertTo()"; +const char *r_Conv_VFF::method_convFrom = "r_Conv_VFF::convertFrom()"; + + +r_Conv_VFF::r_Conv_VFF( const char *src, const r_Minterval &interv, int tp ) throw(r_Error) +: r_Convertor(src, interv, tp) +{ + initVFF(); +} + + +r_Conv_VFF::r_Conv_VFF( const char *src, const r_Minterval &interv, const r_Type *tp ) throw(r_Error) +: r_Convertor(src, interv, tp, true) +{ + initVFF(); +} + + +r_Conv_VFF::~r_Conv_VFF( void ) +{ + if (dorderParam != NULL) + delete [] dorderParam; + if (dimOrderParam != NULL) + delete [] dimOrderParam; +} + + +void r_Conv_VFF::initVFF( void ) +{ + dorderParam = NULL; + dimOrderParam = NULL; + dfltEndianness = 0; // big endian + + if (params == NULL) + params = new r_Parse_Params; + + params->add("dorder", &dorderParam, r_Parse_Params::param_type_string); + params->add("dimorder", &dimOrderParam, r_Parse_Params::param_type_string); + params->add("vffendian", &dfltEndianness, r_Parse_Params::param_type_int); +} + + +void r_Conv_VFF::skip_white( const char *&str ) +{ + while ((*str != endOfHeader) && (isspace((unsigned int)(*str)))) str++; +} + +void r_Conv_VFF::write_interval( const char *keyname, std::ostream &str, const r_Minterval &iv, const unsigned int *order, r_Range inc ) +{ + r_Dimension i; + str << keyname << '=' << (iv[order[0]].high() - iv[order[0]].low() + inc); + for (i=1; i<iv.dimension(); i++) + str << ' ' << (iv[order[i]].high() - iv[order[i]].low() + inc); + str << ";\n"; +} + +void r_Conv_VFF::write_origin( const char *keyname, std::ostream &str, const r_Minterval &iv, const unsigned int *order ) +{ + r_Dimension i; + str << keyname << '=' << iv[order[0]].low(); + for (i=1; i<iv.dimension(); i++) + str << ' ' << iv[order[i]].low(); + str << ";\n"; +} + +const char *r_Conv_VFF::read_vector( r_Dimension dim, const char *str, double *&vec ) +{ + if (dim == 0) + return NULL; + + vec = new double[dim]; + r_Dimension i; + + for (i=0; i<dim; i++) + { + const char *rest; + vec[i] = strtod(str, (char**)&rest); + if (str == rest) + break; + str = rest; + } + if (i < dim) + { + delete [] vec; + vec = NULL; + return NULL; + } + return str; +} + +const char *r_Conv_VFF::read_string( const char *str, char *dest, bool allowSpace ) +{ + const char *d = str; + char *b = dest; + + while (*d != ';') + { + if ((allowSpace == 1) && (isspace((unsigned int)(*d)))) + break; + *b++ = *d++; + } + *b++ = '\0'; + return d; +} + +const char *r_Conv_VFF::get_endian_id( void ) +{ + return ((r_Endian::get_endianness() == r_Endian::r_Endian_Big) ? kval_BEndian : kval_LEndian); +} + + +const char *r_Conv_VFF::get_default_order( r_Dimension dim ) +{ + return (dim == 2) ? dfltDataOrder2 : dfltDataOrder3; +} + + +const char *r_Conv_VFF::get_default_dim_order( r_Dimension dim ) +{ + return (dim == 2) ? dfltDimOrder2 : dfltDimOrder3; +} + + +int r_Conv_VFF::parse_data_order( r_Dimension dim, const char *dstr, unsigned int *order ) +{ + unsigned char *mapped = new unsigned char[dim]; + unsigned int i; + + memset(mapped, 0, dim); + for (i=0; i<dim; i++) + { + unsigned int map; + + switch (dstr[i]) + { + case 'x': + map = 1; break; + case 'y': + map = 2; break; + case 'z': + map = 3; break; + default: + map = 0; break; + } + + if ((map == 0) || (mapped[map-1] != 0)) + break; + + order[i] = map-1; + mapped[map-1] = 1; + //cout << order[i] << endl; + } + + delete [] mapped; + + if (i < dim) + { + RMInit::logOut << "r_Conv_VFF::parse_data_order(): descriptor " << dstr + << " inconsistent, revert to defaults" << endl; + + return parse_data_order(dim, get_default_order(dim), order); + } + + return 0; +} + + +unsigned int *r_Conv_VFF::get_dimension_order( r_Dimension dim ) const +{ + unsigned int *order = new unsigned int[dim]; + char dimOrder[8]; + + // Anders Ledberg: Karolinska reader _always_ uses yzx as dimension order + if (dimOrderParam == NULL) + strncpy(dimOrder, get_default_dim_order(dim), 8); + else + strncpy(dimOrder, dimOrderParam, 8); + + dimOrder[7] = '\0'; + parse_data_order(dim, dimOrder, order); + + return order; +} + + +const char *r_Conv_VFF::get_default_endianness( void ) const +{ + return (dfltEndianness == 0) ? kval_BEndian : kval_LEndian; +} + + +r_convDesc &r_Conv_VFF::convertTo( const char *options ) throw(r_Error) +{ + r_Dimension dim; + int bits, typeSize; + char header[1024]; // and ``640k should be enough for everyone''... + char dataOrder[8]; + + dim = desc.srcInterv.dimension(); + if ((dim < 2) || (dim > 3)) + { + r_Error err(r_Error::r_Error_General); + throw(err); + } + + switch (desc.baseType) + { + case ctype_bool: + case ctype_char: + case ctype_int8: + case ctype_uint8: + bits = 8; typeSize = 1; break; + case ctype_int16: + case ctype_uint16: + bits = 16; typeSize = 2; break; + case ctype_int32: + case ctype_uint32: + bits = 32; typeSize = 4; break; + default: + r_Error err(r_Error::r_Error_General); + throw(err); + break; + } + //cout << "TYPE " << desc.baseType << ", SIZE " << typeSize << endl; + + if (options != NULL) + params->process(options); + + if (dorderParam != NULL) + strcpy(dataOrder, dorderParam); + else + strcpy(dataOrder, get_default_order(dim)); + + std::ostrstream memstr(header, 1024); + + // order of dimensions in vectors + unsigned int *dimOrder = get_dimension_order(dim); + + // write header + memstr << fileMagic << '\n'; + memstr << keywords[vffkey_rank] << '=' << dim << ";\n"; + memstr << keywords[vffkey_type] << '=' << kval_Raster << ";\n"; + memstr << keywords[vffkey_format] << '=' << kval_Slice << ";\n"; + // the dimensions are still ordered like in the VFF file, only the internal + // linearization differs! + write_interval(keywords[vffkey_size], memstr, desc.srcInterv, dimOrder, 1); + write_origin(keywords[vffkey_origin], memstr, desc.srcInterv, dimOrder); + write_interval(keywords[vffkey_extent], memstr, desc.srcInterv, dimOrder); + if (dim == 2) + { + // FIXME, aspect should be modelled too + memstr << keywords[vffkey_aspect] << "=1.0 1.0;\n"; + } + else + { + // FIXME, ditto + memstr << keywords[vffkey_aspect] << "=1.0 1.0 1.0;\n"; + } + + // only suypport one band ATM + memstr << keywords[vffkey_bands] << "=1;\n"; + memstr << keywords[vffkey_bits] << '=' << bits << ";\n"; + memstr << keywords[vffkey_endian] << '=' << get_endian_id() << ";\n"; + memstr << keywords[vffkey_dorder] << '=' << dataOrder << ";\n"; + memstr << '\n' << endOfHeader << '\n' << '\0'; + + unsigned long headerSize, dataSize, totalSize; + + headerSize = strlen(header); + dataSize = desc.srcInterv.cell_count() * typeSize; + totalSize = headerSize + dataSize; + + if ((desc.dest = (char*)mystore.storage_alloc(headerSize + dataSize)) == NULL) + { + r_Error err(r_Error::r_Error_General); + throw(err); + } + memcpy(desc.dest, header, headerSize); + + // treat all dimensions alike thanks to generic iterators + + // source iterator, iterate in user order + r_MiterDirect iter((void*)desc.src, desc.srcInterv, desc.srcInterv, typeSize, 1); + unsigned int *order, *steps; + + order = new unsigned int[dim]; + steps = new unsigned int[dim]; + + for (unsigned int i=0; i<dim; i++) + steps[i] = 1; + + parse_data_order(dim, dataOrder, order); + + // note: dest may not be aligned to a position conforming to its base type, + // so copy byte-wise. + unsigned char *dptr = (unsigned char*)(desc.dest + headerSize); + switch (typeSize) + { + case 1: + { + while (iter.isDone() == 0) + { + *dptr = *((const unsigned char*)iter.getData(order)); + iter.iterateUserOrder(order, steps); + dptr++; + } + } + break; + case 2: + { + while (iter.isDone() == 0) + { + const unsigned char *sptr = (const unsigned char*)iter.getData(order); + dptr[0] = sptr[0]; + dptr[1] = sptr[1]; + //cout << iter << ':' << (long)((const char*)sptr-desc.src) << ':' << (unsigned short)((sptr[0] << 8) | (sptr[1])) << ' '; + iter.iterateUserOrder(order, steps); + dptr+=2; + } + } + break; + case 4: + { + while (iter.isDone() == 0) + { + const unsigned char *sptr = (const unsigned char*)iter.getData(order); + dptr[0] = sptr[0]; + dptr[1] = sptr[1]; + dptr[2] = sptr[2]; + dptr[3] = sptr[3]; + iter.iterateUserOrder(order, steps); + dptr+=4; + } + } + break; + default: + break; + } + + delete [] steps; + delete [] order; + delete [] dimOrder; + + desc.destInterv = r_Minterval(1); + desc.destInterv << r_Sinterval((r_Range)0, (r_Range)totalSize-1); + desc.destType = r_Type::get_any_type("char"); + + return desc; +} + + +r_convDesc &r_Conv_VFF::convertFrom( const char *options ) throw(r_Error) +{ + const char *header = desc.src; + unsigned char *keysRead; + unsigned int i; + r_Dimension dim=0; + int bits, bands; + double *vecSize, *vecOrigin, *vecValue; + char endian[32]; + char dataOrder[8]; + + if (strncmp(header, fileMagic, strlen(fileMagic)) != 0) + { + r_Error err(r_Error::r_Error_General); + throw(err); + } + + keysRead = new unsigned char[vffkey_NUMBER]; + memset(keysRead, 0, vffkey_NUMBER); + + header += strlen(fileMagic); + skip_white(header); + + vecSize = NULL; + vecOrigin = NULL; + vecValue = NULL; + + strcpy(endian, get_default_endianness()); + + if (options != NULL) + params->process(options); + + // no order -- check later if one was defined and init it _after_ we know the rank + dataOrder[0] = '\0'; + + do + { + if (*header != endOfHeader); + { + const char *rest; + double *vecTemp; + + for (i=0; i<(unsigned int)vffkey_NUMBER; i++) + { + if (strncmp(header, keywords[i], strlen(keywords[i])) == 0) + break; + } + + if (i == vffkey_NUMBER) + { + // skip unknown keywords + while ((*header != ';') && (*header != endOfHeader)) + header++; + if (*header == ';') + header++; + } + else + { + //cout << "KEY " << keywords[i] << endl; + + keysRead[i] = 1; + + header += strlen(keywords[i]); + skip_white(header); + + if (*header != '=') + break; + + header++; + skip_white(header); + + rest = header; + switch ((vff_keyword_e)i) + { + case vffkey_rank: + dim = strtol(header, (char**)&rest, 10); + if ((rest == header) || (dim < 2) || (dim > 3)) + { + RMInit::logOut << method_convFrom << ": bad rank " << dim << endl; + rest = NULL; + } + break; + case vffkey_type: + if (strncmp(header, kval_Raster, strlen(kval_Raster)) == 0) + rest = header + strlen(kval_Raster); + else + { + RMInit::logOut << method_convFrom << ": bad type" << endl; + rest = NULL; + } + break; + case vffkey_format: + if (strncmp(header, kval_Slice, strlen(kval_Slice)) == 0) + rest = header + strlen(kval_Slice); + else + { + RMInit::logOut << method_convFrom << ": bad format" << endl; + rest = NULL; + } + break; + case vffkey_size: + rest = read_vector(dim, header, vecSize); + break; + case vffkey_origin: + rest = read_vector(dim, header, vecOrigin); + break; + case vffkey_extent: + // extent just parsed, otherwise ignored + rest = read_vector(dim, header, vecTemp); + delete [] vecTemp; + break; + case vffkey_aspect: + // FIXME: aspect ignored + rest = read_vector(dim, header, vecTemp); + delete [] vecTemp; + break; + case vffkey_bands: + bands = strtol(header, (char**)&rest, 10); + if ((rest == header) || (bands != 1)) + { + RMInit::logOut << method_convFrom << ": bad number of bands " << bands << endl; + rest = NULL; + } + break; + case vffkey_bits: + bits = strtol(header, (char**)&rest, 10); + if ((rest == header) || ((bits != 8) && (bits != 16) && (bits != 32))) + { + RMInit::logOut << method_convFrom << ": bad number of bits " << bits << endl; + rest = NULL; + } + break; + case vffkey_value: + // FIXME: values ignored + rest = read_vector(2, header, vecValue); + break; + case vffkey_endian: + rest = read_string(header, endian); + break; + case vffkey_dorder: + rest = read_string(header, dataOrder); + break; + default: + break; + } + if (rest == NULL) + break; + + header = rest; + skip_white(header); + if (*header == ';') + header++; + } + } + skip_white(header); + } + while (*header != endOfHeader); + + // was there a data order? no ==> init either used-defined or default + if (dataOrder[0] == '\0') + { + if (dorderParam != NULL) + strcpy(dataOrder, dorderParam); + else + strcpy(dataOrder, get_default_order(dim)); + } + + //cout << "RANK " << dim << ", BANDS " << bands << ", BITS " << bits << endl; + + // check whether all mandatory keywords are present + for (i=0; i<(unsigned int)vffkey_value; i++) + { + if (keysRead[i] == 0) + { + header = NULL; + break; + } + } + + if ((header == NULL) || (*header != endOfHeader)) + { + // parse error + RMInit::logOut << method_convFrom << ": PARSE ERROR" << endl; + + delete [] keysRead; + + if (vecSize != NULL) + delete [] vecSize; + if (vecOrigin != NULL) + delete [] vecOrigin; + if (vecValue != NULL) + delete [] vecValue; + + r_Error err(r_Error::r_Error_General); + throw(err); + } + + // after this instruction, header points to the linefeed + header++; + // after this instruction, header points to the data + header++; + + desc.destInterv = r_Minterval(dim); + + // order of dimensions in vectors + unsigned int *dimOrder = get_dimension_order(dim); + + // the order of the dimensions is the same, only the linearization differs + for (i=0; i<dim; i++) + { + // the old method didn't work for high<0 (wrong rounding direction) + r_Range low, width; + low = (r_Range)(vecOrigin[i]); + width = (r_Range)(vecSize[i]); + //cout << "SIZE " << dimOrder[i] << ": " << width << ", ORG " << low << endl; + desc.destInterv[dimOrder[i]] = r_Sinterval(low, low+width-1); + } + //cout << desc.destInterv << endl; + + delete [] vecOrigin; + delete [] vecSize; + + int typeSize = (bits>>3); + unsigned long dataSize = desc.destInterv.cell_count() * typeSize; + //cout << "Type size " << typeSize << ", dim " << dim << endl; + + if ((desc.dest = (char*)mystore.storage_alloc(dataSize)) == NULL) + { + delete [] keysRead; + + if (vecValue != NULL) + delete [] vecValue; + + r_Error err(r_Error::r_Error_General); + throw(err); + } + + // treat all dimensions alike + + // must copy byte-by-byte because the source data may not be aligned! + r_MiterDirect iter(desc.dest, desc.destInterv, desc.destInterv, typeSize, 1); + unsigned int *order, *steps; + const unsigned char *sptr = (const unsigned char *)header; + + order = new unsigned int[dim]; + steps = new unsigned int[dim]; + + for (i=0; i<dim; i++) + steps[i] = 1; + + parse_data_order(dim, dataOrder, order); + + switch (typeSize) + { + case 1: + while (iter.isDone() == 0) + { + *((r_Char*)iter.getData(order)) = *sptr; + iter.iterateUserOrder(order, steps); + sptr++; + } + break; + case 2: + while (iter.isDone() == 0) + { + unsigned char *dptr = (unsigned char*)iter.getData(order); + dptr[0] = sptr[0]; + dptr[1] = sptr[1]; + //cout << iter << ':' << (long)((char*)dptr - desc.dest) << ':' << (long)((char*)sptr - header) << ':' << (unsigned short)((sptr[0] << 8) | sptr[1]) << ' '; + iter.iterateUserOrder(order, steps); + sptr+=2; + } + break; + case 4: + while (iter.isDone() == 0) + { + unsigned char *dptr = (unsigned char*)iter.getData(order); + dptr[0] = sptr[0]; + dptr[1] = sptr[1]; + dptr[2] = sptr[2]; + dptr[3] = sptr[3]; + iter.iterateUserOrder(order, steps); + sptr+=4; + } + break; + default: + break; + } + + delete [] order; + delete [] steps; + delete [] dimOrder; + + switch (typeSize) + { + case 1: + desc.destType = get_external_type(ctype_char); + break; + case 2: + desc.destType = get_external_type(ctype_uint16); + if (strcmp(endian, get_endian_id()) != 0) + r_Endian::swap_array(dataSize, (const r_UShort*)desc.dest, (r_UShort*)desc.dest); + break; + case 4: + desc.destType = get_external_type(ctype_uint32); + if (strcmp(endian, get_endian_id()) != 0) + r_Endian::swap_array(dataSize, (const r_ULong*)desc.dest, (r_ULong*)desc.dest); + break; + default: + break; + } + + //desc.destType->print_status(); + + if (vecValue != NULL) + delete [] vecValue; + + delete [] keysRead; + + return desc; +} + + +const char *r_Conv_VFF::get_name( void ) const +{ + return format_name_vff; +} + + +r_Data_Format r_Conv_VFF::get_data_format( void ) const +{ + return r_VFF; +} + + +r_Convertor *r_Conv_VFF::clone( void ) const +{ + return new r_Conv_VFF(desc.src, desc.srcInterv, desc.baseType); +} |