/* * Cppcheck - A tool for static C/C++ code analysis * Copyright (C) 2007-2015 Daniel Marjamäki and Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "cppchecklibrarydata.h" #include #include const unsigned int CppcheckLibraryData::Function::Arg::ANY = ~0U; CppcheckLibraryData::CppcheckLibraryData() { } static CppcheckLibraryData::Define loadDefine(const QXmlStreamReader &xmlReader) { CppcheckLibraryData::Define define; define.name = xmlReader.attributes().value("name").toString(); define.value = xmlReader.attributes().value("value").toString(); return define; } static CppcheckLibraryData::Function::Arg loadFunctionArg(QXmlStreamReader &xmlReader) { CppcheckLibraryData::Function::Arg arg; QString argnr = xmlReader.attributes().value("nr").toString(); if (argnr == "any") arg.nr = CppcheckLibraryData::Function::Arg::ANY; else arg.nr = argnr.toUInt(); QXmlStreamReader::TokenType type; while ((type = xmlReader.readNext()) != QXmlStreamReader::EndElement || xmlReader.name().toString() != "arg") { if (type != QXmlStreamReader::StartElement) continue; const QString elementName = xmlReader.name().toString(); if (elementName == "not-bool") arg.notbool = true; else if (elementName == "not-null") arg.notnull = true; else if (elementName == "not-uninit") arg.notuninit = true; else if (elementName == "strz") arg.strz = true; else if (elementName == "formatstr") arg.formatstr = true; else if (elementName == "valid") arg.valid = xmlReader.readElementText(); else if (elementName == "minsize") { CppcheckLibraryData::Function::Arg::MinSize minsize; minsize.type = xmlReader.attributes().value("type").toString(); minsize.arg = xmlReader.attributes().value("arg").toString(); minsize.arg2 = xmlReader.attributes().value("arg2").toString(); arg.minsizes.append(minsize); } } return arg; } static CppcheckLibraryData::Function loadFunction(QXmlStreamReader &xmlReader, const QStringList &comments) { CppcheckLibraryData::Function function; function.comments = comments; function.name = xmlReader.attributes().value("name").toString(); QXmlStreamReader::TokenType type; while ((type = xmlReader.readNext()) != QXmlStreamReader::EndElement || xmlReader.name().toString() != "function") { if (type != QXmlStreamReader::StartElement) continue; const QString elementName = xmlReader.name().toString(); if (elementName == "noreturn") function.noreturn = (xmlReader.readElementText() == "true") ? CppcheckLibraryData::Function::True : CppcheckLibraryData::Function::False; else if (elementName == "pure") function.gccPure = true; else if (elementName == "const") function.gccConst = true; else if (elementName == "leak-ignore") function.leakignore = true; else if (elementName == "use-retval") function.useretval = true; else if (elementName == "formatstr") { function.formatstr.scan = xmlReader.attributes().value("scan").toString(); function.formatstr.secure = xmlReader.attributes().value("secure").toString(); } else if (elementName == "arg") function.args.append(loadFunctionArg(xmlReader)); } return function; } static CppcheckLibraryData::MemoryResource loadMemoryResource(QXmlStreamReader &xmlReader) { CppcheckLibraryData::MemoryResource memoryresource; memoryresource.type = xmlReader.name().toString(); QXmlStreamReader::TokenType type; while ((type = xmlReader.readNext()) != QXmlStreamReader::EndElement || xmlReader.name().toString() != memoryresource.type) { if (type != QXmlStreamReader::StartElement) continue; const QString elementName = xmlReader.name().toString(); if (elementName == "alloc") { CppcheckLibraryData::MemoryResource::Alloc alloc; alloc.init = (xmlReader.attributes().value("init").toString() == "true"); alloc.name = xmlReader.readElementText(); memoryresource.alloc.append(alloc); } else if (elementName == "dealloc") memoryresource.dealloc.append(xmlReader.readElementText()); else if (elementName == "use") memoryresource.use.append(xmlReader.readElementText()); } return memoryresource; } static CppcheckLibraryData::PodType loadPodType(const QXmlStreamReader &xmlReader) { CppcheckLibraryData::PodType podtype; podtype.name = xmlReader.attributes().value("name").toString(); podtype.size = xmlReader.attributes().value("size").toString(); podtype.sign = xmlReader.attributes().value("sign").toString(); return podtype; } bool CppcheckLibraryData::open(QIODevice &file) { clear(); QStringList comments; QXmlStreamReader xmlReader(&file); while (!xmlReader.atEnd()) { const QXmlStreamReader::TokenType t = xmlReader.readNext(); switch (t) { case QXmlStreamReader::Comment: comments.append(xmlReader.text().toString()); break; case QXmlStreamReader::StartElement: if (xmlReader.name() == "define") defines.append(loadDefine(xmlReader)); else if (xmlReader.name() == "function") functions.append(loadFunction(xmlReader, comments)); else if (xmlReader.name() == "memory" || xmlReader.name() == "resource") memoryresource.append(loadMemoryResource(xmlReader)); else if (xmlReader.name() == "podtype") podtypes.append(loadPodType(xmlReader)); comments.clear(); break; default: break; } } return true; } static void writeFunction(QXmlStreamWriter &xmlWriter, const CppcheckLibraryData::Function &function) { foreach(const QString &comment, function.comments) { xmlWriter.writeComment(comment); } xmlWriter.writeStartElement("function"); xmlWriter.writeAttribute("name", function.name); if (function.useretval) xmlWriter.writeEmptyElement("use-retval"); if (function.gccConst) xmlWriter.writeEmptyElement("const"); if (function.gccPure) xmlWriter.writeEmptyElement("pure"); if (function.noreturn != CppcheckLibraryData::Function::Unknown) xmlWriter.writeTextElement("noreturn", (function.noreturn == CppcheckLibraryData::Function::True) ? "true" : "false"); if (function.leakignore) xmlWriter.writeEmptyElement("leak-ignore"); // Argument info.. foreach(const CppcheckLibraryData::Function::Arg &arg, function.args) { if (arg.formatstr) { xmlWriter.writeStartElement("formatstr"); if (!function.formatstr.scan.isNull()) xmlWriter.writeAttribute("scan", function.formatstr.scan); if (!function.formatstr.secure.isNull()) xmlWriter.writeAttribute("secure", function.formatstr.secure); xmlWriter.writeEndElement(); } xmlWriter.writeStartElement("arg"); if (arg.nr == CppcheckLibraryData::Function::Arg::ANY) xmlWriter.writeAttribute("nr", "any"); else xmlWriter.writeAttribute("nr", QString::number(arg.nr)); if (arg.formatstr) xmlWriter.writeEmptyElement("formatstr"); if (arg.notnull) xmlWriter.writeEmptyElement("not-null"); if (arg.notuninit) xmlWriter.writeEmptyElement("not-uninit"); if (arg.notbool) xmlWriter.writeEmptyElement("not-bool"); if (arg.strz) xmlWriter.writeEmptyElement("strz"); if (!arg.valid.isEmpty()) xmlWriter.writeTextElement("valid",arg.valid); foreach(const CppcheckLibraryData::Function::Arg::MinSize &minsize, arg.minsizes) { xmlWriter.writeStartElement("minsize"); xmlWriter.writeAttribute("type", minsize.type); xmlWriter.writeAttribute("arg", minsize.arg); if (!minsize.arg2.isEmpty()) xmlWriter.writeAttribute("arg2", minsize.arg2); xmlWriter.writeEndElement(); } xmlWriter.writeEndElement(); } xmlWriter.writeEndElement(); } static void writeMemoryResource(QXmlStreamWriter &xmlWriter, const CppcheckLibraryData::MemoryResource &mr) { xmlWriter.writeStartElement(mr.type); foreach(const CppcheckLibraryData::MemoryResource::Alloc &alloc, mr.alloc) { xmlWriter.writeStartElement("alloc"); if (alloc.init) xmlWriter.writeAttribute("init", "true"); xmlWriter.writeCharacters(alloc.name); xmlWriter.writeEndElement(); } foreach(const QString &dealloc, mr.dealloc) { xmlWriter.writeTextElement("dealloc", dealloc); } foreach(const QString &use, mr.use) { xmlWriter.writeTextElement("use", use); } xmlWriter.writeEndElement(); } QString CppcheckLibraryData::toString() const { QString outputString; QXmlStreamWriter xmlWriter(&outputString); xmlWriter.setAutoFormatting(true); xmlWriter.writeStartDocument("1.0"); xmlWriter.writeStartElement("def"); xmlWriter.writeAttribute("format","2"); foreach(const Define &define, defines) { xmlWriter.writeStartElement("define"); xmlWriter.writeAttribute("name", define.name); xmlWriter.writeAttribute("value", define.value); xmlWriter.writeEndElement(); } foreach(const Function &function, functions) { writeFunction(xmlWriter, function); } foreach(const MemoryResource &mr, memoryresource) { writeMemoryResource(xmlWriter, mr); } foreach(const PodType &podtype, podtypes) { xmlWriter.writeStartElement("podtype"); xmlWriter.writeAttribute("name", podtype.name); if (!podtype.size.isEmpty()) xmlWriter.writeAttribute("size", podtype.size); if (!podtype.sign.isEmpty()) xmlWriter.writeAttribute("sign", podtype.sign); xmlWriter.writeEndElement(); } xmlWriter.writeEndElement(); return outputString; }