From 7938e286967597c7168b855b7e3fdfbd9b949e0e Mon Sep 17 00:00:00 2001 From: Stefan Radomski Date: Mon, 2 Sep 2013 23:38:10 +0200 Subject: New file element for executable content --- CMakeLists.txt | 2 +- contrib/local/bcp-boost.sh | 6 +- contrib/local/compress_and_upload_deps.sh | 1 + src/uscxml/Factory.cpp | 6 + src/uscxml/Message.cpp | 24 +++ src/uscxml/Message.h | 13 +- src/uscxml/NameSpacingParser.h | 2 +- src/uscxml/URL.mm | 2 +- .../ecmascript/JavaScriptCore/JSCDataModel.cpp | 44 ++-- .../plugins/datamodel/ecmascript/TypedArray.cpp | 22 +- .../plugins/datamodel/ecmascript/TypedArray.h | 22 +- .../datamodel/ecmascript/v8/V8DataModel.cpp | 28 ++- src/uscxml/plugins/element/CMakeLists.txt | 19 ++ src/uscxml/plugins/element/file/FileElement.cpp | 224 +++++++++++++++++++++ src/uscxml/plugins/element/file/FileElement.h | 65 ++++++ test/samples/uscxml/test-file-element.scxml | 17 ++ 16 files changed, 427 insertions(+), 70 deletions(-) create mode 100644 src/uscxml/plugins/element/file/FileElement.cpp create mode 100644 src/uscxml/plugins/element/file/FileElement.h create mode 100644 test/samples/uscxml/test-file-element.scxml diff --git a/CMakeLists.txt b/CMakeLists.txt index 925f529..96096ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -501,7 +501,7 @@ if (APPLE OR IOS) endif() -if (APPLE OR IOS) +if (OFF AND APPLE OR IOS) find_library(JSC_LIBRARY JavaScriptCore) list (APPEND USCXML_OPT_LIBS ${JSC_LIBRARY}) set(JSC_FOUND ON) diff --git a/contrib/local/bcp-boost.sh b/contrib/local/bcp-boost.sh index 9f5450d..bdeea97 100755 --- a/contrib/local/bcp-boost.sh +++ b/contrib/local/bcp-boost.sh @@ -5,13 +5,13 @@ DIR="$( cd "$( dirname "$0" )" && pwd )" CWD=`pwd` SOURCE_FILES=`find ${DIR}/../../src/ -name \*.h -print -o -name \*.cpp -print` -ARABICA_FILES=`find ${DIR}/../../contrib/prebuilt/include/arabica -name \*.hpp -print -o -name \*.cpp -print` +ARABICA_FILES=`find ${DIR}/../../contrib/prebuilt/darwin-i386/clang/include/arabica -name \*.hpp -print -o -name \*.cpp -print` # echo ${ARABICA_FILES} # exit -/Users/sradomski/Documents/TK/Code/boost_1_51_0/dist/bin/bcp \ ---boost=/Users/sradomski/Documents/TK/Code/boost_1_51_0 \ +/Users/sradomski/Documents/TK/Code/boost_1_54_0/dist/bin/bcp \ +--boost=/Users/sradomski/Documents/TK/Code/boost_1_54_0 \ --scan ${SOURCE_FILES} ${ARABICA_FILES} \ ${DIR}/../prebuilt/include diff --git a/contrib/local/compress_and_upload_deps.sh b/contrib/local/compress_and_upload_deps.sh index cf7c758..81df0f4 100755 --- a/contrib/local/compress_and_upload_deps.sh +++ b/contrib/local/compress_and_upload_deps.sh @@ -31,6 +31,7 @@ cd ../prebuilt ssh ${USCXML_PREBUILT_HOST} mkdir -p ${USCXML_PREBUILT_PATH}/${VERSION} PLATFORMS=`find . -maxdepth 1 -type d -regex ./[^\.].*` +PLATFORMS="include" for FILE in ${PLATFORMS}; do PLATFORM=`basename $FILE` if [ "$PLATFORM" != "include" ]; then diff --git a/src/uscxml/Factory.cpp b/src/uscxml/Factory.cpp index 1494dff..643c358 100644 --- a/src/uscxml/Factory.cpp +++ b/src/uscxml/Factory.cpp @@ -73,6 +73,7 @@ #include "uscxml/plugins/datamodel/xpath/XPathDataModel.h" +# include "uscxml/plugins/element/file/FileElement.h" # include "uscxml/plugins/element/fetch/FetchElement.h" # include "uscxml/plugins/element/respond/RespondElement.h" # include "uscxml/plugins/element/postpone/PostponeElement.h" @@ -275,6 +276,10 @@ Factory::Factory() { PostponeElement* element = new PostponeElement(); registerExecutableContent(element); } + { + FileElement* element = new FileElement(); + registerExecutableContent(element); + } #endif #endif @@ -417,6 +422,7 @@ boost::shared_ptr Factory::createExecutableContent(const if (_executableContent.find(std::make_pair(localName, actualNameSpace)) != _executableContent.end()) { boost::shared_ptr execContent = _executableContent[std::make_pair(localName, actualNameSpace)]->create(interpreter); execContent->setInterpreter(interpreter); + return execContent; } // lookup in parent factory diff --git a/src/uscxml/Message.cpp b/src/uscxml/Message.cpp index f3f8c27..6388f9f 100644 --- a/src/uscxml/Message.cpp +++ b/src/uscxml/Message.cpp @@ -21,6 +21,30 @@ namespace uscxml { static int _dataIndentation = 1; +Blob::~Blob() { + free(_data); +} + +Blob::Blob(size_t size) { + _data = (char*)malloc(size); + memset(_data, 0, size); + _size = size; +} + +Blob::Blob(void* data, size_t size, bool adopt) { + if (adopt) { + _data = (char*)data; + } else { + _data = (char*)malloc(size); + memcpy(_data, data, size); + } + _size = size; +} + +Data::Data(const char* data, size_t size, bool adopt) { + binary = boost::shared_ptr(new Blob((void*)data, size, adopt)); +} + Data::Data(const Arabica::DOM::Node& dom) { // we may need to convert some keys to arrays if we have the same name as an element std::map > arrays; diff --git a/src/uscxml/Message.h b/src/uscxml/Message.h index 5ccab57..e561c59 100644 --- a/src/uscxml/Message.h +++ b/src/uscxml/Message.h @@ -10,6 +10,7 @@ #include #include +#include #include #define TAGNAME(elem) ((Arabica::DOM::Element)elem).getTagName() @@ -19,16 +20,25 @@ namespace uscxml { +class Blob { +public: + ~Blob(); + Blob(size_t size); + Blob(void* data, size_t size, bool adopt = false); + char* _data; + size_t _size; +}; + class Data { public: enum Type { VERBATIM, INTERPRETED, - BINARY, }; Data() : type(INTERPRETED) {} Data(const std::string& atom_, Type type_ = INTERPRETED) : atom(atom_), type(type_) {} + Data(const char* data, size_t size, bool adopt); explicit Data(const Arabica::DOM::Node& dom); virtual ~Data() {} @@ -109,6 +119,7 @@ protected: std::map compound; std::list array; std::string atom; + boost::shared_ptr binary; Type type; protected: diff --git a/src/uscxml/NameSpacingParser.h b/src/uscxml/NameSpacingParser.h index 47dd9eb..726db7b 100644 --- a/src/uscxml/NameSpacingParser.h +++ b/src/uscxml/NameSpacingParser.h @@ -16,6 +16,7 @@ class ScriptEntityResolver : public Arabica::SAX::EntityResolver { class NameSpacingParser : public Arabica::SAX2DOM::Parser { public: NameSpacingParser(); + NameSpacingParser(const NameSpacingParser& other) {} static NameSpacingParser fromXML(const std::string& xml); static NameSpacingParser fromInputSource(Arabica::SAX::InputSource& source); @@ -33,7 +34,6 @@ public: private: Arabica::SAX::CatchErrorHandler _errorHandler; - NameSpacingParser(const NameSpacingParser& other) {} }; } diff --git a/src/uscxml/URL.mm b/src/uscxml/URL.mm index 46975a0..3344601 100644 --- a/src/uscxml/URL.mm +++ b/src/uscxml/URL.mm @@ -16,7 +16,7 @@ std::string URL::getResourceDir() { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; #endif NSString *resourcePath = [[NSBundle mainBundle] resourcePath]; - return [resourcePath cStringUsingEncoding:NSUTF8StringEncoding]; + return std::string([resourcePath cStringUsingEncoding:NSUTF8StringEncoding]); #if HAS_AUTORELEASE_POOL } diff --git a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp index c5aec92..142f3ec 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp +++ b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp @@ -292,32 +292,32 @@ JSValueRef JSCDataModel::getDataAsValue(const Data& data) { handleException(exception); return value; } - - switch (data.type) { - case Data::VERBATIM: { - JSStringRef stringRef = JSStringCreateWithUTF8CString(data.atom.c_str()); - JSValueRef value = JSValueMakeString(_ctx, stringRef); - JSStringRelease(stringRef); - return value; - break; - } - case Data::INTERPRETED: { - return evalAsValue(data.atom); - break; + if (data.atom.size() > 0) { + switch (data.type) { + case Data::VERBATIM: { + JSStringRef stringRef = JSStringCreateWithUTF8CString(data.atom.c_str()); + JSValueRef value = JSValueMakeString(_ctx, stringRef); + JSStringRelease(stringRef); + return value; + break; + } + case Data::INTERPRETED: { + return evalAsValue(data.atom); + break; + } + } } - case Data::BINARY: { - uscxml::ArrayBuffer* localInstance = new uscxml::ArrayBuffer((void*)data.atom.c_str(), data.atom.size()); - + if (data.binary) { + uscxml::ArrayBuffer* localInstance = new uscxml::ArrayBuffer(data.binary); + JSClassRef retClass = JSCArrayBuffer::getTmpl(); struct JSCArrayBuffer::JSCArrayBufferPrivate* retPrivData = new JSCArrayBuffer::JSCArrayBufferPrivate(); retPrivData->nativeObj = localInstance; - + JSObjectRef retObj = JSObjectMake(_ctx, retClass, retPrivData); return retObj; - break; } - } - + return JSValueMakeUndefined(_ctx); } Data JSCDataModel::getValueAsData(const JSValueRef value) { @@ -356,6 +356,12 @@ Data JSCDataModel::getValueAsData(const JSValueRef value) { JSObjectRef objValue = JSValueToObject(_ctx, value, &exception); if (exception) handleException(exception); + if (JSValueIsObjectOfClass(_ctx, value, JSCArrayBuffer::getTmpl())) { + // binary data! + JSCArrayBuffer::JSCArrayBufferPrivate* privObj = (JSCArrayBuffer::JSCArrayBufferPrivate*)JSObjectGetPrivate(objValue); + data.binary = privObj->nativeObj->_buffer; + return data; + } std::set propertySet; JSPropertyNameArrayRef properties = JSObjectCopyPropertyNames(_ctx, objValue); size_t paramCount = JSPropertyNameArrayGetCount(properties); diff --git a/src/uscxml/plugins/datamodel/ecmascript/TypedArray.cpp b/src/uscxml/plugins/datamodel/ecmascript/TypedArray.cpp index aa15353..d24639a 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/TypedArray.cpp +++ b/src/uscxml/plugins/datamodel/ecmascript/TypedArray.cpp @@ -15,31 +15,15 @@ memcpy(_buffer->_data + (_start + index), &value, sizeof(type)); namespace uscxml { -ArrayBuffer::Buffer::~Buffer() { - free(_data); -} - -ArrayBuffer::Buffer::Buffer(size_t size) { - _data = (char*)malloc(size); - memset(_data, 0, size); - _size = size; -} - -ArrayBuffer::Buffer::Buffer(void* data, size_t size) { - _data = (char*)malloc(size); - memcpy(_data, data, size); - _size = size; -} - ArrayBuffer::ArrayBuffer(unsigned long length) { - _buffer = boost::shared_ptr(new Buffer(length)); + _buffer = boost::shared_ptr(new Blob(length)); } -ArrayBuffer::ArrayBuffer(boost::shared_ptr buffer) : _buffer(buffer) { +ArrayBuffer::ArrayBuffer(boost::shared_ptr buffer) : _buffer(buffer) { } ArrayBuffer::ArrayBuffer(void* data, unsigned int size) { - _buffer = boost::shared_ptr(new Buffer(data, size)); + _buffer = boost::shared_ptr(new Blob(data, size)); } unsigned long ArrayBuffer::getByteLength() { diff --git a/src/uscxml/plugins/datamodel/ecmascript/TypedArray.h b/src/uscxml/plugins/datamodel/ecmascript/TypedArray.h index 37b38a7..5584721 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/TypedArray.h +++ b/src/uscxml/plugins/datamodel/ecmascript/TypedArray.h @@ -1,6 +1,8 @@ #ifndef TYPEDARRAY_H_99815BLY #define TYPEDARRAY_H_99815BLY +#include "uscxml/Message.h" + #include #include #include @@ -21,14 +23,6 @@ namespace uscxml { class ArrayBuffer { public: - class Buffer { - public: - ~Buffer(); - Buffer(size_t size); - Buffer(void* data, size_t size); - char* _data; - size_t _size; - }; ArrayBuffer(void* data, unsigned int size); @@ -38,7 +32,7 @@ public: * be allocated an exception is raised. */ ArrayBuffer(unsigned long length); - ArrayBuffer(boost::shared_ptr); + ArrayBuffer(boost::shared_ptr); /** * The length of the ArrayBuffer in bytes, as fixed at construction time. @@ -79,7 +73,7 @@ public: // memcpy(_buffer->_data + index * sizeof(unsigned char), &value, sizeof(unsigned char)); // } - boost::shared_ptr _buffer; + boost::shared_ptr _buffer; }; class ArrayBufferView { @@ -105,7 +99,7 @@ public: virtual unsigned long getByteLength() = 0; virtual unsigned long getLength() = 0; protected: - boost::shared_ptr _buffer; + boost::shared_ptr _buffer; unsigned long _start; unsigned long _end; }; @@ -224,7 +218,7 @@ public: _buffer = buffer->_buffer; } - TypedArray(boost::shared_ptr buffer, unsigned long byteOffset, unsigned long length) { + TypedArray(boost::shared_ptr buffer, unsigned long byteOffset, unsigned long length) { if (byteOffset % sizeof(S)) return; @@ -247,7 +241,7 @@ public: TypedArray(unsigned long length) { _start = 0; _end = length; - _buffer = boost::shared_ptr(new ArrayBuffer::Buffer(length * sizeof(S))); + _buffer = boost::shared_ptr(new Blob(length * sizeof(S))); } /** @@ -260,7 +254,7 @@ public: TypedArray(std::vector data) { _start = 0; _end = data.size(); - _buffer = boost::shared_ptr(new ArrayBuffer::Buffer(data.size() * sizeof(S))); + _buffer = boost::shared_ptr(new Blob(data.size() * sizeof(S))); set(data, 0); } TypedArray(TypedArray* other) { diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp index caf482b..77efe78 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp @@ -282,6 +282,11 @@ Data V8DataModel::getValueAsData(const v8::Handle& value, std::setIsNumberObject()) { LOG(ERROR) << "IsNumberObject is unimplemented" << std::endl; } else if (value->IsObject()) { + if (V8ArrayBuffer::hasInstance(value)) { + uscxml::V8ArrayBuffer::V8ArrayBufferPrivate* privObj = V8DOM::toClassPtr(value->ToObject()->GetInternalField(0)); + data.binary = privObj->nativeObj->_buffer; + return data; + } v8::Handle object = v8::Handle::Cast(value); v8::Local properties = object->GetPropertyNames(); for (int i = 0; i < properties->Length(); i++) { @@ -350,15 +355,18 @@ v8::Handle V8DataModel::getDataAsValue(const Data& data) { } return value; } - switch (data.type) { - case Data::VERBATIM: - return v8::String::New(data.atom.c_str()); - break; - case Data::INTERPRETED: - return evalAsValue(data.atom); - break; - case Data::BINARY: { - uscxml::ArrayBuffer* arrBuffer = new uscxml::ArrayBuffer((void*)data.atom.c_str(), data.atom.size()); + if (data.atom.length() > 0) { + switch (data.type) { + case Data::VERBATIM: + return v8::String::New(data.atom.c_str()); + break; + case Data::INTERPRETED: + return evalAsValue(data.atom); + break; + } + } + if (data.binary) { + uscxml::ArrayBuffer* arrBuffer = new uscxml::ArrayBuffer(data.binary); v8::Handle retCtor = V8ArrayBuffer::getTmpl()->GetFunction(); v8::Persistent retObj = v8::Persistent::New(retCtor->NewInstance()); @@ -368,8 +376,6 @@ v8::Handle V8DataModel::getDataAsValue(const Data& data) { retObj.MakeWeak(0, V8ArrayBuffer::jsDestructor); return retObj; - break; - } } // this will never be reached return v8::Undefined(); 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 +#include +#include + +#include "uscxml/NameSpacingParser.h" + +#ifdef BUILD_AS_PLUGINS +#include +#endif + +namespace uscxml { + +#ifdef BUILD_AS_PLUGINS +PLUMA_CONNECTOR +bool connect(pluma::Host& host) { + host.add( new FileElementProvider() ); + return true; +} +#endif + +boost::shared_ptr FileElement::create(InterpreterImpl* interpreter) { + boost::shared_ptr element = boost::shared_ptr(new FileElement()); + return element; +} + +FileElement::~FileElement() { +} + +void FileElement::enterElement(const Arabica::DOM::Node& 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& 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 +#include + +#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 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& node); + void exitElement(const Arabica::DOM::Node& 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 */ diff --git a/test/samples/uscxml/test-file-element.scxml b/test/samples/uscxml/test-file-element.scxml new file mode 100644 index 0000000..baeafae --- /dev/null +++ b/test/samples/uscxml/test-file-element.scxml @@ -0,0 +1,17 @@ + + +