00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include "xdrbuf.h"
00035
00036 #include <string.h>
00037
00038 #ifdef WIN32
00039 #include "winsock.h"
00040 #else // WIN32
00041 #include "netinet/in.h"
00042 #endif // WIN32
00043
00044 #include "common/wave_ex.h"
00045
00046
00047 namespace xdrbuf {
00048
00049
00050
00051
00052
00053
00054 Output::~Output(void) throw() { }
00055 Input::~Input(void) throw() { }
00056
00057
00058 static const char s_nameLookup[] = "\0abcdefghijklmnopqrstuvwxyz$*?!=";
00059
00060
00061
00062
00063
00064
00065
00066
00067 static int
00068 getNameIndex
00069 (
00070 IN char a
00071 )
00072 {
00073 if (a >= 'a' && a <= 'z')
00074 return a - 'a' + 1;
00075 if (a == '$')
00076 return 27;
00077 if (a == '*')
00078 return 28;
00079 if (a == '?')
00080 return 29;
00081 if (a == '!')
00082 return 30;
00083 if (a == '=')
00084 return 31;
00085
00086 ASSERT(false, "Invalid name: '%c' = %d", a, a);
00087 return 0;
00088 }
00089
00090
00091
00092 class RealPackletHeader : public PackletHeader {
00093 public:
00094 RealPackletHeader(IN word_t& w) { this->setData(w); }
00095 };
00096
00097
00098
00099 static word_t
00100 createPackletHeaderData
00101 (
00102 IN char name,
00103 IN ePackletType type,
00104 IN int size
00105 )
00106 {
00107 if (!isValidPackletName(name)) {
00108 WAVE_EX(wex);
00109 wex << "Invalid packlet name: " << name;
00110 }
00111 if (type < 1 || type > 5) {
00112 WAVE_EX(wex);
00113 wex << "Invalid packlet type: " << type;
00114 }
00115 if (size < 0 || size > 255) {
00116 WAVE_EX(wex);
00117 wex << "Invalid packlet data size: " << size;
00118 }
00119
00120 word_t p;
00121
00122
00123 p = type;
00124 p = p << 5;
00125
00126
00127 int i = getNameIndex(name);
00128 p += (word_t) i;
00129 p = p << 8;
00130
00131
00132 p += (word_t) size;
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144 return p;
00145 }
00146
00147
00148
00149
00150
00151
00152
00153
00154 class OutBuf : public Output {
00155 public:
00156 OutBuf(void) throw();
00157 ~OutBuf(void) throw();
00158
00159
00160 void initialize(IN int size);
00161
00162
00163 void clear(void);
00164 int getRemainingBytes(void) const throw();
00165 void openPacklet(IN char name);
00166 void closePacklet(IN char name);
00167 void addStringPacklet(IN char name,
00168 IN const char * s,
00169 IN int length);
00170 void addFloatPacklet(IN char name,
00171 IN const float * data,
00172 IN int nFloats);
00173 void addInt32Packlet(IN char name,
00174 IN const int32_t * data,
00175 IN int nInt32s);
00176 const byte_t * getData(void) throw();
00177 int getDataBytes(void) const throw() { return m_pos; }
00178
00179 private:
00180 typedef std::vector<byte_t> vec_data_t;
00181 typedef std::vector<char> vec_char_t;
00182
00183
00184 void addPacklet(IN word_t p);
00185
00186
00187 int m_pos;
00188 vec_data_t m_data;
00189 vec_char_t m_packletStack;
00190 int m_size;
00191 };
00192
00193
00194
00195 OutBuf::OutBuf(void)
00196 throw()
00197 {
00198 m_size = 0;
00199 m_pos = -1;
00200 }
00201
00202
00203
00204 OutBuf::~OutBuf(void)
00205 throw()
00206 {
00207 }
00208
00209
00210
00211 void
00212 OutBuf::initialize
00213 (
00214 IN int bytes
00215 )
00216 {
00217 ASSERT(bytes > 0, "Bad byte size: %d", bytes);
00218
00219 ASSERT(!m_size, "Already initialized?");
00220 m_size = bytes;
00221
00222 m_data.resize(bytes);
00223 m_pos = 0;
00224 }
00225
00226
00227
00228 void
00229 OutBuf::clear
00230 (
00231 void
00232 )
00233 {
00234 ASSERT(m_size > 0, "Bad size: %d", m_size);
00235
00236 m_pos = 0;
00237 ASSERT(m_size == this->getRemainingBytes(),
00238 "Should have %d bytes remaining!", m_size);
00239 m_packletStack.clear();
00240 }
00241
00242
00243
00244 int
00245 OutBuf::getRemainingBytes
00246 (
00247 void
00248 )
00249 const
00250 throw()
00251 {
00252 ASSERT(m_pos >= 0, "Bad position: %d", m_pos);
00253 return m_size - m_pos;
00254 }
00255
00256
00257
00258 void
00259 OutBuf::openPacklet
00260 (
00261 IN char name
00262 )
00263 {
00264 word_t p = createPackletHeaderData(name, ePacklet_ParentBegin, 0);
00265 this->addPacklet(p);
00266 m_packletStack.push_back(name);
00267 }
00268
00269
00270
00271 void
00272 OutBuf::closePacklet
00273 (
00274 IN char name
00275 )
00276 {
00277 if (!isValidPackletName(name)) {
00278 WAVE_EX(wex);
00279 wex << "Invalid packlet name: " << name;
00280 }
00281
00282
00283 if (m_packletStack.size() == 0) {
00284 WAVE_EX(wex);
00285 wex << "Cannot close packlet: nothing open! ";
00286 wex << "Attempting to close packlet '" << name << "'";
00287 }
00288
00289 vec_char_t::iterator i = m_packletStack.end();
00290 --i;
00291 char b = *i;
00292 if (b != name) {
00293 WAVE_EX(wex);
00294 wex << "Closing a packlet that isn't open? ";
00295 wex << "Packlet '" << b << "' was opened, but packlet '";
00296 wex << name << "' was closed.";
00297 }
00298
00299
00300 m_packletStack.pop_back();
00301
00302 word_t p = createPackletHeaderData(name, ePacklet_ParentEnd, 0);
00303 this->addPacklet(p);
00304 }
00305
00306
00307
00308 void
00309 OutBuf::addStringPacklet
00310 (
00311 IN char name,
00312 IN const char * s,
00313 IN int length
00314 )
00315 {
00316 word_t p = createPackletHeaderData(name, ePacklet_String, length);
00317 this->addPacklet(p);
00318
00319
00320 ASSERT_THROW(this->getRemainingBytes() >= length,
00321 "Out of room in outbut buffer--cannot add string packlet");
00322
00323 strncpy((char *) (&m_data[0] + m_pos), s, length);
00324 m_pos += length;
00325 }
00326
00327
00328
00329 void
00330 OutBuf::addFloatPacklet
00331 (
00332 IN char name,
00333 IN const float * data,
00334 IN int nFloats
00335 )
00336 {
00337 word_t p = createPackletHeaderData(name, ePacklet_Floats, nFloats);
00338 this->addPacklet(p);
00339
00340
00341 int bytes_needed = nFloats * sizeof(float);
00342 ASSERT_THROW(sizeof(dword_t) == sizeof(float),
00343 "Our encoding assumes long and float are same size!");
00344 ASSERT_THROW(this->getRemainingBytes() >= bytes_needed,
00345 "out of room in output buffer--cannot add float packlet");
00346
00347 for (int i = 0; i < nFloats; ++i) {
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360 dword_t in;
00361 memcpy(&in, data + i, sizeof(dword_t));
00362 dword_t out = htonl(in);
00363
00364 memcpy(&m_data[0] + m_pos, &out, sizeof(dword_t));
00365 m_pos += sizeof(dword_t);
00366 }
00367 }
00368
00369
00370
00371 void
00372 OutBuf::addInt32Packlet
00373 (
00374 IN char name,
00375 IN const int32_t * data,
00376 IN int nInt32s
00377 )
00378 {
00379 word_t p = createPackletHeaderData(name, ePacklet_Int32s, nInt32s);
00380 this->addPacklet(p);
00381
00382
00383 int bytes_needed = nInt32s * sizeof(int32_t);
00384 ASSERT_THROW(this->getRemainingBytes() >= bytes_needed,
00385 "out of room in output buffer--cannot add long packlet");
00386
00387 for (int i = 0; i < nInt32s; ++i) {
00388 dword_t out = htonl(data[i]);
00389 memcpy(&m_data[0] + m_pos, &out, sizeof(dword_t));
00390 m_pos += sizeof(dword_t);
00391 }
00392 }
00393
00394
00395
00396 const byte_t *
00397 OutBuf::getData
00398 (
00399 void
00400 )
00401 throw()
00402 {
00403 if (m_packletStack.size()) {
00404 WAVE_EX(wex);
00405 wex << "Unclosed packlets? Stack is not empty";
00406 }
00407
00408 return &m_data[0];
00409 }
00410
00411
00412
00413 void
00414 OutBuf::addPacklet
00415 (
00416 IN word_t p
00417 )
00418 {
00419
00420 ASSERT_THROW(this->getRemainingBytes() >= 2,
00421 "Out of room in output buffer--cannot add packlet");
00422
00423
00424 word_t w = htons(p);
00425 byte_t * b = (byte_t *) &w;
00426
00427 m_data[m_pos++] = b[0];
00428 m_data[m_pos++] = b[1];
00429 }
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439 class InBuf : public Input {
00440 public:
00441 InBuf(void) throw();
00442 ~InBuf(void) throw();
00443
00444
00445 void initialize(void) { }
00446
00447
00448 void reset(IN const byte_t * stream,
00449 IN int bytes);
00450 bool endOfStream(void);
00451 PackletHeader getNextPackletHeader(void);
00452 void readInt32s(OUT int32_t * buffer, IN int count);
00453 void readFloats(OUT float * buffer, IN int count);
00454 void readString(OUT char * buffer, IN int count);
00455
00456 private:
00457
00458 enum eExpect {
00459 eExpect_Packlet = 1,
00460 eExpect_Data = 2,
00461 eExpect_Invalid = 0
00462 };
00463
00464 int getRemainingBytes(void) const throw() { return m_bytes - m_pos; }
00465
00466
00467 const byte_t * m_stream;
00468 eExpect m_expect;
00469 ePackletType m_type;
00470 int m_pos;
00471 int m_count;
00472 int m_bytes;
00473 };
00474
00475
00476
00477 InBuf::InBuf
00478 (
00479 void
00480 )
00481 throw()
00482 {
00483 m_expect = eExpect_Invalid;
00484 m_bytes = 0;
00485 m_count = -1;
00486 m_type = ePacklet_Invalid;
00487 m_stream = NULL;
00488 m_pos = -1;
00489 }
00490
00491
00492
00493 InBuf::~InBuf
00494 (
00495 void
00496 )
00497 throw()
00498 {
00499 }
00500
00501
00502
00503 void
00504 InBuf::reset
00505 (
00506 IN const byte_t * stream,
00507 IN int bytes
00508 )
00509 {
00510 ASSERT(stream, "null");
00511 ASSERT(bytes > 0, "bad byte count: %d", bytes);
00512
00513 m_stream = stream;
00514 m_bytes = bytes;
00515 m_expect = eExpect_Packlet;
00516 m_type = ePacklet_Invalid;
00517 m_count = -1;
00518 m_pos = 0;
00519 }
00520
00521
00522
00523 bool
00524 InBuf::endOfStream
00525 (
00526 void
00527 )
00528 {
00529 if (!m_stream)
00530 return true;
00531
00532 return (m_pos >= m_bytes);
00533 }
00534
00535
00536
00537 PackletHeader
00538 InBuf::getNextPackletHeader
00539 (
00540 void
00541 )
00542 {
00543 if (eExpect_Packlet != m_expect) {
00544 WAVE_EX(wex);
00545 wex << "Packlet header is not expected";
00546 }
00547 ASSERT_THROW(this->getRemainingBytes() >= 2,
00548 "Not enough data remaining for another packlet header");
00549
00550
00551 word_t * pw = (word_t *) (m_stream + m_pos);
00552 word_t w = ntohs(*pw);
00553 m_pos += 2;
00554
00555
00556 PackletHeader * pph = (PackletHeader *) &w;
00557 PackletHeader ph = *pph;
00558
00559 m_type = ph.getType();
00560 if (ePacklet_Invalid == m_type) {
00561 WAVE_EX(wex);
00562 wex << "Invalid packet type";
00563 }
00564
00565 m_count = ph.getDataCount();
00566 if (ePacklet_ParentBegin == m_type ||
00567 ePacklet_ParentEnd == m_type) {
00568 m_expect = eExpect_Packlet;
00569 } else {
00570 m_expect = eExpect_Data;
00571 }
00572
00573 return ph;
00574 }
00575
00576
00577
00578 void
00579 InBuf::readInt32s
00580 (
00581 OUT int32_t * buffer,
00582 IN int count
00583 )
00584 {
00585 ASSERT(buffer, "null");
00586 ASSERT(count >= 0, "Bad count");
00587
00588 if (eExpect_Data != m_expect || ePacklet_Int32s != m_type) {
00589 WAVE_EX(wex);
00590 wex << "No int32s available for reading!";
00591 }
00592 m_type = ePacklet_Invalid;
00593 m_expect = eExpect_Packlet;
00594
00595 if (count != m_count) {
00596 WAVE_EX(wex);
00597 wex << "Mismatch in packlet/read counts";
00598 }
00599
00600
00601 int bytes_needed = count * sizeof(int32_t);
00602 ASSERT_THROW(this->getRemainingBytes() >= bytes_needed,
00603 "Not enough remaining data for " << count << " longs");
00604
00605 for (int i = 0; i < count; ++i) {
00606 dword_t in = *(dword_t *)(m_stream + m_pos);
00607 m_pos += sizeof(dword_t);
00608 buffer[i] = ntohl(in);
00609 }
00610 }
00611
00612
00613
00614 void
00615 InBuf::readFloats
00616 (
00617 OUT float * buffer,
00618 IN int count
00619 )
00620 {
00621 ASSERT(buffer, "null");
00622 ASSERT(count >= 0, "Bad count");
00623
00624 if (eExpect_Data != m_expect || ePacklet_Floats != m_type) {
00625 WAVE_EX(wex);
00626 wex << "No floats available for reading!";
00627 }
00628 m_type = ePacklet_Invalid;
00629 m_expect = eExpect_Packlet;
00630
00631 if (count != m_count) {
00632 WAVE_EX(wex);
00633 wex << "Mismatch in packlet/read counts";
00634 }
00635
00636
00637 int bytes_needed = count * sizeof(float);
00638 ASSERT_THROW(this->getRemainingBytes() >= bytes_needed,
00639 "Not enough remaining data for " << count << " floats");
00640 ASSERT_THROW(sizeof(float) == sizeof(dword_t),
00641 "Our decoding assumes floats and longs are the same size");
00642
00643 for (int i = 0; i < count; ++i) {
00644
00645 dword_t in;
00646 memcpy(&in, m_stream + m_pos, sizeof(dword_t));
00647 m_pos += sizeof(dword_t);
00648 dword_t out = ntohl(in);
00649 memcpy(buffer + i, &out, sizeof(dword_t));
00650 }
00651 }
00652
00653
00654
00655 void
00656 InBuf::readString
00657 (
00658 OUT char * buffer,
00659 IN int count
00660 )
00661 {
00662 ASSERT(buffer, "null");
00663 ASSERT(count >= 0, "Bad count");
00664
00665 if (eExpect_Data != m_expect || ePacklet_String != m_type) {
00666 WAVE_EX(wex);
00667 wex << "No string availabile for reading!";
00668 }
00669 m_type = ePacklet_Invalid;
00670 m_expect = eExpect_Packlet;
00671
00672 if (count != m_count) {
00673 WAVE_EX(wex);
00674 wex << "Mismatch in packlet/read counts";
00675 }
00676
00677
00678 ASSERT_THROW(this->getRemainingBytes() >= count,
00679 "Not enough remaining data to read string of size " << count);
00680
00681
00682 strncpy(buffer, (const char *) (m_stream + m_pos), count);
00683 m_pos += count;
00684 }
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694 bool
00695 isValidPackletName
00696 (
00697 IN char a
00698 )
00699 {
00700 if (a >= 'a' && a <= 'z')
00701 return true;
00702 if (a == ')' || a == '(')
00703 return true;
00704 if (a == '?' || a == '!')
00705 return true;
00706 if (a == '=')
00707 return true;
00708
00709 return false;
00710 }
00711
00712
00713
00714 char
00715 PackletHeader::getName
00716 (
00717 void
00718 )
00719 const
00720 throw()
00721 {
00722 byte_t b = (byte_t) ((m_data & 0xFF00) >> 8);
00723 int i = b & 0x1F;
00724
00725
00726
00727 if (i <= 0) {
00728 DPRINTF("Null or invalid packet name? %d", i);
00729 return 0;
00730 }
00731
00732 if (i > 31) {
00733 DPRINTF("Index too large? %d", i);
00734 return 0;
00735 }
00736 return s_nameLookup[i];
00737 }
00738
00739
00740
00741 ePackletType
00742 PackletHeader::getType
00743 (
00744 void
00745 )
00746 const
00747 throw()
00748 {
00749 byte_t b = (byte_t) ((m_data & 0xFF00) >> 8);
00750 int i = b & 0xE0;
00751 i = i >> 5;
00752
00753
00754
00755 if (i <= 0) {
00756 DPRINTF("Null or invalid packlet type? %d", i);
00757 return ePacklet_Invalid;
00758 }
00759 if (i >= 6) {
00760 DPRINTF("Invalid packlet type? %d", i);
00761 return ePacklet_Invalid;
00762 }
00763 return (ePackletType) i;
00764 }
00765
00766
00767
00768 int
00769 PackletHeader::getDataCount
00770 (
00771 void
00772 )
00773 const
00774 throw()
00775 {
00776 byte_t b = (byte_t) (m_data & 0x00FF);
00777
00778
00779
00780 return (int) b;
00781 }
00782
00783
00784
00785 smart_ptr<Output>
00786 Output::create
00787 (
00788 IN int bytes
00789 )
00790 {
00791 ASSERT(bytes > 0, "Bad byte count: %d", bytes);
00792
00793 smart_ptr<OutBuf> local = new OutBuf;
00794 ASSERT(local, "out of memory");
00795
00796 local->initialize(bytes);
00797
00798 return local;
00799 }
00800
00801
00802
00803 smart_ptr<Input>
00804 Input::create
00805 (
00806 void
00807 )
00808 {
00809 smart_ptr<InBuf> local = new InBuf;
00810 ASSERT(local, "out of memory");
00811
00812 local->initialize();
00813
00814 return local;
00815 }
00816
00817
00818
00819 };
00820