00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "CProtocolUtil.h"
00016 #include "IStream.h"
00017 #include "CLog.h"
00018 #include "stdvector.h"
00019 #include <cctype>
00020 #include <cstring>
00021
00022
00023
00024
00025
00026 void
00027 CProtocolUtil::writef(IStream* stream, const char* fmt, ...)
00028 {
00029 assert(stream != NULL);
00030 assert(fmt != NULL);
00031 LOG((CLOG_DEBUG2 "writef(%s)", fmt));
00032
00033 va_list args;
00034 va_start(args, fmt);
00035 UInt32 size = getLength(fmt, args);
00036 va_end(args);
00037 va_start(args, fmt);
00038 vwritef(stream, fmt, size, args);
00039 va_end(args);
00040 }
00041
00042 bool
00043 CProtocolUtil::readf(IStream* stream, const char* fmt, ...)
00044 {
00045 assert(stream != NULL);
00046 assert(fmt != NULL);
00047 LOG((CLOG_DEBUG2 "readf(%s)", fmt));
00048
00049 bool result;
00050 va_list args;
00051 va_start(args, fmt);
00052 try {
00053 vreadf(stream, fmt, args);
00054 result = true;
00055 }
00056 catch (XIO&) {
00057 result = false;
00058 }
00059 va_end(args);
00060 return result;
00061 }
00062
00063 void
00064 CProtocolUtil::vwritef(IStream* stream,
00065 const char* fmt, UInt32 size, va_list args)
00066 {
00067 assert(stream != NULL);
00068 assert(fmt != NULL);
00069
00070
00071 if (size == 0) {
00072 return;
00073 }
00074
00075
00076 UInt8* buffer = new UInt8[size];
00077 writef(buffer, fmt, args);
00078
00079 try {
00080
00081 stream->write(buffer, size);
00082 LOG((CLOG_DEBUG2 "wrote %d bytes", size));
00083
00084 delete[] buffer;
00085 }
00086 catch (XBase&) {
00087 delete[] buffer;
00088 throw;
00089 }
00090 }
00091
00092 void
00093 CProtocolUtil::vreadf(IStream* stream, const char* fmt, va_list args)
00094 {
00095 assert(stream != NULL);
00096 assert(fmt != NULL);
00097
00098
00099 while (*fmt) {
00100 if (*fmt == '%') {
00101
00102 ++fmt;
00103 UInt32 len = eatLength(&fmt);
00104 switch (*fmt) {
00105 case 'i': {
00106
00107 assert(len == 1 || len == 2 || len == 4);
00108
00109
00110 UInt8 buffer[4];
00111 read(stream, buffer, len);
00112
00113
00114 void* v = va_arg(args, void*);
00115 switch (len) {
00116 case 1:
00117
00118 *reinterpret_cast<UInt8*>(v) = buffer[0];
00119 LOG((CLOG_DEBUG2 "readf: read %d byte integer: %d (0x%x)", len, *reinterpret_cast<UInt8*>(v), *reinterpret_cast<UInt8*>(v)));
00120 break;
00121
00122 case 2:
00123
00124 *reinterpret_cast<UInt16*>(v) =
00125 static_cast<UInt16>(
00126 (static_cast<UInt16>(buffer[0]) << 8) |
00127 static_cast<UInt16>(buffer[1]));
00128 LOG((CLOG_DEBUG2 "readf: read %d byte integer: %d (0x%x)", len, *reinterpret_cast<UInt16*>(v), *reinterpret_cast<UInt16*>(v)));
00129 break;
00130
00131 case 4:
00132
00133 *reinterpret_cast<UInt32*>(v) =
00134 (static_cast<UInt32>(buffer[0]) << 24) |
00135 (static_cast<UInt32>(buffer[1]) << 16) |
00136 (static_cast<UInt32>(buffer[2]) << 8) |
00137 static_cast<UInt32>(buffer[3]);
00138 LOG((CLOG_DEBUG2 "readf: read %d byte integer: %d (0x%x)", len, *reinterpret_cast<UInt32*>(v), *reinterpret_cast<UInt32*>(v)));
00139 break;
00140 }
00141 break;
00142 }
00143
00144 case 'I': {
00145
00146 assert(len == 1 || len == 2 || len == 4);
00147
00148
00149 UInt8 buffer[4];
00150 read(stream, buffer, 4);
00151 UInt32 n = (static_cast<UInt32>(buffer[0]) << 24) |
00152 (static_cast<UInt32>(buffer[1]) << 16) |
00153 (static_cast<UInt32>(buffer[2]) << 8) |
00154 static_cast<UInt32>(buffer[3]);
00155
00156
00157 void* v = va_arg(args, void*);
00158 switch (len) {
00159 case 1:
00160
00161 for (UInt32 i = 0; i < n; ++i) {
00162 read(stream, buffer, 1);
00163 reinterpret_cast<std::vector<UInt8>*>(v)->push_back(
00164 buffer[0]);
00165 LOG((CLOG_DEBUG2 "readf: read %d byte integer[%d]: %d (0x%x)", len, i, reinterpret_cast<std::vector<UInt8>*>(v)->back(), reinterpret_cast<std::vector<UInt8>*>(v)->back()));
00166 }
00167 break;
00168
00169 case 2:
00170
00171 for (UInt32 i = 0; i < n; ++i) {
00172 read(stream, buffer, 2);
00173 reinterpret_cast<std::vector<UInt16>*>(v)->push_back(
00174 static_cast<UInt16>(
00175 (static_cast<UInt16>(buffer[0]) << 8) |
00176 static_cast<UInt16>(buffer[1])));
00177 LOG((CLOG_DEBUG2 "readf: read %d byte integer[%d]: %d (0x%x)", len, i, reinterpret_cast<std::vector<UInt16>*>(v)->back(), reinterpret_cast<std::vector<UInt16>*>(v)->back()));
00178 }
00179 break;
00180
00181 case 4:
00182
00183 for (UInt32 i = 0; i < n; ++i) {
00184 read(stream, buffer, 4);
00185 reinterpret_cast<std::vector<UInt32>*>(v)->push_back(
00186 (static_cast<UInt32>(buffer[0]) << 24) |
00187 (static_cast<UInt32>(buffer[1]) << 16) |
00188 (static_cast<UInt32>(buffer[2]) << 8) |
00189 static_cast<UInt32>(buffer[3]));
00190 LOG((CLOG_DEBUG2 "readf: read %d byte integer[%d]: %d (0x%x)", len, i, reinterpret_cast<std::vector<UInt32>*>(v)->back(), reinterpret_cast<std::vector<UInt32>*>(v)->back()));
00191 }
00192 break;
00193 }
00194 break;
00195 }
00196
00197 case 's': {
00198 assert(len == 0);
00199
00200
00201 UInt8 buffer[128];
00202 read(stream, buffer, 4);
00203 UInt32 len = (static_cast<UInt32>(buffer[0]) << 24) |
00204 (static_cast<UInt32>(buffer[1]) << 16) |
00205 (static_cast<UInt32>(buffer[2]) << 8) |
00206 static_cast<UInt32>(buffer[3]);
00207
00208
00209 const bool useFixed = (len <= sizeof(buffer));
00210
00211
00212 UInt8* sBuffer = buffer;
00213 if (!useFixed) {
00214 sBuffer = new UInt8[len];
00215 }
00216
00217
00218 try {
00219 read(stream, sBuffer, len);
00220 }
00221 catch (...) {
00222 if (!useFixed) {
00223 delete[] sBuffer;
00224 }
00225 throw;
00226 }
00227 LOG((CLOG_DEBUG2 "readf: read %d byte string: %.*s", len, len, sBuffer));
00228
00229
00230 CString* dst = va_arg(args, CString*);
00231 dst->assign((const char*)sBuffer, len);
00232
00233
00234 if (!useFixed) {
00235 delete[] sBuffer;
00236 }
00237 break;
00238 }
00239
00240 case '%':
00241 assert(len == 0);
00242 break;
00243
00244 default:
00245 assert(0 && "invalid format specifier");
00246 }
00247
00248
00249 ++fmt;
00250 }
00251 else {
00252
00253 char buffer[1];
00254 read(stream, buffer, 1);
00255
00256
00257 if (buffer[0] != *fmt) {
00258 LOG((CLOG_DEBUG2 "readf: format mismatch: %c vs %c", *fmt, buffer[0]));
00259 throw XIOReadMismatch();
00260 }
00261
00262
00263 ++fmt;
00264 }
00265 }
00266 }
00267
00268 UInt32
00269 CProtocolUtil::getLength(const char* fmt, va_list args)
00270 {
00271 UInt32 n = 0;
00272 while (*fmt) {
00273 if (*fmt == '%') {
00274
00275 ++fmt;
00276 UInt32 len = eatLength(&fmt);
00277 switch (*fmt) {
00278 case 'i':
00279 assert(len == 1 || len == 2 || len == 4);
00280 (void)va_arg(args, UInt32);
00281 break;
00282
00283 case 'I':
00284 assert(len == 1 || len == 2 || len == 4);
00285 switch (len) {
00286 case 1:
00287 len = (va_arg(args, std::vector<UInt8>*))->size() + 4;
00288 break;
00289
00290 case 2:
00291 len = 2 * (va_arg(args, std::vector<UInt16>*))->size() + 4;
00292 break;
00293
00294 case 4:
00295 len = 4 * (va_arg(args, std::vector<UInt32>*))->size() + 4;
00296 break;
00297 }
00298 break;
00299
00300 case 's':
00301 assert(len == 0);
00302 len = (va_arg(args, CString*))->size() + 4;
00303 (void)va_arg(args, UInt8*);
00304 break;
00305
00306 case 'S':
00307 assert(len == 0);
00308 len = va_arg(args, UInt32) + 4;
00309 (void)va_arg(args, UInt8*);
00310 break;
00311
00312 case '%':
00313 assert(len == 0);
00314 len = 1;
00315 break;
00316
00317 default:
00318 assert(0 && "invalid format specifier");
00319 }
00320
00321
00322 n += len;
00323 ++fmt;
00324 }
00325 else {
00326
00327 ++n;
00328 ++fmt;
00329 }
00330 }
00331 return n;
00332 }
00333
00334 void
00335 CProtocolUtil::writef(void* buffer, const char* fmt, va_list args)
00336 {
00337 UInt8* dst = reinterpret_cast<UInt8*>(buffer);
00338
00339 while (*fmt) {
00340 if (*fmt == '%') {
00341
00342 ++fmt;
00343 UInt32 len = eatLength(&fmt);
00344 switch (*fmt) {
00345 case 'i': {
00346 const UInt32 v = va_arg(args, UInt32);
00347 switch (len) {
00348 case 1:
00349
00350 *dst++ = static_cast<UInt8>(v & 0xff);
00351 break;
00352
00353 case 2:
00354
00355 *dst++ = static_cast<UInt8>((v >> 8) & 0xff);
00356 *dst++ = static_cast<UInt8>( v & 0xff);
00357 break;
00358
00359 case 4:
00360
00361 *dst++ = static_cast<UInt8>((v >> 24) & 0xff);
00362 *dst++ = static_cast<UInt8>((v >> 16) & 0xff);
00363 *dst++ = static_cast<UInt8>((v >> 8) & 0xff);
00364 *dst++ = static_cast<UInt8>( v & 0xff);
00365 break;
00366
00367 default:
00368 assert(0 && "invalid integer format length");
00369 return;
00370 }
00371 break;
00372 }
00373
00374 case 'I': {
00375 switch (len) {
00376 case 1: {
00377
00378 const std::vector<UInt8>* list =
00379 va_arg(args, const std::vector<UInt8>*);
00380 const UInt32 n = list->size();
00381 *dst++ = static_cast<UInt8>((n >> 24) & 0xff);
00382 *dst++ = static_cast<UInt8>((n >> 16) & 0xff);
00383 *dst++ = static_cast<UInt8>((n >> 8) & 0xff);
00384 *dst++ = static_cast<UInt8>( n & 0xff);
00385 for (UInt32 i = 0; i < n; ++i) {
00386 *dst++ = (*list)[i];
00387 }
00388 break;
00389 }
00390
00391 case 2: {
00392
00393 const std::vector<UInt16>* list =
00394 va_arg(args, const std::vector<UInt16>*);
00395 const UInt32 n = list->size();
00396 *dst++ = static_cast<UInt8>((n >> 24) & 0xff);
00397 *dst++ = static_cast<UInt8>((n >> 16) & 0xff);
00398 *dst++ = static_cast<UInt8>((n >> 8) & 0xff);
00399 *dst++ = static_cast<UInt8>( n & 0xff);
00400 for (UInt32 i = 0; i < n; ++i) {
00401 const UInt16 v = (*list)[i];
00402 *dst++ = static_cast<UInt8>((v >> 8) & 0xff);
00403 *dst++ = static_cast<UInt8>( v & 0xff);
00404 }
00405 break;
00406 }
00407
00408 case 4: {
00409
00410 const std::vector<UInt32>* list =
00411 va_arg(args, const std::vector<UInt32>*);
00412 const UInt32 n = list->size();
00413 *dst++ = static_cast<UInt8>((n >> 24) & 0xff);
00414 *dst++ = static_cast<UInt8>((n >> 16) & 0xff);
00415 *dst++ = static_cast<UInt8>((n >> 8) & 0xff);
00416 *dst++ = static_cast<UInt8>( n & 0xff);
00417 for (UInt32 i = 0; i < n; ++i) {
00418 const UInt32 v = (*list)[i];
00419 *dst++ = static_cast<UInt8>((v >> 24) & 0xff);
00420 *dst++ = static_cast<UInt8>((v >> 16) & 0xff);
00421 *dst++ = static_cast<UInt8>((v >> 8) & 0xff);
00422 *dst++ = static_cast<UInt8>( v & 0xff);
00423 }
00424 break;
00425 }
00426
00427 default:
00428 assert(0 && "invalid integer vector format length");
00429 return;
00430 }
00431 break;
00432 }
00433
00434 case 's': {
00435 assert(len == 0);
00436 const CString* src = va_arg(args, CString*);
00437 const UInt32 len = (src != NULL) ? src->size() : 0;
00438 *dst++ = static_cast<UInt8>((len >> 24) & 0xff);
00439 *dst++ = static_cast<UInt8>((len >> 16) & 0xff);
00440 *dst++ = static_cast<UInt8>((len >> 8) & 0xff);
00441 *dst++ = static_cast<UInt8>( len & 0xff);
00442 if (len != 0) {
00443 memcpy(dst, src->data(), len);
00444 dst += len;
00445 }
00446 break;
00447 }
00448
00449 case 'S': {
00450 assert(len == 0);
00451 const UInt32 len = va_arg(args, UInt32);
00452 const UInt8* src = va_arg(args, UInt8*);
00453 *dst++ = static_cast<UInt8>((len >> 24) & 0xff);
00454 *dst++ = static_cast<UInt8>((len >> 16) & 0xff);
00455 *dst++ = static_cast<UInt8>((len >> 8) & 0xff);
00456 *dst++ = static_cast<UInt8>( len & 0xff);
00457 memcpy(dst, src, len);
00458 dst += len;
00459 break;
00460 }
00461
00462 case '%':
00463 assert(len == 0);
00464 *dst++ = '%';
00465 break;
00466
00467 default:
00468 assert(0 && "invalid format specifier");
00469 }
00470
00471
00472 ++fmt;
00473 }
00474 else {
00475
00476 *dst++ = *fmt++;
00477 }
00478 }
00479 }
00480
00481 UInt32
00482 CProtocolUtil::eatLength(const char** pfmt)
00483 {
00484 const char* fmt = *pfmt;
00485 UInt32 n = 0;
00486 for (;;) {
00487 UInt32 d;
00488 switch (*fmt) {
00489 case '0': d = 0; break;
00490 case '1': d = 1; break;
00491 case '2': d = 2; break;
00492 case '3': d = 3; break;
00493 case '4': d = 4; break;
00494 case '5': d = 5; break;
00495 case '6': d = 6; break;
00496 case '7': d = 7; break;
00497 case '8': d = 8; break;
00498 case '9': d = 9; break;
00499 default: *pfmt = fmt; return n;
00500 }
00501 n = 10 * n + d;
00502 ++fmt;
00503 }
00504 }
00505
00506 void
00507 CProtocolUtil::read(IStream* stream, void* vbuffer, UInt32 count)
00508 {
00509 assert(stream != NULL);
00510 assert(vbuffer != NULL);
00511
00512 UInt8* buffer = reinterpret_cast<UInt8*>(vbuffer);
00513 while (count > 0) {
00514
00515 UInt32 n = stream->read(buffer, count);
00516
00517
00518 if (n == 0) {
00519 LOG((CLOG_DEBUG2 "unexpected disconnect in readf(), %d bytes left", count));
00520 throw XIOEndOfStream();
00521 }
00522
00523
00524 buffer += n;
00525 count -= n;
00526 }
00527 }
00528
00529
00530
00531
00532
00533
00534 CString
00535 XIOReadMismatch::getWhat() const throw()
00536 {
00537 return format("XIOReadMismatch", "CProtocolUtil::readf() mismatch");
00538 }