/home/bes3soft/bes3soft/Boss/7.0.2/dist/7.0.2/Utilities/JobInfoSvc/JobInfoSvc-00-00-02/xmlrpc++0.7/src/XmlRpcValue.cpp

Go to the documentation of this file.
00001 
00002 #include "XmlRpcValue.h"
00003 #include "XmlRpcException.h"
00004 #include "XmlRpcUtil.h"
00005 #include "base64.h"
00006 
00007 #ifndef MAKEDEPEND
00008 # include <iostream>
00009 # include <ostream>
00010 # include <stdlib.h>
00011 # include <stdio.h>
00012 #endif
00013 
00014 namespace XmlRpc {
00015 
00016 
00017   static const char VALUE_TAG[]     = "<value>";
00018   static const char VALUE_ETAG[]    = "</value>";
00019 
00020   static const char BOOLEAN_TAG[]   = "<boolean>";
00021   static const char BOOLEAN_ETAG[]  = "</boolean>";
00022   static const char DOUBLE_TAG[]    = "<double>";
00023   static const char DOUBLE_ETAG[]   = "</double>";
00024   static const char INT_TAG[]       = "<int>";
00025   static const char I4_TAG[]        = "<i4>";
00026   static const char I4_ETAG[]       = "</i4>";
00027   static const char STRING_TAG[]    = "<string>";
00028   static const char DATETIME_TAG[]  = "<dateTime.iso8601>";
00029   static const char DATETIME_ETAG[] = "</dateTime.iso8601>";
00030   static const char BASE64_TAG[]    = "<base64>";
00031   static const char BASE64_ETAG[]   = "</base64>";
00032 
00033   static const char ARRAY_TAG[]     = "<array>";
00034   static const char DATA_TAG[]      = "<data>";
00035   static const char DATA_ETAG[]     = "</data>";
00036   static const char ARRAY_ETAG[]    = "</array>";
00037 
00038   static const char STRUCT_TAG[]    = "<struct>";
00039   static const char MEMBER_TAG[]    = "<member>";
00040   static const char NAME_TAG[]      = "<name>";
00041   static const char NAME_ETAG[]     = "</name>";
00042   static const char MEMBER_ETAG[]   = "</member>";
00043   static const char STRUCT_ETAG[]   = "</struct>";
00044 
00045 
00046       
00047   // Format strings
00048   std::string XmlRpcValue::_doubleFormat("%f");
00049 
00050 
00051 
00052   // Clean up
00053   void XmlRpcValue::invalidate()
00054   {
00055     switch (_type) {
00056       case TypeString:    delete _value.asString; break;
00057       case TypeDateTime:  delete _value.asTime;   break;
00058       case TypeBase64:    delete _value.asBinary; break;
00059       case TypeArray:     delete _value.asArray;  break;
00060       case TypeStruct:    delete _value.asStruct; break;
00061       default: break;
00062     }
00063     _type = TypeInvalid;
00064     _value.asBinary = 0;
00065   }
00066 
00067   
00068   // Type checking
00069   void XmlRpcValue::assertTypeOrInvalid(Type t)
00070   {
00071     if (_type == TypeInvalid)
00072     {
00073       _type = t;
00074       switch (_type) {    // Ensure there is a valid value for the type
00075         case TypeString:   _value.asString = new std::string(); break;
00076         case TypeDateTime: _value.asTime = new struct tm();     break;
00077         case TypeBase64:   _value.asBinary = new BinaryData();  break;
00078         case TypeArray:    _value.asArray = new ValueArray();   break;
00079         case TypeStruct:   _value.asStruct = new ValueStruct(); break;
00080         default:           _value.asBinary = 0; break;
00081       }
00082     }
00083     else if (_type != t)
00084       throw XmlRpcException("type error");
00085   }
00086 
00087   void XmlRpcValue::assertArray(int size) const
00088   {
00089     if (_type != TypeArray)
00090       throw XmlRpcException("type error: expected an array");
00091     else if (int(_value.asArray->size()) < size)
00092       throw XmlRpcException("range error: array index too large");
00093   }
00094 
00095 
00096   void XmlRpcValue::assertArray(int size)
00097   {
00098     if (_type == TypeInvalid) {
00099       _type = TypeArray;
00100       _value.asArray = new ValueArray(size);
00101     } else if (_type == TypeArray) {
00102       if (int(_value.asArray->size()) < size)
00103         _value.asArray->resize(size);
00104     } else
00105       throw XmlRpcException("type error: expected an array");
00106   }
00107 
00108   void XmlRpcValue::assertStruct()
00109   {
00110     if (_type == TypeInvalid) {
00111       _type = TypeStruct;
00112       _value.asStruct = new ValueStruct();
00113     } else if (_type != TypeStruct)
00114       throw XmlRpcException("type error: expected a struct");
00115   }
00116 
00117 
00118   // Operators
00119   XmlRpcValue& XmlRpcValue::operator=(XmlRpcValue const& rhs)
00120   {
00121     if (this != &rhs)
00122     {
00123       invalidate();
00124       _type = rhs._type;
00125       switch (_type) {
00126         case TypeBoolean:  _value.asBool = rhs._value.asBool; break;
00127         case TypeInt:      _value.asInt = rhs._value.asInt; break;
00128         case TypeDouble:   _value.asDouble = rhs._value.asDouble; break;
00129         case TypeDateTime: _value.asTime = new struct tm(*rhs._value.asTime); break;
00130         case TypeString:   _value.asString = new std::string(*rhs._value.asString); break;
00131         case TypeBase64:   _value.asBinary = new BinaryData(*rhs._value.asBinary); break;
00132         case TypeArray:    _value.asArray = new ValueArray(*rhs._value.asArray); break;
00133         case TypeStruct:   _value.asStruct = new ValueStruct(*rhs._value.asStruct); break;
00134         default:           _value.asBinary = 0; break;
00135       }
00136     }
00137     return *this;
00138   }
00139 
00140 
00141   // Predicate for tm equality
00142   static bool tmEq(struct tm const& t1, struct tm const& t2) {
00143     return t1.tm_sec == t2.tm_sec && t1.tm_min == t2.tm_min &&
00144             t1.tm_hour == t2.tm_hour && t1.tm_mday == t1.tm_mday &&
00145             t1.tm_mon == t2.tm_mon && t1.tm_year == t2.tm_year;
00146   }
00147 
00148   bool XmlRpcValue::operator==(XmlRpcValue const& other) const
00149   {
00150     if (_type != other._type)
00151       return false;
00152 
00153     switch (_type) {
00154       case TypeBoolean:  return ( !_value.asBool && !other._value.asBool) ||
00155                                 ( _value.asBool && other._value.asBool);
00156       case TypeInt:      return _value.asInt == other._value.asInt;
00157       case TypeDouble:   return _value.asDouble == other._value.asDouble;
00158       case TypeDateTime: return tmEq(*_value.asTime, *other._value.asTime);
00159       case TypeString:   return *_value.asString == *other._value.asString;
00160       case TypeBase64:   return *_value.asBinary == *other._value.asBinary;
00161       case TypeArray:    return *_value.asArray == *other._value.asArray;
00162 
00163       // The map<>::operator== requires the definition of value< for kcc
00164       case TypeStruct:   //return *_value.asStruct == *other._value.asStruct;
00165         {
00166           if (_value.asStruct->size() != other._value.asStruct->size())
00167             return false;
00168           
00169           ValueStruct::const_iterator it1=_value.asStruct->begin();
00170           ValueStruct::const_iterator it2=other._value.asStruct->begin();
00171           while (it1 != _value.asStruct->end()) {
00172             const XmlRpcValue& v1 = it1->second;
00173             const XmlRpcValue& v2 = it2->second;
00174             if ( ! (v1 == v2))
00175               return false;
00176             it1++;
00177             it2++;
00178           }
00179           return true;
00180         }
00181       default: break;
00182     }
00183     return true;    // Both invalid values ...
00184   }
00185 
00186   bool XmlRpcValue::operator!=(XmlRpcValue const& other) const
00187   {
00188     return !(*this == other);
00189   }
00190 
00191 
00192   // Works for strings, binary data, arrays, and structs.
00193   int XmlRpcValue::size() const
00194   {
00195     switch (_type) {
00196       case TypeString: return int(_value.asString->size());
00197       case TypeBase64: return int(_value.asBinary->size());
00198       case TypeArray:  return int(_value.asArray->size());
00199       case TypeStruct: return int(_value.asStruct->size());
00200       default: break;
00201     }
00202 
00203     throw XmlRpcException("type error");
00204   }
00205 
00206   // Checks for existence of struct member
00207   bool XmlRpcValue::hasMember(const std::string& name) const
00208   {
00209     return _type == TypeStruct && _value.asStruct->find(name) != _value.asStruct->end();
00210   }
00211 
00212   // Set the value from xml. The chars at *offset into valueXml 
00213   // should be the start of a <value> tag. Destroys any existing value.
00214   bool XmlRpcValue::fromXml(std::string const& valueXml, int* offset)
00215   {
00216     int savedOffset = *offset;
00217 
00218     invalidate();
00219     if ( ! XmlRpcUtil::nextTagIs(VALUE_TAG, valueXml, offset))
00220       return false;       // Not a value, offset not updated
00221 
00222         int afterValueOffset = *offset;
00223     std::string typeTag = XmlRpcUtil::getNextTag(valueXml, offset);
00224     bool result = false;
00225     if (typeTag == BOOLEAN_TAG)
00226       result = boolFromXml(valueXml, offset);
00227     else if (typeTag == I4_TAG || typeTag == INT_TAG)
00228       result = intFromXml(valueXml, offset);
00229     else if (typeTag == DOUBLE_TAG)
00230       result = doubleFromXml(valueXml, offset);
00231     else if (typeTag.empty() || typeTag == STRING_TAG)
00232       result = stringFromXml(valueXml, offset);
00233     else if (typeTag == DATETIME_TAG)
00234       result = timeFromXml(valueXml, offset);
00235     else if (typeTag == BASE64_TAG)
00236       result = binaryFromXml(valueXml, offset);
00237     else if (typeTag == ARRAY_TAG)
00238       result = arrayFromXml(valueXml, offset);
00239     else if (typeTag == STRUCT_TAG)
00240       result = structFromXml(valueXml, offset);
00241     // Watch for empty/blank strings with no <string>tag
00242     else if (typeTag == VALUE_ETAG)
00243     {
00244       *offset = afterValueOffset;   // back up & try again
00245       result = stringFromXml(valueXml, offset);
00246     }
00247 
00248     if (result)  // Skip over the </value> tag
00249       XmlRpcUtil::findTag(VALUE_ETAG, valueXml, offset);
00250     else        // Unrecognized tag after <value>
00251       *offset = savedOffset;
00252 
00253     return result;
00254   }
00255 
00256   // Encode the Value in xml
00257   std::string XmlRpcValue::toXml() const
00258   {
00259     switch (_type) {
00260       case TypeBoolean:  return boolToXml();
00261       case TypeInt:      return intToXml();
00262       case TypeDouble:   return doubleToXml();
00263       case TypeString:   return stringToXml();
00264       case TypeDateTime: return timeToXml();
00265       case TypeBase64:   return binaryToXml();
00266       case TypeArray:    return arrayToXml();
00267       case TypeStruct:   return structToXml();
00268       default: break;
00269     }
00270     return std::string();   // Invalid value
00271   }
00272 
00273 
00274   // Boolean
00275   bool XmlRpcValue::boolFromXml(std::string const& valueXml, int* offset)
00276   {
00277     const char* valueStart = valueXml.c_str() + *offset;
00278     char* valueEnd;
00279     long ivalue = strtol(valueStart, &valueEnd, 10);
00280     if (valueEnd == valueStart || (ivalue != 0 && ivalue != 1))
00281       return false;
00282 
00283     _type = TypeBoolean;
00284     _value.asBool = (ivalue == 1);
00285     *offset += int(valueEnd - valueStart);
00286     return true;
00287   }
00288 
00289   std::string XmlRpcValue::boolToXml() const
00290   {
00291     std::string xml = VALUE_TAG;
00292     xml += BOOLEAN_TAG;
00293     xml += (_value.asBool ? "1" : "0");
00294     xml += BOOLEAN_ETAG;
00295     xml += VALUE_ETAG;
00296     return xml;
00297   }
00298 
00299   // Int
00300   bool XmlRpcValue::intFromXml(std::string const& valueXml, int* offset)
00301   {
00302     const char* valueStart = valueXml.c_str() + *offset;
00303     char* valueEnd;
00304     long ivalue = strtol(valueStart, &valueEnd, 10);
00305     if (valueEnd == valueStart)
00306       return false;
00307 
00308     _type = TypeInt;
00309     _value.asInt = int(ivalue);
00310     *offset += int(valueEnd - valueStart);
00311     return true;
00312   }
00313 
00314   std::string XmlRpcValue::intToXml() const
00315   {
00316     char buf[256];
00317     snprintf(buf, sizeof(buf)-1, "%d", _value.asInt);
00318     buf[sizeof(buf)-1] = 0;
00319     std::string xml = VALUE_TAG;
00320     xml += I4_TAG;
00321     xml += buf;
00322     xml += I4_ETAG;
00323     xml += VALUE_ETAG;
00324     return xml;
00325   }
00326 
00327   // Double
00328   bool XmlRpcValue::doubleFromXml(std::string const& valueXml, int* offset)
00329   {
00330     const char* valueStart = valueXml.c_str() + *offset;
00331     char* valueEnd;
00332     double dvalue = strtod(valueStart, &valueEnd);
00333     if (valueEnd == valueStart)
00334       return false;
00335 
00336     _type = TypeDouble;
00337     _value.asDouble = dvalue;
00338     *offset += int(valueEnd - valueStart);
00339     return true;
00340   }
00341 
00342   std::string XmlRpcValue::doubleToXml() const
00343   {
00344     char buf[256];
00345     snprintf(buf, sizeof(buf)-1, getDoubleFormat().c_str(), _value.asDouble);
00346     buf[sizeof(buf)-1] = 0;
00347 
00348     std::string xml = VALUE_TAG;
00349     xml += DOUBLE_TAG;
00350     xml += buf;
00351     xml += DOUBLE_ETAG;
00352     xml += VALUE_ETAG;
00353     return xml;
00354   }
00355 
00356   // String
00357   bool XmlRpcValue::stringFromXml(std::string const& valueXml, int* offset)
00358   {
00359     size_t valueEnd = valueXml.find('<', *offset);
00360     if (valueEnd == std::string::npos)
00361       return false;     // No end tag;
00362 
00363     _type = TypeString;
00364     _value.asString = new std::string(XmlRpcUtil::xmlDecode(valueXml.substr(*offset, valueEnd-*offset)));
00365     *offset += int(_value.asString->length());
00366     return true;
00367   }
00368 
00369   std::string XmlRpcValue::stringToXml() const
00370   {
00371     std::string xml = VALUE_TAG;
00372     //xml += STRING_TAG; optional
00373     xml += XmlRpcUtil::xmlEncode(*_value.asString);
00374     //xml += STRING_ETAG;
00375     xml += VALUE_ETAG;
00376     return xml;
00377   }
00378 
00379   // DateTime (stored as a struct tm)
00380   bool XmlRpcValue::timeFromXml(std::string const& valueXml, int* offset)
00381   {
00382     size_t valueEnd = valueXml.find('<', *offset);
00383     if (valueEnd == std::string::npos)
00384       return false;     // No end tag;
00385 
00386     std::string stime = valueXml.substr(*offset, valueEnd-*offset);
00387 
00388     struct tm t;
00389     if (sscanf(stime.c_str(),"%4d%2d%2dT%2d:%2d:%2d",&t.tm_year,&t.tm_mon,&t.tm_mday,&t.tm_hour,&t.tm_min,&t.tm_sec) != 6)
00390       return false;
00391 
00392     t.tm_isdst = -1;
00393     _type = TypeDateTime;
00394     _value.asTime = new struct tm(t);
00395     *offset += int(stime.length());
00396     return true;
00397   }
00398 
00399   std::string XmlRpcValue::timeToXml() const
00400   {
00401     struct tm* t = _value.asTime;
00402     char buf[20];
00403     snprintf(buf, sizeof(buf)-1, "%4d%02d%02dT%02d:%02d:%02d", 
00404       t->tm_year,t->tm_mon,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec);
00405     buf[sizeof(buf)-1] = 0;
00406 
00407     std::string xml = VALUE_TAG;
00408     xml += DATETIME_TAG;
00409     xml += buf;
00410     xml += DATETIME_ETAG;
00411     xml += VALUE_ETAG;
00412     return xml;
00413   }
00414 
00415 
00416   // Base64
00417   bool XmlRpcValue::binaryFromXml(std::string const& valueXml, int* offset)
00418   {
00419     size_t valueEnd = valueXml.find('<', *offset);
00420     if (valueEnd == std::string::npos)
00421       return false;     // No end tag;
00422 
00423     _type = TypeBase64;
00424     std::string asString = valueXml.substr(*offset, valueEnd-*offset);
00425     _value.asBinary = new BinaryData();
00426     // check whether base64 encodings can contain chars xml encodes...
00427 
00428     // convert from base64 to binary
00429     int iostatus = 0;
00430           base64<char> decoder;
00431     std::back_insert_iterator<BinaryData> ins = std::back_inserter(*(_value.asBinary));
00432                 decoder.get(asString.begin(), asString.end(), ins, iostatus);
00433 
00434     *offset += int(asString.length());
00435     return true;
00436   }
00437 
00438 
00439   std::string XmlRpcValue::binaryToXml() const
00440   {
00441     // convert to base64
00442     std::vector<char> base64data;
00443     int iostatus = 0;
00444           base64<char> encoder;
00445     std::back_insert_iterator<std::vector<char> > ins = std::back_inserter(base64data);
00446                 encoder.put(_value.asBinary->begin(), _value.asBinary->end(), ins, iostatus, base64<>::crlf());
00447 
00448     // Wrap with xml
00449     std::string xml = VALUE_TAG;
00450     xml += BASE64_TAG;
00451     xml.append(base64data.begin(), base64data.end());
00452     xml += BASE64_ETAG;
00453     xml += VALUE_ETAG;
00454     return xml;
00455   }
00456 
00457 
00458   // Array
00459   bool XmlRpcValue::arrayFromXml(std::string const& valueXml, int* offset)
00460   {
00461     if ( ! XmlRpcUtil::nextTagIs(DATA_TAG, valueXml, offset))
00462       return false;
00463 
00464     _type = TypeArray;
00465     _value.asArray = new ValueArray;
00466     XmlRpcValue v;
00467     while (v.fromXml(valueXml, offset))
00468       _value.asArray->push_back(v);       // copy...
00469 
00470     // Skip the trailing </data>
00471     (void) XmlRpcUtil::nextTagIs(DATA_ETAG, valueXml, offset);
00472     return true;
00473   }
00474 
00475 
00476   // In general, its preferable to generate the xml of each element of the
00477   // array as it is needed rather than glomming up one big string.
00478   std::string XmlRpcValue::arrayToXml() const
00479   {
00480     std::string xml = VALUE_TAG;
00481     xml += ARRAY_TAG;
00482     xml += DATA_TAG;
00483 
00484     int s = int(_value.asArray->size());
00485     for (int i=0; i<s; ++i)
00486        xml += _value.asArray->at(i).toXml();
00487 
00488     xml += DATA_ETAG;
00489     xml += ARRAY_ETAG;
00490     xml += VALUE_ETAG;
00491     return xml;
00492   }
00493 
00494 
00495   // Struct
00496   bool XmlRpcValue::structFromXml(std::string const& valueXml, int* offset)
00497   {
00498     _type = TypeStruct;
00499     _value.asStruct = new ValueStruct;
00500 
00501     while (XmlRpcUtil::nextTagIs(MEMBER_TAG, valueXml, offset)) {
00502       // name
00503       const std::string name = XmlRpcUtil::parseTag(NAME_TAG, valueXml, offset);
00504       // value
00505       XmlRpcValue val(valueXml, offset);
00506       if ( ! val.valid()) {
00507         invalidate();
00508         return false;
00509       }
00510       const std::pair<const std::string, XmlRpcValue> p(name, val);
00511       _value.asStruct->insert(p);
00512 
00513       (void) XmlRpcUtil::nextTagIs(MEMBER_ETAG, valueXml, offset);
00514     }
00515     return true;
00516   }
00517 
00518 
00519   // In general, its preferable to generate the xml of each element
00520   // as it is needed rather than glomming up one big string.
00521   std::string XmlRpcValue::structToXml() const
00522   {
00523     std::string xml = VALUE_TAG;
00524     xml += STRUCT_TAG;
00525 
00526     ValueStruct::const_iterator it;
00527     for (it=_value.asStruct->begin(); it!=_value.asStruct->end(); ++it) {
00528       xml += MEMBER_TAG;
00529       xml += NAME_TAG;
00530       xml += XmlRpcUtil::xmlEncode(it->first);
00531       xml += NAME_ETAG;
00532       xml += it->second.toXml();
00533       xml += MEMBER_ETAG;
00534     }
00535 
00536     xml += STRUCT_ETAG;
00537     xml += VALUE_ETAG;
00538     return xml;
00539   }
00540 
00541 
00542 
00543   // Write the value without xml encoding it
00544   std::ostream& XmlRpcValue::write(std::ostream& os) const {
00545     switch (_type) {
00546       default:           break;
00547       case TypeBoolean:  os << _value.asBool; break;
00548       case TypeInt:      os << _value.asInt; break;
00549       case TypeDouble:   os << _value.asDouble; break;
00550       case TypeString:   os << *_value.asString; break;
00551       case TypeDateTime:
00552         {
00553           struct tm* t = _value.asTime;
00554           char buf[20];
00555           snprintf(buf, sizeof(buf)-1, "%4d%02d%02dT%02d:%02d:%02d", 
00556             t->tm_year,t->tm_mon,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec);
00557           buf[sizeof(buf)-1] = 0;
00558           os << buf;
00559           break;
00560         }
00561       case TypeBase64:
00562         {
00563           int iostatus = 0;
00564           std::ostreambuf_iterator<char> out(os);
00565           base64<char> encoder;
00566           encoder.put(_value.asBinary->begin(), _value.asBinary->end(), out, iostatus, base64<>::crlf());
00567           break;
00568         }
00569       case TypeArray:
00570         {
00571           int s = int(_value.asArray->size());
00572           os << '{';
00573           for (int i=0; i<s; ++i)
00574           {
00575             if (i > 0) os << ',';
00576             _value.asArray->at(i).write(os);
00577           }
00578           os << '}';
00579           break;
00580         }
00581       case TypeStruct:
00582         {
00583           os << '[';
00584           ValueStruct::const_iterator it;
00585           for (it=_value.asStruct->begin(); it!=_value.asStruct->end(); ++it)
00586           {
00587             if (it!=_value.asStruct->begin()) os << ',';
00588             os << it->first << ':';
00589             it->second.write(os);
00590           }
00591           os << ']';
00592           break;
00593         }
00594       
00595     }
00596     
00597     return os;
00598   }
00599 
00600 } // namespace XmlRpc
00601 
00602 
00603 // ostream
00604 std::ostream& operator<<(std::ostream& os, XmlRpc::XmlRpcValue& v) 
00605 { 
00606   // If you want to output in xml format:
00607   //return os << v.toXml(); 
00608   return v.write(os);
00609 }
00610 

Generated on Tue Nov 29 23:14:44 2016 for BOSS_7.0.2 by  doxygen 1.4.7