/*
* 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 .
*
* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
rasdaman GmbH.
*
* For more information please see
* or contact Peter Baumann via .
/
/**
* FILE: vff.cc
*
* MODULE: conversion
*
* CLASSES: r_Conv_VFF
*
* COMMENTS:
*
* Provides interface to convert data to VFF and back.
*
*/
#include
#include
#include
#include
#include
#include
#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 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; iprocess(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>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; iprint_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);
}