You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

399 lines
9.0 KiB
C++

/***************************************************************************
* Copyright (C) 2009 by gempa GmbH *
* *
* All Rights Reserved. *
* *
* NOTICE: All information contained herein is, and remains *
* the property of gempa GmbH and its suppliers, if any. The intellectual *
* and technical concepts contained herein are proprietary to gempa GmbH *
* and its suppliers. *
* Dissemination of this information or reproduction of this material *
* is strictly forbidden unless prior written permission is obtained *
* from gempa GmbH. *
***************************************************************************/
#include <gempa/caps/riff.h>
#include <gempa/caps/endianess.h>
#include <cstdio>
#include <cstring>
namespace Gempa {
namespace CAPS {
namespace RIFF {
bool ChunkHeader::setChunkType(const char *t) {
int i;
if ( t != NULL ) {
for ( i = 0; i < 4; ++i ) {
if ( t[i] == '\0' ) break;
chunkType[i] = t[i];
}
// Input type must not have more than 4 characters
if ( i == 3 && t[i] != '\0' && t[i+1] != '\0' ) {
memset(chunkType, ' ', 4);
return false;
}
}
else
i = 0;
// Pad with whitespaces
for ( ; i < 4; ++i )
chunkType[i] = ' ';
return true;
}
bool ChunkHeader::isChunkType(const char *t) const {
for ( int i = 0; i < 4; ++i ) {
if ( t[i] == '\0' && chunkType[i] == ' ' ) break;
if ( t[i] != chunkType[i] ) return false;
}
return true;
}
bool ChunkHeader::validChunkType() const {
for ( int i = 0; i < 4; ++i ) {
if ( chunkType[i] == '\0' ) continue;
if ( chunkType[i] >= 'a' && chunkType[i] <= 'z' ) continue;
if ( chunkType[i] >= 'A' && chunkType[i] <= 'Z' ) continue;
if ( chunkType[i] >= '0' && chunkType[i] <= '9' ) continue;
if ( chunkType[i] == '-' ) continue;
if ( chunkType[i] == '_' ) continue;
if ( chunkType[i] == ' ' ) continue;
return false;
}
return true;
}
bool ChunkHeader::get(std::streambuf &input) {
Endianess::Reader get(input);
get(chunkType, 4);
get(chunkSize);
return get.good;
}
bool ChunkHeader::put(std::streambuf &output) const {
Endianess::Writer put(output);
put(chunkType, 4);
put(chunkSize);
return put.good;
}
ChunkIterator::ChunkIterator() : _stream(&_own) {}
ChunkIterator::ChunkIterator(const std::string &filename) {
begin(filename);
}
ChunkIterator::ChunkIterator(std::istream &input) {
begin(input);
}
void ChunkIterator::begin(const std::string &filename) {
_stream = &_own;
_index = 0;
_own.open(filename.c_str());
memset(&_header, 0, sizeof(_header));
}
void ChunkIterator::begin(std::istream &input) {
_stream = &input;
_index = input.tellg();
_header.chunkSize = 0;
memset(&_header, 0, sizeof(_header));
}
bool ChunkIterator::next() {
while ( _stream->good() ) {
// Jump to next header
_stream->seekg(_index + _header.chunkSize);
if ( !_header.read(*_stream) )
break;
//std::cout << " - "; std::cout.write(_header.chunkType, 4); std::cout << " : " << _header.chunkSize << std::endl;
_index = _stream->tellg();
return true;
}
return false;
}
const ChunkHeader &ChunkIterator::header() const {
return _header;
}
size_t ChunkIterator::headerPos() const {
return _index - _header.dataSize();
}
size_t ChunkIterator::contentPos() const {
return _index;
}
Chunk::~Chunk() {}
bool HeadChunk::get(std::streambuf &input, int size) {
Endianess::Reader r(input);
r(data.version);
char dt;
r(dt);
data.packetType = static_cast<PacketType>(dt);
r(data.unitOfMeasurement.str, 4);
return r.good;
}
bool HeadChunk::put(std::streambuf &output) const {
Endianess::Writer w(output);
w(data.version);
char dt = data.packetType;
w(dt);
w(data.unitOfMeasurement.str, 4);
return w.good;
}
int HeadChunk::chunkSize() const {
return sizeof(data.version) +
sizeof(data.unitOfMeasurement.str) +
sizeof(char);
}
bool SIDChunk::put(std::streambuf &output) const {
char null = '\0';
Endianess::Writer w(output);
if ( !networkCode.empty() )
w(networkCode.c_str(), networkCode.size());
w(&null, 1);
if ( !stationCode.empty() )
w(stationCode.c_str(), stationCode.size());
w(&null, 1);
if ( !locationCode.empty() )
w(locationCode.c_str(), locationCode.size());
w(&null, 1);
if ( !channelCode.empty() )
w(channelCode.c_str(), channelCode.size());
return w.good;
}
bool SIDChunk::get(std::streambuf &input, int size) {
char tmp;
int count = size;
Endianess::Reader r(input);
r(&tmp, 1);
networkCode.clear();
while ( r.good && count-- ) {
if ( tmp == '\0' ) break;
networkCode += tmp;
r(&tmp, 1);
}
if ( !r.good ) return false;
r(&tmp, 1);
stationCode.clear();
while ( r.good && count-- ) {
if ( tmp == '\0' ) break;
stationCode += tmp;
r(&tmp, 1);
}
if ( !r.good ) return false;
r(&tmp, 1);
locationCode.clear();
while ( r.good && count-- ) {
if ( tmp == '\0' ) break;
locationCode += tmp;
r(&tmp, 1);
}
if ( !r.good ) return false;
r(&tmp, 1);
channelCode.clear();
while ( r.good && count-- ) {
if ( tmp == '\0' ) break;
channelCode += tmp;
r(&tmp, 1);
}
return true;
}
int SIDChunk::chunkSize() const {
return networkCode.size() + 1 +
stationCode.size() + 1 +
locationCode.size() + 1 +
channelCode.size();
}
template <int SIZE_T, bool BigEndian>
CPtrChunk<SIZE_T,BigEndian>::CPtrChunk(const char* d, int len) : data(d), size(len) {}
template <int SIZE_T, bool BigEndian>
int CPtrChunk<SIZE_T,BigEndian>::chunkSize() const {
return size;
}
template <int SIZE_T, bool BigEndian>
bool CPtrChunk<SIZE_T,BigEndian>::get(std::streambuf &, int) {
return false;
}
template <typename T, int SIZE_T, bool BigEndian>
struct CPtrWriter {
static bool Take(std::streambuf &output, const T*, int count);
};
// To little endian
template <typename T, int SIZE_T>
struct CPtrWriter<T,SIZE_T,true> {
static bool Take(std::streambuf &output, const T *data, int count) {
Endianess::Writer w(output);
for ( int i = 0; i < count; ++i ) {
T tmp = Endianess::Swapper<T,true,SIZE_T>::Take(data[i]);
w((const char*)&tmp, SIZE_T);
}
return w.good;
}
};
template <typename T, int SIZE_T>
struct CPtrWriter<T,SIZE_T,false> {
static bool Take(std::streambuf &output, const T *data, int count) {
return (int)output.sputn((const char*)data, SIZE_T*count) == SIZE_T*count;
}
};
template <int SIZE_T, bool BigEndian>
bool CPtrChunk<SIZE_T,BigEndian>::put(std::streambuf &output) const {
typedef typename Endianess::TypeMap<SIZE_T>::ValueType T;
return CPtrWriter<T,SIZE_T,BigEndian>::Take(output, (const T*)data, size/SIZE_T);
}
template <int SIZE_T, bool BigEndian>
VectorChunk<SIZE_T,BigEndian>::VectorChunk(std::vector<char> &d)
: data(d), startOfs(-1), len(-1) {}
template <int SIZE_T, bool BigEndian>
VectorChunk<SIZE_T,BigEndian>::VectorChunk(std::vector<char> &d, int ofs, int count)
: data(d), startOfs(ofs), len(count) {}
template <int SIZE_T, bool BigEndian>
int VectorChunk<SIZE_T,BigEndian>::chunkSize() const {
return data.size();
}
template <int SIZE_T, bool BigEndian>
bool VectorChunk<SIZE_T,BigEndian>::get(std::streambuf &input, int size) {
int count = size/SIZE_T;
if ( len >= 0 ) {
if ( len > count )
return false;
count = len;
}
// Skip first samples (bytes = samples*sizeof(T))
if ( startOfs > 0 )
input.pubseekoff(startOfs*SIZE_T, std::ios_base::cur, std::ios_base::in);
Endianess::Reader r(input);
data.resize(count*SIZE_T);
r(&data[0], data.size());
// Convert array to little endian
Endianess::ByteSwapper<BigEndian,SIZE_T>::Take(&data[0], count);
// Go the end of chunk
if ( (int)data.size() < size )
input.pubseekoff(size-data.size(), std::ios_base::cur, std::ios_base::in);
return r.good;
}
template <int SIZE_T, bool BigEndian>
bool VectorChunk<SIZE_T,BigEndian>::put(std::streambuf &output) const {
typedef typename Endianess::TypeMap<SIZE_T>::ValueType T;
return CPtrWriter<T,SIZE_T,BigEndian>::Take(output, (const T*)data.data(), data.size()/SIZE_T);
}
template struct SC_GEMPA_CAPS_API CPtrChunk<1,false>;
template struct SC_GEMPA_CAPS_API CPtrChunk<1,true>;
template struct SC_GEMPA_CAPS_API CPtrChunk<2,false>;
template struct SC_GEMPA_CAPS_API CPtrChunk<2,true>;
template struct SC_GEMPA_CAPS_API CPtrChunk<4,false>;
template struct SC_GEMPA_CAPS_API CPtrChunk<4,true>;
template struct SC_GEMPA_CAPS_API CPtrChunk<8,false>;
template struct SC_GEMPA_CAPS_API CPtrChunk<8,true>;
template struct SC_GEMPA_CAPS_API VectorChunk<1,false>;
template struct SC_GEMPA_CAPS_API VectorChunk<1,true>;
template struct SC_GEMPA_CAPS_API VectorChunk<2,false>;
template struct SC_GEMPA_CAPS_API VectorChunk<2,true>;
template struct SC_GEMPA_CAPS_API VectorChunk<4,false>;
template struct SC_GEMPA_CAPS_API VectorChunk<4,true>;
template struct SC_GEMPA_CAPS_API VectorChunk<8,false>;
template struct SC_GEMPA_CAPS_API VectorChunk<8,true>;
}
}
}