/*************************************************************************** * 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 #include #include #include 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(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 CPtrChunk::CPtrChunk(const char* d, int len) : data(d), size(len) {} template int CPtrChunk::chunkSize() const { return size; } template bool CPtrChunk::get(std::streambuf &, int) { return false; } template struct CPtrWriter { static bool Take(std::streambuf &output, const T*, int count); }; // To little endian template struct CPtrWriter { 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::Take(data[i]); w((const char*)&tmp, SIZE_T); } return w.good; } }; template struct CPtrWriter { 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 bool CPtrChunk::put(std::streambuf &output) const { typedef typename Endianess::TypeMap::ValueType T; return CPtrWriter::Take(output, (const T*)data, size/SIZE_T); } template VectorChunk::VectorChunk(std::vector &d) : data(d), startOfs(-1), len(-1) {} template VectorChunk::VectorChunk(std::vector &d, int ofs, int count) : data(d), startOfs(ofs), len(count) {} template int VectorChunk::chunkSize() const { return data.size(); } template bool VectorChunk::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::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 bool VectorChunk::put(std::streambuf &output) const { typedef typename Endianess::TypeMap::ValueType T; return CPtrWriter::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>; } } }