llsdserialize_xml.cpp

Go to the documentation of this file.
00001 
00032 #include "linden_common.h"
00033 #include "llsdserialize_xml.h"
00034 
00035 #include <iostream>
00036 #include <deque>
00037 
00038 #include "apr-1/apr_base64.h"
00039 
00040 extern "C"
00041 {
00042 #ifdef LL_STANDALONE
00043 # include <expat.h>
00044 #else
00045 # include "expat/expat.h"
00046 #endif
00047 }
00048 
00052 LLSDXMLFormatter::LLSDXMLFormatter()
00053 {
00054 }
00055 
00056 // virtual
00057 LLSDXMLFormatter::~LLSDXMLFormatter()
00058 {
00059 }
00060 
00061 // virtual
00062 S32 LLSDXMLFormatter::format(const LLSD& data, std::ostream& ostr, U32 options) const
00063 {
00064         std::streamsize old_precision = ostr.precision(25);
00065 
00066         LLString post = "";
00067         if (options & LLSDFormatter::OPTIONS_PRETTY)
00068         {
00069                 post = "\n";
00070         }
00071         ostr << "<llsd>" << post;
00072         S32 rv = format_impl(data, ostr, options, 1);
00073         ostr << "</llsd>\n";
00074 
00075         ostr.precision(old_precision);
00076         return rv;
00077 }
00078 
00079 S32 LLSDXMLFormatter::format_impl(const LLSD& data, std::ostream& ostr, U32 options, U32 level) const
00080 {
00081         S32 format_count = 1;
00082         LLString pre = "";
00083         LLString post = "";
00084 
00085         if (options & LLSDFormatter::OPTIONS_PRETTY)
00086         {
00087                 for (U32 i = 0; i < level; i++)
00088                 {
00089                         pre += "    ";
00090                 }
00091                 post = "\n";
00092         }
00093 
00094         switch(data.type())
00095         {
00096         case LLSD::TypeMap:
00097                 if(0 == data.size())
00098                 {
00099                         ostr << pre << "<map />" << post;
00100                 }
00101                 else
00102                 {
00103                         ostr << pre << "<map>" << post;
00104                         LLSD::map_const_iterator iter = data.beginMap();
00105                         LLSD::map_const_iterator end = data.endMap();
00106                         for(; iter != end; ++iter)
00107                         {
00108                                 ostr << pre << "<key>" << escapeString((*iter).first) << "</key>" << post;
00109                                 format_count += format_impl((*iter).second, ostr, options, level + 1);
00110                         }
00111                         ostr << pre <<  "</map>" << post;
00112                 }
00113                 break;
00114 
00115         case LLSD::TypeArray:
00116                 if(0 == data.size())
00117                 {
00118                         ostr << pre << "<array />" << post;
00119                 }
00120                 else
00121                 {
00122                         ostr << pre << "<array>" << post;
00123                         LLSD::array_const_iterator iter = data.beginArray();
00124                         LLSD::array_const_iterator end = data.endArray();
00125                         for(; iter != end; ++iter)
00126                         {
00127                                 format_count += format_impl(*iter, ostr, options, level + 1);
00128                         }
00129                         ostr << pre << "</array>" << post;
00130                 }
00131                 break;
00132 
00133         case LLSD::TypeUndefined:
00134                 ostr << pre << "<undef />" << post;
00135                 break;
00136 
00137         case LLSD::TypeBoolean:
00138                 ostr << pre << "<boolean>";
00139                 if(mBoolAlpha ||
00140 #if( LL_WINDOWS || __GNUC__ > 2)
00141                    (ostr.flags() & std::ios::boolalpha)
00142 #else
00143                    (ostr.flags() & 0x0100)
00144 #endif
00145                         )
00146                 {
00147                         ostr << (data.asBoolean() ? "true" : "false");
00148                 }
00149                 else
00150                 {
00151                         ostr << (data.asBoolean() ? 1 : 0);
00152                 }
00153                 ostr << "</boolean>" << post;
00154                 break;
00155 
00156         case LLSD::TypeInteger:
00157                 ostr << pre << "<integer>" << data.asInteger() << "</integer>" << post;
00158                 break;
00159 
00160         case LLSD::TypeReal:
00161                 ostr << pre << "<real>";
00162                 if(mRealFormat.empty())
00163                 {
00164                         ostr << data.asReal();
00165                 }
00166                 else
00167                 {
00168                         formatReal(data.asReal(), ostr);
00169                 }
00170                 ostr << "</real>" << post;
00171                 break;
00172 
00173         case LLSD::TypeUUID:
00174                 if(data.asUUID().isNull()) ostr << pre << "<uuid />" << post;
00175                 else ostr << pre << "<uuid>" << data.asUUID() << "</uuid>" << post;
00176                 break;
00177 
00178         case LLSD::TypeString:
00179                 if(data.asString().empty()) ostr << pre << "<string />" << post;
00180                 else ostr << pre << "<string>" << escapeString(data.asString()) <<"</string>" << post;
00181                 break;
00182 
00183         case LLSD::TypeDate:
00184                 ostr << pre << "<date>" << data.asDate() << "</date>" << post;
00185                 break;
00186 
00187         case LLSD::TypeURI:
00188                 ostr << pre << "<uri>" << escapeString(data.asString()) << "</uri>" << post;
00189                 break;
00190 
00191         case LLSD::TypeBinary:
00192         {
00193                 LLSD::Binary buffer = data.asBinary();
00194                 if(buffer.empty())
00195                 {
00196                         ostr << pre << "<binary />" << post;
00197                 }
00198                 else
00199                 {
00200                         // *FIX: memory inefficient.
00201                         // *TODO: convert to use LLBase64
00202                         ostr << pre << "<binary encoding=\"base64\">";
00203                         int b64_buffer_length = apr_base64_encode_len(buffer.size());
00204                         char* b64_buffer = new char[b64_buffer_length];
00205                         b64_buffer_length = apr_base64_encode_binary(
00206                                 b64_buffer,
00207                                 &buffer[0],
00208                                 buffer.size());
00209                         ostr.write(b64_buffer, b64_buffer_length - 1);
00210                         delete[] b64_buffer;
00211                         ostr << "</binary>" << post;
00212                 }
00213                 break;
00214         }
00215         default:
00216                 // *NOTE: This should never happen.
00217                 ostr << pre << "<undef />" << post;
00218                 break;
00219         }
00220         return format_count;
00221 }
00222 
00223 // static
00224 std::string LLSDXMLFormatter::escapeString(const std::string& in)
00225 {
00226         std::ostringstream out;
00227         std::string::const_iterator it = in.begin();
00228         std::string::const_iterator end = in.end();
00229         for(; it != end; ++it)
00230         {
00231                 switch((*it))
00232                 {
00233                 case '<':
00234                         out << "&lt;";
00235                         break;
00236                 case '>':
00237                         out << "&gt;";
00238                         break;
00239                 case '&':
00240                         out << "&amp;";
00241                         break;
00242                 case '\'':
00243                         out << "&apos;";
00244                         break;
00245                 case '"':
00246                         out << "&quot;";
00247                         break;
00248                 default:
00249                         out << (*it);
00250                         break;
00251                 }
00252         }
00253         return out.str();
00254 }
00255 
00256 
00257 
00258 class LLSDXMLParser::Impl
00259 {
00260 public:
00261         Impl();
00262         ~Impl();
00263         
00264         S32 parse(std::istream& input, LLSD& data);
00265 
00266         void parsePart(const char *buf, int len);
00267         
00268 private:
00269         void reset();
00270         
00271         void startElementHandler(const XML_Char* name, const XML_Char** attributes);
00272         void endElementHandler(const XML_Char* name);
00273         void characterDataHandler(const XML_Char* data, int length);
00274         
00275         static void sStartElementHandler(
00276                 void* userData, const XML_Char* name, const XML_Char** attributes);
00277         static void sEndElementHandler(
00278                 void* userData, const XML_Char* name);
00279         static void sCharacterDataHandler(
00280                 void* userData, const XML_Char* data, int length);
00281 
00282         void startSkipping();
00283         
00284         enum Element {
00285                 ELEMENT_LLSD,
00286                 ELEMENT_UNDEF,
00287                 ELEMENT_BOOL,
00288                 ELEMENT_INTEGER,
00289                 ELEMENT_REAL,
00290                 ELEMENT_STRING,
00291                 ELEMENT_UUID,
00292                 ELEMENT_DATE,
00293                 ELEMENT_URI,
00294                 ELEMENT_BINARY,
00295                 ELEMENT_MAP,
00296                 ELEMENT_ARRAY,
00297                 ELEMENT_KEY,
00298                 ELEMENT_UNKNOWN
00299         };
00300         static Element readElement(const XML_Char* name);
00301         
00302         static const XML_Char* findAttribute(const XML_Char* name, const XML_Char** pairs);
00303         
00304 
00305         XML_Parser      mParser;
00306 
00307         LLSD mResult;
00308         
00309         bool mInLLSDElement;
00310         bool mGracefullStop;
00311         
00312         typedef std::deque<LLSD*> LLSDRefStack;
00313         LLSDRefStack mStack;
00314         
00315         int mDepth;
00316         bool mSkipping;
00317         int mSkipThrough;
00318         
00319         std::string mCurrentKey;
00320         std::ostringstream mCurrentContent;
00321 
00322         bool mPreStaged;
00323 };
00324 
00325 
00326 LLSDXMLParser::Impl::Impl()
00327 {
00328         mParser = XML_ParserCreate(NULL);
00329         mPreStaged = false;
00330         reset();
00331 }
00332 
00333 LLSDXMLParser::Impl::~Impl()
00334 {
00335         XML_ParserFree(mParser);
00336 }
00337 
00338 bool is_eol(char c)
00339 {
00340         return (c == '\n' || c == '\r');
00341 }
00342 
00343 void clear_eol(std::istream& input)
00344 {
00345         char c = input.peek();
00346         while (input.good() && is_eol(c))
00347         {
00348                 input.get(c);
00349                 c = input.peek();
00350         }
00351 }
00352 
00353 static unsigned get_till_eol(std::istream& input, char *buf, unsigned bufsize)
00354 {
00355         unsigned count = 0;
00356         while (count < bufsize && input.good())
00357         {
00358                 input.get(buf[count]);
00359                 count++;
00360                 if (is_eol(buf[count - 1]))
00361                         break;
00362         }
00363         return count;
00364 }
00365 
00366 S32 LLSDXMLParser::Impl::parse(std::istream& input, LLSD& data)
00367 {
00368         reset();
00369         XML_Status status;
00370         
00371         static const int BUFFER_SIZE = 1024;
00372         void* buffer = NULL;    
00373         int count = 0;
00374         while (input.good() && !input.eof())
00375         {
00376                 buffer = XML_GetBuffer(mParser, BUFFER_SIZE);
00377 
00378                 /*
00379                  * If we happened to end our last buffer right at the end of the llsd, but the
00380                  * stream is still going we will get a null buffer here.  Check for mGracefullStop.
00381                  */
00382                 if (!buffer)
00383                 {
00384                         break;
00385                 }
00386                 count = get_till_eol(input, (char *)buffer, BUFFER_SIZE);
00387                 if (!count)
00388                 {
00389                         break;
00390                 }
00391                 status = XML_ParseBuffer(mParser, count, false);
00392 
00393                 if (status == XML_STATUS_ERROR)
00394                 {
00395                         break;
00396                 }
00397         }
00398         
00399         // *FIX.: This code is buggy - if the stream was empty or not
00400         // good, there is not buffer to parse, both the call to
00401         // XML_ParseBuffer and the buffer manipulations are illegal
00402         // futhermore, it isn't clear that the expat buffer semantics are
00403         // preserved
00404 
00405         status = XML_ParseBuffer(mParser, 0, true);
00406         if (status == XML_STATUS_ERROR && !mGracefullStop)
00407         {
00408                 if (buffer)
00409                 {
00410                         ((char*) buffer)[count ? count - 1 : 0] = '\0';
00411                 }
00412                 llinfos << "LLSDXMLParser::Impl::parse: XML_STATUS_ERROR parsing:" << (char*) buffer << llendl;
00413                 data = LLSD();
00414                 return -1;
00415         }
00416 
00417         clear_eol(input);
00418         data = mResult;
00419         return 1;
00420 }
00421 
00422 void LLSDXMLParser::Impl::reset()
00423 {
00424         if (mPreStaged)
00425         {
00426                 mPreStaged = false;
00427                 return;
00428         }
00429 
00430         mResult.clear();
00431 
00432         mInLLSDElement = false;
00433         mDepth = 0;
00434 
00435         mGracefullStop = false;
00436 
00437         mStack.clear();
00438         
00439         mSkipping = false;
00440         
00441 #if( LL_WINDOWS || __GNUC__ > 2)
00442         mCurrentKey.clear();
00443 #else
00444         mCurrentKey = std::string();
00445 #endif
00446 
00447         
00448         XML_ParserReset(mParser, "utf-8");
00449         XML_SetUserData(mParser, this);
00450         XML_SetElementHandler(mParser, sStartElementHandler, sEndElementHandler);
00451         XML_SetCharacterDataHandler(mParser, sCharacterDataHandler);
00452 }
00453 
00454 
00455 void LLSDXMLParser::Impl::startSkipping()
00456 {
00457         mSkipping = true;
00458         mSkipThrough = mDepth;
00459 }
00460 
00461 const XML_Char*
00462 LLSDXMLParser::Impl::findAttribute(const XML_Char* name, const XML_Char** pairs)
00463 {
00464         while (NULL != pairs && NULL != *pairs)
00465         {
00466                 if(0 == strcmp(name, *pairs))
00467                 {
00468                         return *(pairs + 1);
00469                 }
00470                 pairs += 2;
00471         }
00472         return NULL;
00473 }
00474 
00475 void LLSDXMLParser::Impl::parsePart(const char *buf, int len)
00476 {
00477         void * buffer = XML_GetBuffer(mParser, len);
00478         if (buffer != NULL && buf != NULL)
00479         {
00480                 memcpy(buffer, buf, len);
00481         }
00482         XML_ParseBuffer(mParser, len, false);
00483 
00484         mPreStaged = true;
00485 }
00486 
00487 void LLSDXMLParser::Impl::startElementHandler(const XML_Char* name, const XML_Char** attributes)
00488 {
00489         mDepth += 1;
00490         if (mSkipping)
00491         {
00492                 return;
00493         }
00494         
00495         Element element = readElement(name);
00496         mCurrentContent.str("");
00497 
00498         switch (element)
00499         {
00500                 case ELEMENT_LLSD:
00501                         if (mInLLSDElement) { return startSkipping(); }
00502                         mInLLSDElement = true;
00503                         return;
00504         
00505                 case ELEMENT_KEY:
00506                         if (mStack.empty()  ||  !(mStack.back()->isMap()))
00507                         {
00508                                 return startSkipping();
00509                         }
00510                         return;
00511 
00512                 case ELEMENT_BINARY:
00513                 {
00514                         const XML_Char* encoding = findAttribute("encoding", attributes);
00515                         if(encoding && strcmp("base64", encoding) != 0) { return startSkipping(); }
00516                         break;
00517                 }
00518                 
00519                 default:
00520                         // all rest are values, fall through
00521                         ;
00522         }
00523         
00524 
00525         if (!mInLLSDElement) { return startSkipping(); }
00526         
00527         if (mStack.empty())
00528         {
00529                 mStack.push_back(&mResult);
00530         }
00531         else if (mStack.back()->isMap())
00532         {
00533                 if (mCurrentKey.empty()) { return startSkipping(); }
00534                 
00535                 LLSD& map = *mStack.back();
00536                 LLSD& newElement = map[mCurrentKey];
00537                 mStack.push_back(&newElement);          
00538 
00539 #if( LL_WINDOWS || __GNUC__ > 2)
00540                 mCurrentKey.clear();
00541 #else
00542                 mCurrentKey = std::string();
00543 #endif
00544         }
00545         else if (mStack.back()->isArray())
00546         {
00547                 LLSD& array = *mStack.back();
00548                 array.append(LLSD());
00549                 LLSD& newElement = array[array.size()-1];
00550                 mStack.push_back(&newElement);
00551         }
00552         else {
00553                 // improperly nested value in a non-structure
00554                 return startSkipping();
00555         }
00556 
00557         switch (element)
00558         {
00559                 case ELEMENT_MAP:
00560                         *mStack.back() = LLSD::emptyMap();
00561                         break;
00562                 
00563                 case ELEMENT_ARRAY:
00564                         *mStack.back() = LLSD::emptyArray();
00565                         break;
00566                         
00567                 default:
00568                         // all the other values will be set in the end element handler
00569                         ;
00570         }
00571 }
00572 
00573 void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
00574 {
00575         mDepth -= 1;
00576         if (mSkipping)
00577         {
00578                 if (mDepth < mSkipThrough)
00579                 {
00580                         mSkipping = false;
00581                 }
00582                 return;
00583         }
00584         
00585         Element element = readElement(name);
00586         
00587         switch (element)
00588         {
00589                 case ELEMENT_LLSD:
00590                         if (mInLLSDElement)
00591                         {
00592                                 mInLLSDElement = false;
00593                                 mGracefullStop = true;
00594                                 XML_StopParser(mParser, false);
00595                         }
00596                         return;
00597         
00598                 case ELEMENT_KEY:
00599                         mCurrentKey = mCurrentContent.str();
00600                         return;
00601                         
00602                 default:
00603                         // all rest are values, fall through
00604                         ;
00605         }
00606         
00607         if (!mInLLSDElement) { return; }
00608 
00609         LLSD& value = *mStack.back();
00610         mStack.pop_back();
00611         
00612         std::string content = mCurrentContent.str();
00613         mCurrentContent.str("");
00614 
00615         switch (element)
00616         {
00617                 case ELEMENT_UNDEF:
00618                         value.clear();
00619                         break;
00620                 
00621                 case ELEMENT_BOOL:
00622                         value = content == "true" || content == "1";
00623                         break;
00624                 
00625                 case ELEMENT_INTEGER:
00626                         value = LLSD(content).asInteger();
00627                         break;
00628                 
00629                 case ELEMENT_REAL:
00630                         value = LLSD(content).asReal();
00631                         break;
00632                 
00633                 case ELEMENT_STRING:
00634                         value = content;
00635                         break;
00636                 
00637                 case ELEMENT_UUID:
00638                         value = LLSD(content).asUUID();
00639                         break;
00640                 
00641                 case ELEMENT_DATE:
00642                         value = LLSD(content).asDate();
00643                         break;
00644                 
00645                 case ELEMENT_URI:
00646                         value = LLSD(content).asURI();
00647                         break;
00648                 
00649                 case ELEMENT_BINARY:
00650                 {
00651                         S32 len = apr_base64_decode_len(content.c_str());
00652                         std::vector<U8> data;
00653                         data.resize(len);
00654                         len = apr_base64_decode_binary(&data[0], content.c_str());
00655                         data.resize(len);
00656                         value = data;
00657                         break;
00658                 }
00659                 
00660                 case ELEMENT_UNKNOWN:
00661                         value.clear();
00662                         break;
00663                         
00664                 default:
00665                         // other values, map and array, have already been set
00666                         break;
00667         }
00668 }
00669 
00670 void LLSDXMLParser::Impl::characterDataHandler(const XML_Char* data, int length)
00671 {
00672         mCurrentContent.write(data, length);
00673 }
00674 
00675 
00676 void LLSDXMLParser::Impl::sStartElementHandler(
00677         void* userData, const XML_Char* name, const XML_Char** attributes)
00678 {
00679         ((LLSDXMLParser::Impl*)userData)->startElementHandler(name, attributes);
00680 }
00681 
00682 void LLSDXMLParser::Impl::sEndElementHandler(
00683         void* userData, const XML_Char* name)
00684 {
00685         ((LLSDXMLParser::Impl*)userData)->endElementHandler(name);
00686 }
00687 
00688 void LLSDXMLParser::Impl::sCharacterDataHandler(
00689         void* userData, const XML_Char* data, int length)
00690 {
00691         ((LLSDXMLParser::Impl*)userData)->characterDataHandler(data, length);
00692 }
00693 
00694 
00695 LLSDXMLParser::Impl::Element LLSDXMLParser::Impl::readElement(const XML_Char* name)
00696 {
00697         if (strcmp(name, "llsd") == 0) { return ELEMENT_LLSD; }
00698         if (strcmp(name, "undef") == 0) { return ELEMENT_UNDEF; }
00699         if (strcmp(name, "boolean") == 0) { return ELEMENT_BOOL; }
00700         if (strcmp(name, "integer") == 0) { return ELEMENT_INTEGER; }
00701         if (strcmp(name, "real") == 0) { return ELEMENT_REAL; }
00702         if (strcmp(name, "string") == 0) { return ELEMENT_STRING; }
00703         if (strcmp(name, "uuid") == 0) { return ELEMENT_UUID; }
00704         if (strcmp(name, "date") == 0) { return ELEMENT_DATE; }
00705         if (strcmp(name, "uri") == 0) { return ELEMENT_URI; }
00706         if (strcmp(name, "binary") == 0) { return ELEMENT_BINARY; }
00707         if (strcmp(name, "map") == 0) { return ELEMENT_MAP; }
00708         if (strcmp(name, "array") == 0) { return ELEMENT_ARRAY; }
00709         if (strcmp(name, "key") == 0) { return ELEMENT_KEY; }
00710         
00711         return ELEMENT_UNKNOWN;
00712 }
00713 
00714 
00715 
00716 
00717 
00718 
00719 
00720 LLSDXMLParser::LLSDXMLParser()
00721         : impl(* new Impl)
00722 {
00723 }
00724 
00725 LLSDXMLParser::~LLSDXMLParser()
00726 {
00727         delete &impl;
00728 }
00729 
00730 void LLSDXMLParser::parsePart(const char *buf, int len)
00731 {
00732         impl.parsePart(buf, len);
00733 }
00734 
00735 // virtual
00736 S32 LLSDXMLParser::parse(std::istream& input, LLSD& data) const
00737 {
00738         return impl.parse(input, data); 
00739 }

Generated on Thu Jul 1 06:09:09 2010 for Second Life Viewer by  doxygen 1.4.7