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++
399 lines
9.0 KiB
C++
4 years ago
|
/***************************************************************************
|
||
|
* 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>;
|
||
|
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|