#include <cassert>
#include "buffer.h"
#include "dnsutil.h"
using std::memset;
using std::memcmp;
Buffer::Buffer(size_t i_szBufferMax) {
m_szBuffer = 0;
m_szBufferMax = i_szBufferMax;
m_ucpBuffer = new unsigned char[m_szBufferMax];
m_ofPos = 0;
memset(m_ucpBuffer,0,m_szBufferMax);
}
off_t Buffer::FindInRange(off_t i_ofBegin, off_t i_ofEnd, const unsigned char *ci_ucpFind, size_t i_szFind) {
off_t i_ofMax = i_ofEnd - i_szFind;
while(i_ofBegin<i_ofMax) {
if (memcmp(m_ucpBuffer+i_ofBegin,ci_ucpFind,i_szFind)==0) return i_ofBegin;
i_ofBegin++;
}
return i_ofEnd;
}
off_t Buffer::FindPreviousLabelList(off_t i_ofBegin, off_t i_ofEnd, const unsigned char *ci_ucpFind, size_t i_szFind) {
while(i_ofBegin<i_ofEnd) {
if (TestLabelList(ci_ucpFind,i_szFind,i_ofBegin)==true) return i_ofBegin;
i_ofBegin++;
}
return i_ofEnd;
}
bool Buffer::ReadBit(off_t i_off, unsigned char i_ucBit) const {
assert(i_off<(off_t)m_szBuffer);
unsigned char ucVal = 1;
ucVal <<= i_ucBit;
if ((m_ucpBuffer[i_off]&ucVal)==ucVal) return true;
return false;
}
void Buffer::ReadBits(bool &o_br7, bool &o_br6, bool &o_br5, bool &o_br4, bool &o_br3, bool &o_br2, bool &o_br1, bool &o_br0) const {
unsigned char uc;
this->Read(uc);
o_br7 = ((uc&128)==128);
o_br6 = ((uc&64)==64);
o_br5 = ((uc&32)==32);
o_br4 = ((uc&16)==16);
o_br3 = ((uc&8)==8);
o_br2 = ((uc&4)==4);
o_br1 = ((uc&2)==2);
o_br0 = ((uc&1)==1);
}
void Buffer::ReadData(void *o_ptrData, size_t i_szData) const {
this->ReadData(o_ptrData,i_szData,m_ofPos);
}
void Buffer::ReadData(void *o_ptrData, size_t i_szData, off_t &io_of) const {
assert(o_ptrData!=NULL);
if (io_of+i_szData>m_szBuffer)
throw BufferEx(FOUT("Buffer::ReadData: overflow reading ",i_szData," bytes at ",io_of," (max ",m_szBuffer-1,")"));
memcpy(o_ptrData,m_ucpBuffer+io_of,i_szData);
io_of += i_szData;
}
void Buffer::ReadLabelList(unsigned char *o_ucpOut, size_t i_szOut, unsigned short &o_usLength, bool i_bUseCompression) const {
o_usLength = 0;
this->ReadLabelList(o_ucpOut,i_szOut,o_usLength,i_bUseCompression,m_ofPos);
}
void Buffer::ReadLabelList(unsigned char *o_ucpOut, size_t i_szOut, unsigned short &o_usLength, bool i_bUseCompression, off_t &io_ofrPos) const {
unsigned char uc;
LogHandle lh(LF_PACKETFORMAT,LY_DEBUG);
lh << "LABEL(" << io_ofrPos << "): ";
uc = this->Get(io_ofrPos++);
while(uc!=0) {
if ((uc>=192)&&(i_bUseCompression==true)) {
off_t offCache;
offCache = uc - 192;
offCache <<= 8;
offCache += this->Get(io_ofrPos++);
return this->ReadLabelList(o_ucpOut,i_szOut,o_usLength,i_bUseCompression,offCache);
}
if (uc>=64) {
lh << "!" << (unsigned)uc << " at " << (io_ofrPos-1) << endl;
throw BadParseEx(FOUT("Buffer::ReadLabelList: unexpected high bit at ",io_ofrPos-1));
}
*o_ucpOut++ = uc;
i_szOut--;
this->ReadData(o_ucpOut,uc,io_ofrPos);
o_ucpOut += uc;
i_szOut -= uc;
o_usLength += (uc + 1);
uc = this->Get(io_ofrPos++);
lh << ".";
}
*o_ucpOut = 0;
i_szOut--;
o_usLength++;
}
void Buffer::ReadLabelList(LabelListPtr &o_llpr, bool i_bUseCompression) const {
unsigned char uca[256];
unsigned short us;
this->ReadLabelList(uca,255,us,i_bUseCompression);
o_llpr = new LabelList(uca);
}
bool Buffer::TestLabelList(const unsigned char *i_ucpLabels, size_t i_szLabels, off_t i_ofPos) {
unsigned short us;
while(1) {
if ((*i_ucpLabels==0)&&(m_ucpBuffer[i_ofPos]==0)) return true;
if (m_ucpBuffer[i_ofPos]>=192) {
this->PReadNBO(us,i_ofPos);
us -= 0xC000;
if(us>=i_ofPos) return false;
return this->TestLabelList(i_ucpLabels,i_szLabels,us);
}
if (*i_ucpLabels != m_ucpBuffer[i_ofPos]) return false;
if (MemCaseCmp((const char*)i_ucpLabels+1,(const char*)m_ucpBuffer+i_ofPos+1,*i_ucpLabels)!=0) return false;
i_ucpLabels += (*i_ucpLabels + 1);
i_ofPos += (m_ucpBuffer[i_ofPos] + 1);
}
}
void Buffer::TryCompression(off_t i_ofStart) {
assert(i_ofStart<=m_ofPos);
unsigned short usPrev;
size_t sz = size_t(m_ofPos - i_ofStart);
while(sz>3) {
usPrev = this->FindPreviousLabelList(12,i_ofStart,m_ucpBuffer+i_ofStart,sz);
if (usPrev!=i_ofStart) {
usPrev += 0xC000;
this->SetPos(i_ofStart);
this->WriteNBO(usPrev);
return;
}
i_ofStart += (this->Get(i_ofStart) + 1);
sz = size_t(m_ofPos - i_ofStart);
}
}
void Buffer::WriteBit(bool i_bBit, off_t i_off, unsigned char i_ucBit) {
assert(i_off<(off_t)m_szBuffer);
unsigned char ucVal = (1 << i_ucBit);
if (i_bBit==false) {
ucVal = 255 - ucVal;
m_ucpBuffer[i_off] &= ucVal;
} else {
m_ucpBuffer[i_off] |= ucVal;
}
}
void Buffer::WriteBits(bool i_b7, bool i_b6, bool i_b5, bool i_b4, bool i_b3, bool i_b2, bool i_b1, bool i_b0) {
unsigned char uc = FromBits(i_b7,i_b6,i_b5,i_b4,i_b3,i_b2,i_b1,i_b0);
this->Write(uc);
}
void Buffer::WriteData(const void *i_ptrData, size_t i_szData) {
this->WriteData(i_ptrData,i_szData,m_ofPos);
m_ofPos += i_szData;
}
void Buffer::WriteData(const void *i_ptrData, size_t i_szData, off_t i_of) {
if ((i_of+i_szData) > m_szBufferMax)
throw BufferEx(FOUT("Buffer::WriteData: buffer overflow writing ",i_szData," bytes at ",i_of," (max ",m_szBufferMax-1,")"));
memcpy(m_ucpBuffer+i_of,i_ptrData,i_szData);
if (m_szBuffer<(size_t)(i_of+i_szData)) m_szBuffer = (size_t)i_of + i_szData;
}
unsigned short Buffer::WriteLabelList(LabelListConstPtr ci_llp, bool i_bUseCompression) {
LabelList::const_iterator lni;
off_t ofStart = m_ofPos;
for(lni=ci_llp->begin();lni!=ci_llp->end();++lni) {
assert((*lni).GetLength()<64);
this->Write((unsigned char)(*lni).GetLength());
this->WriteData( (*lni).GetString(), (*lni).GetLength());
}
this->Write((unsigned char)0);
this->TryCompression(ofStart);
return (unsigned short)(m_ofPos-ofStart);
}
Buffer::~Buffer() {
SoftDeleteArray(m_ucpBuffer);
m_szBuffer = 0;
m_szBufferMax = 0;
}
ostream& operator<<(ostream &io_smr, const Buffer &ci_bfr) {
ci_bfr.DumpRange(io_smr,0,ci_bfr.GetSize());
io_smr << std::endl;
return io_smr;
}
ostream& operator<<(ostream &io_smr, BufferConstPtr ci_bfp) {
io_smr << *ci_bfp;
return io_smr;
}