| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /* |
| * $Id$ |
| */ |
| |
| |
| // --------------------------------------------------------------------------- |
| // Includes |
| // --------------------------------------------------------------------------- |
| #include "MemoryMonitor.hpp" |
| #if defined(XERCES_NEW_IOSTREAMS) |
| #include <iostream> |
| #include <fstream> |
| #else |
| #include <iostream.h> |
| #include <fstream.h> |
| #endif |
| #include <assert.h> |
| #include <xercesc/util/XercesDefs.hpp> |
| #include <xercesc/util/OutOfMemoryException.hpp> |
| #include <xercesc/dom/DOM.hpp> |
| |
| MemoryManager* MemoryMonitor::getExceptionMemoryManager() |
| { |
| return this; |
| } |
| |
| void* MemoryMonitor::allocate(XMLSize_t size) |
| { |
| void *key = ::operator new(size); |
| fHashTable->put(key, (unsigned int)size); |
| return key; |
| } |
| |
| void MemoryMonitor::deallocate(void* p) |
| { |
| // if fHashTable doesn't contain p, then this memory manager |
| // didn't allocate that memory--a segfault waiting to happen... |
| assert(p == 0 || fHashTable->containsKey(p) != 0); |
| if (p != 0) |
| { |
| fHashTable->removeKey(p); |
| ::operator delete(p); |
| } |
| } |
| |
| unsigned int MemoryMonitor::getTotalMemory() |
| { |
| unsigned int total = 0; |
| ValueHashTableOfEnumerator<unsigned int> *memEnum = |
| new ValueHashTableOfEnumerator<unsigned int>(fHashTable); |
| while(memEnum->hasMoreElements()) { |
| total += memEnum->nextElement(); |
| } |
| delete memEnum; |
| return total; |
| } |
| |
| static void usage() |
| { |
| XERCES_STD_QUALIFIER cout << "\nUsage:\n" |
| " MemHandlerTest [options] <XML file | List file>\n\n" |
| "This program invokes the XercesDOMParser, DOMLSParser, SAXParser ,\n" |
| "and the SAX2XMLReader, and ensures that MemoryManagers set on these\n" |
| "domBuilders are called to delete just as many bytes as they allocate.\n" |
| "This is done for each XML file, and each file is processed\n" |
| "as many times as indicated.\n" |
| "Options:\n" |
| " -l Indicate the input file is a List File that has a list of xml files.\n" |
| " Default to off (Input file is an XML file).\n" |
| " -v=xxx Validation scheme [always | never | auto*].\n" |
| " -n Enable namespace processing. Defaults to off.\n" |
| " -s Enable schema processing. Defaults to off.\n" |
| " -f Enable full schema constraint checking. Defaults to off.\n" |
| " -r=n Run file through domBuilders n times.\n" |
| " -? Show this help.\n\n" |
| " * = Default if not provided explicitly.\n" |
| << XERCES_STD_QUALIFIER endl; |
| } |
| |
| class DOMLSParserHandler : public DOMErrorHandler |
| { |
| public: |
| DOMLSParserHandler() {}; |
| ~DOMLSParserHandler() {}; |
| bool handleError(const DOMError &error) |
| { |
| char *message = 0; |
| XERCES_STD_QUALIFIER cerr << "Error occurred in DOMBuilder! Message: " << |
| (message = XMLString::transcode(error.getMessage())) << " of severity " << error.getSeverity() << "." << XERCES_STD_QUALIFIER endl; |
| XMLString::release(&message); |
| return true; |
| } |
| }; |
| |
| class SAXErrorHandler : public ErrorHandler |
| { |
| public: |
| SAXErrorHandler() {}; |
| ~SAXErrorHandler() {}; |
| void warning(const SAXParseException &exc ) |
| { |
| char *message = 0; |
| XERCES_STD_QUALIFIER cerr << "SAX warning received! Text: " << |
| (message = XMLString::transcode(exc.getMessage())) << "." << XERCES_STD_QUALIFIER endl; |
| XMLString::release(&message); |
| } |
| void error(const SAXParseException &exc ) |
| { |
| char *message = 0; |
| XERCES_STD_QUALIFIER cerr << "SAX error received! Text: " << |
| (message = XMLString::transcode(exc.getMessage())) << "." << XERCES_STD_QUALIFIER endl; |
| XMLString::release(&message); |
| } |
| void fatalError(const SAXParseException &exc ) |
| { |
| char *message = 0; |
| XERCES_STD_QUALIFIER cerr << "SAX fatalError received! Text: " << |
| (message = XMLString::transcode(exc.getMessage())) << "." << XERCES_STD_QUALIFIER endl; |
| XMLString::release(&message); |
| } |
| |
| // no state so no body |
| void resetErrors() {}; |
| }; |
| |
| /** |
| * This utility takes similar parameters as DOMCount, |
| * with similar meanings. The only difference is that it runs |
| * the file(s) in question through a DOMParser, a DOMBuilder, a SAXParser and |
| * a SAX2XMLReader, setting options as appropriate. It does this |
| * sequentially, n times per file with a single domBuilder |
| * object, and reports what it finds in terms of memory |
| * allocations/deallocations. |
| */ |
| |
| int main (int argC, char *argV[]) |
| { |
| |
| MemoryMonitor *staticMemMonitor = new MemoryMonitor(); |
| |
| // Initialize the XML4C system |
| try |
| { |
| XMLPlatformUtils::Initialize(XMLUni::fgXercescDefaultLocale, 0, 0, staticMemMonitor); |
| } |
| catch (const XMLException& toCatch) |
| { |
| char *msg = XMLString::transcode(toCatch.getMessage()); |
| XERCES_STD_QUALIFIER cerr << "Error during initialization! :\n" |
| << msg << XERCES_STD_QUALIFIER endl; |
| XMLString::release(&msg); |
| return 1; |
| } |
| |
| // Check command line and extract arguments. |
| if (argC < 2) |
| { |
| usage(); |
| return 1; |
| } |
| |
| const char* xmlFile = 0; |
| AbstractDOMParser::ValSchemes domBuilderValScheme = AbstractDOMParser::Val_Auto; |
| bool doNamespaces = false; |
| bool doSchema = false; |
| bool schemaFullChecking = false; |
| bool doList = false; |
| int numReps =1; |
| |
| int argInd; |
| for (argInd = 1; argInd < argC; argInd++) |
| { |
| // Break out on first parm not starting with a dash |
| if (argV[argInd][0] != '-') |
| break; |
| |
| // Watch for special case help request |
| if (!strcmp(argV[argInd], "-?")) |
| { |
| usage(); |
| return 2; |
| } |
| else if (!strncmp(argV[argInd], "-v=", 3) |
| || !strncmp(argV[argInd], "-V=", 3)) |
| { |
| const char* const parm = &argV[argInd][3]; |
| |
| if (!strcmp(parm, "never")) |
| domBuilderValScheme = AbstractDOMParser::Val_Never; |
| else if (!strcmp(parm, "auto")) |
| domBuilderValScheme = AbstractDOMParser::Val_Auto; |
| else if (!strcmp(parm, "always")) |
| domBuilderValScheme = AbstractDOMParser::Val_Always; |
| else |
| { |
| XERCES_STD_QUALIFIER cerr << "Unknown -v= value: " << parm << XERCES_STD_QUALIFIER endl; |
| return 2; |
| } |
| } |
| else if (!strcmp(argV[argInd], "-n") |
| || !strcmp(argV[argInd], "-N")) |
| { |
| doNamespaces = true; |
| } |
| else if (!strcmp(argV[argInd], "-s") |
| || !strcmp(argV[argInd], "-S")) |
| { |
| doSchema = true; |
| } |
| else if (!strcmp(argV[argInd], "-f") |
| || !strcmp(argV[argInd], "-F")) |
| { |
| schemaFullChecking = true; |
| } |
| else if (!strcmp(argV[argInd], "-l") |
| || !strcmp(argV[argInd], "-L")) |
| { |
| doList = true; |
| } |
| else if (!strncmp(argV[argInd], "-r=", 3) |
| || !strncmp(argV[argInd], "-R=", 3)) |
| { |
| const char* const numStr = &argV[argInd][3]; |
| XMLCh* numXStr = XMLString::transcode(numStr); |
| numReps = XMLString::parseInt(numXStr); |
| XMLString::release(&numXStr); |
| } |
| else |
| { |
| XERCES_STD_QUALIFIER cerr << "Unknown option '" << argV[argInd] |
| << "', ignoring it\n" << XERCES_STD_QUALIFIER endl; |
| } |
| } |
| |
| // |
| // There should be only one and only one parameter left, and that |
| // should be the file name. |
| // |
| if (argInd != argC - 1) |
| { |
| usage(); |
| return 1; |
| } |
| |
| // Instantiate the DOM domBuilder with its memory manager. |
| MemoryMonitor *domBuilderMemMonitor = new MemoryMonitor(); |
| static const XMLCh gLS[] = { chLatin_L, chLatin_S, chNull }; |
| DOMImplementation *impl = DOMImplementationRegistry::getDOMImplementation(gLS); |
| DOMLSParser *domBuilder = ((DOMImplementationLS*)impl)->createLSParser(DOMImplementationLS::MODE_SYNCHRONOUS, 0, domBuilderMemMonitor); |
| DOMLSParserHandler domBuilderHandler; |
| domBuilder->getDomConfig()->setParameter(XMLUni::fgDOMErrorHandler, &domBuilderHandler); |
| |
| // Instantiate the SAX2 parser with its memory manager. |
| MemoryMonitor *sax2MemMonitor = new MemoryMonitor(); |
| SAX2XMLReader *sax2parser = XMLReaderFactory::createXMLReader(sax2MemMonitor); |
| SAXErrorHandler saxErrorHandler; |
| sax2parser->setErrorHandler(&saxErrorHandler); |
| |
| // Instantiate the SAX 1 parser with its memory manager. |
| MemoryMonitor *sax1MemMonitor = new MemoryMonitor(); |
| SAXParser *saxParser = new (sax1MemMonitor) SAXParser(0, sax1MemMonitor); |
| saxParser->setErrorHandler(&saxErrorHandler); |
| |
| // set features |
| domBuilder->getDomConfig()->setParameter(XMLUni::fgDOMNamespaces, doNamespaces); |
| sax2parser->setFeature(XMLUni::fgSAX2CoreNameSpaces, doNamespaces); |
| saxParser->setDoNamespaces(doNamespaces); |
| |
| domBuilder->getDomConfig()->setParameter(XMLUni::fgXercesSchema, doSchema); |
| sax2parser->setFeature(XMLUni::fgXercesSchema, doSchema); |
| saxParser->setDoSchema(doSchema); |
| |
| domBuilder->getDomConfig()->setParameter(XMLUni::fgXercesSchemaFullChecking, schemaFullChecking); |
| sax2parser->setFeature(XMLUni::fgXercesSchemaFullChecking, schemaFullChecking); |
| saxParser->setValidationSchemaFullChecking(schemaFullChecking); |
| |
| if (domBuilderValScheme == AbstractDOMParser::Val_Auto) |
| { |
| domBuilder->getDomConfig()->setParameter(XMLUni::fgDOMValidateIfSchema, true); |
| sax2parser->setFeature(XMLUni::fgSAX2CoreValidation, true); |
| sax2parser->setFeature(XMLUni::fgXercesDynamic, true); |
| saxParser->setValidationScheme(SAXParser::Val_Auto); |
| } |
| else if (domBuilderValScheme == AbstractDOMParser::Val_Never) |
| { |
| domBuilder->getDomConfig()->setParameter(XMLUni::fgDOMValidate, false); |
| sax2parser->setFeature(XMLUni::fgSAX2CoreValidation, false); |
| saxParser->setValidationScheme(SAXParser::Val_Never); |
| } |
| else if (domBuilderValScheme == AbstractDOMParser::Val_Always) |
| { |
| domBuilder->getDomConfig()->setParameter(XMLUni::fgDOMValidate, true); |
| sax2parser->setFeature(XMLUni::fgSAX2CoreValidation, true); |
| sax2parser->setFeature(XMLUni::fgXercesDynamic, false); |
| saxParser->setValidationScheme(SAXParser::Val_Always); |
| } |
| |
| // enable datatype normalization - default is off |
| domBuilder->getDomConfig()->setParameter(XMLUni::fgDOMDatatypeNormalization, true); |
| |
| XERCES_STD_QUALIFIER ifstream fin; |
| bool more = true; |
| |
| // the input is a list file |
| if (doList) |
| fin.open(argV[argInd]); |
| |
| if (fin.fail()) { |
| XERCES_STD_QUALIFIER cerr <<"Cannot open the list file: " << argV[argInd] << XERCES_STD_QUALIFIER endl; |
| return 2; |
| } |
| |
| while (more) |
| { |
| char fURI[1000]; |
| //initialize the array to zeros |
| memset(fURI,0,sizeof(fURI)); |
| |
| if (doList) { |
| if (! fin.eof() ) { |
| fin.getline (fURI, sizeof(fURI)); |
| if (!*fURI) |
| continue; |
| else { |
| xmlFile = fURI; |
| XERCES_STD_QUALIFIER cerr << "==Parsing== " << xmlFile << XERCES_STD_QUALIFIER endl; |
| } |
| } |
| else |
| break; |
| } |
| else { |
| xmlFile = argV[argInd]; |
| more = false; |
| } |
| |
| // parse numReps times (in case we need it for some reason) |
| for (int i=0; i<numReps; i++) |
| { |
| |
| XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *doc = 0; |
| |
| try |
| { |
| // reset document pool |
| domBuilder->resetDocumentPool(); |
| |
| doc = domBuilder->parseURI(xmlFile); |
| if(doc && doc->getDocumentElement()) |
| { |
| XERCES_CPP_NAMESPACE_QUALIFIER DOMNodeList *list=NULL; |
| if(doNamespaces) |
| list=doc->getElementsByTagNameNS(doc->getDocumentElement()->getNamespaceURI(), doc->getDocumentElement()->getLocalName()); |
| else |
| list=doc->getElementsByTagName(doc->getDocumentElement()->getNodeName()); |
| if(list==NULL) |
| XERCES_STD_QUALIFIER cout << "getElementsByTagName didn't return a valid DOMNodeList." << XERCES_STD_QUALIFIER endl; |
| else if(list->item(0)!=doc->getDocumentElement()) |
| XERCES_STD_QUALIFIER cout << "getElementsByTagName didn't find the root element." << XERCES_STD_QUALIFIER endl; |
| } |
| sax2parser->parse(xmlFile); |
| saxParser->parse(xmlFile); |
| } |
| catch (const OutOfMemoryException&) |
| { |
| XERCES_STD_QUALIFIER cerr << "OutOfMemoryException during parsing: '" << xmlFile << "'\n" << XERCES_STD_QUALIFIER endl;; |
| continue; |
| } |
| catch (const XMLException& toCatch) |
| { |
| char *msg = XMLString::transcode(toCatch.getMessage()); |
| XERCES_STD_QUALIFIER cerr << "\nError during parsing: '" << xmlFile << "'\n" |
| << "Exception message is: \n" |
| << msg << "\n" << XERCES_STD_QUALIFIER endl; |
| XMLString::release(&msg); |
| continue; |
| } |
| catch (const DOMException& toCatch) |
| { |
| const unsigned int maxChars = 2047; |
| XMLCh errText[maxChars + 1]; |
| |
| XERCES_STD_QUALIFIER cerr << "\nDOM Error during parsing: '" << xmlFile << "'\n" |
| << "DOMException code is: " << toCatch.code << XERCES_STD_QUALIFIER endl; |
| |
| if (DOMImplementation::loadDOMExceptionMsg(toCatch.code, errText, maxChars)) |
| { |
| char * msg = XMLString::transcode(errText); |
| XERCES_STD_QUALIFIER cerr << "Message is: " << msg << XERCES_STD_QUALIFIER endl; |
| |
| continue; |
| } |
| } |
| catch (...) |
| { |
| XERCES_STD_QUALIFIER cerr << "\nUnexpected exception during parsing: '" << xmlFile << "'\n"; |
| continue; |
| } |
| |
| } |
| } |
| |
| // |
| // Delete the domBuilder itself. Must be done prior to calling Terminate, below. |
| // |
| domBuilder->release(); |
| delete sax2parser; |
| delete saxParser; |
| |
| XERCES_STD_QUALIFIER cout << "At destruction, domBuilderMemMonitor has " << domBuilderMemMonitor->getTotalMemory() << " bytes." << XERCES_STD_QUALIFIER endl; |
| XERCES_STD_QUALIFIER cout << "At destruction, sax2MemMonitor has " << sax2MemMonitor->getTotalMemory() << " bytes." << XERCES_STD_QUALIFIER endl; |
| XERCES_STD_QUALIFIER cout << "At destruction, sax1MemMonitor has " << sax1MemMonitor->getTotalMemory() << " bytes." << XERCES_STD_QUALIFIER endl; |
| delete domBuilderMemMonitor; |
| delete sax2MemMonitor; |
| delete sax1MemMonitor; |
| |
| XMLPlatformUtils::Terminate(); |
| XERCES_STD_QUALIFIER cout << "At destruction, staticMemMonitor has " << staticMemMonitor->getTotalMemory() << " bytes." << XERCES_STD_QUALIFIER endl; |
| delete staticMemMonitor; |
| return 0; |
| } |
| |