ValueToString.cpp
上传用户:xqtpzdz
上传日期:2022-05-21
资源大小:1764k
文件大小:15k
源码类别:

xml/soap/webservice

开发平台:

Visual C++

  1. /****************License************************************************
  2.  * Vocalocity OpenVXI
  3.  * Copyright (C) 2004-2005 by Vocalocity, Inc. All Rights Reserved.
  4.  * This program is free software; you can redistribute it and/or
  5.  * modify it under the terms of the GNU General Public License
  6.  * as published by the Free Software Foundation; either version 2
  7.  * of the License, or (at your option) any later version.
  8.  *  
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  17.  * Vocalocity, the Vocalocity logo, and VocalOS are trademarks or 
  18.  * registered trademarks of Vocalocity, Inc. 
  19.  * OpenVXI is a trademark of Scansoft, Inc. and used under license 
  20.  * by Vocalocity.
  21.  ***********************************************************************/
  22. #define VXIVALUE_EXPORTS
  23. #include "VXIvalue.h"                    // Header for this function
  24. #ifndef NO_STL
  25. #include <stdio.h>                       // For sprintf( )
  26. #include <string.h>                      // For strlen( )
  27. #include <wchar.h>
  28. #include <string>                        // For std::basic_string
  29. #include <vector>
  30. #include <iostream>
  31. #ifdef WIN32
  32. #define WIN32_LEAN_AND_MEAN
  33. #include <windows.h>
  34. static inline char GetDecimalSeparator( ) {
  35.   // Get the locale dependant decimal separator using a Win32 API call
  36.   char sepBuf[32];
  37.   return (GetLocaleInfoA (LOCALE_USER_DEFAULT, LOCALE_SDECIMAL,
  38.   sepBuf, 32) > 0 ? sepBuf[0] : '');
  39. }
  40. #else
  41. #include <locale.h>
  42. static inline char GetDecimalSeparator( ) {
  43.   // Get the locale dependant decimal separator using a POSIX call
  44.   struct lconv *info = localeconv( );
  45.   return (info ? info->decimal_point[0] : '');
  46. }
  47. #endif
  48. // Definitions of VXIchar based C++ string types
  49. typedef std::basic_string<VXIchar> myString;
  50. #ifdef WIN32
  51. typedef std::basic_string<VXIbyte> myUTF8String;
  52. #else
  53. // Portability: stl on UNIX is not always portable, therefore using
  54. // std::basic_string<unsigned char> is not always compiled and linked.
  55. // The simple solution for this issue is to represent unsigned char string 
  56. // as a vector
  57. typedef std::vector<VXIbyte> myUTF8String;
  58. #endif
  59. // Prototypes for local functions
  60. static void appendValue(myString &result,
  61. const VXIValue *value,
  62. const VXIchar *fieldName);
  63. // These functions ensure that the string has enough capacity to hold the extra characters.
  64. // To ensure amortized linear time, we reserve twice as many bytes as required.
  65. template <class T> static void ensureCapacity(std::basic_string<T>& buffer,
  66.                                               typename std::basic_string<T>::size_type extraChars)
  67. {
  68.   typename std::basic_string<T>::size_type requiredCapacity = buffer.length() + extraChars;
  69.   if (requiredCapacity > buffer.capacity())
  70.   {
  71.     buffer.reserve(2 * requiredCapacity);
  72.   }
  73. }
  74. #ifndef WIN32
  75. static void ensureCapacity(myUTF8String& buffer, unsigned int extraChars)
  76. {
  77.   unsigned int requiredCapacity = buffer.size() + extraChars;
  78.   if (requiredCapacity > buffer.capacity())
  79.   {
  80.     buffer.reserve(2 * requiredCapacity);
  81.   }
  82. }
  83. #endif
  84. //
  85. // VXIchar string to Unicode UTF-8 string conversion
  86. //
  87. static bool convertToUTF8(const VXIchar *input,
  88.   myUTF8String &output)
  89. {
  90.   //  firstByteMark
  91.   //      A list of values to mask onto the first byte of an encoded sequence,
  92.   //      indexed by the number of bytes used to create the sequence.
  93.   static const char firstByteMark[7] =
  94.     {  char(0x00), char(0x00), char(0xC0), char(0xE0),
  95.        char(0xF0), char(0xF8), char(0xFC) };
  96.   //  Get pointers to our start and end points of the input buffer.
  97.   const VXIchar* srcPtr = input;
  98.   const VXIchar* srcEnd = srcPtr + wcslen(input);
  99.   output.resize (0);
  100.   while (srcPtr < srcEnd) {
  101.     VXIchar curVal = *srcPtr++;
  102.     // Watchout for surrogates, if found truncate
  103.     if ((curVal >= 0xD800) && (curVal <= 0xDBFF)) {
  104.       break;
  105.     }
  106.     // Figure out how many bytes we need
  107.     unsigned int encodedBytes;
  108.     if (curVal < 0x80)                encodedBytes = 1;
  109.     else if (curVal < 0x800)          encodedBytes = 2;
  110.     else if (curVal < 0x10000)        encodedBytes = 3;
  111.     else if (curVal < 0x200000)       encodedBytes = 4;
  112.     else if (curVal < 0x4000000)      encodedBytes = 5;
  113.     else if (curVal <= 0x7FFFFFFF)    encodedBytes = 6;
  114.     else {
  115.       // THIS SHOULD NOT HAPPEN!
  116.       return false;
  117.     }
  118.     //  And spit out the bytes. We spit them out in reverse order
  119.     //  here, so bump up the output pointer and work down as we go.
  120.     char buffer[7] = { 0, 0, 0, 0, 0, 0, 0 };
  121.     char * outPtr = buffer + encodedBytes;
  122.     switch(encodedBytes) {
  123.     case 6 : *--outPtr = char((curVal | 0x80) & 0xBF);
  124.       curVal >>= 6;
  125.     case 5 : *--outPtr = char((curVal | 0x80) & 0xBF);
  126.       curVal >>= 6;
  127.     case 4 : *--outPtr = char((curVal | 0x80) & 0xBF);
  128.       curVal >>= 6;
  129.     case 3 : *--outPtr = char((curVal | 0x80) & 0xBF);
  130.       curVal >>= 6;
  131.     case 2 : *--outPtr = char((curVal | 0x80) & 0xBF);
  132.       curVal >>= 6;
  133.     case 1 : *--outPtr = char(curVal | firstByteMark[encodedBytes]);
  134.     }
  135.     ensureCapacity(output, encodedBytes);
  136.     for (int i = 0; buffer[i] != 0; i++)
  137.     {
  138. #ifdef WIN32
  139.       output += buffer[i];
  140. #else
  141.       output.push_back( buffer[i] );
  142. #endif      
  143.     }
  144.   }
  145.   return true;
  146. }
  147. //
  148. // Append escaped binary data
  149. //
  150. static void appendEscapedData(myString &result,
  151.       const VXIbyte *data,
  152.       VXIulong size)
  153. {
  154.   static const unsigned char isAcceptable[96] =
  155.     /*0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xA 0xB 0xC 0xD 0xE 0xF */
  156.     {
  157.       /* 2x  !"#$%&'()*+,-./   */
  158.       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xF,0xE,0x0,0xF,0xF,0xC,
  159.       /* 3x 0123456789:;<=>?   */
  160.       0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0x8,0x0,0x0,0x0,0x0,0x0,
  161.       /* 4x @ABCDEFGHIJKLMNO   */
  162.       0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,
  163.       /* 5X PQRSTUVWXYZ[]^_   */
  164.       0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0x0,0x0,0x0,0x0,0xF,
  165.       /* 6x `abcdefghijklmno   */
  166.       0x0,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,
  167.       /* 7X pqrstuvwxyz{}~DEL */
  168.       0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF,0x0,0x0,0x0,0x0,0x0
  169.     };
  170.   static const VXIchar *hexChar = L"0123456789ABCDEF";
  171.   static const int mask = 0x1;
  172.   if ( ! data)
  173.     return;
  174.   VXIulong i;
  175.   const VXIbyte *p;
  176.   for (i = 0, p = data; i < size; i++, p++)
  177.   {
  178.     VXIbyte a = *p;
  179.     if (a < 32 || a >= 128 || !(isAcceptable[a-32] & mask))
  180.     {
  181.       ensureCapacity(result, 3);
  182.       result += '%';
  183.       result += hexChar[a >> 4];
  184.       result += hexChar[a & 15];
  185.     }
  186.     else
  187.     {
  188.       ensureCapacity(result, 1);
  189.       result += *p;
  190.     }
  191.   }
  192. }
  193. //
  194. // Append a string. Resulting byte sequence is a URL encoded Unicode
  195. // UTF-8 string, meaning that the ASCII character set appears as
  196. // normally done for URL encoded data, and any Latin-1 or Unicode
  197. // characters will be translated into a URL encoded UTF-8 byte
  198. // sequence where each character consumes 2 to 18 bytes (2 or more
  199. // bytes in the UTF-8 representation where each of those bytes is
  200. // encoded as 1 to 3 bytes depending on whether they need to get
  201. // escaped for URL encoding).
  202. //
  203. static void appendEscapedString(myString &result,
  204. const VXIchar *str)
  205. {
  206.   if (!str)
  207.     return;
  208.   // Convert to UTF-8
  209.   myUTF8String utf8;
  210.   utf8.reserve (wcslen(str) * 4); // For efficiency, pre-allocate buffer
  211.   if (! convertToUTF8 (str, utf8))
  212.     return;
  213.     
  214.   // Now URL encode the bytes
  215. #ifdef WIN32
  216.   appendEscapedData (result, utf8.c_str(), utf8.length());
  217. #else
  218.   appendEscapedData (result, &utf8[0], utf8.size());  
  219. #endif
  220. }
  221. static void appendKeyValuePair(myString &result,
  222.        const VXIchar *key,
  223.        const VXIchar *value)
  224. {
  225.   if ((key) && (value) && (*key))
  226.   {
  227.     if (result.length() > 0)
  228.     {
  229.       ensureCapacity(result, 1);
  230.       result += L'&';
  231.     }
  232.     appendEscapedString(result, key);
  233.     ensureCapacity(result, 1);
  234.     result += L'=';
  235.     if (*value)
  236.       appendEscapedString(result, value);
  237.   }
  238. }
  239. static void appendKeyValuePair(myString &result,
  240.        const VXIchar *key,
  241.        char *value)
  242. {
  243.   if ((key) && (value) && (*key))
  244.   {
  245.     if (result.length() > 0)
  246.     {
  247.       ensureCapacity(result, 1);
  248.       result += L'&';
  249.     }
  250.     appendEscapedString(result, key);
  251.     ensureCapacity(result, 1);
  252.     result += L'=';
  253.     
  254.     if (*value)
  255.       appendEscapedData (result,
  256.  reinterpret_cast<const unsigned char *>(value),
  257.  strlen(value));
  258.   }
  259. }
  260. static void appendVector(myString &result,
  261.  const VXIVector *vxivector,
  262.  const VXIchar *fieldName)
  263. {
  264.   const VXIValue *value = NULL;
  265.   VXIunsigned vectorLen = VXIVectorLength(vxivector);
  266.   VXIunsigned i;
  267.   for (i = 0; i < vectorLen; i++)
  268.   {
  269.     value = VXIVectorGetElement(vxivector, i);
  270.     if ( value )
  271.     {
  272.       // sprintf( ) is more portable then swprintf( )
  273.       char intStr[64];
  274.       sprintf(intStr, "%d", i);
  275.       myString fieldNameWithIndex(fieldName);
  276.       if (! fieldNameWithIndex.empty())
  277.         fieldNameWithIndex += L'.';
  278.       for (const char *ptr = intStr; *ptr; ptr++)
  279.         fieldNameWithIndex += static_cast<VXIchar>(*ptr);
  280.       appendValue(result, value, fieldNameWithIndex.c_str());
  281.     }
  282.   }
  283. }
  284. static void appendMap(myString &result,
  285.       const VXIMap *vximap,
  286.       const VXIchar *fieldName)
  287. {
  288.   const VXIchar  *key = NULL;
  289.   const VXIValue *value = NULL;
  290.   VXIMapIterator *mapIterator = VXIMapGetFirstProperty(vximap, &key, &value);
  291.   do
  292.   {
  293.     if ((key) && (value))
  294.     {
  295.       myString fieldNameWithIndex (fieldName);
  296.       if (! fieldNameWithIndex.empty())
  297.         fieldNameWithIndex += L'.';
  298.       fieldNameWithIndex += key;
  299.       appendValue(result, value, fieldNameWithIndex.c_str());
  300.     }
  301.   } while (VXIMapGetNextProperty(mapIterator, &key, &value) ==
  302.            VXIvalue_RESULT_SUCCESS);
  303.   VXIMapIteratorDestroy(&mapIterator);
  304. }
  305. static void appendContent(myString &result,
  306.   const VXIContent *vxicontent,
  307.   const VXIchar *fieldName)
  308. {
  309.   const VXIchar *type;
  310.   const VXIbyte *data;
  311.   VXIulong size;
  312.   VXIContentValue(vxicontent, &type, &data, &size);
  313.   if (result.length() > 0)
  314.     result += L'&';
  315.   appendEscapedString(result, fieldName);
  316.   ensureCapacity(result, 1);
  317.   result += L'=';
  318.   appendEscapedData(result, data, size);
  319. }
  320. static void appendValue(myString &result,
  321. const VXIValue *value,
  322. const VXIchar *fieldName)
  323. {
  324.   char valueStr[128];
  325.   
  326.   switch (VXIValueGetType(value)) {
  327.   case VALUE_MAP:
  328.     // nested object
  329.     // append the object name to the field name prefix
  330.     appendMap(result, (const VXIMap *) value, fieldName);
  331.     break;
  332.   case VALUE_VECTOR:
  333.     // nested vector
  334.     // append the vector name to the field name prefix
  335.     appendVector(result, (const VXIVector *) value, fieldName);
  336.     break;
  337.   case VALUE_CONTENT:
  338.     appendContent(result, (const VXIContent *) value, fieldName);
  339.     break;
  340.   case VALUE_BOOLEAN:
  341.     if (VXIBooleanValue((const VXIBoolean *) value) == TRUE)
  342.       appendKeyValuePair(result, fieldName, L"true");
  343.     else
  344.       appendKeyValuePair(result, fieldName, L"false");
  345.     break;
  346.   case VALUE_INTEGER:
  347.     // sprintf( ) is more portable then swprintf( )
  348.     sprintf(valueStr, "%d", VXIIntegerValue((const VXIInteger *) value));
  349.     appendKeyValuePair(result, fieldName, valueStr);
  350.     break;
  351.   case VALUE_ULONG:
  352.     // sprintf( ) is more portable then swprintf( )
  353.     sprintf(valueStr, "%u", VXIULongValue((const VXIULong *) value));
  354.     appendKeyValuePair(result, fieldName, valueStr);
  355.     break;
  356.   case VALUE_LONG:
  357.     // sprintf( ) is more portable then swprintf( )
  358.     sprintf(valueStr, "%d", VXILongValue((const VXILong *) value));
  359.     appendKeyValuePair(result, fieldName, valueStr);
  360.     break;
  361.   case VALUE_FLOAT:
  362.     {
  363.       // sprintf( ) is more portable then swprintf( ), but have to
  364.       // watch for locale dependance where the integer and fractional
  365.       // parts may be separated by a comma in some locales
  366.       sprintf(valueStr, "%#.6g",
  367.       (double) VXIFloatValue((const VXIFloat *) value));
  368.       char sep = GetDecimalSeparator( );
  369.       // printf("decimalSeparator = '%c'n", (sep ? sep : 'e'));
  370.       if ((sep) && (sep != '.')) {
  371.         char *ptr = strchr(valueStr, sep);
  372.         if (ptr)
  373.           *ptr = '.';
  374.       }
  375.       appendKeyValuePair(result, fieldName, valueStr);
  376.     }
  377.     break;
  378.   case VALUE_DOUBLE:
  379.     {
  380.       // sprintf( ) is more portable then swprintf( ), but have to
  381.       // watch for locale dependance where the integer and fractional
  382.       // parts may be separated by a comma in some locales
  383.       sprintf(valueStr, "%#.6g",
  384.       (double) VXIDoubleValue((const VXIDouble *) value));
  385.       char sep = GetDecimalSeparator( );
  386.       // printf("decimalSeparator = '%c'n", (sep ? sep : 'e'));
  387.       if ((sep) && (sep != '.')) {
  388.         char *ptr = strchr(valueStr, sep);
  389.         if (ptr)
  390.           *ptr = '.';
  391.       }
  392.       appendKeyValuePair(result, fieldName, valueStr);
  393.     }
  394.     break;
  395.   case VALUE_STRING:
  396.     appendKeyValuePair(result, fieldName,
  397.        VXIStringCStr((const VXIString *) value));
  398.     break;
  399.   case VALUE_PTR:
  400.     {
  401.       // Can't rely on the C library to give consistant enough results.
  402.       // sprintf( ) is more portable then swprintf( )
  403.       sprintf(valueStr, "%p", VXIPtrValue((const VXIPtr *) value));
  404.       myString finalValue;
  405.       if ( strncmp(valueStr, "0x", 2) != 0 )
  406. finalValue += L"0x";
  407.       for (const char *ptr = valueStr; *ptr; ptr++) {
  408. switch (*ptr) {
  409. case 'a': finalValue += L'A'; break;
  410. case 'b': finalValue += L'B'; break;
  411. case 'c': finalValue += L'C'; break;
  412. case 'd': finalValue += L'D'; break;
  413. case 'e': finalValue += L'E'; break;
  414. case 'f': finalValue += L'F'; break;
  415. default:  finalValue += static_cast<VXIchar>(*ptr);
  416. }
  417.       }
  418.       appendKeyValuePair(result, fieldName, finalValue.c_str());
  419.     }
  420.     break;
  421.   default:
  422.     appendKeyValuePair(result, fieldName, L"errorInvalidType");
  423.     break;
  424.   }
  425. }
  426. #endif /* #ifndef NO_STL */
  427. /**
  428.  * Generic Value to string conversion
  429.  *
  430.  * This converts any VXIValue type to a string.
  431.  *
  432.  * @param   v       Value to convert to a string
  433.  * @param   name    Name to use for labeling the VXIValue data
  434.  * @param   format  Format to use for the string, see above
  435.  * @return          VXIString, NULL on error
  436.  */
  437. VXIVALUE_API VXIString *VXIValueToString(const VXIValue      *v,
  438.  const VXIchar       *name,
  439.  VXIValueStringFormat format)
  440. {
  441.   if (( ! v ) || ( ! name ))
  442.     return NULL;
  443. #ifdef NO_STL
  444.   return NULL;
  445. #else
  446.   myString str;
  447.   str.reserve(1024); // For efficiency, preallocate 1024 char buffer
  448.   appendValue (str, v, name);
  449.   return (str.length( ) > 0 ? VXIStringCreate (str.c_str()) : NULL);
  450. #endif
  451. }