1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 29 #include <parse.hxx> 30 31 #include <string.h> 32 #include <iostream> 33 #include <xmlelem.hxx> 34 35 #if (_MSC_VER >=1400) 36 #pragma warning(disable:4365) 37 #endif 38 39 #ifdef UNX 40 #define strnicmp strncasecmp 41 #endif 42 43 44 45 // NOT FULLY DEFINED SERVICES 46 47 48 49 #define AssertionOf(x) \ 50 {if (!(x)) {std::cerr << "Assertion failed: " << #x << __FILE__ << __LINE__ << std::endl; exit(3); }} 51 52 53 54 X2CParser::X2CParser( XmlElement & o_rDocumentData ) 55 : // sFileName, 56 nFileLine(0), 57 pDocumentData(&o_rDocumentData), 58 // sWord, 59 text(0) 60 { 61 } 62 63 X2CParser::~X2CParser() 64 { 65 } 66 67 68 bool 69 X2CParser::LoadFile( const char * i_sFilename ) 70 { 71 sFileName = i_sFilename; 72 nFileLine = 1; 73 74 // Load file: 75 if ( ! LoadXmlFile( aFile, i_sFilename ) ) 76 return false; 77 78 // Test correct end: 79 const char * pLastTag = strrchr(aFile.operator const char *(),'<'); 80 if (pLastTag == 0) 81 return false; 82 if ( strnicmp(pLastTag+2, pDocumentData->Name().str(), pDocumentData->Name().l()) != 0 83 || strnicmp(pLastTag, "</", 2) != 0 ) 84 return false; 85 if (strchr(pLastTag,'>') == 0) 86 return false; 87 return true; 88 } 89 90 void 91 X2CParser::Parse() 92 { 93 // Parse: 94 text = aFile.operator const char *(); 95 96 Parse_XmlDeclaration(); 97 Parse_Doctype(); 98 99 pDocumentData->Parse(*this); 100 } 101 102 bool 103 X2CParser::Parse( const char * i_sFilename ) 104 { 105 bool ret = LoadFile(i_sFilename); 106 if (ret) 107 Parse(); 108 return ret; 109 } 110 111 void 112 X2CParser::Parse_XmlDeclaration() 113 { 114 Goto('<'); 115 if ( IsText("<?xml") ) 116 { 117 Goto_And_Pass('>'); 118 } 119 } 120 121 void 122 X2CParser::Parse_Doctype() 123 { 124 Goto('<'); 125 if ( IsText("<!DOCTYPE") ) 126 Goto_And_Pass('>'); 127 } 128 129 void 130 X2CParser::Parse_Sequence( DynamicList<XmlElement> & o_rElements, 131 const Simstr & i_sElementName ) 132 { 133 CheckAndPassBeginTag(i_sElementName.str()); 134 135 unsigned int i_max = o_rElements.size(); 136 for (unsigned i = 0; i < i_max; ++i) 137 { 138 o_rElements[i]->Parse(*this); 139 } // end for 140 141 CheckAndPassEndTag(i_sElementName.str()); 142 } 143 144 void 145 X2CParser::Parse_FreeChoice( DynamicList<XmlElement> & o_rElements ) 146 { 147 unsigned nSize = o_rElements.size(); 148 149 for ( bool bBreak = false; !bBreak; ) 150 { 151 bBreak = true; 152 for ( unsigned i = 0; i < nSize; ++i ) 153 { 154 Goto('<'); 155 if ( IsBeginTag(o_rElements[i]->Name().str()) ) 156 { 157 o_rElements[i]->Parse(*this); 158 bBreak = false; 159 break; 160 } 161 } // end for i 162 } // end for !bBreak 163 } 164 165 void 166 X2CParser::Parse_List( ListElement & o_rListElem ) 167 { 168 169 for ( Goto('<'); IsBeginTag(o_rListElem.Name().str()); Goto('<') ) 170 { 171 XmlElement * pNew = o_rListElem.Create_and_Add_NewElement(); 172 pNew->Parse(*this); 173 } 174 } 175 176 void 177 X2CParser::Parse_Text( Simstr & o_sText, 178 const Simstr & i_sElementName, 179 bool i_bReverseName ) 180 { 181 182 if ( ! CheckAndPassBeginTag(i_sElementName.str()) ) 183 return; 184 185 // Add new Element 186 GetTextTill( o_sText, '<', i_bReverseName ); 187 o_sText.remove_trailing_blanks(); 188 189 CheckAndPassEndTag(i_sElementName.str()); 190 } 191 192 void 193 X2CParser::Parse_MultipleText( List<Simstr> & o_rTexts, 194 const Simstr & i_sElementName, 195 bool i_bReverseName ) 196 { 197 for ( Goto('<'); IsBeginTag(i_sElementName.str()); Goto('<') ) 198 { 199 Simstr sNew; 200 Parse_Text(sNew, i_sElementName, i_bReverseName); 201 if (sNew.l() > 0) 202 o_rTexts.push_back(sNew); 203 } 204 } 205 206 void 207 X2CParser::Parse_SglAttr( Simstr & o_sAttrValue, 208 const Simstr & i_sElementName, 209 const Simstr & i_sAttrName ) 210 { 211 Goto('<'); 212 if ( !IsBeginTag(i_sElementName.str()) ) 213 SyntaxError("unexpected element"); 214 Move( i_sElementName.l() + 1 ); 215 216 Pass_White(); 217 if (*text == '>') 218 SyntaxError("no attribute found, where one was expected"); 219 Simstr sAttrName; 220 Get_Attribute(o_sAttrValue, sAttrName); 221 if (sAttrName != i_sAttrName) 222 SyntaxError("unknown attribute found"); 223 Pass_White(); 224 if (strncmp(text,"/>",2) != 0) 225 SyntaxError("missing \"/>\" at end of empty element"); 226 Move(2); 227 } 228 229 void 230 X2CParser::Parse_MultipleAttr( List<Simstr> & o_rAttrValues, 231 const Simstr & i_sElementName, 232 const List<Simstr> & i_rAttrNames ) 233 { 234 Goto('<'); 235 if ( !IsBeginTag(i_sElementName.str()) ) 236 SyntaxError("unexpected element"); 237 Move( i_sElementName.l() + 1 ); 238 Simstr sAttrName; 239 Simstr sAttrValue; 240 unsigned nSize = i_rAttrNames.size(); 241 unsigned i; 242 243 for ( Pass_White(); *text != '/'; Pass_White() ) 244 { 245 246 Get_Attribute(sAttrValue, sAttrName); 247 248 for ( i = 0; i < nSize; ++i ) 249 { 250 if ( i_rAttrNames[i] == sAttrName ) 251 { 252 o_rAttrValues[i] = sAttrValue; 253 break; 254 } 255 } 256 if (i == nSize) 257 SyntaxError("unknown attribute found"); 258 } 259 Move(2); 260 } 261 262 263 void 264 X2CParser::Get_Attribute( Simstr & o_rAttrValue, 265 Simstr & o_rAttrName ) 266 { 267 GetTextTill( o_rAttrName, '='); 268 269 while (*(++text) != '"') 270 { 271 if (*text == '\0') 272 SyntaxError("unexpected end of file"); 273 } 274 275 ++text; 276 GetTextTill( o_rAttrValue, '"'); 277 ++text; 278 } 279 280 bool 281 X2CParser::IsText( const char * i_sComparedText ) 282 { 283 return strnicmp( text, i_sComparedText, strlen(i_sComparedText) ) == 0; 284 } 285 286 bool 287 X2CParser::IsBeginTag( const char * i_sTagName ) 288 { 289 return strnicmp( text+1, i_sTagName, strlen(i_sTagName) ) == 0 290 && *text == '<'; 291 } 292 293 bool 294 X2CParser::IsEndTag( const char * i_sTagName ) 295 { 296 return strnicmp( text+2, i_sTagName, strlen(i_sTagName) ) == 0 297 && strnicmp( text, "</", 2 ) == 0; 298 } 299 300 void 301 X2CParser::Goto( char i_cNext ) 302 { 303 while (*text != i_cNext) 304 { 305 TestCurChar(); 306 ++text; 307 } 308 } 309 310 void 311 X2CParser::Goto_And_Pass( char i_cNext ) 312 { 313 Goto(i_cNext); 314 ++text; 315 } 316 317 void 318 X2CParser::Move( int i_nForward ) 319 { 320 text += i_nForward; 321 } 322 323 void 324 X2CParser::Pass_White() 325 { 326 while (*text <= 32) 327 { 328 TestCurChar(); 329 ++text; 330 } 331 } 332 333 void 334 X2CParser::GetTextTill( Simstr & o_rText, 335 char i_cEnd, 336 bool i_bReverseName ) 337 { 338 char * pResult = &sWord[0]; 339 char * pSet; 340 341 for ( pSet = pResult; 342 *text != i_cEnd; 343 ++text ) 344 { 345 TestCurChar(); 346 *pSet++ = *text; 347 } 348 349 while ( *pResult < 33 && *pResult > 0 ) 350 ++pResult; 351 while ( pSet > pResult ? *(pSet-1) < 33 : false ) 352 pSet--; 353 *pSet = '\0'; 354 355 356 if (i_bReverseName) 357 { 358 const unsigned int nMaxLen = 1000; 359 if (strlen(pResult) < nMaxLen) 360 { 361 char * sBreak = strrchr(pResult,'.'); 362 if (sBreak != 0) 363 { 364 static char sScope[nMaxLen+10]; 365 static char sName[nMaxLen+10]; 366 367 unsigned nScopeLen = sBreak - pResult; 368 strncpy ( sScope, pResult, nScopeLen ); // STRNCPY SAFE HERE 369 sScope[nScopeLen] = '\0'; 370 strcpy( sName, sBreak + 1 ); // STRCPY SAFE HERE 371 strcat( sName, " in " ); // STRCAT SAFE HERE 372 strcat( sName, sScope ); // STRCAT SAFE HERE 373 374 o_rText = sName; 375 return; 376 } 377 } 378 } // endif (i_bReverseName) 379 380 o_rText = &sWord[0]; 381 } 382 383 bool 384 X2CParser::CheckAndPassBeginTag( const char * i_sElementName ) 385 { 386 bool ret = true; 387 Goto('<'); 388 if ( ! IsBeginTag(i_sElementName) ) 389 SyntaxError( "unexpected element"); 390 if (IsAbsoluteEmpty()) 391 ret = false; 392 Goto_And_Pass('>'); 393 if (ret) 394 Pass_White(); 395 return ret; 396 } 397 398 void 399 X2CParser::CheckAndPassEndTag( const char * i_sElementName ) 400 { 401 Pass_White(); 402 if ( !IsEndTag(i_sElementName) ) 403 SyntaxError("missing or not matching end tag"); 404 Goto_And_Pass('>'); 405 } 406 407 bool 408 X2CParser::IsAbsoluteEmpty() const 409 { 410 const char * pEnd = strchr(text+1, '>'); 411 if (pEnd != 0) 412 { 413 if ( *(pEnd-1) == '/' ) 414 { 415 const char * pAttr = strchr(text+1, '"'); 416 if (pAttr == 0) 417 return true; 418 else if ( (pAttr-text) > (pEnd-text) ) 419 return true; 420 } 421 } 422 return false; 423 } 424 425 void 426 X2CParser::SyntaxError( const char * i_sText ) 427 { 428 std::cerr 429 << "Syntax error " 430 << i_sText 431 << " in file: " 432 << sFileName.str() 433 << " in line " 434 << nFileLine 435 << "." 436 << std::endl; 437 438 exit(3); 439 } 440 441 void 442 X2CParser::TestCurChar() 443 { 444 // if (*text == '\0') 445 // SyntaxError("unexpected end of file"); 446 // else 447 448 if (*text == '\n') 449 nFileLine++; 450 } 451 452 453