summaryrefslogtreecommitdiffstats
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
parenta874a181add7b292e52140f8c753f663a4cb5a87 (diff)
downloaduscxml-7938e286967597c7168b855b7e3fdfbd9b949e0e.zip
uscxml-7938e286967597c7168b855b7e3fdfbd9b949e0e.tar.gz
uscxml-7938e286967597c7168b855b7e3fdfbd9b949e0e.tar.bz2
New file element for executable content
-rw-r--r--CMakeLists.txt2
-rwxr-xr-xcontrib/local/bcp-boost.sh6
-rwxr-xr-xcontrib/local/compress_and_upload_deps.sh1
-rw-r--r--src/uscxml/Factory.cpp6
-rw-r--r--src/uscxml/Message.cpp24
-rw-r--r--src/uscxml/Message.h13
-rw-r--r--src/uscxml/NameSpacingParser.h2
-rw-r--r--src/uscxml/URL.mm2
-rw-r--r--src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp44
-rw-r--r--src/uscxml/plugins/datamodel/ecmascript/TypedArray.cpp22
-rw-r--r--src/uscxml/plugins/datamodel/ecmascript/TypedArray.h22
-rw-r--r--src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp28
-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
-rw-r--r--test/samples/uscxml/test-file-element.scxml17
16 files changed, 427 insertions, 70 deletions
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<ExecutableContentImpl> Factory::createExecutableContent(const
if (_executableContent.find(std::make_pair(localName, actualNameSpace)) != _executableContent.end()) {
boost::shared_ptr<ExecutableContentImpl> 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<Blob>(new Blob((void*)data, size, adopt));
+}
+
Data::Data(const Arabica::DOM::Node<std::string>& dom) {
// we may need to convert some keys to arrays if we have the same name as an element
std::map<std::string, std::list<Data> > 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 <DOM/Document.hpp>
#include <DOM/io/Stream.hpp>
+#include <boost/shared_ptr.hpp>
#include <inttypes.h>
#define TAGNAME(elem) ((Arabica::DOM::Element<std::string>)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<std::string>& dom);
virtual ~Data() {}
@@ -109,6 +119,7 @@ protected:
std::map<std::string, Data> compound;
std::list<Data> array;
std::string atom;
+ boost::shared_ptr<Blob> 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<std::string> {
class NameSpacingParser : public Arabica::SAX2DOM::Parser<std::string> {
public:
NameSpacingParser();
+ NameSpacingParser(const NameSpacingParser& other) {}
static NameSpacingParser fromXML(const std::string& xml);
static NameSpacingParser fromInputSource(Arabica::SAX::InputSource<std::string>& source);
@@ -33,7 +34,6 @@ public:
private:
Arabica::SAX::CatchErrorHandler<std::string> _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<std::string> 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<Buffer>(new Buffer(length));
+ _buffer = boost::shared_ptr<Blob>(new Blob(length));
}
-ArrayBuffer::ArrayBuffer(boost::shared_ptr<ArrayBuffer::Buffer> buffer) : _buffer(buffer) {
+ArrayBuffer::ArrayBuffer(boost::shared_ptr<Blob> buffer) : _buffer(buffer) {
}
ArrayBuffer::ArrayBuffer(void* data, unsigned int size) {
- _buffer = boost::shared_ptr<Buffer>(new Buffer(data, size));
+ _buffer = boost::shared_ptr<Blob>(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 <string>
#include <vector>
#include <boost/shared_ptr.hpp>
@@ -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::Buffer>);
+ ArrayBuffer(boost::shared_ptr<Blob>);
/**
* 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> _buffer;
+ boost::shared_ptr<Blob> _buffer;
};
class ArrayBufferView {
@@ -105,7 +99,7 @@ public:
virtual unsigned long getByteLength() = 0;
virtual unsigned long getLength() = 0;
protected:
- boost::shared_ptr<ArrayBuffer::Buffer> _buffer;
+ boost::shared_ptr<Blob> _buffer;
unsigned long _start;
unsigned long _end;
};
@@ -224,7 +218,7 @@ public:
_buffer = buffer->_buffer;
}
- TypedArray(boost::shared_ptr<ArrayBuffer::Buffer> buffer, unsigned long byteOffset, unsigned long length) {
+ TypedArray(boost::shared_ptr<Blob> 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<ArrayBuffer::Buffer>(new ArrayBuffer::Buffer(length * sizeof(S)));
+ _buffer = boost::shared_ptr<Blob>(new Blob(length * sizeof(S)));
}
/**
@@ -260,7 +254,7 @@ public:
TypedArray(std::vector<T> data) {
_start = 0;
_end = data.size();
- _buffer = boost::shared_ptr<ArrayBuffer::Buffer>(new ArrayBuffer::Buffer(data.size() * sizeof(S)));
+ _buffer = boost::shared_ptr<Blob>(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<v8::Value>& value, std::set<v8
} else if (value->IsNumberObject()) {
LOG(ERROR) << "IsNumberObject is unimplemented" << std::endl;
} else if (value->IsObject()) {
+ if (V8ArrayBuffer::hasInstance(value)) {
+ uscxml::V8ArrayBuffer::V8ArrayBufferPrivate* privObj = V8DOM::toClassPtr<V8ArrayBuffer::V8ArrayBufferPrivate >(value->ToObject()->GetInternalField(0));
+ data.binary = privObj->nativeObj->_buffer;
+ return data;
+ }
v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(value);
v8::Local<v8::Array> properties = object->GetPropertyNames();
for (int i = 0; i < properties->Length(); i++) {
@@ -350,15 +355,18 @@ v8::Handle<v8::Value> 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<v8::Function> retCtor = V8ArrayBuffer::getTmpl()->GetFunction();
v8::Persistent<v8::Object> retObj = v8::Persistent<v8::Object>::New(retCtor->NewInstance());
@@ -368,8 +376,6 @@ v8::Handle<v8::Value> 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 <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 */
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 @@
+<scxml datamodel="ecmascript">
+ <!-- This exemplifies the file element and TypedArrays in _event['data']['content'] -->
+ <script src="http://uscxml.tk.informatik.tu-darmstadt.de/scripts/dump.js" />
+ <state id="read">
+ <onentry>
+ <file url="foo.bin" operation="read" type="binary" callback="foo.bin" />
+ </onentry>
+ <transition event="foo.bin" target="write">
+ <log expr="dump(_event)" />
+ </transition>
+ </state>
+ <state id="write">
+ <onentry>
+ <file url="bar.bin" operation="write" type="binary" contentexpr="_event['data']['content']" />
+ </onentry>
+ </state>
+</scxml> \ No newline at end of file