You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
387 lines
7.7 KiB
387 lines
7.7 KiB
15 years ago
|
/*
|
||
|
|
||
|
Copyright (C) 2000 Stefan Westerfeld
|
||
|
stefan@space.twc.de
|
||
|
|
||
|
This library is free software; you can redistribute it and/or
|
||
|
modify it under the terms of the GNU Library General Public
|
||
|
License as published by the Free Software Foundation; either
|
||
|
version 2 of the License, or (at your option) any later version.
|
||
|
|
||
|
This library 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
|
||
|
Library General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU Library General Public License
|
||
|
along with this library; see the file COPYING.LIB. If not, write to
|
||
15 years ago
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||
|
Boston, MA 02110-1301, USA.
|
||
15 years ago
|
|
||
|
*/
|
||
|
|
||
|
#include "buffer.h"
|
||
|
#include <assert.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
using namespace std;
|
||
|
using namespace Arts;
|
||
|
|
||
|
Buffer::Buffer() : rpos(0), _readError(false),d(0)
|
||
|
{
|
||
|
contents.reserve(128);
|
||
|
}
|
||
|
|
||
|
Buffer::~Buffer()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
long Buffer::size()
|
||
|
{
|
||
|
return contents.size();
|
||
|
}
|
||
|
|
||
|
long Buffer::remaining()
|
||
|
{
|
||
|
return size()-rpos;
|
||
|
}
|
||
|
|
||
|
bool Buffer::readError() {
|
||
|
return _readError;
|
||
|
}
|
||
|
|
||
|
void Buffer::writeBool(bool b) {
|
||
|
contents.push_back(b?1:0);
|
||
|
}
|
||
|
|
||
|
void Buffer::writeByte(mcopbyte b) {
|
||
|
contents.push_back(b);
|
||
|
}
|
||
|
|
||
|
void Buffer::writeLong(long l) {
|
||
|
contents.push_back((l >> 24) & 0xff);
|
||
|
contents.push_back((l >> 16) & 0xff);
|
||
|
contents.push_back((l >> 8) & 0xff);
|
||
|
contents.push_back(l & 0xff);
|
||
|
}
|
||
|
|
||
|
void Buffer::writeBoolSeq(const vector<bool>& seq) {
|
||
|
writeLong(seq.size());
|
||
|
|
||
|
vector<bool>::const_iterator i;
|
||
|
for(i = seq.begin(); i != seq.end(); i++) writeBool(*i);
|
||
|
}
|
||
|
|
||
|
void Buffer::writeByteSeq(const vector<mcopbyte>& seq) {
|
||
|
writeLong(seq.size()); // bytes are sent raw, so we can call read here
|
||
|
write(seq);
|
||
|
}
|
||
|
|
||
|
void Buffer::writeLongSeq(const vector<long>& seq) {
|
||
|
writeLong(seq.size());
|
||
|
|
||
|
vector<long>::const_iterator i;
|
||
|
for(i = seq.begin(); i != seq.end(); i++) writeLong(*i);
|
||
|
}
|
||
|
|
||
|
void Buffer::writeFloat(float f) {
|
||
|
// FIXME: on some machines this may fail badly (there is explicit
|
||
4 years ago
|
// float marshalling and demarshalling code in mico/orb/util.cpp)
|
||
15 years ago
|
union { float f; long l; } u = {f};
|
||
|
writeLong(u.l);
|
||
|
}
|
||
|
|
||
|
void Buffer::writeFloatSeq(const std::vector<float>& seq) {
|
||
|
writeLong(seq.size());
|
||
|
|
||
|
vector<float>::const_iterator i;
|
||
|
for(i = seq.begin(); i != seq.end(); i++) writeFloat(*i);
|
||
|
}
|
||
|
|
||
|
void Buffer::writeString(const string& s) {
|
||
|
long len = s.size()+1;
|
||
|
|
||
|
writeLong(len);
|
||
|
contents.insert(contents.end(),reinterpret_cast<const unsigned char*>(s.c_str()),
|
||
|
reinterpret_cast<const unsigned char*>(s.c_str()+len));
|
||
|
}
|
||
|
|
||
|
void Buffer::writeStringSeq(const vector<string>& seq) {
|
||
|
writeLong(seq.size());
|
||
|
|
||
|
vector<string>::const_iterator i;
|
||
|
for(i = seq.begin(); i != seq.end(); i++) writeString(*i);
|
||
|
}
|
||
|
|
||
|
void Buffer::write(void *data, long len) {
|
||
|
unsigned char *c = (unsigned char *)data;
|
||
|
|
||
|
contents.insert(contents.end(),c,c+len);
|
||
|
}
|
||
|
|
||
|
void Buffer::write(const vector<mcopbyte>& raw)
|
||
|
{
|
||
|
contents.insert(contents.end(), raw.begin(), raw.end());
|
||
|
}
|
||
|
|
||
|
void Buffer::read(vector<mcopbyte>& raw, long l)
|
||
|
{
|
||
|
if(l >= 0 && remaining() >= l) {
|
||
|
raw.clear();
|
||
|
raw.insert(raw.end(), contents.begin()+rpos, contents.begin()+rpos+l);
|
||
|
rpos += l;
|
||
|
} else {
|
||
|
_readError = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void *Buffer::read(long l) {
|
||
|
void *result = 0;
|
||
|
|
||
|
if(l >= 0 && remaining() >= l) {
|
||
|
result = &contents[rpos];
|
||
|
rpos += l;
|
||
|
} else {
|
||
|
_readError = true;
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
void *Buffer::peek(long l) {
|
||
|
assert(l >= 0 && remaining() >= l);
|
||
|
return &contents[rpos];
|
||
|
}
|
||
|
|
||
|
void Buffer::skip(long l) {
|
||
|
if(l >= 0 && remaining() >= l) {
|
||
|
rpos += l;
|
||
|
} else {
|
||
|
_readError = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Buffer::rewind() {
|
||
|
rpos = 0;
|
||
|
}
|
||
|
|
||
|
bool Buffer::readBool()
|
||
|
{
|
||
|
long result = false;
|
||
|
if(remaining() >= 1) {
|
||
|
if(contents[rpos] == 1)
|
||
|
result = true;
|
||
|
else
|
||
|
{
|
||
|
assert(contents[rpos] == 0);
|
||
|
}
|
||
|
rpos += 1;
|
||
|
} else {
|
||
|
_readError = true;
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
void Buffer::readBoolSeq(vector<bool>& result)
|
||
|
{
|
||
|
// might be optimizable a bit
|
||
|
long i,seqlen = readLong();
|
||
|
|
||
|
result.clear();
|
||
|
if(seqlen >= 0 && remaining() >= seqlen)
|
||
|
{
|
||
|
for(i=0;i<seqlen;i++) result.push_back(readBool());
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_readError = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
mcopbyte Buffer::readByte()
|
||
|
{
|
||
|
if(remaining() >= 1)
|
||
|
{
|
||
|
return contents[rpos++];
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_readError = true;
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Buffer::readByteSeq(vector<mcopbyte>& result)
|
||
|
{
|
||
|
long seqlen = readLong(); // bytes are sent raw, so we can call read here
|
||
|
read(result, seqlen);
|
||
|
}
|
||
|
|
||
|
long Buffer::readLong()
|
||
|
{
|
||
|
long result = 0;
|
||
|
if(remaining() >= 4) {
|
||
|
result = (contents[rpos] << 24)
|
||
|
+ (contents[rpos+1] << 16)
|
||
|
+ (contents[rpos+2] << 8)
|
||
|
+ contents[rpos+3];
|
||
|
rpos += 4;
|
||
|
} else {
|
||
|
_readError = true;
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
void Buffer::readLongSeq(vector<long>& result)
|
||
|
{
|
||
|
// might be optimizable a bit
|
||
|
long i,seqlen = readLong();
|
||
|
|
||
|
result.clear();
|
||
|
if(seqlen * 4 >= 0 && remaining() >= seqlen * 4)
|
||
|
{
|
||
|
for(i=0;i<seqlen;i++) result.push_back(readLong());
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_readError = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
float Buffer::readFloat()
|
||
|
{
|
||
|
// FIXME: see writeFloat()
|
||
|
union {float f; long l; } u;
|
||
|
u.l = readLong();
|
||
|
|
||
|
if(!_readError) return u.f;
|
||
|
return 0.0;
|
||
|
}
|
||
|
|
||
|
void Buffer::readFloatSeq(vector<float>& result)
|
||
|
{
|
||
|
// might be optimizable a bit
|
||
|
long i,seqlen = readLong();
|
||
|
|
||
|
result.clear();
|
||
|
if(seqlen * 4 >= 0 && remaining() >= seqlen * 4)
|
||
|
{
|
||
|
for(i=0;i<seqlen;i++) result.push_back(readFloat());
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_readError = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Buffer::readString(string& result)
|
||
|
{
|
||
|
long len = readLong();
|
||
|
char *data = (char *)read(len);
|
||
|
|
||
|
if(data && len)
|
||
|
result.assign(data,len-1);
|
||
|
else
|
||
|
result = "";
|
||
|
}
|
||
|
|
||
|
void Buffer::readStringSeq(vector<string>& result)
|
||
|
{
|
||
|
// might be optimizable a bit
|
||
|
|
||
|
long i,seqlen = readLong();
|
||
|
|
||
|
result.clear();
|
||
|
//result.reserve(seqlen);
|
||
|
|
||
|
for(i=0;i<seqlen;i++) {
|
||
|
string s;
|
||
|
|
||
|
readString(s);
|
||
|
if(_readError) return;
|
||
|
|
||
|
result.push_back(s);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void Buffer::patchLength()
|
||
|
{
|
||
|
long len = size();
|
||
|
assert(len >= 8);
|
||
|
|
||
|
contents[4] = (len >> 24) & 0xff;
|
||
|
contents[5] = (len >> 16) & 0xff;
|
||
|
contents[6] = (len >> 8) & 0xff;
|
||
|
contents[7] = len & 0xff;
|
||
|
}
|
||
|
|
||
|
void Buffer::patchLong(long position, long value)
|
||
|
{
|
||
|
long len = size();
|
||
|
assert(len >= position+4);
|
||
|
|
||
|
contents[position] = (value >> 24) & 0xff;
|
||
|
contents[position+1] = (value >> 16) & 0xff;
|
||
|
contents[position+2] = (value >> 8) & 0xff;
|
||
|
contents[position+3] = value & 0xff;
|
||
|
}
|
||
|
|
||
|
string Buffer::toString(const string& name)
|
||
|
{
|
||
|
string result;
|
||
|
char hex[17] = "0123456789abcdef";
|
||
|
|
||
|
vector<unsigned char>::iterator ci;
|
||
|
for(ci = contents.begin(); ci != contents.end(); ci++)
|
||
|
{
|
||
|
result += hex[(*ci >> 4) & 0xf];
|
||
|
result += hex[*ci & 0xf];
|
||
|
}
|
||
|
|
||
|
if(name.empty()) return result;
|
||
|
return name + ":" + result;
|
||
|
}
|
||
|
|
||
|
unsigned char Buffer::fromHexNibble(char c)
|
||
|
{
|
||
|
int uc = (unsigned char)c;
|
||
|
|
||
|
if(uc >= '0' && uc <= '9') return uc - (unsigned char)'0';
|
||
|
if(uc >= 'a' && uc <= 'f') return uc + 10 - (unsigned char)'a';
|
||
|
if(uc >= 'A' && uc <= 'F') return uc + 10 - (unsigned char)'A';
|
||
|
|
||
|
return 16; // error
|
||
|
}
|
||
|
|
||
|
static int stringncmp(const string& s1, const string& s2, size_t n)
|
||
|
{
|
||
|
// I don't know a way to implement that compliant to all STL string
|
||
|
// implementations (compare seems to work differently sometimes)
|
||
|
return strncmp(s1.c_str(),s2.c_str(),n);
|
||
|
}
|
||
|
|
||
|
bool Buffer::fromString(const string& data, const string& name)
|
||
|
{
|
||
|
string start = name+":";
|
||
|
if(name.empty()) start = "";
|
||
|
|
||
|
if(stringncmp(data,start,start.size()) != 0) return false;
|
||
|
contents.clear();
|
||
|
|
||
|
string::const_iterator di = data.begin() + start.size();
|
||
|
|
||
|
while(di != data.end())
|
||
|
{
|
||
|
unsigned char h = fromHexNibble(*di++); // high nibble
|
||
|
if(di == data.end()) return false;
|
||
|
|
||
|
unsigned char l = fromHexNibble(*di++); // low nibble
|
||
|
|
||
|
if(h >= 16 || l >= 16) return false; // no proper hex digit
|
||
|
contents.push_back((h << 4) + l);
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|