From d2e90c02e5ad19a5857e7c7fb87f248182fdb32d Mon Sep 17 00:00:00 2001 From: Stefan Radomski Date: Sat, 15 Nov 2014 22:44:59 +0100 Subject: Fixed file:// handling bug on windows --- README.md | 12 +++- apps/uscxml-dot.cpp | 2 +- src/bindings/CMakeLists.txt | 7 ++- src/bindings/swig/java/CMakeLists.txt | 4 +- src/uscxml/Interpreter.cpp | 27 +++----- src/uscxml/Interpreter.h | 1 - src/uscxml/URL.cpp | 28 ++++++++- src/uscxml/URL.h | 4 +- test/src/test-url.cpp | 112 ++++++++++++++++++++++++++-------- 9 files changed, 142 insertions(+), 55 deletions(-) diff --git a/README.md b/README.md index 67f04f6..ff10818 100644 --- a/README.md +++ b/README.md @@ -96,6 +96,10 @@ This will perform a single iteration on the invoked components with a maximum of or return immediately. You will have to call this method every now and then if you are using e.g. the scenegraph invoker. +Note: Running the interpreter in its own thread via start is not exposed into the +language bindings. Just use the threading concepts native to your language to call step or +interpret as outlined below. + ### Blocking Interpretation with inline SCXML Interpreter scxml = Interpreter::fromXML(""); scxml.interpret(); // blocking @@ -107,11 +111,13 @@ it will call runOnMainThread between stable configurations. Interpreter scxml = Interpreter::fromXML(""); InterpreterState state; do { - state = interpreter.step(true); // boolean argument causes blocking or not - } while(state > 0) + state = interpreter.step(ms); + } while(state != InterpreterState::USCXML_FINISHED) Using step, you can run a single macrostep of the interpreter and interleave -interpretation with the rest of your code. +interpretation with the rest of your code. The step function will take an optional integer as +the time in milliseconds it will block and wait if no more events are available, default is to block +indefinitely until an event arrives or the interpreter finished. ### Callbacks for an Interpreter diff --git a/apps/uscxml-dot.cpp b/apps/uscxml-dot.cpp index 11e2994..e79c3f9 100644 --- a/apps/uscxml-dot.cpp +++ b/apps/uscxml-dot.cpp @@ -86,7 +86,7 @@ int main(int argc, char** argv) { try { // current option has to be the interpreter's name URL inputFile(argv[optind]); - Interpreter interpreter = Interpreter::fromURI(inputFile); + Interpreter interpreter = Interpreter::fromURI(inputFile.asString()); optind++; while(optind < argc) { diff --git a/src/bindings/CMakeLists.txt b/src/bindings/CMakeLists.txt index 25c11a1..edddc31 100644 --- a/src/bindings/CMakeLists.txt +++ b/src/bindings/CMakeLists.txt @@ -11,8 +11,9 @@ if (WIN32) LIST(APPEND CMAKE_PROGRAM_PATH "${PROJECT_BINARY_DIR}/../../swig/") endif() - LIST(APPEND CMAKE_PROGRAM_PATH "C:/Program Files/swig") # swig.exe - LIST(APPEND CMAKE_PROGRAM_PATH "C:/Program Files (x86)/swig") # swig.exe + file(GLOB POTENTIAL_SWIG "C:/Program Files/swig*" "C:/Program Files (x86)/swig*") + LIST(APPEND CMAKE_PROGRAM_PATH ${POTENTIAL_SWIG}) # swig.exe + # message(FATAL_ERROR "POTENTIAL_SWIG: ${POTENTIAL_SWIG}") endif() LIST(APPEND CMAKE_PROGRAM_PATH $ENV{SWIG_DIR}) @@ -29,7 +30,7 @@ if (SWIG_FOUND) message(STATUS "SWIG version > 3.0 is recommended, found ${SWIG_VERSION}") endif() else() - message(STATUS "SWIG version 2.0.5 is required, found ${SWIG_VERSION} - skipping java wrapper generation") + message(STATUS "SWIG version 2.0.5 is required, found ${SWIG_VERSION} - skipping wrapper generation") endif() else() message(STATUS "SWIG not found - skipping wrapper generation") diff --git a/src/bindings/swig/java/CMakeLists.txt b/src/bindings/swig/java/CMakeLists.txt index eb51f83..de2a161 100644 --- a/src/bindings/swig/java/CMakeLists.txt +++ b/src/bindings/swig/java/CMakeLists.txt @@ -31,7 +31,9 @@ set_target_properties(uscxmlNativeJava PROPERTIES COMPILE_FLAGS "-DSWIG") swig_link_libraries(uscxmlNativeJava uscxml) -FIND_PROGRAM(ANT_EXECUTABLE ant PATHS $ENV{ANT_HOME}/bin ENV PATH ) +file(GLOB POTENTIAL_ANT "C:/Program Files/apache-ant**/bin" "C:/Program Files (x86)/apache-ant**/bin") + +FIND_PROGRAM(ANT_EXECUTABLE ant PATHS $ENV{ANT_HOME}/bin ${POTENTIAL_ANT} ENV PATH ) if (ANT_EXECUTABLE) set(USCXML_LANGUAGE_BINDINGS "java ${USCXML_LANGUAGE_BINDINGS}") diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp index 5d9d1cd..dc53906 100644 --- a/src/uscxml/Interpreter.cpp +++ b/src/uscxml/Interpreter.cpp @@ -407,13 +407,9 @@ Interpreter Interpreter::fromXML(const std::string& xml) { return fromInputSource(inputSource); } -Interpreter Interpreter::fromURI(const std::string& uri) { - URL url(uri); - return fromURI(url); -} -Interpreter Interpreter::fromURI(const URL& uri) { - URL absUrl = uri; +Interpreter Interpreter::fromURI(const std::string& uri) { + URL absUrl(uri); if (!absUrl.isAbsolute()) { if (!absUrl.toAbsoluteCwd()) { ERROR_COMMUNICATION_THROW("URL is not absolute or does not have file schema"); @@ -426,15 +422,8 @@ Interpreter Interpreter::fromURI(const URL& uri) { Arabica::SAX::InputSource inputSource; inputSource.setSystemId(absUrl.asString()); interpreter = fromInputSource(inputSource); -#if 0 - } else if (iequals(absUrl.scheme(), "http")) { - // handle http per arabica - this will not follow redirects - Arabica::SAX::InputSource inputSource; - inputSource.setSystemId(absUrl.asString()); - interpreter = fromInputSource(inputSource); -#endif } else { - // use curl for everything else + // use curl for everything !file - even for http as arabica won't follow redirects std::stringstream ss; ss << absUrl; if (absUrl.downloadFailed()) { @@ -547,14 +536,14 @@ InterpreterImpl::~InterpreterImpl() { event.name = "unblock.and.die"; receive(event); - _thread->join(); - delete(_thread); } else { // this can happen with a shared_from_this at an interpretermonitor setInterpreterState(USCXML_DESTROYED); } + _thread->join(); + delete(_thread); } - join(); + if (_sendQueue) delete _sendQueue; @@ -1153,8 +1142,8 @@ bool InterpreterImpl::runOnMainThread(int fps, bool blocking) { return false; if (fps > 0) { - uint64_t nextRun = _lastRunOnMainThread + (1000 / fps); - if (blocking) { + if (blocking && _lastRunOnMainThread > 0) { + uint64_t nextRun = _lastRunOnMainThread + (1000 / fps); while(nextRun > tthread::timeStamp()) { tthread::this_thread::sleep_for(tthread::chrono::milliseconds(nextRun - tthread::timeStamp())); } diff --git a/src/uscxml/Interpreter.h b/src/uscxml/Interpreter.h index 70c9c0e..d6da7bd 100644 --- a/src/uscxml/Interpreter.h +++ b/src/uscxml/Interpreter.h @@ -586,7 +586,6 @@ public: const NameSpaceInfo& nameSpaceInfo); static Interpreter fromXML(const std::string& xml); static Interpreter fromURI(const std::string& uri); - static Interpreter fromURI(const URL& uri); static Interpreter fromClone(const Interpreter& other); Interpreter() : _impl() {} // the empty, invalid interpreter diff --git a/src/uscxml/URL.cpp b/src/uscxml/URL.cpp index d18b55c..b1297d5 100644 --- a/src/uscxml/URL.cpp +++ b/src/uscxml/URL.cpp @@ -52,6 +52,21 @@ namespace uscxml { +void URL::dump() { + std::cout << ">>>" << asString() << "<<< "; + std::cout << (isAbsolute() ? "absolute" : "relative") << std::endl; + std::cout << "[scheme]" << scheme(); + std::cout << "[host]" << host(); + std::cout << "[port]" << port(); + std::cout << "[path]" << path(); + std::cout << "[file]" << file() << std::endl; + std::cout << "[segmts " << pathComponents().size() << "]: "; + for (int i = 0; i < pathComponents().size(); i++) { + std::cout << pathComponents()[i] << ", "; + } + std::cout << std::endl << std::endl; +} + std::string URL::tmpDir() { // try hard to find a temporary directory const char* tmpDir = NULL; @@ -157,7 +172,12 @@ std::string URL::getResourceDir() { } #endif -URLImpl::URLImpl(const std::string& url) : _handle(NULL), _uri(url), _isDownloaded(false), _hasFailed(false) { +URLImpl::URLImpl(const std::string& url) : _handle(NULL), _isDownloaded(false), _hasFailed(false) { + if (url[0] == '/') { + _uri = Arabica::io::URI("file://" + url); + } else { + _uri = Arabica::io::URI(url); + } std::stringstream ss(_uri.path()); std::string item; while(std::getline(ss, item, '/')) { @@ -472,8 +492,11 @@ const bool URLImpl::toAbsolute(const std::string& baseUrl) { return true; std::string uriStr = _uri.as_string(); +// std::cout << "## bas # " << baseUrl << std::endl; +// std::cout << "## rel # " << _uri.as_string() << std::endl; + #ifdef _WIN32 - if (baseUrl.find("file://") == 0) { + if (baseUrl.find("file://") == 0 && false) { _uri = Arabica::io::URI("file:///" + baseUrl.substr(7), _uri.as_string()); } else { _uri = Arabica::io::URI(baseUrl, _uri.as_string()); @@ -481,6 +504,7 @@ const bool URLImpl::toAbsolute(const std::string& baseUrl) { #else _uri = Arabica::io::URI(baseUrl, _uri.as_string()); #endif +// std::cout << "## abs # " << _uri.as_string() << std::endl; if (!_uri.is_absolute()) return false; diff --git a/src/uscxml/URL.h b/src/uscxml/URL.h index 00c2b30..09d5ed0 100644 --- a/src/uscxml/URL.h +++ b/src/uscxml/URL.h @@ -231,13 +231,15 @@ public: return URL(impl); } + void dump(); + void addMonitor(URLMonitor* monitor) { _impl->addMonitor(monitor); } void removeMonitor(URLMonitor* monitor) { _impl->removeMonitor(monitor); } - + bool downloadFailed() { return _impl->downloadFailed(); } diff --git a/test/src/test-url.cpp b/test/src/test-url.cpp index 5e5f4ea..1ebcac3 100644 --- a/test/src/test-url.cpp +++ b/test/src/test-url.cpp @@ -3,6 +3,8 @@ #include "uscxml/Interpreter.h" #include "uscxml/server/HTTPServer.h" +#include "uscxml/config.h" + #include #include @@ -42,17 +44,99 @@ bool canResolve(const std::string& url) { } } +void testFileURLs() { + + // absolute + std::list absURLs; + { + // with explicit file schema + absURLs.push_back(URL("file:///")); + absURLs.push_back(URL("file:/")); + + // platform specific + absURLs.push_back(URL("file:/Z:/Windows/workspace/uscxml/bin/com/carmeq/scxml/test-xml-access.xml")); + absURLs.push_back(URL("file:/C:/Windows/config.sys")); + absURLs.push_back(URL("file:/Macintosh%20HD/fileURLs/text.txt")); + absURLs.push_back(URL("file:/fileURLs/text.txt")); + + // usual filesystem paths + absURLs.push_back(URL("C:\\Windows\\sradomski\\Desktop\\foo.txt")); +// absURLs.push_back(URL("C:\\Windows\\Some Spaces\\index.txt")); +// absURLs.push_back(URL("C:/Windows/Some Spaces/index.txt")); +// absURLs.push_back(URL("/Users/sradomski/Desktop/")); +// absURLs.push_back(URL("/Users/sradomski/Desktop/foo.txt")); + } + + std::list absWithHostURLs; + { + absWithHostURLs.push_back(URL("file://hostname/")); + absWithHostURLs.push_back(URL("file://localhost/")); + absWithHostURLs.push_back(URL("file://C:/config.sys")); + absWithHostURLs.push_back(URL("file://config.sys")); + absWithHostURLs.push_back(URL("file://config.sys")); + absWithHostURLs.push_back(URL("file://Macintosh%20HD/fileURLs/text.txt")); + absWithHostURLs.push_back(URL("file://fileURLs/text.txt")); + absWithHostURLs.push_back(URL("file://Desktop/workspace/uscxml/bin/com/carmeq/scxml/test-xml-access.xml")); + absWithHostURLs.push_back(URL("file://Windows\\sradomski\\Desktop\\foo.txt")); + + } + // relative URLs + std::list relURLs; + + { + relURLs.push_back(URL("file")); + relURLs.push_back(URL("file:")); + relURLs.push_back(URL("file://")); + + // platform specific + relURLs.push_back(URL("file:Macintosh%20HD/fileURLs/text.txt")); + relURLs.push_back(URL("file:fileURLs/text.txt")); + relURLs.push_back(URL("file:Document/Text.foo")); + + // usual filesystem paths + relURLs.push_back(URL("Users\\sradomski\\Desktop\\foo.txt")); + relURLs.push_back(URL("Document\\Some Spaces\\index.txt")); + relURLs.push_back(URL("Document/Some Spaces/index.txt")); + relURLs.push_back(URL("Users/sradomski/Desktop/")); + relURLs.push_back(URL("Users/sradomski/Desktop/foo.txt")); + } + + for (std::list::iterator absIter = absURLs.begin(); absIter != absURLs.end(); absIter++) { + absIter->dump(); + assert(absIter->isAbsolute()); + assert(absIter->scheme() == "file"); + assert(absIter->host() == ""); + } + + for (std::list::iterator relIter = relURLs.begin(); relIter != relURLs.end(); relIter++) { + assert(!relIter->isAbsolute()); + } + + for (std::list::iterator absIter = absURLs.begin(); absIter != absURLs.end(); absIter++) { + for (std::list::iterator relIter = relURLs.begin(); relIter != relURLs.end(); relIter++) { + URL relURL(*relIter); + relURL.toAbsolute(*absIter); + assert(relURL.isAbsolute()); + } + } + +} + int main(int argc, char** argv) { #ifdef _WIN32 WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); #endif + // some URLs from http://www-archive.mozilla.org/quality/networking/testing/filetests.html + HTTPServer::getInstance(8099, 8100); std::string exeName = argv[0]; exeName = exeName.substr(exeName.find_last_of("\\/") + 1); + testFileURLs(); + { try { URL url("http://asdfasdfasdfasdf.wgferg"); @@ -171,6 +255,7 @@ int main(int argc, char** argv) { content << url; } +#ifndef _WIN32 { URL url("https://raw.github.com/tklab-tud/uscxml/master/test/samples/uscxml/test-ecmascript.scxml"); std::cout << url.asString() << std::endl; @@ -179,17 +264,8 @@ int main(int argc, char** argv) { std::stringstream content; content << url; } - - { - URL url("file:Document/Text.foo"); - std::cout << url.asString() << std::endl; - assert(!url.isAbsolute()); - assert(iequals(url.scheme(), "file")); - assert(iequals(url.host(), "")); - assert(iequals(url.port(), "0")); - assert(iequals(url.path(), "Document/Text.foo")); - assert(iequals(url.asString(), "file:Document/Text.foo")); - } +#endif + { URL url("test/index.html"); assert(iequals(url.scheme(), "")); @@ -197,24 +273,12 @@ int main(int argc, char** argv) { assert(iequals(url.scheme(), "file")); std::cout << url.asString() << std::endl; } - { - URL url("C:\\Document\\Some Spaces\\index.txt"); - assert(url.isAbsolute()); - assert(iequals(url.scheme(), "file")); - std::cout << url.asString() << std::endl; - } + { URL url = URL::toLocalFile("this is quite some content!", "txt"); std::cout << url.asLocalFile("txt"); assert(url.isAbsolute()); assert(iequals(url.scheme(), "file")); } - { - URL url("C:\\Document\\Some Spaces\\index.txt"); - assert(iequals(url.pathComponents()[0], "C:")); - assert(iequals(url.pathComponents()[1], "Document")); - assert(iequals(url.pathComponents()[2], "Some Spaces")); - assert(iequals(url.pathComponents()[3], "index.txt")); - } } \ No newline at end of file -- cgit v0.12