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