summaryrefslogtreecommitdiffstats
path: root/src/uscxml/plugins/element
diff options
context:
space:
mode:
authorStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2013-09-02 21:38:10 (GMT)
committerStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2013-09-02 21:38:10 (GMT)
commit7938e286967597c7168b855b7e3fdfbd9b949e0e (patch)
treebc5d9bfb80a07ec80b36dc025b3fac9f3ca03ec4 /src/uscxml/plugins/element
parenta874a181add7b292e52140f8c753f663a4cb5a87 (diff)
downloaduscxml-7938e286967597c7168b855b7e3fdfbd9b949e0e.zip
uscxml-7938e286967597c7168b855b7e3fdfbd9b949e0e.tar.gz
uscxml-7938e286967597c7168b855b7e3fdfbd9b949e0e.tar.bz2
New file element for executable content
Diffstat (limited to 'src/uscxml/plugins/element')
-rw-r--r--src/uscxml/plugins/element/CMakeLists.txt19
-rw-r--r--src/uscxml/plugins/element/file/FileElement.cpp224
-rw-r--r--src/uscxml/plugins/element/file/FileElement.h65
3 files changed, 308 insertions, 0 deletions
diff --git a/src/uscxml/plugins/element/CMakeLists.txt b/src/uscxml/plugins/element/CMakeLists.txt
index f24a609..fd69417 100644
--- a/src/uscxml/plugins/element/CMakeLists.txt
+++ b/src/uscxml/plugins/element/CMakeLists.txt
@@ -53,6 +53,25 @@ else()
endif()
+# File element
+
+set(USCXML_ELEMENTS "file ${USCXML_ELEMENTS}")
+file(GLOB_RECURSE FILE_ELEMENT
+ file/*.cpp
+ file/*.h
+)
+source_group("Element\\file" FILES ${FILE_ELEMENT})
+if (BUILD_AS_PLUGINS)
+ add_library(
+ element_file SHARED
+ ${FILE_ELEMENT})
+ target_link_libraries(element_file uscxml)
+ set_target_properties(element_file PROPERTIES FOLDER "Plugin Element")
+else()
+ list (APPEND USCXML_FILES ${FILE_ELEMENT})
+endif()
+
+
# Respond element
set(USCXML_ELEMENTS "respond ${USCXML_ELEMENTS}")
diff --git a/src/uscxml/plugins/element/file/FileElement.cpp b/src/uscxml/plugins/element/file/FileElement.cpp
new file mode 100644
index 0000000..e51fa70
--- /dev/null
+++ b/src/uscxml/plugins/element/file/FileElement.cpp
@@ -0,0 +1,224 @@
+#include "FileElement.h"
+#include <glog/logging.h>
+#include <stdio.h>
+#include <vector>
+
+#include "uscxml/NameSpacingParser.h"
+
+#ifdef BUILD_AS_PLUGINS
+#include <Pluma/Connector.hpp>
+#endif
+
+namespace uscxml {
+
+#ifdef BUILD_AS_PLUGINS
+PLUMA_CONNECTOR
+bool connect(pluma::Host& host) {
+ host.add( new FileElementProvider() );
+ return true;
+}
+#endif
+
+boost::shared_ptr<ExecutableContentImpl> FileElement::create(InterpreterImpl* interpreter) {
+ boost::shared_ptr<FileElement> element = boost::shared_ptr<FileElement>(new FileElement());
+ return element;
+}
+
+FileElement::~FileElement() {
+}
+
+void FileElement::enterElement(const Arabica::DOM::Node<std::string>& node) {
+ if (!HAS_ATTR(node, "url") && !HAS_ATTR(node, "urlexpr")) {
+ LOG(ERROR) << "File element requires url or urlexpr";
+ return;
+ }
+ _givenUrl = (HAS_ATTR(node, "url") ? ATTR(node, "url") : _interpreter->getDataModel().evalAsString(ATTR(node, "urlexpr")));
+
+ std::string sandBoxStr = (HAS_ATTR(node, "sandboxed") ? ATTR(node, "sandboxed") : "on");
+ if (boost::iequals(sandBoxStr, "off") || boost::iequals(sandBoxStr, "false") || boost::iequals(sandBoxStr, "no")) {
+ _sandBoxed = false;
+ }
+
+ if (HAS_ATTR(node, "operation")) {
+ std::string operation = ATTR(node, "operation");
+ if (boost::iequals(operation, "read") || boost::iequals(operation, "load")) {
+ _operation = READ;
+ } else if(boost::iequals(operation, "write")) {
+ _operation = WRITE;
+ } else if(boost::iequals(operation, "append")) {
+ _operation = APPEND;
+ } else {
+ LOG(ERROR) << "File element operation attribute not one of read, write or append.";
+ return;
+ }
+ } else {
+ _operation = READ;
+ }
+
+ // callback is only needed for reading
+ std::string callback;
+ if (_operation == READ) {
+ if (!HAS_ATTR(node, "callback") && !HAS_ATTR(node, "callbackexpr")) {
+ LOG(ERROR) << "File element requires callback or callbackexpr";
+ return;
+ }
+ callback = (HAS_ATTR(node, "callback") ? ATTR(node, "callback") : _interpreter->getDataModel().evalAsString(ATTR(node, "callbackexpr")));
+ }
+
+ std::string contentStr;
+ char* content = NULL;
+ size_t contentSize;
+ if (_operation == WRITE || _operation == APPEND) {
+ if (!HAS_ATTR(node, "content") && !HAS_ATTR(node, "contentexpr")) {
+ LOG(ERROR) << "File element requires content or contentexpr";
+ return;
+ }
+ if (HAS_ATTR(node, "content")) {
+ contentStr = ATTR(node, "content");
+ } else {
+ Data data = _interpreter->getDataModel().getStringAsData(ATTR(node, "contentexpr"));
+ if (data.binary) {
+ content = data.binary->_data;
+ contentSize = data.binary->_size;
+ } else if (data.atom.length() > 0) {
+ contentStr = data.atom;
+ }
+ }
+ }
+
+ std::string type = "text";
+ if (HAS_ATTR(node, "type")) {
+ type = ATTR(node, "type");
+ } else if(HAS_ATTR(node, "typeexpr")) {
+ type = _interpreter->getDataModel().evalAsString(ATTR(node, "typeexpr"));
+ }
+ if (boost::iequals(type, "text")) {
+ _type = TEXT;
+ } else if (boost::iequals(type, "json")) {
+ _type = JSON;
+ } else if (boost::iequals(type, "binary")) {
+ _type = BINARY;
+ } else if(boost::iequals(type, "xml")) {
+ _type = XML;
+ } else {
+ LOG(ERROR) << "File element type attribute not one of text, json, xml or binary.";
+ return;
+ }
+
+ _actualUrl = URL(_givenUrl);
+ if (_sandBoxed && _actualUrl.isAbsolute()) {
+ LOG(ERROR) << "Given URL is absolute with sandboxing enabled.";
+ return;
+ }
+
+ if (_sandBoxed)
+ _actualUrl.toAbsolute(URL::getResourceDir());
+
+ _filename = _actualUrl.path();
+
+ std::string writeMode;
+ switch (_operation) {
+ case APPEND:
+ writeMode = "a+";
+ case WRITE: {
+ if (writeMode.length() == 0)
+ writeMode = "w+";
+
+ FILE *fp;
+ fp = fopen(_filename.c_str(), writeMode.c_str());
+ if (fp == NULL) {
+ LOG(ERROR) << "Error opening '" << _filename << "' for writing: " << strerror(errno);
+ }
+
+ if (content && contentSize > 0) {
+ size_t written = fwrite(content, 1, contentSize, fp);
+ if (written != contentSize) {
+ LOG(ERROR) << "Error writing to '" << _filename << "': " << strerror(errno);
+ return;
+ }
+ } else if (contentStr.length() > 0) {
+ size_t written = fwrite(contentStr.c_str(), contentStr.length(), 1, fp);
+ if (written < 1) {
+ LOG(ERROR) << "Error writing to '" << _filename << "': " << strerror(errno);
+ }
+ } else {
+ LOG(WARNING) << "Nothing to write to '" << _filename;
+ }
+ fclose(fp);
+ break;
+ }
+ case READ: {
+ struct stat fileStat;
+ int err = stat(_filename.c_str(), &fileStat);
+ if (err < 0) {
+ LOG(ERROR) << "Cannot stat file '" << _filename << "': " << strerror(errno);
+ return;
+ }
+
+ Event event;
+ event.name = callback;
+ event.data.compound["file"].compound["name"] = Data(_filename, Data::VERBATIM);
+ event.data.compound["file"].compound["mtime"] = toStr(fileStat.st_mtime);
+ event.data.compound["file"].compound["ctime"] = toStr(fileStat.st_ctime);
+ event.data.compound["file"].compound["atime"] = toStr(fileStat.st_atime);
+ event.data.compound["file"].compound["size"] = toStr(fileStat.st_size);
+
+
+ FILE *fp;
+ fp = fopen(_filename.c_str(), "r");
+
+ fseek (fp, 0, SEEK_END);
+ size_t filesize = ftell(fp);
+ rewind (fp);
+
+ char* fileContents = (char*)malloc(filesize);
+ size_t read = fread(fileContents, 1, filesize, fp);
+ fclose(fp);
+ if (read != filesize) {
+ LOG(ERROR) << "Error reading from '" << _filename << "': " << strerror(errno);
+ return;
+ }
+
+ switch (_type) {
+ case BINARY:
+ event.data.compound["content"] = Data(fileContents, fileStat.st_size, 1);
+ break;
+ case TEXT:
+ event.data.compound["content"] = Data(fileContents, Data::VERBATIM);
+ free(fileContents);
+ break;
+ case JSON: {
+ Data json = Data::fromJSON(fileContents);
+ free(fileContents);
+ if (!json) {
+ LOG(ERROR) << "Cannot parse contents of " << _filename << " as JSON";
+ return;
+ }
+ event.data.compound["content"] = json;
+ break;
+ }
+ case XML: {
+ NameSpacingParser parser = NameSpacingParser::fromXML(fileContents);
+ if (parser.errorsReported()) {
+ LOG(ERROR) << "Cannot parse contents of " << _filename << " as XML";
+ return;
+ }
+ event.dom = parser.getDocument().getDocumentElement();
+ break;
+ }
+ }
+ _interpreter->receive(event);
+ break;
+ }
+ }
+
+
+
+
+}
+
+void FileElement::exitElement(const Arabica::DOM::Node<std::string>& node) {
+
+}
+
+} \ No newline at end of file
diff --git a/src/uscxml/plugins/element/file/FileElement.h b/src/uscxml/plugins/element/file/FileElement.h
new file mode 100644
index 0000000..b9e43bc
--- /dev/null
+++ b/src/uscxml/plugins/element/file/FileElement.h
@@ -0,0 +1,65 @@
+#ifndef FILEELEMENT_H_VJ3JIMEJ
+#define FILEELEMENT_H_VJ3JIMEJ
+
+#include <uscxml/Interpreter.h>
+#include <sys/stat.h>
+
+#ifdef BUILD_AS_PLUGINS
+#include "uscxml/plugins/Plugins.h"
+#endif
+
+namespace uscxml {
+
+class FileElement : public ExecutableContentImpl {
+public:
+ enum Operation {
+ READ,
+ WRITE,
+ APPEND
+ };
+
+ enum Type {
+ XML,
+ JSON,
+ TEXT,
+ BINARY
+ };
+
+ FileElement() {
+ _sandBoxed = true;
+ }
+ virtual ~FileElement();
+ boost::shared_ptr<ExecutableContentImpl> create(InterpreterImpl* interpreter);
+
+ std::string getLocalName() {
+ return "file";
+ }
+
+ std::string getNamespace() {
+ return "http://www.w3.org/2005/07/scxml";
+ }
+
+ bool processChildren() {
+ return false;
+ }
+
+ void enterElement(const Arabica::DOM::Node<std::string>& node);
+ void exitElement(const Arabica::DOM::Node<std::string>& node);
+
+protected:
+
+ bool _sandBoxed;
+ std::string _givenUrl;
+ URL _actualUrl;
+ std::string _filename;
+ Operation _operation;
+ Type _type;
+};
+
+#ifdef BUILD_AS_PLUGINS
+PLUMA_INHERIT_PROVIDER(FileElement, ExecutableContentImpl);
+#endif
+
+}
+
+#endif /* end of include guard: FILEELEMENT_H_VJ3JIMEJ */