Newer
Older
fPSVIElemContext.fCurrentTypeInfo = ((SchemaValidator*) fValidator)->getCurrentTypeInfo();
if(!fPSVIElemContext.fCurrentTypeInfo)
fPSVIElemContext.fCurrentDV = ((SchemaValidator*) fValidator)->getCurrentDatatypeValidator();
else
fPSVIElemContext.fCurrentDV = 0;
if(fPSVIHandler)
{
fPSVIElemContext.fNormalizedValue = ((SchemaValidator*) fValidator)->getNormalizedValue();
if (XMLString::equals(fPSVIElemContext.fNormalizedValue, XMLUni::fgZeroLenString))
fPSVIElemContext.fNormalizedValue = 0;
}
}
else
{
fPSVIElemContext.fCurrentDV = 0;
fPSVIElemContext.fCurrentTypeInfo = 0;
fPSVIElemContext.fNormalizedValue = 0;
// If validation is enabled, then lets pass him the list of children and
// this element and let him validate it.
PeiYong Zhang
committed
//
// XML1.0-3rd
// Validity Constraint:
// The declaration matches EMPTY and the element has no content (not even
// entity references, comments, PIs or white space).
//
if ( (fGrammarType == Grammar::DTDGrammarType) &&
(topElem->fCommentOrPISeen) &&
(((DTDElementDecl*) topElem->fThisElement)->getModelType() == DTDElementDecl::Empty))
{
fValidator->emitError
(
XMLValid::EmptyElemHasContent
, topElem->fThisElement->getFullName()
);
}
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
//
// XML1.0-3rd
// Validity Constraint:
//
// The declaration matches children and the sequence of child elements
// belongs to the language generated by the regular expression in the
// content model, with optional white space, comments and PIs
// (i.e. markup matching production [27] Misc) between the start-tag and
// the first child element, between child elements, or between the last
// child element and the end-tag.
//
// Note that
// a CDATA section containing only white space or
// a reference to an entity whose replacement text is character references
// expanding to white space do not match the nonterminal S, and hence
// cannot appear in these positions; however,
// a reference to an internal entity with a literal value consisting
// of character references expanding to white space does match S,
// since its replacement text is the white space resulting from expansion
// of the character references.
//
if ( (fGrammarType == Grammar::DTDGrammarType) &&
(topElem->fReferenceEscaped) &&
(((DTDElementDecl*) topElem->fThisElement)->getModelType() == DTDElementDecl::Children))
{
fValidator->emitError
(
XMLValid::ElemChildrenHasInvalidWS
, topElem->fThisElement->getFullName()
);
}
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
int res = fValidator->checkContent
(
topElem->fThisElement
, topElem->fChildren
, topElem->fChildCount
);
if (res >= 0)
{
// One of the elements is not valid for the content. NOTE that
// if no children were provided but the content model requires
// them, it comes back with a zero value. But we cannot use that
// to index the child array in this case, and have to put out a
// special message.
if (!topElem->fChildCount)
{
fValidator->emitError
(
XMLValid::EmptyNotValidForContent
, topElem->fThisElement->getFormattedContentModel()
);
}
else if ((unsigned int)res >= topElem->fChildCount)
{
fValidator->emitError
(
XMLValid::NotEnoughElemsForCM
, topElem->fThisElement->getFormattedContentModel()
);
}
else
{
fValidator->emitError
(
XMLValid::ElementNotValidForContent
, topElem->fChildren[res]->getRawName()
, topElem->fThisElement->getFormattedContentModel()
);
}
}
Gareth Reakes
committed
if (fGrammarType == Grammar::SchemaGrammarType) {
if (((SchemaValidator*) fValidator)->getErrorOccurred())
fPSVIElemContext.fErrorOccurred = true;
else if (fPSVIElemContext.fCurrentDV && fPSVIElemContext.fCurrentDV->getType() == DatatypeValidator::Union)
psviMemberType = fValidationContext->getValidatingMemberType();
if (fPSVIHandler)
{
fPSVIElemContext.fIsSpecified = ((SchemaValidator*) fValidator)->getIsElemSpecified();
if(fPSVIElemContext.fIsSpecified)
fPSVIElemContext.fNormalizedValue = ((SchemaElementDecl *)topElem->fThisElement)->getDefaultValue();
if (toCheckIdentityConstraint())
{
fICHandler->deactivateContext
(
(SchemaElementDecl *) topElem->fThisElement
, fContent.getRawBuffer()
);
if (fGrammarType == Grammar::SchemaGrammarType)
{
if (fPSVIHandler)
{
endElementPSVI(
(SchemaElementDecl*)topElem->fThisElement, psviMemberType);
}
Neil Graham
committed
// now we can reset the datatype buffer, since the
// application has had a chance to copy the characters somewhere else
((SchemaValidator *)fValidator)->clearDatatypeBuffer();
// If we have a doc handler, tell it about the end tag
if (fDocHandler)
{
fDocHandler->endElement
(
*topElem->fThisElement
, uriId
, isRoot
, fPrefixBuf.getRawBuffer()
);
}
if (fGrammarType == Grammar::SchemaGrammarType) {
if (!isRoot)
{
// update error information
fErrorStack->push(fErrorStack->pop() || fPSVIElemContext.fErrorOccurred);
}
Gareth Reakes
committed
}
// If this was the root, then done with content
gotData = !isRoot;
if (gotData) {
if (fDoNamespaces) {
// Restore the grammar
fGrammar = fElemStack.getCurrentGrammar();
fGrammarType = fGrammar->getGrammarType();
if (fGrammarType == Grammar::SchemaGrammarType && !fValidator->handlesSchema()) {
if (fValidatorFromUser)
David Abram Cargill
committed
ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::Gen_NoSchemaValidator, fMemoryManager);
else {
fValidator = fSchemaValidator;
}
}
else if (fGrammarType == Grammar::DTDGrammarType && !fValidator->handlesDTD()) {
if (fValidatorFromUser)
David Abram Cargill
committed
ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::Gen_NoDTDValidator, fMemoryManager);
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
else {
fValidator = fDTDValidator;
}
}
fValidator->setGrammar(fGrammar);
}
// Restore the validation flag
fValidate = fElemStack.getValidationFlag();
}
}
// This method handles the high level logic of scanning the DOCType
// declaration. This calls the DTDScanner and kicks off both the scanning of
// the internal subset and the scanning of the external subset, if any.
//
// When we get here the '<!DOCTYPE' part has already been scanned, which is
// what told us that we had a doc type decl to parse.
void IGXMLScanner::scanDocTypeDecl()
{
// We have a doc type. So, switch the Grammar.
switchGrammar(XMLUni::fgDTDEntityString);
if (fDocTypeHandler)
fDocTypeHandler->resetDocType();
// There must be some space after DOCTYPE
if (!fReaderMgr.skipPastSpaces())
{
emitError(XMLErrs::ExpectedWhitespace);
// Just skip the Doctype declaration and return
fReaderMgr.skipPastChar(chCloseAngle);
return;
}
// Get a buffer for the root element
XMLBufBid bbRootName(&fBufMgr);
// Get a name from the input, which should be the name of the root
// element of the upcoming content.
fReaderMgr.getName(bbRootName.getBuffer());
if (bbRootName.isEmpty())
{
emitError(XMLErrs::NoRootElemInDOCTYPE);
fReaderMgr.skipPastChar(chCloseAngle);
return;
}
// Store the root element name for later check
setRootElemName(bbRootName.getRawBuffer());
// This element obviously is not going to exist in the element decl
// pool yet, but we need to call docTypeDecl. So force it into
// the element decl pool, marked as being there because it was in
// the DOCTYPE. Later, when its declared, the status will be updated.
//
// Only do this if we are not reusing the validator! If we are reusing,
// then look it up instead. It has to exist!
DTDElementDecl* rootDecl = new (fGrammarPoolMemoryManager) DTDElementDecl
(
bbRootName.getRawBuffer()
, fEmptyNamespaceId
, DTDElementDecl::Any
, fGrammarPoolMemoryManager
Neil Graham
committed
);
Janitor<DTDElementDecl> rootDeclJanitor(rootDecl);
rootDecl->setCreateReason(DTDElementDecl::AsRootElem);
rootDecl->setExternalElemDeclaration(true);
Neil Graham
committed
if(!fUseCachedGrammar)
{
// this will break getRootElemId on DTDGrammar when
// cached grammars are in use, but
// why would one use this anyway???
((DTDGrammar*)fGrammar)->setRootElemId(fGrammar->putElemDecl(rootDecl));
rootDeclJanitor.release();
Neil Graham
committed
} else
{
// attach this to the undeclared element pool so that it gets deleted
XMLElementDecl* elemDecl = fDTDElemNonDeclPool->getByKey(bbRootName.getRawBuffer());
if (elemDecl)
{
rootDecl->setId(elemDecl->getId());
}
else
{
rootDecl->setId(fDTDElemNonDeclPool->put((DTDElementDecl*)rootDecl));
rootDeclJanitor.release();
Neil Graham
committed
}
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
// Skip any spaces after the name
fReaderMgr.skipPastSpaces();
// And now if we are looking at a >, then we are done. It is not
// required to have an internal or external subset, though why you
// would not escapes me.
if (fReaderMgr.skippedChar(chCloseAngle)) {
// If we have a doc type handler and advanced callbacks are enabled,
// call the doctype event.
if (fDocTypeHandler)
fDocTypeHandler->doctypeDecl(*rootDecl, 0, 0, false);
return;
}
// either internal/external subset
if (fValScheme == Val_Auto && !fValidate)
fValidate = true;
bool hasIntSubset = false;
bool hasExtSubset = false;
XMLCh* sysId = 0;
XMLCh* pubId = 0;
DTDScanner dtdScanner
(
(DTDGrammar*) fGrammar
, fDocTypeHandler
, fGrammarPoolMemoryManager
, fMemoryManager
);
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
dtdScanner.setScannerInfo(this, &fReaderMgr, &fBufMgr);
// If the next character is '[' then we have no external subset cause
// there is no system id, just the opening character of the internal
// subset. Else, has to be an id.
//
// Just look at the next char, don't eat it.
if (fReaderMgr.peekNextChar() == chOpenSquare)
{
hasIntSubset = true;
}
else
{
// Indicate we have an external subset
hasExtSubset = true;
fHasNoDTD = false;
// Get buffers for the ids
XMLBufBid bbPubId(&fBufMgr);
XMLBufBid bbSysId(&fBufMgr);
// Get the external subset id
if (!dtdScanner.scanId(bbPubId.getBuffer(), bbSysId.getBuffer(), DTDScanner::IDType_External))
{
fReaderMgr.skipPastChar(chCloseAngle);
return;
}
// Get copies of the ids we got
pubId = XMLString::replicate(bbPubId.getRawBuffer(), fMemoryManager);
sysId = XMLString::replicate(bbSysId.getRawBuffer(), fMemoryManager);
// Skip spaces and check again for the opening of an internal subset
fReaderMgr.skipPastSpaces();
// Just look at the next char, don't eat it.
if (fReaderMgr.peekNextChar() == chOpenSquare) {
hasIntSubset = true;
}
}
// Insure that the ids get cleaned up, if they got allocated
ArrayJanitor<XMLCh> janSysId(sysId, fMemoryManager);
ArrayJanitor<XMLCh> janPubId(pubId, fMemoryManager);
// If we have a doc type handler and advanced callbacks are enabled,
// call the doctype event.
if (fDocTypeHandler)
fDocTypeHandler->doctypeDecl(*rootDecl, pubId, sysId, hasIntSubset, hasExtSubset);
// Ok, if we had an internal subset, we are just past the [ character
// and need to parse that first.
if (hasIntSubset)
{
// Eat the opening square bracket
fReaderMgr.getNextChar();
checkInternalDTD(hasExtSubset, sysId);
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
// And try to scan the internal subset. If we fail, try to recover
// by skipping forward tot he close angle and returning.
if (!dtdScanner.scanInternalSubset())
{
fReaderMgr.skipPastChar(chCloseAngle);
return;
}
// Do a sanity check that some expanded PE did not propogate out of
// the doctype. This could happen if it was terminated early by bad
// syntax.
if (fReaderMgr.getReaderDepth() > 1)
{
emitError(XMLErrs::PEPropogated);
// Ask the reader manager to pop back down to the main level
fReaderMgr.cleanStackBackTo(1);
}
fReaderMgr.skipPastSpaces();
}
// And that should leave us at the closing > of the DOCTYPE line
if (!fReaderMgr.skippedChar(chCloseAngle))
{
// Do a special check for the common scenario of an extra ] char at
// the end. This is easy to recover from.
if (fReaderMgr.skippedChar(chCloseSquare)
&& fReaderMgr.skippedChar(chCloseAngle))
{
emitError(XMLErrs::ExtraCloseSquare);
}
else
{
emitError(XMLErrs::UnterminatedDOCTYPE);
fReaderMgr.skipPastChar(chCloseAngle);
}
}
// If we had an external subset, then we need to deal with that one
// next. If we are reusing the validator, then don't scan it.
if (hasExtSubset) {
if (fUseCachedGrammar)
{
InputSource* sysIdSrc = resolveSystemId(sysId);
Janitor<InputSource> janSysIdSrc(sysIdSrc);
Grammar* grammar = fGrammarResolver->getGrammar(sysIdSrc->getSystemId());
if (grammar && grammar->getGrammarType() == Grammar::DTDGrammarType) {
fDTDGrammar = (DTDGrammar*) grammar;
fGrammar = fDTDGrammar;
fValidator->setGrammar(fGrammar);
Neil Graham
committed
// should not be modifying cached grammars!
/********
rootDecl = (DTDElementDecl*) fGrammar->getElemDecl(fEmptyNamespaceId, 0, bbRootName.getRawBuffer(), Grammar::TOP_LEVEL_SCOPE);
if (rootDecl)
((DTDGrammar*)fGrammar)->setRootElemId(rootDecl->getId());
else {
rootDecl = new (fGrammarPoolMemoryManager) DTDElementDecl
(
bbRootName.getRawBuffer()
, fEmptyNamespaceId
, DTDElementDecl::Any
, fGrammarPoolMemoryManager
rootDecl->setCreateReason(DTDElementDecl::AsRootElem);
rootDecl->setExternalElemDeclaration(true);
((DTDGrammar*)fGrammar)->setRootElemId(fGrammar->putElemDecl(rootDecl));
}
Neil Graham
committed
********/
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
return;
}
}
if (fLoadExternalDTD || fValidate)
{
// And now create a reader to read this entity
InputSource* srcUsed;
XMLReader* reader = fReaderMgr.createReader
(
sysId
, pubId
, false
, XMLReader::RefFrom_NonLiteral
, XMLReader::Type_General
, XMLReader::Source_External
, srcUsed
, fCalculateSrcOfs
);
// Put a janitor on the input source
Janitor<InputSource> janSrc(srcUsed);
// If it failed then throw an exception
if (!reader)
David Abram Cargill
committed
ThrowXMLwithMemMgr1(RuntimeException, XMLExcepts::Gen_CouldNotOpenDTD, srcUsed->getSystemId(), fMemoryManager);
if (fToCacheGrammar) {
unsigned int stringId = fGrammarResolver->getStringPool()->addOrFind(srcUsed->getSystemId());
const XMLCh* sysIdStr = fGrammarResolver->getStringPool()->getValueForId(stringId);
fGrammarResolver->orphanGrammar(XMLUni::fgDTDEntityString);
((XMLDTDDescription*) (fGrammar->getGrammarDescription()))->setSystemId(sysIdStr);
fGrammarResolver->putGrammar(fGrammar);
}
// In order to make the processing work consistently, we have to
// make this look like an external entity. So create an entity
// decl and fill it in and push it with the reader, as happens
// with an external entity. Put a janitor on it to insure it gets
// cleaned up. The reader manager does not adopt them.
const XMLCh gDTDStr[] = { chLatin_D, chLatin_T, chLatin_D , chNull };
DTDEntityDecl* declDTD = new (fGrammarPoolMemoryManager) DTDEntityDecl(gDTDStr, false, fGrammarPoolMemoryManager);
declDTD->setSystemId(sysId);
Janitor<DTDEntityDecl> janDecl(declDTD);
// Mark this one as a throw at end
reader->setThrowAtEnd(true);
// And push it onto the stack, with its pseudo name
fReaderMgr.pushReader(reader, declDTD);
// Tell it its not in an include section
dtdScanner.scanExtSubsetDecl(false, true);
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
}
}
}
bool IGXMLScanner::scanStartTag(bool& gotData)
{
// Assume we will still have data until proven otherwise. It will only
// ever be false if this is the root and its empty.
gotData = true;
// Get the QName. In this case, we are not doing namespaces, so we just
// use it as is and don't have to break it into parts.
if (!fReaderMgr.getName(fQNameBuf))
{
emitError(XMLErrs::ExpectedElementName);
fReaderMgr.skipToChar(chOpenAngle);
return false;
}
// Assume it won't be an empty tag
bool isEmpty = false;
// Lets try to look up the element in the validator's element decl pool
// We can pass bogus values for the URI id and the base name. We know that
// this can only be called if we are doing a DTD style validator and that
// he will only look at the QName.
//
// We tell him to fault in a decl if he does not find one.
Neil Graham
committed
// Actually, we *don't* tell him to fault in a decl if he does not find one- NG
Neil Graham
committed
const XMLCh *rawQName = fQNameBuf.getRawBuffer();
XMLElementDecl* elemDecl = fGrammar->getElemDecl
Neil Graham
committed
, rawQName
Neil Graham
committed
// look for it in the undeclared pool:
if(!elemDecl)
{
elemDecl = fDTDElemNonDeclPool->getByKey(rawQName);
}
if(!elemDecl)
{
// we're assuming this must be a DTD element. DTD's can be
// used with or without namespaces, but schemas cannot be used without
// namespaces.
wasAdded = true;
elemDecl = new (fMemoryManager) DTDElementDecl
(
rawQName
, fEmptyNamespaceId
, DTDElementDecl::Any
, fMemoryManager
);
elemDecl->setId(fDTDElemNonDeclPool->put((DTDElementDecl*)elemDecl));
}
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
// We do something different here according to whether we found the
// element or not.
if (wasAdded)
{
// If validating then emit an error
if (fValidate)
{
// This is to tell the reuse Validator that this element was
// faulted-in, was not an element in the validator pool originally
elemDecl->setCreateReason(XMLElementDecl::JustFaultIn);
fValidator->emitError
(
XMLValid::ElementNotDefined
, elemDecl->getFullName()
);
}
}
else
{
// If its not marked declared and validating, then emit an error
if (fValidate && !elemDecl->isDeclared())
{
fValidator->emitError
(
XMLValid::ElementNotDefined
, elemDecl->getFullName()
);
}
}
// See if its the root element
const bool isRoot = fElemStack.isEmpty();
// Expand the element stack and add the new element
fElemStack.addLevel(elemDecl, fReaderMgr.getCurrentReaderNum());
fElemStack.setValidationFlag(fValidate);
// Validate the element
if (fValidate)
fValidator->validateElement(elemDecl);
// If this is the first element and we are validating, check the root
// element.
if (isRoot)
{
fRootGrammar = fGrammar;
if (fValidate)
{
// If a DocType exists, then check if it matches the root name there.
if (fRootElemName && !XMLString::equals(fQNameBuf.getRawBuffer(), fRootElemName))
fValidator->emitError(XMLValid::RootElemNotLikeDocType);
// Some validators may also want to check the root, call the
// XMLValidator::checkRootElement
if (fValidatorFromUser && !fValidator->checkRootElement(elemDecl->getId()))
fValidator->emitError(XMLValid::RootElemNotLikeDocType);
}
}
else
{
// If the element stack is not empty, then add this element as a
// child of the previous top element. If its empty, this is the root
// elem and is not the child of anything.
fElemStack.addChild(elemDecl->getElementName(), true);
}
// Ask the element decl to clear out the 'provided' flag on all of its
// att defs.
elemDecl->resetDefs();
// Skip any whitespace after the name
fReaderMgr.skipPastSpaces();
// We loop until we either see a /> or >, handling attribute/value
// pairs until we get there.
unsigned int attCount = 0;
unsigned int curAttListSize = fAttrList->size();
wasAdded = false;
Alberto Massari
committed
fElemCount++;
while (true)
{
// And get the next non-space character
XMLCh nextCh = fReaderMgr.peekNextChar();
// If the next character is not a slash or closed angle bracket,
// then it must be whitespace, since whitespace is required
// between the end of the last attribute and the name of the next
// one.
if (attCount)
{
if ((nextCh != chForwardSlash) && (nextCh != chCloseAngle))
{
{
// Ok, skip by them and peek another char
fReaderMgr.skipPastSpaces();
nextCh = fReaderMgr.peekNextChar();
}
else
{
// Emit the error but keep on going
emitError(XMLErrs::ExpectedWhitespace);
}
}
}
// Ok, here we first check for any of the special case characters.
// If its not one, then we do the normal case processing, which
// assumes that we've hit an attribute value, Otherwise, we do all
// the special case checks.
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
{
// Assume its going to be an attribute, so get a name from
// the input.
if (!fReaderMgr.getName(fAttNameBuf))
{
emitError(XMLErrs::ExpectedAttrName);
fReaderMgr.skipPastChar(chCloseAngle);
return false;
}
// And next must be an equal sign
if (!scanEq())
{
static const XMLCh tmpList[] =
{
chSingleQuote, chDoubleQuote, chCloseAngle
, chOpenAngle, chForwardSlash, chNull
};
emitError(XMLErrs::ExpectedEqSign);
// Try to sync back up by skipping forward until we either
// hit something meaningful.
const XMLCh chFound = fReaderMgr.skipUntilInOrWS(tmpList);
if ((chFound == chCloseAngle) || (chFound == chForwardSlash))
{
// Jump back to top for normal processing of these
continue;
}
else if ((chFound == chSingleQuote)
|| (chFound == chDoubleQuote)
{
// Just fall through assuming that the value is to follow
}
else if (chFound == chOpenAngle)
{
// Assume a malformed tag and that new one is starting
emitError(XMLErrs::UnterminatedStartTag, elemDecl->getFullName());
return false;
}
else
{
// Something went really wrong
return false;
}
}
// See if this attribute is declared for this element. If we are
// not validating of course it will not be at first, but we will
// fault it into the pool (to avoid lots of redundant errors.)
XMLCh * namePtr = fAttNameBuf.getRawBuffer();
XMLAttDef* attDef = ((DTDElementDecl *)elemDecl)->getAttDef(namePtr);
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
// Add this attribute to the attribute list that we use to
// pass them to the handler. We reuse its existing elements
// but expand it as required.
// Note that we want to this first since this will
// make a copy of the namePtr; we can then make use of
// that copy in the hashtable lookup that checks
// for duplicates. This will mean we may have to update
// the type of the XMLAttr later.
XMLAttr* curAtt;
if (attCount >= curAttListSize)
{
curAtt = new (fMemoryManager) XMLAttr
(
-1
, namePtr
, XMLUni::fgZeroLenString
, XMLUni::fgZeroLenString
, (attDef)?attDef->getType():XMLAttDef::CData
, true
, fMemoryManager
);
fAttrList->addElement(curAtt);
}
else
{
curAtt = fAttrList->elementAt(attCount);
curAtt->set
(
-1
, namePtr
, XMLUni::fgZeroLenString
, XMLUni::fgZeroLenString
, (attDef)?attDef->getType():XMLAttDef::CData
);
curAtt->setSpecified(true);
}
// reset namePtr so it refers to newly-allocated memory
namePtr = (XMLCh *)curAtt->getName();
if (!attDef)
{
// If there is a validation handler, then we are validating
// so emit an error.
if (fValidate)
fValidator->emitError
(
XMLValid::AttNotDefinedForElement
, fAttNameBuf.getRawBuffer()
, elemDecl->getFullName()
);
}
unsigned int *curCountPtr = fUndeclaredAttrRegistry->get(namePtr);
if(!curCountPtr)
{
curCountPtr = getNewUIntPtr();
*curCountPtr = fElemCount;
fUndeclaredAttrRegistry->put((void *)namePtr, curCountPtr);
}
else if(*curCountPtr < fElemCount)
*curCountPtr = fElemCount;
else
{
emitError
(
XMLErrs::AttrAlreadyUsedInSTag
, namePtr
, elemDecl->getFullName()
);
}
// prepare for duplicate detection
unsigned int *curCountPtr = fAttDefRegistry->get(attDef);
if(!curCountPtr)
curCountPtr = getNewUIntPtr();
*curCountPtr = fElemCount;
fAttDefRegistry->put(attDef, curCountPtr);
}
else if(*curCountPtr < fElemCount)
*curCountPtr = fElemCount;
else
{
emitError
(
XMLErrs::AttrAlreadyUsedInSTag
, attDef->getFullName()
// Skip any whitespace before the value and then scan the att
// value. This will come back normalized with entity refs and
// char refs expanded.
fReaderMgr.skipPastSpaces();
if (!scanAttValue(attDef, namePtr, fAttValueBuf))
{
static const XMLCh tmpList[] =
{
chCloseAngle, chOpenAngle, chForwardSlash, chNull
};
emitError(XMLErrs::ExpectedAttrValue);
// It failed, so lets try to get synced back up. We skip
// forward until we find some whitespace or one of the
// chars in our list.
const XMLCh chFound = fReaderMgr.skipUntilInOrWS(tmpList);
if ((chFound == chCloseAngle)
|| (chFound == chForwardSlash)
{
// Just fall through and process this attribute, though
// the value will be "".
}
else if (chFound == chOpenAngle)
{
// Assume a malformed tag and that new one is starting
emitError(XMLErrs::UnterminatedStartTag, elemDecl->getFullName());
return false;
}
else
{
// Something went really wrong
return false;
}
}
// must set the newly-minted value on the XMLAttr:
curAtt->setValue(fAttValueBuf.getRawBuffer());
// Now that its all stretched out, lets look at its type and
// determine if it has a valid value. It will output any needed
// errors, but we just keep going. We only need to do this if
// we are validating.
if (attDef)
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
{
// Let the validator pass judgement on the attribute value
if (fValidate)
{
fValidator->validateAttrValue
(
attDef
, fAttValueBuf.getRawBuffer()
, false
, elemDecl
);
}
}
attCount++;
// And jump back to the top of the loop
continue;
}
// It was some special case character so do all of the checks and
// deal with it.
if (!nextCh)
David Abram Cargill
committed
ThrowXMLwithMemMgr(UnexpectedEOFException, XMLExcepts::Gen_UnexpectedEOF, fMemoryManager);
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
if (nextCh == chForwardSlash)
{
fReaderMgr.getNextChar();
isEmpty = true;
if (!fReaderMgr.skippedChar(chCloseAngle))
emitError(XMLErrs::UnterminatedStartTag, elemDecl->getFullName());
break;
}
else if (nextCh == chCloseAngle)
{
fReaderMgr.getNextChar();
break;
}
else if (nextCh == chOpenAngle)
{
// Check for this one specially, since its going to be common
// and it is kind of auto-recovering since we've already hit the
// next open bracket, which is what we would have seeked to (and
// skipped this whole tag.)
emitError(XMLErrs::UnterminatedStartTag, elemDecl->getFullName());
break;
}
else if ((nextCh == chSingleQuote) || (nextCh == chDoubleQuote))
{
// Check for this one specially, which is probably a missing
// attribute name, e.g. ="value". Just issue expected name
// error and eat the quoted string, then jump back to the
// top again.
emitError(XMLErrs::ExpectedAttrName);
fReaderMgr.getNextChar();
fReaderMgr.skipQuotedString(nextCh);
fReaderMgr.skipPastSpaces();
continue;
}
}
if(attCount)
{
// clean up after ourselves:
// clear the map used to detect duplicate attributes
fUndeclaredAttrRegistry->removeAll();
}
// Ok, so lets get an enumerator for the attributes of this element
// and run through them for well formedness and validity checks. But
// make sure that we had any attributes before we do it, since the list
// would have have gotten faulted in anyway.
if (elemDecl->hasAttDefs())
{
// N.B.: this assumes DTD validation.
XMLAttDefList& attDefList = elemDecl->getAttDefList();
Neil Graham
committed
for(unsigned int i=0; i<attDefList.getAttDefCount(); i++)
{
// Get the current att def, for convenience and its def type
Neil Graham
committed
const XMLAttDef& curDef = attDefList.getAttDef(i);
const XMLAttDef::DefAttTypes defType = curDef.getDefaultType();
unsigned int *attCountPtr = fAttDefRegistry->get(&curDef);
if (!attCountPtr || *attCountPtr < fElemCount)
{ // did not occur
if (fValidate)
{
// If we are validating and its required, then an error
if (defType == XMLAttDef::Required)
{
fValidator->emitError
(
XMLValid::RequiredAttrNotProvided
, curDef.getFullName()
);
}
else if ((defType == XMLAttDef::Default) ||
(defType == XMLAttDef::Fixed) )
{
if (fStandalone && curDef.isExternal())
{
// XML 1.0 Section 2.9
// Document is standalone, so attributes must not be defaulted.
fValidator->emitError(XMLValid::NoDefAttForStandalone, curDef.getFullName(), elemDecl->getFullName());
Gareth Reakes
committed
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
}
}
}
// Fault in the value if needed, and bump the att count
if ((defType == XMLAttDef::Default)
|| (defType == XMLAttDef::Fixed))
{
// Let the validator pass judgement on the attribute value
if (fValidate)
{
fValidator->validateAttrValue
(
&curDef
, curDef.getValue()
, false
, elemDecl
);
}
XMLAttr* curAtt;
if (attCount >= curAttListSize)