00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "stdmisc.h"
00027
00028 #include "nel/misc/o_xml.h"
00029
00030 #ifndef NL_DONT_USE_EXTERNAL_CODE
00031
00032 using namespace std;
00033
00034 namespace NLMISC
00035 {
00036
00037
00038
00039 const char SEPARATOR = ' ';
00040
00041
00042
00043 #define writenumber(src,format,digits) \
00044 char number_as_cstring [digits+1]; \
00045 sprintf( number_as_cstring, format, src ); \
00046 serialSeparatedBufferOut( number_as_cstring );
00047
00048
00049
00050 inline void COXml::flushContentString ()
00051 {
00052
00053 nlassert (_CurrentNode);
00054
00055
00056 uint size=_ContentString.length();
00057
00058
00059 if (size)
00060 {
00061
00062 xmlNodePtr textNode = xmlNewText ((const xmlChar *)_ContentString.c_str());
00063 xmlAddChild (_CurrentNode, textNode);
00064
00065
00066 _ContentString.erase ();
00067 }
00068 }
00069
00070
00071
00072 COXml::COXml () : IStream (false )
00073 {
00074
00075 setXMLMode (true);
00076
00077
00078 _InternalStream = NULL;
00079
00080
00081 _Version = "1.0";
00082
00083
00084 _Document = NULL;
00085
00086
00087 _CurrentNode = NULL;
00088
00089
00090 _ContentString = "";
00091
00092
00093 _PushBegin = false;
00094 }
00095
00096
00097
00098 bool COXml::init (IStream *stream, const char *version)
00099 {
00100
00101 if (!stream->isReading())
00102 {
00103
00104 setXMLMode (true);
00105
00106
00107 _InternalStream = stream;
00108
00109
00110 _Version = version;
00111
00112
00113 _Document = NULL;
00114
00115
00116 _CurrentNode = NULL;
00117
00118
00119 _ContentString = "";
00120
00121
00122 _PushBegin = false;
00123
00124
00125 return true;
00126 }
00127 else
00128 return false;
00129 }
00130
00131
00132
00133 COXml::~COXml ()
00134 {
00135
00136 flush ();
00137 }
00138
00139
00140
00141 void COXml::serialSeparatedBufferOut( const char *value )
00142 {
00143 nlassert( ! isReading() );
00144
00145
00146 if ( _InternalStream )
00147 {
00148
00149 if (_CurrentNode)
00150 {
00151
00152 if (_PushBegin)
00153 {
00154
00155 if (_AttribPresent)
00156 {
00157
00158 xmlSetProp (_CurrentNode, (const xmlChar*)_AttribName.c_str(), (const xmlChar*)value);
00159
00160
00161 _AttribPresent = false;
00162 }
00163 else
00164 {
00165
00166
00167
00168
00169 nlerror ( "Error, the stream don't use XML streaming properly" );
00170 }
00171 }
00172 else
00173 {
00174
00175 uint size=_ContentString.length();
00176
00177
00178 if ((size) && (_ContentString[size-1]!='\n'))
00179 _ContentString += SEPARATOR;
00180
00181
00182 _ContentString += value;
00183 }
00184 }
00185 else
00186 {
00187
00188
00189 nlerror ( "Error, the stream don't use XML streaming properly" );
00190 }
00191 }
00192 else
00193 {
00194 nlerror ( "Output stream has not been setuped" );
00195 }
00196 }
00197
00198
00199
00200 void COXml::serial(uint8 &b)
00201 {
00202
00203 writenumber( (uint16)b,"%hu", 3 );
00204 }
00205
00206
00207
00208 void COXml::serial(sint8 &b)
00209 {
00210 writenumber( (sint16)b, "%hd", 4 );
00211 }
00212
00213
00214
00215 void COXml::serial(uint16 &b)
00216 {
00217 writenumber( b, "%hu", 5 );
00218 }
00219
00220
00221
00222 void COXml::serial(sint16 &b)
00223 {
00224 writenumber( b, "%hd", 6 );
00225 }
00226
00227
00228
00229 void COXml::serial(uint32 &b)
00230 {
00231 writenumber( b, "%u", 10 );
00232 }
00233
00234
00235
00236 void COXml::serial(sint32 &b)
00237 {
00238 writenumber( b, "%d", 11 );
00239 }
00240
00241
00242
00243 void COXml::serial(uint64 &b)
00244 {
00245 writenumber( b, "%"NL_I64"u", 20 );
00246 }
00247
00248
00249
00250 void COXml::serial(sint64 &b)
00251 {
00252 writenumber( b, "%"NL_I64"d", 20 );
00253 }
00254
00255
00256
00257 void COXml::serial(float &b)
00258 {
00259 writenumber( (double)b, "%f", 128 );
00260 }
00261
00262
00263
00264 void COXml::serial(double &b)
00265 {
00266 writenumber( b, "%f", 128 );
00267 }
00268
00269
00270
00271 void COXml::serial(bool &b)
00272 {
00273 serialBit(b);
00274 }
00275
00276
00277
00278 void COXml::serialBit(bool &bit)
00279 {
00280 uint8 u = (uint8)bit;
00281 serial( u );
00282 }
00283
00284
00285
00286 #ifndef NL_OS_CYGWIN
00287 void COXml::serial(char &b)
00288 {
00289 char tmp[2] = {b , 0};
00290 serialSeparatedBufferOut( tmp );
00291 }
00292 #endif // NL_OS_CYGWIN
00293
00294
00295
00296 void COXml::serial(std::string &b)
00297 {
00298 nlassert( ! isReading() );
00299
00300
00301 if (_PushBegin)
00302 {
00303
00304 serialSeparatedBufferOut( b.c_str() );
00305 }
00306 else
00307 {
00308
00309 xmlPush ("S");
00310
00311
00312 serialSeparatedBufferOut( b.c_str() );
00313
00314
00315 xmlPop ();
00316 }
00317 }
00318
00319
00320
00321 void COXml::serial(ucstring &b)
00322 {
00323 nlassert( ! isReading() );
00324
00325
00326 uint size=b.length();
00327
00328
00329 string output;
00330 output.resize (b.length());
00331
00332
00333 for (uint i=0; i<size; i++)
00334 {
00335
00336 if (b[i]<0x7F)
00337 {
00338 output[i]=(char)b[i];
00339 }
00340 else
00341 {
00343 nlwarning ("handle ucstring to utf-8");
00344 output[i]=(b[i]&0xff);
00345 }
00346 }
00347
00348
00349 serial (output);
00350 }
00351
00352
00353
00354 void COXml::serialBuffer(uint8 *buf, uint len)
00355 {
00356
00357 xmlPush ("BUFFER");
00358
00359
00360 for (uint i=0; i<len; i++)
00361 {
00362 xmlPush ("ELM");
00363
00364 serial (buf[i]);
00365
00366 xmlPop ();
00367 }
00368
00369
00370 xmlPop ();
00371 }
00372
00373
00374
00375 bool COXml::xmlPushBeginInternal (const char *nodeName)
00376 {
00377 nlassert( ! isReading() );
00378
00379
00380 if ( _InternalStream )
00381 {
00382
00383 if ( ! _PushBegin )
00384 {
00385
00386 if (_CurrentNode==NULL)
00387 {
00388
00389 if (_Document == NULL)
00390 {
00391
00392 _Document = xmlNewDoc ((const xmlChar *)_Version.c_str());
00393
00394
00395 nlassert (_Document);
00396 }
00397
00398
00399 _CurrentNode=xmlNewDocNode (_Document, NULL, (const xmlChar*)nodeName, NULL);
00400 xmlDocSetRootElement (_Document, _CurrentNode);
00401
00402
00403 nlassert (_CurrentNode);
00404 }
00405 else
00406 {
00407
00408 flushContentString ();
00409
00410
00411 _CurrentNode=xmlNewChild (_CurrentNode, NULL, (const xmlChar*)nodeName, NULL);
00412
00413
00414 nlassert (_CurrentNode);
00415 }
00416
00417
00418 _PushBegin = true;
00419 }
00420 else
00421 {
00422 nlwarning ( "You must close your xmlPushBegin - xmlPushEnd before calling a new xmlPushBegin.");
00423 return false;
00424 }
00425 }
00426 else
00427 {
00428 nlwarning ( "Output stream has not been setuped.");
00429 return false;
00430 }
00431
00432
00433 return true;
00434 }
00435
00436
00437
00438 bool COXml::xmlPushEndInternal ()
00439 {
00440 nlassert( ! isReading() );
00441
00442
00443 if ( _InternalStream )
00444 {
00445
00446 if ( _PushBegin )
00447 {
00448
00449 _PushBegin = false;
00450 }
00451 else
00452 {
00453 nlwarning ( "You must call xmlPushBegin before calling xmlPushEnd.");
00454 return false;
00455 }
00456 }
00457 else
00458 {
00459 nlwarning ( "Output stream has not been setuped.");
00460 return false;
00461 }
00462
00463
00464 return true;
00465 }
00466
00467
00468
00469 bool COXml::xmlPopInternal ()
00470 {
00471 nlassert( ! isReading() );
00472
00473
00474 if ( _InternalStream )
00475 {
00476
00477 if ( ! _PushBegin )
00478 {
00479
00480 flushContentString ();
00481
00482
00483 _CurrentNode=_CurrentNode->parent;
00484 }
00485 else
00486 {
00487 nlwarning ( "You must call xmlPop after xmlPushEnd.");
00488 return false;
00489 }
00490 }
00491 else
00492 {
00493 nlwarning ( "Output stream has not been setuped.");
00494 return false;
00495 }
00496
00497
00498 return true;
00499 }
00500
00501
00502
00503 bool COXml::xmlSetAttribInternal (const char *attribName)
00504 {
00505 nlassert( ! isReading() );
00506
00507
00508 if ( _InternalStream )
00509 {
00510
00511 if ( _PushBegin )
00512 {
00513
00514 _AttribName = attribName;
00515
00516
00517 _AttribPresent = true;
00518 }
00519 else
00520 {
00521 nlwarning ( "You must call xmlSetAttrib between xmlPushBegin and xmlPushEnd calls.");
00522 return false;
00523 }
00524 }
00525 else
00526 {
00527 nlwarning ( "Output stream has not been setuped.");
00528 return false;
00529 }
00530
00531
00532 return true;
00533 }
00534
00535
00536
00537 bool COXml::xmlBreakLineInternal ()
00538 {
00539 nlassert( ! isReading() );
00540
00541
00542 if ( _InternalStream )
00543 {
00544
00545 if ( ! _PushBegin )
00546 {
00547
00548 _ContentString += '\n';
00549 }
00550 else
00551 {
00552 nlwarning ( "You must call xmlNBreakLine after xmlPushEnd.");
00553 return false;
00554 }
00555 }
00556 else
00557 {
00558 nlwarning ( "Output stream has not been setuped.");
00559 return false;
00560 }
00561
00562
00563 return true;
00564 }
00565
00566
00567
00568 bool COXml::xmlCommentInternal (const char *comment)
00569 {
00570 nlassert( ! isReading() );
00571
00572
00573 if ( _InternalStream )
00574 {
00575
00576 if ( _CurrentNode != NULL)
00577 {
00578
00579 xmlNodePtr commentPtr = xmlNewComment ((const xmlChar *)comment);
00580
00581
00582 xmlAddChild (_CurrentNode, commentPtr);
00583 }
00584 else
00585 {
00586 nlwarning ( "You must call xmlCommentInternal between xmlPushBegin and xmlPushEnd.");
00587 return false;
00588 }
00589 }
00590 else
00591 {
00592 nlwarning ( "Output stream has not been setuped.");
00593 return false;
00594 }
00595
00596 return true;
00597 }
00598
00599
00600
00601 void COXml::flush ()
00602 {
00603 if (_Document)
00604 {
00605
00606 xmlKeepBlanksDefault (0);
00607
00608
00609 xmlOutputBufferPtr outputBuffer = xmlOutputBufferCreateIO ( xmlOutputWriteCallbackForNeL, xmlOutputCloseCallbackForNeL, this, NULL );
00610
00611
00612 int res = xmlSaveFormatFileTo (outputBuffer, _Document, NULL, 1);
00613
00614
00615 nlassert (res!=-1);
00616
00617
00618 xmlFreeDoc (_Document);
00619 _Document = NULL;
00620 }
00621 }
00622
00623
00624
00625
00626
00627
00628
00629 int xmlOutputWriteCallbackForNeL ( void *context, const char *buffer, int len)
00630 {
00631
00632 COXml *object = (COXml*) context;
00633
00634
00635 object->_InternalStream->serialBuffer ((uint8*)buffer, len);
00636
00637
00638 return len;
00639 }
00640
00641
00642
00643 int xmlOutputCloseCallbackForNeL ( void *context )
00644 {
00645
00646
00647
00648
00649 return 1;
00650 }
00651
00652
00653
00654 xmlDocPtr COXml::getDocument ()
00655 {
00656 if (_Document)
00657 return _Document;
00658
00659
00660 _Document = xmlNewDoc ((const xmlChar *)_Version.c_str());
00661
00662 return _Document;
00663 }
00664
00665
00666
00667 bool COXml::isStringValidForProperties (const char *str)
00668 {
00669 while (*str)
00670 {
00671 if (*str == '\n')
00672 return false;
00673 str++;
00674 }
00675 return true;
00676 }
00677
00678
00679
00680 }
00681
00682 #endif // NL_DONT_USE_EXTERNAL_CODE