• Main Page
  • Classes
  • Files
  • File List

CProtocolUtil.cpp

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

Generated on Mon May 20 2013 00:00:05 for Synergy by  doxygen 1.7.1