App: Add support for in-memory Metadata creation

This commit is contained in:
Chris Hennes
2023-02-09 17:50:08 -08:00
committed by Chris Hennes
parent a637937cac
commit 766923a3da
4 changed files with 98 additions and 50 deletions

View File

@@ -30,7 +30,10 @@
#include "Metadata.h"
#include <utility>
#include <xercesc/framework/LocalFileFormatTarget.hpp>
#include <xercesc/framework/LocalFileInputSource.hpp>
#include <xercesc/framework/MemBufInputSource.hpp>
#include <xercesc/sax/HandlerBase.hpp>
#include "App/Application.h"
@@ -89,37 +92,13 @@ class XMLErrorHandler: public HandlerBase
Metadata::Metadata(const fs::path &metadataFile)
{
// Any exception thrown by the XML code propagates out and prevents object creation
XMLPlatformUtils::Initialize();
_parser = std::make_shared<XercesDOMParser>();
_parser->setValidationScheme(XercesDOMParser::Val_Never);
_parser->setDoNamespaces(true);
auto errHandler = std::make_unique<MetadataInternal::XMLErrorHandler>();
_parser->setErrorHandler(errHandler.get());
#if defined(FC_OS_WIN32)
_parser->parse(reinterpret_cast<const XMLCh *>(metadataFile.wstring().c_str()));
auto source =
LocalFileInputSource(reinterpret_cast<const XMLCh*>(metadataFile.wstring().c_str()));
#else
_parser->parse(metadataFile.string().c_str());
auto source = LocalFileInputSource(XUTF8Str(metadataFile.string().c_str()).unicodeForm());
#endif
auto doc = _parser->getDocument();
_dom = doc->getDocumentElement();
auto rootTagName = StrXUTF8(_dom->getTagName()).str;
if (rootTagName != "package") {
throw Base::XMLBaseException(
"Malformed package.xml document: Root <package> group not found");
}
auto formatVersion = XMLString::parseInt(_dom->getAttribute(XUTF8Str("format").unicodeForm()));
switch (formatVersion) {
case 1: parseVersion1(_dom); break;
default:
throw Base::XMLBaseException(
"package.xml format version is not supported by this version of FreeCAD");
}
loadFromInputSource(source);
}
Metadata::Metadata() : _dom(nullptr) {}
@@ -137,6 +116,47 @@ Metadata::Metadata(const DOMNode *domNode, int format) : _dom(nullptr)
}
}
App::Metadata::Metadata(const std::string& rawData)
: _dom(nullptr)
{
MemBufInputSource buffer(
reinterpret_cast<const XMLByte*>(rawData.c_str()), rawData.size(), "raw data (in memory)");
loadFromInputSource(buffer);
}
void Metadata::loadFromInputSource(const InputSource& source)
{
// Any exception thrown by the XML code propagates out and prevents object creation
XMLPlatformUtils::Initialize();
_parser = std::make_shared<XercesDOMParser>();
_parser->setValidationScheme(XercesDOMParser::Val_Never);
_parser->setDoNamespaces(true);
auto errHandler = std::make_unique<MetadataInternal::XMLErrorHandler>();
_parser->setErrorHandler(errHandler.get());
_parser->parse(source);
auto doc = _parser->getDocument();
_dom = doc->getDocumentElement();
auto rootTagName = StrXUTF8(_dom->getTagName()).str;
if (rootTagName != "package") {
throw Base::XMLBaseException(
"Malformed package.xml document: Root <package> group not found");
}
auto formatVersion = XMLString::parseInt(_dom->getAttribute(XUTF8Str("format").unicodeForm()));
switch (formatVersion) {
case 1:
parseVersion1(_dom);
break;
default:
throw Base::XMLBaseException(
"package.xml format version is not supported by this version of FreeCAD");
}
}
Metadata::~Metadata() = default;
std::string Metadata::name() const { return _name; }

View File

@@ -206,6 +206,11 @@ public:
*/
Metadata(const XERCES_CPP_NAMESPACE::DOMNode *domNode, int format);
/**
* Treat the incoming rawData as metadata to be parsed.
*/
explicit Metadata(const std::string& rawData);
~Metadata();
@@ -369,6 +374,7 @@ private:
XERCES_CPP_NAMESPACE::DOMElement *_dom;
std::shared_ptr<XERCES_CPP_NAMESPACE::XercesDOMParser> _parser;
void loadFromInputSource(const XERCES_CPP_NAMESPACE::InputSource& source);
void parseVersion1(const XERCES_CPP_NAMESPACE::DOMNode *startNode);
void parseContentNodeVersion1(const XERCES_CPP_NAMESPACE::DOMElement *contentNode);

View File

@@ -28,7 +28,10 @@ Copy constructor.
metadata : App.Metadata\n
Metadata(file)
Reads the XML file and provides access to the metadata it specifies.
file : str\n XML file name.</UserDocu>
file : str\n XML file name.\n
Metadata(bytes)
Treats the bytes as UTF-8-encoded XML data and provides access to the metadata it specifies.
bytes : bytes\n Python bytes-like object.</UserDocu>
<DeveloperDocu>Metadata</DeveloperDocu>
</Documentation>

View File

@@ -1,24 +1,24 @@
/***************************************************************************
* Copyright (c) 2021 Chris Hennes <chennes@pioneerlibrarysystem.org> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file LICENSE.html. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
/**************************************************************************
* *
* Copyright (c) 2022 FreeCAD Project Association *
* *
* This file is part of FreeCAD. *
* *
* FreeCAD is free software: you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 2.1 of the *
* License, or (at your option) any later version. *
* *
* FreeCAD 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 *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with FreeCAD. If not, see *
* <https://www.gnu.org/licenses/>. *
* *
**************************************************************************/
#include "PreCompiled.h"
@@ -63,6 +63,25 @@ int MetadataPy::PyInit(PyObject *args, PyObject * /*kwd*/)
return 0;
}
// Data may be passed directly in as a bytes-like object buffer
PyErr_Clear();
Py_buffer dataBuffer;
if (PyArg_ParseTuple(args, "y*", &dataBuffer)) {
try {
// NB: This is making a copy of the buffer for simplicity, but that shouldn't be
// necessary. Use either a string_view or a span to avoid the copy in the future.
auto md = new Metadata(
std::string(static_cast<const char*>(dataBuffer.buf), dataBuffer.len)
);
setTwinPointer(md);
return 0;
}
catch (const Base::XMLBaseException&) {
// If the XML read failed, this might have been a path to a file, rather than a
// bytes-like object. Fall through to the next case.
}
}
// Main class constructor -- takes a file path, loads the metadata from it
PyErr_Clear();
char *filename;