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 // skip XML comment 96 Goto('<'); 97 if ( IsText("<!--") ) 98 Goto_And_Pass('>'); 99 100 pDocumentData->Parse(*this); 101 } 102 103 bool 104 X2CParser::Parse( const char * i_sFilename ) 105 { 106 bool ret = LoadFile(i_sFilename); 107 if (ret) 108 Parse(); 109 return ret; 110 } 111 112 void 113 X2CParser::Parse_XmlDeclaration() 114 { 115 Goto('<'); 116 if ( IsText("<?xml") ) 117 { 118 Goto_And_Pass('>'); 119 } 120 } 121 122 void 123 X2CParser::Parse_Doctype() 124 { 125 Goto('<'); 126 if ( IsText("<!DOCTYPE") ) 127 Goto_And_Pass('>'); 128 } 129 130 void 131 X2CParser::Parse_Sequence( DynamicList<XmlElement> & o_rElements, 132 const Simstr & i_sElementName ) 133 { 134 CheckAndPassBeginTag(i_sElementName.str()); 135 136 unsigned int i_max = o_rElements.size(); 137 for (unsigned i = 0; i < i_max; ++i) 138 { 139 o_rElements[i]->Parse(*this); 140 } // end for 141 142 CheckAndPassEndTag(i_sElementName.str()); 143 } 144 145 void 146 X2CParser::Parse_FreeChoice( DynamicList<XmlElement> & o_rElements ) 147 { 148 unsigned nSize = o_rElements.size(); 149 150 for ( bool bBreak = false; !bBreak; ) 151 { 152 bBreak = true; 153 for ( unsigned i = 0; i < nSize; ++i ) 154 { 155 Goto('<'); 156 if ( IsBeginTag(o_rElements[i]->Name().str()) ) 157 { 158 o_rElements[i]->Parse(*this); 159 bBreak = false; 160 break; 161 } 162 } // end for i 163 } // end for !bBreak 164 } 165 166 void 167 X2CParser::Parse_List( ListElement & o_rListElem ) 168 { 169 170 for ( Goto('<'); IsBeginTag(o_rListElem.Name().str()); Goto('<') ) 171 { 172 XmlElement * pNew = o_rListElem.Create_and_Add_NewElement(); 173 pNew->Parse(*this); 174 } 175 } 176 177 void 178 X2CParser::Parse_Text( Simstr & o_sText, 179 const Simstr & i_sElementName, 180 bool i_bReverseName ) 181 { 182 183 if ( ! CheckAndPassBeginTag(i_sElementName.str()) ) 184 return; 185 186 // Add new Element 187 GetTextTill( o_sText, '<', i_bReverseName ); 188 o_sText.remove_trailing_blanks(); 189 190 CheckAndPassEndTag(i_sElementName.str()); 191 } 192 193 void 194 X2CParser::Parse_MultipleText( List<Simstr> & o_rTexts, 195 const Simstr & i_sElementName, 196 bool i_bReverseName ) 197 { 198 for ( Goto('<'); IsBeginTag(i_sElementName.str()); Goto('<') ) 199 { 200 Simstr sNew; 201 Parse_Text(sNew, i_sElementName, i_bReverseName); 202 if (sNew.l() > 0) 203 o_rTexts.push_back(sNew); 204 } 205 } 206 207 void 208 X2CParser::Parse_SglAttr( Simstr & o_sAttrValue, 209 const Simstr & i_sElementName, 210 const Simstr & i_sAttrName ) 211 { 212 Goto('<'); 213 if ( !IsBeginTag(i_sElementName.str()) ) 214 SyntaxError("unexpected element"); 215 Move( i_sElementName.l() + 1 ); 216 217 Pass_White(); 218 if (*text == '>') 219 SyntaxError("no attribute found, where one was expected"); 220 Simstr sAttrName; 221 Get_Attribute(o_sAttrValue, sAttrName); 222 if (sAttrName != i_sAttrName) 223 SyntaxError("unknown attribute found"); 224 Pass_White(); 225 if (strncmp(text,"/>",2) != 0) 226 SyntaxError("missing \"/>\" at end of empty element"); 227 Move(2); 228 } 229 230 void 231 X2CParser::Parse_MultipleAttr( List<Simstr> & o_rAttrValues, 232 const Simstr & i_sElementName, 233 const List<Simstr> & i_rAttrNames ) 234 { 235 Goto('<'); 236 if ( !IsBeginTag(i_sElementName.str()) ) 237 SyntaxError("unexpected element"); 238 Move( i_sElementName.l() + 1 ); 239 Simstr sAttrName; 240 Simstr sAttrValue; 241 unsigned nSize = i_rAttrNames.size(); 242 unsigned i; 243 244 for ( Pass_White(); *text != '/'; Pass_White() ) 245 { 246 247 Get_Attribute(sAttrValue, sAttrName); 248 249 for ( i = 0; i < nSize; ++i ) 250 { 251 if ( i_rAttrNames[i] == sAttrName ) 252 { 253 o_rAttrValues[i] = sAttrValue; 254 break; 255 } 256 } 257 if (i == nSize) 258 SyntaxError("unknown attribute found"); 259 } 260 Move(2); 261 } 262 263 264 void 265 X2CParser::Get_Attribute( Simstr & o_rAttrValue, 266 Simstr & o_rAttrName ) 267 { 268 GetTextTill( o_rAttrName, '='); 269 270 while (*(++text) != '"') 271 { 272 if (*text == '\0') 273 SyntaxError("unexpected end of file"); 274 } 275 276 ++text; 277 GetTextTill( o_rAttrValue, '"'); 278 ++text; 279 } 280 281 bool 282 X2CParser::IsText( const char * i_sComparedText ) 283 { 284 return strnicmp( text, i_sComparedText, strlen(i_sComparedText) ) == 0; 285 } 286 287 bool 288 X2CParser::IsBeginTag( const char * i_sTagName ) 289 { 290 return strnicmp( text+1, i_sTagName, strlen(i_sTagName) ) == 0 291 && *text == '<'; 292 } 293 294 bool 295 X2CParser::IsEndTag( const char * i_sTagName ) 296 { 297 return strnicmp( text+2, i_sTagName, strlen(i_sTagName) ) == 0 298 && strnicmp( text, "</", 2 ) == 0; 299 } 300 301 void 302 X2CParser::Goto( char i_cNext ) 303 { 304 while (*text != i_cNext) 305 { 306 TestCurChar(); 307 ++text; 308 } 309 } 310 311 void 312 X2CParser::Goto_And_Pass( char i_cNext ) 313 { 314 Goto(i_cNext); 315 ++text; 316 } 317 318 void 319 X2CParser::Move( int i_nForward ) 320 { 321 text += i_nForward; 322 } 323 324 void 325 X2CParser::Pass_White() 326 { 327 while (*text <= 32) 328 { 329 TestCurChar(); 330 ++text; 331 } 332 } 333 334 void 335 X2CParser::GetTextTill( Simstr & o_rText, 336 char i_cEnd, 337 bool i_bReverseName ) 338 { 339 char * pResult = &sWord[0]; 340 char * pSet; 341 342 for ( pSet = pResult; 343 *text != i_cEnd; 344 ++text ) 345 { 346 TestCurChar(); 347 *pSet++ = *text; 348 } 349 350 while ( *pResult < 33 && *pResult > 0 ) 351 ++pResult; 352 while ( pSet > pResult ? *(pSet-1) < 33 : false ) 353 pSet--; 354 *pSet = '\0'; 355 356 357 if (i_bReverseName) 358 { 359 const unsigned int nMaxLen = 1000; 360 if (strlen(pResult) < nMaxLen) 361 { 362 char * sBreak = strrchr(pResult,'.'); 363 if (sBreak != 0) 364 { 365 static char sScope[nMaxLen+10]; 366 static char sName[nMaxLen+10]; 367 368 unsigned nScopeLen = sBreak - pResult; 369 strncpy ( sScope, pResult, nScopeLen ); // STRNCPY SAFE HERE 370 sScope[nScopeLen] = '\0'; 371 strcpy( sName, sBreak + 1 ); // STRCPY SAFE HERE 372 strcat( sName, " in " ); // STRCAT SAFE HERE 373 strcat( sName, sScope ); // STRCAT SAFE HERE 374 375 o_rText = sName; 376 return; 377 } 378 } 379 } // endif (i_bReverseName) 380 381 o_rText = &sWord[0]; 382 } 383 384 bool 385 X2CParser::CheckAndPassBeginTag( const char * i_sElementName ) 386 { 387 bool ret = true; 388 Goto('<'); 389 if ( ! IsBeginTag(i_sElementName) ) 390 SyntaxError( "unexpected element"); 391 if (IsAbsoluteEmpty()) 392 ret = false; 393 Goto_And_Pass('>'); 394 if (ret) 395 Pass_White(); 396 return ret; 397 } 398 399 void 400 X2CParser::CheckAndPassEndTag( const char * i_sElementName ) 401 { 402 Pass_White(); 403 if ( !IsEndTag(i_sElementName) ) 404 SyntaxError("missing or not matching end tag"); 405 Goto_And_Pass('>'); 406 } 407 408 bool 409 X2CParser::IsAbsoluteEmpty() const 410 { 411 const char * pEnd = strchr(text+1, '>'); 412 if (pEnd != 0) 413 { 414 if ( *(pEnd-1) == '/' ) 415 { 416 const char * pAttr = strchr(text+1, '"'); 417 if (pAttr == 0) 418 return true; 419 else if ( (pAttr-text) > (pEnd-text) ) 420 return true; 421 } 422 } 423 return false; 424 } 425 426 void 427 X2CParser::SyntaxError( const char * i_sText ) 428 { 429 std::cerr 430 << "Syntax error " 431 << i_sText 432 << " in file: " 433 << sFileName.str() 434 << " in line " 435 << nFileLine 436 << "." 437 << std::endl; 438 439 exit(3); 440 } 441 442 void 443 X2CParser::TestCurChar() 444 { 445 // if (*text == '\0') 446 // SyntaxError("unexpected end of file"); 447 // else 448 449 if (*text == '\n') 450 nFileLine++; 451 } 452 453 454