App: Add support for in-memory Metadata creation
This commit is contained in:
committed by
Chris Hennes
parent
a637937cac
commit
766923a3da
@@ -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; }
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user