Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members

CProtocolUtil.cpp

00001 /*
00002  * synergy -- mouse and keyboard sharing utility
00003  * Copyright (C) 2002 Chris Schoeneman
00004  * 
00005  * This package is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU General Public License
00007  * found in the file COPYING that should have accompanied this file.
00008  * 
00009  * This package is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
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 // CProtocolUtil
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     // done if nothing to write
00071     if (size == 0) {
00072         return;
00073     }
00074 
00075     // fill buffer
00076     UInt8* buffer = new UInt8[size];
00077     writef(buffer, fmt, args);
00078 
00079     try {
00080         // write buffer
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     // begin scanning
00099     while (*fmt) {
00100         if (*fmt == '%') {
00101             // format specifier.  determine argument size.
00102             ++fmt;
00103             UInt32 len = eatLength(&fmt);
00104             switch (*fmt) {
00105             case 'i': {
00106                 // check for valid length
00107                 assert(len == 1 || len == 2 || len == 4);
00108 
00109                 // read the data
00110                 UInt8 buffer[4];
00111                 read(stream, buffer, len);
00112 
00113                 // convert it
00114                 void* v = va_arg(args, void*);
00115                 switch (len) {
00116                 case 1:
00117                     // 1 byte integer
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                     // 2 byte integer
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                     // 4 byte integer
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                 // check for valid length
00146                 assert(len == 1 || len == 2 || len == 4);
00147 
00148                 // read the vector length
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                 // convert it
00157                 void* v = va_arg(args, void*);
00158                 switch (len) {
00159                 case 1:
00160                     // 1 byte integer
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                     // 2 byte integer
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                     // 4 byte integer
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                 // read the string length
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                 // use a fixed size buffer if its big enough
00209                 const bool useFixed = (len <= sizeof(buffer));
00210 
00211                 // allocate a buffer to read the data
00212                 UInt8* sBuffer = buffer;
00213                 if (!useFixed) {
00214                     sBuffer = new UInt8[len];
00215                 }
00216 
00217                 // read the data
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                 // save the data
00230                 CString* dst = va_arg(args, CString*);
00231                 dst->assign((const char*)sBuffer, len);
00232 
00233                 // release the buffer
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             // next format character
00249             ++fmt;
00250         }
00251         else {
00252             // read next character
00253             char buffer[1];
00254             read(stream, buffer, 1);
00255 
00256             // verify match
00257             if (buffer[0] != *fmt) {
00258                 LOG((CLOG_DEBUG2 "readf: format mismatch: %c vs %c", *fmt, buffer[0]));
00259                 throw XIOReadMismatch();
00260             }
00261 
00262             // next format character
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             // format specifier.  determine argument size.
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             // accumulate size
00322             n += len;
00323             ++fmt;
00324         }
00325         else {
00326             // regular character
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             // format specifier.  determine argument size.
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                     // 1 byte integer
00350                     *dst++ = static_cast<UInt8>(v & 0xff);
00351                     break;
00352 
00353                 case 2:
00354                     // 2 byte integer
00355                     *dst++ = static_cast<UInt8>((v >> 8) & 0xff);
00356                     *dst++ = static_cast<UInt8>( v       & 0xff);
00357                     break;
00358 
00359                 case 4:
00360                     // 4 byte integer
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                     // 1 byte integers
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                     // 2 byte integers
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                     // 4 byte integers
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             // next format character
00472             ++fmt;
00473         }
00474         else {
00475             // copy regular character
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         // read more
00515         UInt32 n = stream->read(buffer, count);
00516 
00517         // bail if stream has hungup
00518         if (n == 0) {
00519             LOG((CLOG_DEBUG2 "unexpected disconnect in readf(), %d bytes left", count));
00520             throw XIOEndOfStream();
00521         }
00522 
00523         // prepare for next read
00524         buffer += n;
00525         count  -= n;
00526     }
00527 }
00528 
00529 
00530 //
00531 // XIOReadMismatch
00532 //
00533 
00534 CString
00535 XIOReadMismatch::getWhat() const throw()
00536 {
00537     return format("XIOReadMismatch", "CProtocolUtil::readf() mismatch");
00538 }

Generated on Fri Nov 6 00:21:14 2009 for synergy-plus by  doxygen 1.3.9.1