diff options
author | Stefan Radomski <radomski@tk.informatik.tu-darmstadt.de> | 2013-12-20 00:56:45 (GMT) |
---|---|---|
committer | Stefan Radomski <radomski@tk.informatik.tu-darmstadt.de> | 2013-12-20 00:56:45 (GMT) |
commit | 0388c7ac478187ff8d264b6e0275a4c4a43796b9 (patch) | |
tree | 7e62439ebf72b6369ee7b1daa370e6251c06b7e0 | |
parent | 22e22bfd0965e01fea041e053873d352387805f6 (diff) | |
download | uscxml-0388c7ac478187ff8d264b6e0275a4c4a43796b9.zip uscxml-0388c7ac478187ff8d264b6e0275a4c4a43796b9.tar.gz uscxml-0388c7ac478187ff8d264b6e0275a4c4a43796b9.tar.bz2 |
Performance and bugfix for WebSockets
31 files changed, 1409 insertions, 159 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 0454f4c..da50553 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -70,6 +70,18 @@ if (APPLE) MACOSX_VERSION_MINOR MACOSX_VERSION_PATCH) endif() + if (MACOSX_VERSION VERSION_GREATER "10.8.99") + # LIST(APPEND CMAKE_FIND_ROOT_PATH ${CMAKE_OSX_SYSROOT}) + # make sure that we find libxml2 here first + set(CMAKE_FIND_ROOT_PATH ${CMAKE_OSX_SYSROOT} ${CMAKE_FIND_ROOT_PATH}) + endif() +endif() + +if (NOT $ENV{MACOSX_DEPLOYMENT_TARGET} STREQUAL "" + AND ENV{MACOSX_DEPLOYMENT_TARGET} VERSION_LESS "10.9" + AND MACOSX_VERSION VERSION_GREATER "10.8.99") + message(WARNING "\nMACOSX_DEPLOYMENT_TARGET is set to $ENV{MACOSX_DEPLOYMENT_TARGET} implying libstdc++ instead of libc++ - linking against prebuilts from 10.8") + set(MACOSX_VERSION_MINOR 8) endif() # We use the toolchain file from http://code.google.com/p/android-cmake/ @@ -249,6 +261,8 @@ else() endif() include_directories(${USCXML_PREBUILT_LIBRARY_PATH}/include) +#message(STATUS "Searching for prebuilt libraries in: ${CMAKE_FIND_ROOT_PATH}") + if (WIN32) include_directories(${PROJECT_SOURCE_DIR}/contrib/src/getopt) include_directories(${PROJECT_SOURCE_DIR}/contrib/src/inttypes) @@ -266,8 +280,8 @@ if (CMAKE_CROSSCOMPILING) OPTION(BUILD_TESTS "Build USCXML tests" OFF) else() OPTION(BUILD_TESTS "Build USCXML tests" ON) - OPTION(RUN_W3C_ECMA_TESTS "Run W3C ECMAScript tests" OFF) - OPTION(RUN_W3C_XPATH_TESTS "Run W3C XPath tests" OFF) + OPTION(BUILD_TESTS_W3C_ECMA "Run W3C ECMAScript tests" OFF) + OPTION(BUILD_TESTS_W3C_XPATH "Run W3C XPath tests" OFF) endif() OPTION(ENABLE_GCOV "Compile with gcov support" OFF) @@ -500,7 +514,8 @@ if (NOT WIN32) # message("CMAKE_SYSTEM_PROGRAM_PATH: ${CMAKE_SYSTEM_PROGRAM_PATH}") # message("CMAKE_FIND_ROOT_PATH: ${CMAKE_FIND_ROOT_PATH}") - if (APPLE) + # MacOSX Mavericks moved libxml2 into SDK + if (APPLE AND ${MACOSX_VERSION} VERSION_LESS "10.9.0") set(PC_LIBXML_INCLUDEDIR "/usr/include/libxml2/") endif() @@ -957,6 +972,7 @@ foreach(LIBRARY ${USCXML_OPT_LIBS}) set(SKIP_NEXT ON) endif() elseif (LIBRARY MATCHES "uscxml.*") + elseif (LIBRARY MATCHES ".*\\.framework.*") elseif (LIBRARY MATCHES "mmi_proto.*") else() if (NOT SKIP_NEXT) diff --git a/apps/samples/miles/miles.js b/apps/samples/miles/miles.js index cd61f64..01bb134 100644 --- a/apps/samples/miles/miles.js +++ b/apps/samples/miles/miles.js @@ -54,7 +54,7 @@ function Miles(element, params) { var audioEncoding = ""; var repollInterval = { - image: 50, + image: 20, chat: 500, participants: 1000 }; diff --git a/apps/samples/miles/miles.scxml b/apps/samples/miles/miles.scxml index c1c6c69..8281e9f 100644 --- a/apps/samples/miles/miles.scxml +++ b/apps/samples/miles/miles.scxml @@ -8,6 +8,7 @@ <if cond="_event.data.origin"> <!-- <log label="Reply-length" expr="_event.data.base64.length" /> --> <if cond="_event.name === 'thumbnail.reply'"> + <!-- <log expr="_event.data.image.base64().length" /> --> <respond status="200" to="_event.data.origin"> <header name="Cache-Control" value="no-cache" /> <!-- force IE to actually reload --> <header name="Access-Control-Allow-Origin" value="*" /> diff --git a/apps/samples/vrml/ffmpeg-server.invoked.scxml b/apps/samples/vrml/ffmpeg-server.invoked.scxml index bac0792..0c6449f 100644 --- a/apps/samples/vrml/ffmpeg-server.invoked.scxml +++ b/apps/samples/vrml/ffmpeg-server.invoked.scxml @@ -121,7 +121,7 @@ --> <script> //<![CDATA[ -// dump(_event); + dump(_event); var pathDelim = ':'; // we need to flatten directories - this will seperate them in filenames // store event @@ -158,9 +158,7 @@ } var keyFrame = job.keyFrames[kfIndex]; - keyFrame.modelFile = keyFrame.imageURL.substr(keyFrame.serverURL.length + 1); - keyFrame.file = keyFrame.modelFile.substr(0, keyFrame.modelFile.indexOf('.')); - keyFrame.ext = keyFrame.modelFile.substr(keyFrame.modelFile.indexOf('.') + 1); + keyFrame.file = keyFrame.imagePath.substr(1); keyFrame.modelFile = keyFrame.file + ".osgb"; keyFrame.modelFile = keyFrame.modelFile.replace(/\//g, pathDelim); @@ -236,6 +234,7 @@ _event.data.pathComponent.length == 3 && _event.data.pathComponent[1] === 'movie' && _event.data.pathComponent[2] === 'codecs'"> + <log expr="_invokers['ffmpeg']" /> <send target="#_parent" event="send.codecs"> <param name="context" expr="_event.origin" /> <param name="codecs" expr="_invokers['ffmpeg']" /> diff --git a/apps/samples/vrml/viewer-webgl.js b/apps/samples/vrml/viewer-webgl.js index c376e25..10dbd72 100644 --- a/apps/samples/vrml/viewer-webgl.js +++ b/apps/samples/vrml/viewer-webgl.js @@ -184,7 +184,7 @@ function VRMLViewer(element, params) { } if (self.enableSceneshots) { self.imgElem.src = self.serverURL + self.imagePath + self.imageFormat + urlSuffixForPose(self.pose); - if (self.enableMovies) { + if (self.enableMovies && self.movieAddButton) { // we are showing an image, activate movie controls self.movieAddButton.domNode.style.display = ""; self.movieDropDown.domNode.style.display = ""; @@ -964,7 +964,7 @@ function VRMLViewer(element, params) { avatarPose.width = 60; avatarPose.height = 60; var avatarImgUrl = urlSuffixForPose(avatarPose); - avatar.innerHTML = '<img src=' + self.imagePath + avatarImgUrl + ' /> '; + avatar.innerHTML = '<img src=' + self.imagePath + self.imageFormat + avatarImgUrl + ' /> '; item.srcEcc = "VRMLViewer"; item.iconPoseUrl = self.imagePath + avatarImgUrl; item.imagePath = self.imagePath; @@ -1054,7 +1054,7 @@ function VRMLViewer(element, params) { thumbPose.height = self.pose.height / 10; var thumbImgUrl = urlSuffixForPose(thumbPose); - thumbImgElem.src = self.imagePath + thumbImgUrl; + thumbImgElem.src = self.serverURL + self.imagePath + self.imageFormat + thumbImgUrl; // removeImgElem.src = self.resRoot + 'img/close.png'; item.srcEcc = "VRMLViewer"; @@ -1074,7 +1074,7 @@ function VRMLViewer(element, params) { style: "width: 320px", options: [] }); - self.populateMovieCodecs("http://" + self.serverURL + '/movie/codecs', self.movieFormatSelection); + self.populateMovieCodecs(self.serverURL + '/movie/codecs', self.movieFormatSelection); self.movieFormatLengthRowElem.appendChild(dojo.create('td', { innerHTML: 'Format:'} )); self.movieFormatLengthRowElem.appendChild(dojo.create('td', { colspan: "2"})); diff --git a/apps/samples/vrml/viewer.html b/apps/samples/vrml/viewer.html index 345ee56..50a2fef 100644 --- a/apps/samples/vrml/viewer.html +++ b/apps/samples/vrml/viewer.html @@ -60,7 +60,32 @@ <script type="text/javascript"> require(["dojo/domReady!", "dojo"], function(dom, dojo) { - var viewer = new VRMLViewer("scene1", { + var viewer = new VRMLViewer("scene1", { + pose: { + pitch : 0, + roll : 0, + yaw : 0, + zoom : 1, + x : 0, + y : 0, + z : 0, + autorotate : true + }, + height: 300, + width: 400, + enableMovies: false, + enableDND: false, + enableWebGL: true, + enableSceneshots: false, + enableDraggables: false, + listNavigationStyle: true, + treeNavigationStyle: true, + listDirectory: "/hard_mp", + imagePath: "/hard_mp/HARD_MP_VAL_000", + imageFormat: "png", + serverURL: "http://localhost:8082/vrml", + }); + var viewer2 = new VRMLViewer("scene2", { pose: { pitch : 0, roll : 0, @@ -71,22 +96,20 @@ z : 0, autorotate : true }, - height: 600, - width: 800, - enableMovies: false, + height: 300, + width: 400, + enableMovies: true, enableDND: false, - enableWebGL: true, - enableSceneshots: false, - enableDraggables: false, + enableWebGL: false, + enableSceneshots: true, + enableDraggables: true, listNavigationStyle: true, treeNavigationStyle: true, listDirectory: "/hard_mp", imagePath: "/hard_mp/HARD_MP_VAL_000", imageFormat: "png", - serverURL: "http://localhost:8081/vrml", + serverURL: "http://localhost:8082/vrml" }); - //var viewer2 = new VRMLViewer("scene2"); -// var annotations = new Annotations("annotations1", { 'viewer': viewer }); }); </script> </head> diff --git a/apps/samples/vrml/vrml-server.scxml b/apps/samples/vrml/vrml-server.scxml index e35d221..c71f066 100644 --- a/apps/samples/vrml/vrml-server.scxml +++ b/apps/samples/vrml/vrml-server.scxml @@ -325,8 +325,7 @@ <script>//dump(_event);</script> <respond status="200" to="_event.data.context"> <header name="Connection" value="close" /> - <header name="Content-Type" valueexpr="application/json" /> - <header name="Content-Disposition" valueexpr="'attachment; filename=' + _event.data.filename" /> + <header name="Content-Type" value="application/json" /> <content expr="_event.data.codecs" /> </respond> </transition> diff --git a/apps/samples/websockets/websockets.html b/apps/samples/websockets/websockets.html index c90f728..88e4def 100644 --- a/apps/samples/websockets/websockets.html +++ b/apps/samples/websockets/websockets.html @@ -43,8 +43,8 @@ function onOpen(evt) { writeToScreen("CONNECTED"); doSend(littlePacket); - // doSend(mediumPacket); - // doSend(hugePacket); + doSend(mediumPacket); + //doSend(hugePacket); } function onClose(evt) { writeToScreen("DISCONNECTED"); diff --git a/contrib/build-scripts/build-arabica-macosx.sh b/contrib/build-scripts/build-arabica-macosx.sh index 8489815..c5a4bb9 100755 --- a/contrib/build-scripts/build-arabica-macosx.sh +++ b/contrib/build-scripts/build-arabica-macosx.sh @@ -1,8 +1,9 @@ #!/bin/bash # -# build libevent for MacOSX +# build arabica for MacOSX # +# ./configure --with-boost=/opt/local/include/ --with-libxml2=`xcrun --show-sdk-path`/usr --with-parser=libxml2 # exit on error set -e @@ -12,6 +13,7 @@ DIR="$( cd "$( dirname "$0" )" && pwd )" MACOSX_VER=`/usr/bin/sw_vers -productVersion` MACOSX_COMP=(`echo $MACOSX_VER | tr '.' ' '`) DEST_DIR="${DIR}/../prebuilt/darwin-i386/${MACOSX_COMP[0]}.${MACOSX_COMP[1]}/gnu" +SYSROOT=`xcrun --show-sdk-path` if [ ! -f src/arabica.cpp ]; then echo @@ -63,6 +65,7 @@ LDFLAGS="${MACOSX_VERSION_MIN} -arch x86_64" \ --disable-dependency-tracking \ --with-pic + make cp ./src/.libs/libarabica.a ./libarabica.x86_64.a make clean diff --git a/contrib/build-scripts/build-v8-mac.sh b/contrib/build-scripts/build-v8-mac.sh index 4d5aa62..e979c4d 100755 --- a/contrib/build-scripts/build-v8-mac.sh +++ b/contrib/build-scripts/build-v8-mac.sh @@ -37,6 +37,14 @@ fi DEPOT_PATH="${PWD}/../depot_tools" export PATH="${DEPOT_PATH}:${PATH}" +if [ ${MACOSX_COMP[1]} -lt 9 ]; then + CXXFLAGS="-mmacosx-version-min=10.6 -stdlib=libstdc++" + LDFLAGS="-stdlib=libstdc++" +else + CXXFLAGS="-mmacosx-version-min=10.7 -stdlib=libc++" + LDFLAGS="-stdlib=libc++" +fi + make dependencies make ia32.release diff --git a/contrib/dom/scripts/CodeGeneratorArabicaV8.pm.new b/contrib/dom/scripts/CodeGeneratorArabicaV8.pm.new new file mode 100644 index 0000000..cbe33e8 --- /dev/null +++ b/contrib/dom/scripts/CodeGeneratorArabicaV8.pm.new @@ -0,0 +1,1018 @@ +# Copyright (C) 2005, 2006 Nikolas Zimmermann <zimmermann@kde.org> +# Copyright (C) 2006 Anders Carlsson <andersca@mac.com> +# Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com> +# Copyright (C) 2006 Alexey Proskuryakov <ap@webkit.org> +# Copyright (C) 2006 Apple Computer, Inc. +# Copyright (C) 2007, 2008, 2009, 2012 Google Inc. +# Copyright (C) 2009 Cameron McCormack <cam@mcc.id.au> +# Copyright (C) Research In Motion Limited 2010. All rights reserved. +# Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) +# Copyright (C) 2012 Ericsson AB. All rights reserved. +# Copyright (C) 2013 Stefan Radomski <radomski@tk.informatik.tu-darmstadt.de> +# +# 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 COPYING.LIB. If not, write to +# the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# + +package CodeGeneratorArabicaV8; + +use strict; +use Data::Dumper; +use Carp qw/longmess cluck confess/; + +use constant FileNamePrefix => "V8"; + +my $codeGenerator; + + +my @headerContent = (); +my @implContentHeader = (); +my @implContent = (); +my @implContentDecls = (); +my %implIncludes = (); +my %headerIncludes = (); + +# Default .h template +my $headerTemplate = << 'EOF'; +/** + * @file + * @author This file has been generated by generate-bindings.pl. DO NOT MODIFY! + * @copyright Simplified BSD + * + * @cond + * This program is free software: you can redistribute it and/or modify + * it under the terms of the FreeBSD license as published by the FreeBSD + * project. + * + * This program 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. + * + * You should have received a copy of the FreeBSD license along with this + * program. If not, see <http://www.opensource.org/licenses/bsd-license>. + * @endcond + */ + +EOF + +# Default constructor +sub new +{ + my $object = shift; + my $reference = { }; + + $codeGenerator = shift; + + bless($reference, $object); + return $reference; +} + +sub GenerateInterface +{ + my $object = shift; + my $interface = shift; + +# print Dumper($interface); + + # Start actual generation + if ($interface->extendedAttributes->{"Callback"}) { + die(); + $object->GenerateCallbackHeader($interface); + $object->GenerateCallbackImplementation($interface); + } else { + $object->GenerateHeader($interface); + $object->GenerateImplementation($interface); + } +} + +sub AddToImplIncludes +{ + my $header = shift; + my $conditional = shift; + + if ($header eq "V8bool.h") { + confess(); + } + + if (not $conditional) { + $implIncludes{$header} = 1; + } elsif (not exists($implIncludes{$header})) { + $implIncludes{$header} = $conditional; + } else { + my $oldValue = $implIncludes{$header}; + if ($oldValue ne 1) { + my %newValue = (); + $newValue{$conditional} = 1; + foreach my $condition (split(/\|/, $oldValue)) { + $newValue{$condition} = 1; + } + $implIncludes{$header} = join("|", sort keys %newValue); + } + } +} + +sub GenerateHeader +{ + my $object = shift; + my $interface = shift; + my $interfaceName = $interface->name; + my $extensions = $interface->extendedAttributes; +# print Dumper($extensions); + + # Copy contents of parent interfaces except the first parent. + my @parents; + $codeGenerator->AddMethodsConstantsAndAttributesFromParentInterfaces($interface, \@parents, 1); + $codeGenerator->LinkOverloadedFunctions($interface); + + # - Add default header template + push(@headerContent, GenerateHeaderContentHeader($interface)); + + $headerIncludes{"string"} = 1; + $headerIncludes{"uscxml/plugins/datamodel/ecmascript/v8/V8DOM.h"} = 1; + $headerIncludes{"DOM/Node.hpp"} = 1; + $headerIncludes{"v8.h"} = 1; + + if ($interfaceName =~ /.*Array$/ or $interfaceName =~ /^ArrayBuffer.*/) { + $headerIncludes{"../../TypedArray.h"} = 1; + } + + foreach (@{$interface->parents}) { + my $parent = $_; + $headerIncludes{"V8${parent}.h"} = 1; + } + + push(@headerContent, "#include \<string\>\n"); + foreach my $headerInclude (sort keys(%headerIncludes)) { + if ($headerInclude =~ /wtf|v8\.h/) { + push(@headerContent, "#include \<${headerInclude}\>\n"); + } else { + push(@headerContent, "#include \"${headerInclude}\"\n"); + } + } + + push(@headerContent, ""); + push(@headerContent, "\nnamespace Arabica {"); + push(@headerContent, "\nnamespace DOM {\n"); + + push(@headerContent, "\nclass V8${interfaceName} {"); + push(@headerContent, "\npublic:"); + + my $wrapperType = IdlToWrapperType($interfaceName); + push(@headerContent, <<END); + + struct V8${interfaceName}Private { + V8DOM* dom; + ${wrapperType}* nativeObj; + }; +END + + if ($extensions->{'DontDestroyWrapped'}) { + push(@headerContent, "\n V8_DESTRUCTOR_KEEP_WRAPPED(V8${interfaceName}Private);"); + } else { + push(@headerContent, "\n V8_DESTRUCTOR(V8${interfaceName}Private);"); + } + push(@headerContent, "\n static bool hasInstance(v8::Handle<v8::Value>);"); + push(@headerContent, "\n"); + + # callbacks for actual functions + my %generated; + foreach my $function (@{$interface->functions}) { + my $name = $function->signature->name; + my $attrExt = $function->signature->extendedAttributes; + my $custom = ($attrExt->{'Custom'} ? "Custom" : ""); + next if (exists $generated{"${name}${custom}Callback"}); + push(@headerContent, "\n static void ${name}${custom}Callback(const v8::FunctionCallbackInfo<v8::Value>&);"); + $generated{"${name}${custom}Callback"} = 1; + } + push(@headerContent, "\n"); + + # attribute getter and setters + foreach my $attribute (@{$interface->attributes}) { + my $name = $attribute->signature->name; + my $attrExt = $attribute->signature->extendedAttributes; + my $customGetter = ($attrExt->{'CustomGetter'} ? "Custom" : ""); + my $customSetter = ($attrExt->{'CustomSetter'} ? "Custom" : ""); + push(@headerContent, "\n static void ${name}${customGetter}AttrGetter(v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value>& info);"); + if (!IsReadonly($attribute)) { + push(@headerContent, "\n static void ${name}${customSetter}AttrSetter(v8::Local<v8::String> property, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<void>& info);"); + } + } + + if ($extensions->{'CustomIndexedGetter'}) { + push(@headerContent, "\n static void indexedPropertyCustomGetter(uint32_t, const v8::AccessorInfo&);"); + } + if ($extensions->{'CustomIndexedSetter'}) { + push(@headerContent, "\n static void indexedPropertyCustomSetter(uint32_t, v8::Local<v8::Value>, const v8::AccessorInfo&);"); + } + push(@headerContent, "\n"); + + GenerateClassPrototypeHeader($interface); + + push(@headerContent, "\n};\n\n}\n}\n\n"); + push(@headerContent, "#endif // V8${interfaceName}" . "_h\n"); + +} + +# +# Write class template prototype constructor +# +sub GenerateClassPrototypeHeader +{ + my $interface = shift; + my $interfaceName = $interface->name; + my $extensions = $interface->extendedAttributes; + + if ($extensions->{'Constructors'}) { + + push(@headerContent, "\n"); + push(@headerContent, " static void constructor(const v8::FunctionCallbackInfo<v8::Value>&);\n"); + push(@headerContent, <<END); + static v8::Handle<v8::FunctionTemplate> getConstructor(v8::Isolate* isolate) { + return v8::FunctionTemplate::New(isolate, constructor); + } +END + } + + push(@headerContent, <<END); + static v8::Handle<v8::FunctionTemplate> getTmpl(v8::Isolate* isolate) { + v8::Handle<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(); + tmpl->SetClassName(v8::String::NewFromUtf8(isolate, "${interfaceName}")); + tmpl->ReadOnlyPrototype(); + + v8::Local<v8::ObjectTemplate> instance = tmpl->InstanceTemplate(); + v8::Local<v8::ObjectTemplate> prototype = tmpl->PrototypeTemplate(); + (void)prototype; // surpress unused warnings + + instance->SetInternalFieldCount(1); +END + + push(@headerContent, "\n"); + foreach my $attribute (@{$interface->attributes}) { + my $name = $attribute->signature->name; + my $attrExt = $attribute->signature->extendedAttributes; + my $customGetter = ($attrExt->{'CustomGetter'} ? "Custom" : ""); + my $customSetter = ($attrExt->{'CustomSetter'} ? "Custom" : ""); + my $getter = "V8${interfaceName}::${name}${customGetter}AttrGetter"; + my $setter = (IsReadonly($attribute) ? "0" : "V8${interfaceName}::${name}${customSetter}AttrSetter"); + push(@headerContent, <<END); + instance->SetAccessor(v8::String::NewFromUtf8(isolate, "${name}"), ${getter}, ${setter}, + v8::External::New(isolate, 0), static_cast<v8::AccessControl>(v8::DEFAULT), static_cast<v8::PropertyAttribute>(v8::None)); +END + } + + if ($extensions->{'CustomIndexedGetter'} || $extensions->{'CustomIndexedSetter'}) { + my $indexedGetter = ($extensions->{'CustomIndexedGetter'} ? "V8${interfaceName}::indexedPropertyCustomGetter" : 0); + my $indexedSetter = ($extensions->{'CustomIndexedSetter'} ? "V8${interfaceName}::indexedPropertyCustomSetter" : 0); + push(@headerContent, "\n instance->SetIndexedPropertyHandler(${indexedGetter}, ${indexedSetter});"); + } + + push(@headerContent, "\n"); + my %generated; + foreach my $function (@{$interface->functions}) { + my $name = $function->signature->name; + my $attrExt = $function->signature->extendedAttributes; + my $custom = ($attrExt->{'Custom'} ? "Custom" : ""); + next if (exists $generated{"${name}"}); + $generated{"${name}"} = 1; + push(@headerContent, <<END); + prototype->Set(v8::String::NewFromUtf8(isolate, "${name}"), + v8::FunctionTemplate::New(isolate, V8${interfaceName}::${name}${custom}Callback, v8::Undefined(isolate)), static_cast<v8::PropertyAttribute>(v8::DontDelete)); +END + } + + push(@headerContent, "\n"); + foreach my $constant (@{$interface->constants}) { + my $name = $constant->name; + my $value = $constant->value; + my $type = IdlToV8Type($constant->type); + push(@headerContent, <<END); + tmpl->Set(v8::String::NewFromUtf8(isolate, "${name}"), ${type}::New(${value}), static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontEnum)); + prototype->Set(v8::String::NewFromUtf8(isolate, "${name}"), ${type}::New(${value}), static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontEnum)); +END + } + + push(@headerContent, "\n"); + if (@{$interface->parents}) { + my $parent = @{$interface->parents}[0]; + push(@headerContent, " tmpl->Inherit(V8${parent}::getTmpl());\n"); + } + push(@headerContent, <<END); + return tmpl; + } + +END + +} + +sub GenerateImplementationAttributes +{ + my $interface = shift; + my $interfaceName = $interface->name; + my $extensions = $interface->extendedAttributes; + + # Generate property accessors for attributes. + for (my $index = 0; $index < @{$interface->attributes}; $index++) { + my $attribute = @{$interface->attributes}[$index]; + my $attrType = $attribute->signature->type; + my $attrName = $attribute->signature->name; + my $attrExt = $attribute->signature->extendedAttributes; + + my $wrapperRetType = IdlToWrapperType($attrType); + my $wrapperType = IdlToWrapperType($interfaceName); + my $wrapperGetter; + + if ($attrExt->{'AttributeIsPublic'} || $extensions->{'AttributesArePublic'}) { + $wrapperGetter = $attrName; + } else { + $wrapperGetter = IdlToWrapperAttrGetter($interface, $attribute)."()"; + + } + + # getter + if (!$attrExt->{'CustomGetter'}) { + push(@implContent, <<END); + + void V8${interfaceName}::${attrName}AttrGetter(v8::Local<v8::String> property, const v8::PropertyCallbackInfo<v8::Value>& info) { + v8::Isolate* isolate = args.GetIsolate(); + v8::Local<v8::Object> self = info.Holder(); + struct V8${interfaceName}Private* privData = V8DOM::toClassPtr<V8${interfaceName}Private >(self->GetInternalField(0)); +END + if (IsWrapperType($attrType)) { + AddToImplIncludes("V8".$attrType.".h"); + push(@implContent, "\n ".GenerateConditionalUndefReturn($interface, $attribute, "privData->nativeObj->${wrapperGetter}")); + + push(@implContent, <<END); + + ${wrapperRetType}* arbaicaRet = new ${wrapperRetType}(privData->nativeObj->${wrapperGetter}); + + v8::Handle<v8::Function> arbaicaRetCtor = V8${attrType}::getTmpl(isolate)->GetFunction(); + v8::Persistent<v8::Object> arbaicaRetObj = v8::Persistent<v8::Object>::New(arbaicaRetCtor->NewInstance()); + + struct V8${attrType}::V8${attrType}Private* retPrivData = new V8${attrType}::V8${attrType}Private(); + retPrivData->dom = privData->dom; + retPrivData->nativeObj = arbaicaRet; + + arbaicaRetObj->SetInternalField(0, V8DOM::toExternal(retPrivData)); + arbaicaRetObj.MakeWeak(0, V8${attrType}::jsDestructor); + return arbaicaRetObj; +END + } else { + my $v8Type = IdlToV8Type($attrType); + if ($attrType eq "DOMString") { + if ($attrExt->{'EmptyAsNull'}) { + push(@implContent, "\n if (privData->nativeObj->${wrapperGetter}.length() == 0)"); + push(@implContent, "\n return v8::Undefined(isolate);"); + } + push(@implContent, "\n return ${v8Type}::New(privData->nativeObj->${wrapperGetter}.c_str());"); + } else { + push(@implContent, "\n return ${v8Type}::New(privData->nativeObj->${wrapperGetter});"); + } + } + push(@implContent, "\n }\n"); + } + + if (!$attrExt->{'CustomSetter'}) { + # setter + if (!IsReadonly($attribute)) { + my $wrapperSetter = IdlToWrapperAttrSetter($attrName); + push(@implContent, "\n void V8${interfaceName}::${attrName}AttrSetter(v8::Local<v8::String> property, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<v8::Value>& info) {"); + push(@implContent, "\n v8::Isolate* isolate = args.GetIsolate();"); + push(@implContent, "\n v8::Local<v8::Object> self = info.Holder();"); + push(@implContent, "\n struct V8${interfaceName}Private* privData = V8DOM::toClassPtr<V8${interfaceName}Private >(self->GetInternalField(0));"); + + my ($handle, $deref) = IdlToArgHandle($attribute->signature->type, "local".ucfirst($attribute->signature->name), "value", $interfaceName); + + push(@implContent, "\n $handle"); + push(@implContent, "\n privData->nativeObj->${wrapperSetter}(${deref});"); + push(@implContent, "\n }\n"); + + } + } + } +} + +sub GenerateConditionalUndefReturn +{ + my $interface = shift; + my $attribute = shift; + my $getterExpression = shift; + + return "" if ($attribute->signature->type eq "NamedNodeMap"); + return "" if ($attribute->signature->type eq "NodeList"); + return "if (!$getterExpression) return v8::Undefined(isolate);"; +} + +sub GenerateConstructor +{ + my $interface = shift; + my $interfaceName = $interface->name; + my $wrapperType = IdlToWrapperType($interfaceName); + my $extensions = $interface->extendedAttributes; + + if ($extensions->{'Constructors'}) { + + push(@implContent, "\n void V8${interfaceName}::constructor(const v8::FunctionCallbackInfo<v8::Value>& args) {"); + push(@implContent, <<END); + + v8::Isolate* isolate = args.GetIsolate(); + if (!args.IsConstructCall()) { + isolate->ThrowException(v8::String::NewFromUtf8(isolate, "Cannot call constructor as function")); + return; + } +END + + push(@implContent, "\n ".IdlToWrapperType($interfaceName)."* localInstance = NULL;"); + # dispatch the actual constructor + push(@implContent, "\n if (false) {\n}"); + my @variants; + foreach my $fullCons (@{$extensions->{'Constructors'}}) { + push (@variants, $fullCons); + + for (my $i = @{$fullCons}; $i > 0; $i--) { + my $variant = @{$fullCons}[$i]; + if ($variant->{'domSignature::isOptional'}) { + my $slice; + for (my $j = 0; $j < $i; $j++) { + push(@{$slice}, @{$fullCons}[$j]); + } + push (@variants, $slice); + } + } + + # sort to put most determinate signatures first + @variants = sort { + if (@{$b} != @{$a}) { + # more arguments are more determinant + @{$b} <=> @{$a}; + } else { + my @aWrap = grep(IsWrapperType($_->{'domSignature::type'}), @{$a}); + my @bWrap = grep(IsWrapperType($_->{'domSignature::type'}), @{$b}); + @bWrap <=> @aWrap; + } + } @variants; + } + foreach my $constructor (@variants) { + push(@implContent, " else if (args.Length() == " . @{$constructor}); + + for (my $i = 0; $i < @{$constructor}; $i++) { + my $type = $constructor->[$i]->{'domSignature::type'}; + AddToImplIncludes("V8".$type.".h") if (IsWrapperType($type)); + push(@implContent, " &&\n " . IdlToTypeChecker($type, "args[$i]")); + + } + push(@implContent, ") {\n"); + my $constructorArgs; + my $constructorSep = ""; + for (my $i = 0; $i < @{$constructor}; $i++) { + my $type = $constructor->[$i]->{'domSignature::type'}; + my $name = $constructor->[$i]->{'domSignature::name'}; + my ($handle, $deref) = IdlToArgHandle($type, "local".ucfirst($name), "args[$i]", $interfaceName); + $constructorArgs .= ${constructorSep}.${deref}; + $constructorSep = ", "; + push(@implContent, "\n $handle"); + + } + push(@implContent, "\n localInstance = new ".IdlToWrapperType($interfaceName)."(${constructorArgs});"); + push(@implContent, "\n\n }"); + } + push(@implContent, "\n"); + + push(@implContent, <<END); + if (!localInstance) { + throw V8Exception("Parameter mismatch while calling constructor for ${interfaceName}"); + } + + v8::Handle<v8::Function> retCtor = V8${interfaceName}::getTmpl(isolate)->GetFunction(); + v8::Persistent<v8::Object> retObj = v8::Persistent<v8::Object>::New(retCtor->NewInstance()); + + struct V8${interfaceName}::V8${interfaceName}Private* retPrivData = new V8${interfaceName}::V8${interfaceName}Private(); + retPrivData->nativeObj = localInstance; + + retObj->SetInternalField(0, V8DOM::toExternal(retPrivData)); + retObj.MakeWeak(0, V8${interfaceName}::jsDestructor); + + args.GetReturnValue().Set(retObj); + return; + } +END + } + +} + +sub GenerateImplementationFunctionCallbacks +{ + my $interface = shift; + my $interfaceName = $interface->name; + my $wrapperType = IdlToWrapperType($interfaceName); + my $extensions = $interface->extendedAttributes; + + + # Generate methods for functions. + my %generated; + foreach my $function (@{$interface->functions}) { + my $name = $function->signature->name; + my $attrExt = $function->signature->extendedAttributes; + my $retType = $function->signature->type; + my $wrapperRetType = IdlToWrapperType($retType); + + next if ($attrExt->{'Custom'}); + next if (exists $generated{"${name}Callback"}); + $generated{"${name}Callback"} = 1; + + # get all functions with this name + my @sameFunctions = grep($_->signature->name eq $name, @{$interface->functions}); + + # signature + push(@implContent, <<END); + + void V8${interfaceName}::${name}Callback(const v8::FunctionCallbackInfo<v8::Value>& args) { + v8::Isolate* isolate = args.GetIsolate(); +END + + # get this + push(@implContent, "\n v8::Local<v8::Object> self = args.Holder();"); + push(@implContent, "\n struct V8${interfaceName}Private* privData = V8DOM::toClassPtr<V8${interfaceName}Private >(self->GetInternalField(0));"); + + # establish all variants + my @variants; + foreach my $functionVar (@sameFunctions) { + push (@variants, $functionVar->parameters); + + for (my $i = @{$functionVar->parameters}; $i > 0; $i--) { + my $variant = @{$functionVar->parameters}[$i]; + if ($variant->{'domSignature::isOptional'}) { + my $slice; + for (my $j = 0; $j < $i; $j++) { + push(@{$slice}, @{$functionVar->parameters}[$j]); + } + push (@variants, $slice); + } + } + } + + # arguments to local handles + push(@implContent, "\n if (false) {"); + + # sort to put most determinate signatures first + @variants = sort { + if (@{$b} != @{$a}) { + # more arguments are more determinant + @{$b} <=> @{$a}; + } else { + my @aWrap = grep(IsWrapperType($_->{'domSignature::type'}), @{$a}); + my @bWrap = grep(IsWrapperType($_->{'domSignature::type'}), @{$b}); + @bWrap <=> @aWrap; + } + } @variants; + + foreach my $variant (@variants) { + my $parameterIndex = 0; + my @argList; + + push(@implContent, "\n } else if (args.Length() == " . @{$variant}); + for (my $i = 0; $i < @{$variant}; $i++) { + my $type = $variant->[$i]->{'domSignature::type'}; + push(@implContent, " &&\n " . IdlToTypeChecker($type, "args[$i]")); + } + push(@implContent, ")\n {"); + foreach my $parameter (@{$variant}) { + my $value = "args[$parameterIndex]"; + my $type = $parameter->type; + AddToImplIncludes("V8".$type.".h") if (IsWrapperType($type)); + + my ($handle, $deref) = IdlToArgHandle($parameter->type, "local".ucfirst($parameter->name), "args[${parameterIndex}]", $interfaceName); + push(@implContent, "\n ${handle}"); + push(@argList, $deref); + $parameterIndex++; + } + + # invoke native function with argument handles + my $retNativeType = IdlToNativeType($retType); + my $wrapperFunctionName = IdlToWrapperFunction($interface, $function); + if (IsWrapperType($retType)) { + push(@implContent, "\n\n ${retNativeType}* retVal = new $wrapperRetType(privData->nativeObj->${wrapperFunctionName}(" . join(", ", @argList) . "));\n"); + } elsif ($retNativeType eq "void") { + push(@implContent, "\n\n privData->nativeObj->${wrapperFunctionName}(" . join(", ", @argList) . ");\n"); + } else { + push(@implContent, "\n\n ${retNativeType} retVal = privData->nativeObj->${wrapperFunctionName}(" . join(", ", @argList) . ");\n"); + } + + # wrap return type if needed + if (IsWrapperType($retType)) { + AddToImplIncludes("V8".$retType.".h"); + + push(@implContent, <<END); + v8::Handle<v8::Function> retCtor = V8${retType}::getTmpl(isolate)->GetFunction(); + v8::Persistent<v8::Object> retObj = v8::Persistent<v8::Object>::New(retCtor->NewInstance()); + + struct V8${retType}::V8${retType}Private* retPrivData = new V8${retType}::V8${retType}Private(); + retPrivData->dom = privData->dom; + retPrivData->nativeObj = retVal; + + retObj->SetInternalField(0, V8DOM::toExternal(retPrivData)); + + retObj.MakeWeak(0, V8${retType}::jsDestructor); + return retObj; +END + } else { + my $toHandleString = NativeToHandle($retNativeType, "retVal"); + push(@implContent, "\n return ${toHandleString};"); + } + } + push(@implContent, <<END); + + } + throw V8Exception("Parameter mismatch while calling ${name}"); + return v8::Undefined(isolate); + } +END + } + +} + +sub GenerateImplementation +{ + my $object = shift; + my $interface = shift; + my $interfaceName = $interface->name; + my $visibleInterfaceName = $codeGenerator->GetVisibleInterfaceName($interface); + my $v8InterfaceName = "V8$interfaceName"; + my $wrapperType = IdlToWrapperType($interfaceName); + my $extensions = $interface->extendedAttributes; + + AddToImplIncludes("V8${interfaceName}.h"); + + # Find the super descriptor. + my $parentClass = ""; + my $parentClassTemplate = ""; + foreach (@{$interface->parents}) { + my $parent = $_; + AddToImplIncludes("V8${parent}.h"); + $parentClass = "V8" . $parent; + last; + } + + push(@implContent, "namespace Arabica {\n"); + push(@implContent, "namespace DOM {\n\n"); + + if ($extensions->{'Constructors'}) { + GenerateConstructor($interface); + } + + GenerateImplementationAttributes($interface); + GenerateImplementationFunctionCallbacks($interface); + + + push(@implContent, <<END); + bool V8${interfaceName}::hasInstance(v8::Handle<v8::Value> value) { + return getTmpl()->HasInstance(value); + } + +} +} +END + + # We've already added the header for this file in implContentHeader, so remove + # it from implIncludes to ensure we don't #include it twice. +# delete $implIncludes{"${v8InterfaceName}.h"}; +} + +sub WriteData +{ + my $object = shift; + my $interface = shift; + my $outputDir = shift; + my $outputHeadersDir = shift; + + my $name = $interface->name; + my $prefix = FileNamePrefix; + my $headerFileName = "$outputHeadersDir/$prefix$name.h"; + my $implFileName = "$outputDir/$prefix$name.cpp"; + + # print "WriteData\n"; + # print Dumper($interface); + # exit(); + + # Update a .cpp file if the contents are changed. + my $contents = $headerTemplate; + $contents .= join "", @implContentHeader; + + my @includes = (); + my %implIncludeConditions = (); + foreach my $include (keys %implIncludes) { + my $condition = $implIncludes{$include}; + my $checkType = $include; + $checkType =~ s/\.h//; + next if $codeGenerator->IsSVGAnimatedType($checkType); + + if ($include =~ /wtf/) { + $include = "\<$include\>"; + } else { + $include = "\"$include\""; + } + + if ($condition eq 1) { + push @includes, $include; + } else { + push @{$implIncludeConditions{$condition}}, $include; + } + } + foreach my $include (sort @includes) { + $contents .= "#include $include\n"; + } + foreach my $condition (sort keys %implIncludeConditions) { + $contents .= "\n#if " . $codeGenerator->GenerateConditionalStringFromAttributeValue($condition) . "\n"; + foreach my $include (sort @{$implIncludeConditions{$condition}}) { + $contents .= "#include $include\n"; + } + $contents .= "#endif\n"; + } + + $contents .= "\n"; + $contents .= join "", @implContentDecls, @implContent; + $codeGenerator->UpdateFile($implFileName, $contents); + + %implIncludes = (); + @implContentHeader = (); + @implContentDecls = (); + @implContent = (); + + # Update a .h file if the contents are changed. + $contents = join "", @headerContent; + $codeGenerator->UpdateFile($headerFileName, $contents); + + @headerContent = (); +} + +sub IdlToV8Type +{ + my $idlType = shift; + return "v8::Integer" if ($idlType eq "unsigned short"); + return "v8::Integer" if ($idlType eq "short"); + return "v8::Integer" if ($idlType eq "unsigned long"); + return "v8::Integer" if ($idlType eq "long"); + return "v8::String" if ($idlType eq "DOMString"); + return "v8::Boolean" if ($idlType eq "boolean"); + return "v8::Number" if ($idlType eq "double"); + die($idlType); +} + +sub IdlToNativeType +{ + my $idlType = shift; + + return IdlToWrapperType($idlType) if (IsWrapperType($idlType)); + + return "std::string" if ($idlType eq "DOMString"); + return "bool" if ($idlType eq "boolean"); + return "short" if ($idlType eq "short"); + return "long" if ($idlType eq "long"); + return "unsigned short" if ($idlType eq "unsigned short"); + return "unsigned long" if ($idlType eq "unsigned long"); + return "void" if ($idlType eq "void"); + return "char" if ($idlType eq "byte"); + return "unsigned char" if ($idlType eq "octet"); + return "double" if ($idlType eq "double"); + return "float" if ($idlType eq "float"); + die(${idlType}); +} + +sub NativeToHandle +{ + my $nativeType = shift; + my $nativeName = shift; + + return ("v8::Boolean::New(${nativeName})") if ($nativeType eq "bool"); + return ("v8::Number::New(${nativeName})") if ($nativeType eq "double"); + return ("v8::Number::New(${nativeName})") if ($nativeType eq "double"); + return ("v8::Number::New(${nativeName})") if ($nativeType eq "float"); + return ("v8::Number::New(${nativeName})") if ($nativeType eq "short"); + return ("v8::Number::New(${nativeName})") if ($nativeType eq "char"); + return ("v8::Number::New(${nativeName})") if ($nativeType eq "unsigned short"); + return ("v8::Number::New(${nativeName})") if ($nativeType eq "unsigned long"); + return ("v8::Number::New(${nativeName})") if ($nativeType eq "unsigned char"); + return ("v8::Number::New(${nativeName})") if ($nativeType eq "long"); + return ("v8::String::NewFromUtf8(isolate, ${nativeName}.c_str())") if ($nativeType eq "std::string"); + return ("v8::Undefined(isolate)") if ($nativeType eq "void"); + + die($nativeType); +} + +sub IdlToWrapperType +{ + my $idlType = shift; + return "Arabica::XPath::XPathValue<std::string>" if ($idlType eq "XPathResult"); + return "Arabica::XPath::NodeSet<std::string>" if ($idlType eq "NodeSet"); + return "Arabica::DOM::Node<std::string>" if ($idlType eq "Node"); + return "Arabica::DOM::Element<std::string>" if ($idlType eq "Element"); + return "uscxml::Event" if ($idlType eq "SCXMLEvent"); + return "uscxml::Storage" if ($idlType eq "Storage"); + return "uscxml::ArrayBuffer" if ($idlType eq "ArrayBuffer"); + return "uscxml::ArrayBufferView" if ($idlType eq "ArrayBufferView"); + return "uscxml::Int8Array" if ($idlType eq "Int8Array"); + return "uscxml::Uint8Array" if ($idlType eq "Uint8Array"); + return "uscxml::Uint8ClampedArray" if ($idlType eq "Uint8ClampedArray"); + return "uscxml::Int16Array" if ($idlType eq "Int16Array"); + return "uscxml::Uint16Array" if ($idlType eq "Uint16Array"); + return "uscxml::Int32Array" if ($idlType eq "Int32Array"); + return "uscxml::Uint32Array" if ($idlType eq "Uint32Array"); + return "uscxml::Float32Array" if ($idlType eq "Float32Array"); + return "uscxml::Float64Array" if ($idlType eq "Float64Array"); + return "uscxml::DataView" if ($idlType eq "DataView"); + return "Arabica::DOM::${idlType}<std::string>"; +} + +sub IdlToArgHandle +{ + my $type = shift; + my $localName = shift; + my $paramName = shift; + my $thisType = shift; + + return ("v8::String::AsciiValue ${localName}(${paramName});", "*${localName}") if ($type eq "DOMString"); + return ("unsigned long ${localName} = ${paramName}->ToNumber()->Uint32Value();", ${localName}) if ($type eq "unsigned long"); + return ("long ${localName} = ${paramName}->ToNumber()->Int32Value();", ${localName}) if ($type eq "long"); + return ("double ${localName} = ${paramName}->ToNumber()->Value();", ${localName}) if ($type eq "double"); + return ("float ${localName} = ${paramName}->ToNumber()->Value();", ${localName}) if ($type eq "float"); + return ("unsigned short ${localName} = ${paramName}->ToNumber()->Uint32Value();", ${localName}) if ($type eq "unsigned short"); + return ("bool ${localName} = ${paramName}->ToBoolean()->BooleanValue();", ${localName}) if ($type eq "boolean"); + return ("char ${localName} = ${paramName}->ToNumber()->Int32Value();", ${localName}) if ($type eq "byte"); + return ("short ${localName} = ${paramName}->ToNumber()->Int32Value();", ${localName}) if ($type eq "short"); + return ("unsigned char ${localName} = ${paramName}->ToNumber()->Uint32Value();", ${localName}) if ($type eq "octet"); + return ("void* ${localName} = v8::External::Unwrap(${paramName}->ToObject()->GetInternalField(0));", ${localName}) if ($type eq "any"); + return ("std::vector<long> ${localName};\nv8::Handle<v8::Array> ${localName}Array(v8::Array::Cast(*args[0]));\nfor (int i = 0; i < ${localName}Array->Length(); i++) {\n ${localName}.push_back(${localName}Array->Get(i)->ToInteger()->Value());\n}", "${localName}") if ($type eq "long[]"); + return ("std::vector<float> ${localName};\nv8::Handle<v8::Array> ${localName}Array(v8::Array::Cast(*args[0]));\nfor (int i = 0; i < ${localName}Array->Length(); i++) {\n ${localName}.push_back(${localName}Array->Get(i)->ToNumber()->Value());\n}", "${localName}") if ($type eq "float[]"); + return ("std::vector<double> ${localName};\nv8::Handle<v8::Array> ${localName}Array(v8::Array::Cast(*args[0]));\nfor (int i = 0; i < ${localName}Array->Length(); i++) {\n ${localName}.push_back(${localName}Array->Get(i)->ToNumber()->Value());\n}", "${localName}") if ($type eq "double[]"); + return ("std::vector<char> ${localName};\nv8::Handle<v8::Array> ${localName}Array(v8::Array::Cast(*args[0]));\nfor (int i = 0; i < ${localName}Array->Length(); i++) {\n ${localName}.push_back(${localName}Array->Get(i)->ToInt32()->Value());\n}", "${localName}") if ($type eq "byte[]"); + return ("std::vector<short> ${localName};\nv8::Handle<v8::Array> ${localName}Array(v8::Array::Cast(*args[0]));\nfor (int i = 0; i < ${localName}Array->Length(); i++) {\n ${localName}.push_back(${localName}Array->Get(i)->ToInt32()->Value());\n}", "${localName}") if ($type eq "short[]"); + return ("std::vector<unsigned short> ${localName};\nv8::Handle<v8::Array> ${localName}Array(v8::Array::Cast(*args[0]));\nfor (int i = 0; i < ${localName}Array->Length(); i++) {\n ${localName}.push_back(${localName}Array->Get(i)->ToUint32()->Value());\n}", "${localName}") if ($type eq "unsigned short[]"); + return ("std::vector<unsigned long> ${localName};\nv8::Handle<v8::Array> ${localName}Array(v8::Array::Cast(*args[0]));\nfor (int i = 0; i < ${localName}Array->Length(); i++) {\n ${localName}.push_back(${localName}Array->Get(i)->ToUint32()->Value());\n}", "${localName}") if ($type eq "unsigned long[]"); + return ("std::vector<unsigned char> ${localName};\nv8::Handle<v8::Array> ${localName}Array(v8::Array::Cast(*args[0]));\nfor (int i = 0; i < ${localName}Array->Length(); i++) {\n ${localName}.push_back(${localName}Array->Get(i)->ToUint32()->Value());\n}", "${localName}") if ($type eq "octet[]"); + + if (IsWrapperType($type)) { + my $wrapperType = IdlToWrapperType($type); + if ($type =~ /.*Array$/ or $type =~ /^ArrayBuffer.*/) { + return ("${wrapperType}* ${localName} = V8DOM::toClassPtr<V8${type}::V8${type}Private >(${paramName}->ToObject()->GetInternalField(0))->nativeObj;", "${localName}"); + } + + return ("${wrapperType}* ${localName} = V8DOM::toClassPtr<V8${type}::V8${type}Private >(${paramName}->ToObject()->GetInternalField(0))->nativeObj;", "*${localName}"); + } + + print $type."\n"; + die(); +} + +sub IdlToTypeChecker +{ + my $idlType = shift; + my $attr = shift; + + return $attr."->IsString()" if ($idlType eq "DOMString"); + return $attr."->IsBoolean()" if ($idlType eq "boolean"); + return $attr."->IsInt32()" if ($idlType eq "short"); + return $attr."->IsInt32()" if ($idlType eq "long"); + return $attr."->IsArray()" if ($idlType eq "long[]"); + return $attr."->IsUint32()" if ($idlType eq "unsigned short"); + return $attr."->IsUint32()" if ($idlType eq "unsigned long"); + return $attr."->IsInt32()" if ($idlType eq "byte"); + return $attr."->IsUint32()" if ($idlType eq "octet"); + return $attr."->IsNumber()" if ($idlType eq "double"); + return $attr."->IsArray()" if ($idlType eq "double[]"); + return $attr."->IsNumber()" if ($idlType eq "float"); + return $attr."->IsArray()" if ($idlType eq "float[]"); + return $attr."->IsArray()" if ($idlType eq "short[]"); + return $attr."->IsArray()" if ($idlType eq "unsigned short[]"); + return $attr."->IsArray()" if ($idlType eq "unsigned long[]"); + return $attr."->IsArray()" if ($idlType eq "byte[]"); + return $attr."->IsArray()" if ($idlType eq "octet[]"); + return "true" if ($idlType eq "any"); + + return $attr."->IsObject() && V8".$idlType."::hasInstance(".$attr.")" if (IsWrapperType($idlType)); + + print $idlType."\n"; + die(); + +} + +sub IdlToWrapperAttrGetter +{ + my $interface = shift; + my $attribute = shift; + + return $attribute->signature->name if ($interface->name eq "NodeSet" && $attribute->signature->name eq "size"); + return $attribute->signature->name if ($interface->name eq "NodeSet" && $attribute->signature->name eq "empty"); + return "asString" if ($interface->name eq "XPathResult" && $attribute->signature->name eq "stringValue"); + return "asBool" if ($interface->name eq "XPathResult" && $attribute->signature->name eq "booleanValue"); + return "asNumber" if ($interface->name eq "XPathResult" && $attribute->signature->name eq "numberValue"); + + return "get" . ucfirst($attribute->signature->name); +} + +sub IdlToWrapperFunction +{ + my $interface = shift; + my $function = shift; + + # if ($interface->name eq "NodeSet" && $function->signature->name eq "toDocumentOrder") { + # print Dumper($interface); + # print Dumper($function); + # } + + return "to_document_order" if ($interface->name eq "NodeSet" && $function->signature->name eq "toDocumentOrder"); + + return $function->signature->name; + +} + +sub IdlToWrapperAttrSetter +{ + my $idlAttr = shift; + return "set" . ucfirst($idlAttr); +} + + +sub IsReadonly +{ + my $attribute = shift; + my $attrExt = $attribute->signature->extendedAttributes; + return ($attribute->type =~ /readonly/ || $attrExt->{"V8ReadOnly"}) && !$attrExt->{"Replaceable"}; +} + + +my %non_wrapper_types = ( + 'CompareHow' => 1, + 'DOMObject' => 1, + 'DOMString' => 1, + 'DOMString[]' => 1, + 'DOMTimeStamp' => 1, + 'Date' => 1, + 'Dictionary' => 1, + 'EventListener' => 1, + # FIXME: When EventTarget is an interface and not a mixin, fix this so that + # EventTarget is treated as a wrapper type. + 'EventTarget' => 1, + 'IDBKey' => 1, + 'JSObject' => 1, + 'MediaQueryListListener' => 1, + 'NodeFilter' => 1, + 'any' => 1, + 'boolean' => 1, + 'double' => 1, + 'float' => 1, + 'int' => 1, + 'long long' => 1, + 'long' => 1, + 'long[]' => 1, + 'short' => 1, + 'short[]' => 1, + 'void' => 1, + 'byte' => 1, + 'byte[]' => 1, + 'octet' => 1, + 'char' => 1, + 'float[]' => 1, + 'float' => 1, + 'double[]' => 1, + 'octet[]' => 1, + 'double' => 1, + 'unsigned int' => 1, + 'unsigned long long' => 1, + 'unsigned long' => 1, + 'unsigned long[]' => 1, + 'unsigned short' => 1, + 'unsigned short[]' => 1 +); + +sub IsWrapperType +{ + my $type = shift; + return !($non_wrapper_types{$type}); +} + +sub GenerateHeaderContentHeader +{ + my $interface = shift; + my $v8InterfaceName = "V8" . $interface->name; + my $conditionalString = $codeGenerator->GenerateConditionalString($interface); + + my @headerContentHeader = split("\r", $headerTemplate); + + push(@headerContentHeader, "\n#if ${conditionalString}\n") if $conditionalString; + push(@headerContentHeader, "\n#ifndef ${v8InterfaceName}" . "_h"); + push(@headerContentHeader, "\n#define ${v8InterfaceName}" . "_h\n\n"); + return @headerContentHeader; +} + +1; diff --git a/contrib/local/compress_and_upload_deps.sh b/contrib/local/compress_and_upload_deps.sh index 90a398d..6fcffde 100755 --- a/contrib/local/compress_and_upload_deps.sh +++ b/contrib/local/compress_and_upload_deps.sh @@ -32,6 +32,7 @@ ssh ${USCXML_PREBUILT_HOST} mkdir -p ${USCXML_PREBUILT_PATH}/${VERSION} PLATFORMS=`find . -maxdepth 1 -type d -regex ./[^\.].*` #PLATFORMS="linux-x86_64" +PLATFORMS="darwin-i386" for FILE in ${PLATFORMS}; do PLATFORM=`basename $FILE` echo $FILE diff --git a/contrib/src/evws/evws.c b/contrib/src/evws/evws.c index b39bc03..5dbd8e9 100644 --- a/contrib/src/evws/evws.c +++ b/contrib/src/evws/evws.c @@ -66,11 +66,11 @@ struct evws *evws_new(struct event_base *base) { ret_obj->base = base; ret_obj->listener = NULL; - ret_obj->connections.tqh_first = NULL; - ret_obj->connections.tqh_last = &(ret_obj->connections.tqh_first); - - ret_obj->callbacks.tqh_first = NULL; - ret_obj->callbacks.tqh_last = &(ret_obj->callbacks.tqh_first); + (&ret_obj->connections)->tqh_first = NULL; + (&ret_obj->connections)->tqh_last = &((&ret_obj->connections)->tqh_first); + + (&ret_obj->callbacks)->tqh_first = NULL; + (&ret_obj->callbacks)->tqh_last = &((&ret_obj->callbacks)->tqh_first); return ret_obj; } @@ -89,16 +89,22 @@ evutil_socket_t evws_bind_socket(struct evws * ws, unsigned short port) { sin.sin_addr.s_addr = htonl(0); sin.sin_port = htons(port); - if(!(ws->listener = evconnlistener_new_bind(ws->base, cb_accept, ws, LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE|LEV_OPT_THREADSAFE, -1, (struct sockaddr*)&sin, sizeof(sin)))) { + if(!(ws->listener = evconnlistener_new_bind(ws->base, + cb_accept, + ws, + LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE|LEV_OPT_THREADSAFE, + -1, + (struct sockaddr*)&sin, sizeof(sin))) + ) { return 0; } return evconnlistener_get_fd(ws->listener); } int evws_set_cb(struct evws * ws, const char * uri, cb_frame_type message_cb, cb_type connect_cb, void * arg) { - struct evws_cb *ws_cb; + struct evws_cb *ws_cb = NULL; - for (ws_cb = ws->callbacks.tqh_first; ws_cb; ws_cb = ws_cb->next.tqe_next) { + for (ws_cb = (&ws->callbacks)->tqh_first; ws_cb; ws_cb = ws_cb->next.tqe_next) { if (strcmp(ws_cb->uri, uri) == 0) return (-1); } @@ -114,9 +120,9 @@ int evws_set_cb(struct evws * ws, const char * uri, cb_frame_type message_cb, cb // TAILQ_INSERT_TAIL ws_cb->next.tqe_next = NULL; - ws_cb->next.tqe_prev = ws->callbacks.tqh_last; - ws->callbacks.tqh_last = &ws_cb; - ws->callbacks.tqh_last = &ws_cb->next.tqe_next; + ws_cb->next.tqe_prev = (&ws->callbacks)->tqh_last; + *(&ws->callbacks)->tqh_last = ws_cb; + (&ws->callbacks)->tqh_last = &(ws_cb->next.tqe_next); return (0); } @@ -131,7 +137,7 @@ cb_frame_type evws_set_gencb(struct evws *ws, cb_frame_type cb, void * arg) { // Broadcast data to all buffers associated with pattern void evws_broadcast(struct evws *ws, const char *uri, enum evws_opcode opcode, const char *data, uint64_t length) { struct evws_connection *ws_connection; - for (ws_connection = ws->connections.tqh_first; ws_connection; ws_connection = ws_connection->next.tqe_next) { + for ((ws_connection) = (&ws->connections)->tqh_first; ws_connection; ws_connection = ws_connection->next.tqe_next) { if (strcmp(ws_connection->uri, uri) == 0) evws_send_data(ws_connection, opcode, data, length); } @@ -140,15 +146,12 @@ void evws_broadcast(struct evws *ws, const char *uri, enum evws_opcode opcode, c // Error callback static void cb_error(struct bufferevent *bev, short what, void *ctx) { struct evws_connection *conn = ctx; - - //TAILQ_REMOVE - if (conn->next.tqe_next != NULL) + if (conn->next.tqe_next != NULL) { conn->next.tqe_next->next.tqe_prev = conn->next.tqe_prev; - else { - conn->ws->connections.tqh_last = conn->next.tqe_prev; + } else { + (&(conn->ws->connections))->tqh_last = conn->next.tqe_prev; } - conn->next.tqe_prev = &conn->next.tqe_next; - + *(conn)->next.tqe_prev = conn->next.tqe_next; evws_connection_free(conn); } @@ -224,11 +227,12 @@ void cb_read_handshake(struct bufferevent *bev, void *arg) { origin = strdup(svalue); } header = evws_header_new(skey, svalue); - //TAILQ_INSERT_TAIL + + // TAILQ_INSERT_TAIL header->next.tqe_next = NULL; - header->next.tqe_prev = ws_conn->headers.tqh_last; - ws_conn->headers.tqh_last = &header; - ws_conn->headers.tqh_last = &header->next.tqe_next; + header->next.tqe_prev = (&ws_conn->headers)->tqh_last; + *(&ws_conn->headers)->tqh_last = header; + (&ws_conn->headers)->tqh_last = &(header->next.tqe_next); free(line); } @@ -236,6 +240,9 @@ void cb_read_handshake(struct bufferevent *bev, void *arg) { break; }; + if (key == NULL) + return; + // -- SHA1 SHA1Reset(&sha1); @@ -280,24 +287,24 @@ void cb_read_handshake(struct bufferevent *bev, void *arg) { "\r\n", chksumBase64 ); - bufferevent_setcb(ws_conn->bufev, cb_read_frame, NULL, cb_error, ws_conn); - - //TAILQ_INSERT_TAIL(&(ws_conn->ws->connections), ws_conn, next); + bufferevent_setcb(ws_conn->bufev, cb_read_frame, ((void*)0), cb_error, ws_conn); + ws_conn->next.tqe_next = NULL; - ws_conn->next.tqe_prev = ws_conn->ws->connections.tqh_last; - ws_conn->ws->connections.tqh_last = &ws_conn; - ws_conn->ws->connections.tqh_last = &ws_conn->next.tqe_next; + ws_conn->next.tqe_prev = (&(ws_conn->ws->connections))->tqh_last; + *(&(ws_conn->ws->connections))->tqh_last = ws_conn; + (&(ws_conn->ws->connections))->tqh_last = &(ws_conn->next.tqe_next); { struct evws_cb *ws_cb; - for (ws_cb = ws_conn->ws->callbacks.tqh_first; ws_cb; ws_cb = ws_cb->next.tqe_next) { + for (ws_cb = ((&ws_conn->ws->callbacks))->tqh_first; ws_cb; ws_cb = ws_cb->next.tqe_next) { if (strcmp(ws_cb->uri, ws_conn->uri) == 0) { - if(ws_cb->conn_cb != NULL) - ws_cb->conn_cb(ws_conn, NULL, 0, ws_cb->cb_arg); + if(ws_cb->conn_cb != ((void*)0)) + ws_cb->conn_cb(ws_conn, ((void*)0), 0, ws_cb->cb_arg); return; } } } + } int evws_parse_header_line(char *line, char **skey, char **svalue) @@ -317,7 +324,7 @@ void cb_read_frame(struct bufferevent *bev, void *arg) { struct evws_connection *conn = arg; struct evws *ws = conn->ws; - char readbuf[1024]; + char readbuf[2048]; // make sure a MTU fits int size = 0; struct evbuffer *buffer = bufferevent_get_input(bev); while ((size = evbuffer_remove(buffer, readbuf, sizeof(readbuf))) > 0) { @@ -414,11 +421,12 @@ NEXT_FRAME: if (conn->frame->payload_read == conn->frame->size) { // done reading this frame - invoke callbacks struct evws_cb *ws_cb; - for (ws_cb = ws->callbacks.tqh_first; ws_cb; ws_cb = ws_cb->next.tqe_next) { + // TAILQ_FOREACH + for (ws_cb = ((&ws->callbacks))->tqh_first; ws_cb; ws_cb = (ws_cb->next.tqe_next)) { if (strcmp(ws_cb->uri, conn->uri) == 0) { - if(ws_cb->msg_cb != NULL) + if(ws_cb->msg_cb != ((void*)0)) ws_cb->msg_cb(conn, conn->frame, ws_cb->cb_arg); - continue; + return; } } ws->gencb(conn, conn->frame, ws->gencb_arg); @@ -484,27 +492,28 @@ struct evws_connection* evws_connection_new(struct evws *ws, evutil_socket_t fd) struct evws_connection* conn = calloc(1, sizeof(struct evws_connection)); conn->ws = ws; conn->fd = fd; - conn->uri = NULL; - + conn->uri = ((void*)0); + conn->bufev = bufferevent_socket_new(ws->base, fd, BEV_OPT_CLOSE_ON_FREE); conn->state = 0; - conn->frame = NULL; + conn->frame = ((void*)0); + + (&conn->headers)->tqh_first = NULL; + (&conn->headers)->tqh_last = &(((&conn->headers))->tqh_first); - conn->headers.tqh_first = NULL; - conn->headers.tqh_last = &(conn->headers.tqh_first); - return conn; } void evws_connection_free(struct evws_connection *conn) { struct evws_header *header; bufferevent_free(conn->bufev); - if(conn->uri != NULL) + if(conn->uri != ((void*)0)) free(conn->uri); - - for (header = conn->headers.tqh_first; header; header = header->next.tqe_next) { + + for (header = (&conn->headers)->tqh_first; header; header = header->next.tqe_next) { evws_header_free(header); } + free(conn); } @@ -530,19 +539,18 @@ struct evws_header *evws_header_new(char *key, char *value) void evws_header_free(struct evws_header *header) { if(header->key != NULL) free(header->key); - // @Note: segfault when freeing value, some strange value if(header->value != NULL) free(header->value); free(header); } char *evws_find_header(const struct wsheadersq *q, const char *key) { - struct evws_header *header; - char * ret = NULL; - for (header = q->tqh_first; header; header = header->next.tqe_next) { - - if(strcmp(header->key, key) == 0) { - ret = header->value; + struct evws_header *hdr; + char * ret = ((void*)0); + + for (hdr = q->tqh_first; hdr; hdr = hdr->next.tqe_next) { + if(strcmp(hdr->key, key) == 0) { + ret = hdr->value; break; } } diff --git a/docs/Ubuntu-LTS.md b/docs/Ubuntu-LTS.md index 4dbc0e2..df687ab 100644 --- a/docs/Ubuntu-LTS.md +++ b/docs/Ubuntu-LTS.md @@ -17,6 +17,10 @@ $ ./configure --disable-render-text-node --disable-script-node-javascript --disa $ sudo make install $ cd .. +for mavericks: +PNG_CFLAGS="-I/opt/local/include" PNG_LIBS="-L/opt/local/lib" XML_CFLAGS="-I`xcrun --show-sdk-path`/usr/include/libxml2" XML_LIBS="-L`xcrun --show-sdk-path`/usr/lib" CPPFLAGS="--sysroot=`xcrun --show-sdk-path` -I/opt/local/include -I`xcrun --show-sdk-path`/usr/include/libxml2" LDFLAGS="--sysroot=`xcrun --show-sdk-path` -L/opt/local/lib -lboost_system-mt -lxml2 -lpng" ./configure --disable-render-text-node --disable-script-node-javascript --disable-script-node-java --disable-gl-renderer --disable-xembed --disable-player --disable-examples --disable-mozilla-plugin + + $ sudo apt-get install git $ git clone https://github.com/openscenegraph/osg $ cd osg diff --git a/src/bindings/swig/php/uscxmlNativePHP.php b/src/bindings/swig/php/uscxmlNativePHP.php index d7bb3d0..3aba5be 100644 --- a/src/bindings/swig/php/uscxmlNativePHP.php +++ b/src/bindings/swig/php/uscxmlNativePHP.php @@ -2,12 +2,12 @@ /* ---------------------------------------------------------------------------- * This file was automatically generated by SWIG (http://www.swig.org). - * Version 2.0.9 - * - * This file is not intended to be easily readable and contains a number of + * Version 2.0.11 + * + * This file is not intended to be easily readable and contains a number of * coding conventions designed to improve portability and efficiency. Do not make - * changes to this file unless you know what you are doing--modify the SWIG - * interface file instead. + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. * ----------------------------------------------------------------------------- */ // Try to load our extension if it's not already loaded. @@ -1030,13 +1030,7 @@ class Interpreter { } static function tokenizeIdRefs($idRefs) { - $r=Interpreter_tokenizeIdRefs($idRefs); - if (is_resource($r)) { - $c=substr(get_resource_type($r), (strpos(get_resource_type($r), '__') ? strpos(get_resource_type($r), '__') + 2 : 3)); - if (class_exists($c)) return new $c($r); - return new StringVector($r); - } - return $r; + return Interpreter_tokenizeIdRefs($idRefs); } static function spaceNormalize($text) { diff --git a/src/uscxml/Convenience.h b/src/uscxml/Convenience.h index 9f4c1a1..0177476 100644 --- a/src/uscxml/Convenience.h +++ b/src/uscxml/Convenience.h @@ -49,7 +49,7 @@ inline bool isNumeric( const char* pszInput, int nNumberBase) { } inline bool iequals(const std::string& a, const std::string& b) { - // this impementation beats boost::iequals 2700ms vs 2100ms for test-performance.scxml + // this impementation beats boost::iequals 2700ms vs 2100ms for test-performance.scxml - we don't care for non-ascii yet unsigned int size = a.size(); if (b.size() != size) return false; @@ -59,6 +59,16 @@ inline bool iequals(const std::string& a, const std::string& b) { return true; } +inline bool equals(const std::string& a, const std::string& b) { + unsigned int size = a.size(); + if (b.size() != size) + return false; + for (unsigned int i = 0; i < size; ++i) + if (a[i] != b[i]) + return false; + return true; +} + // see http://www.cplusplus.com/forum/general/27544/ // Little-endian operating systems: diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp index 1314986..dfd9311 100644 --- a/src/uscxml/Interpreter.cpp +++ b/src/uscxml/Interpreter.cpp @@ -912,11 +912,11 @@ void InterpreterImpl::send(const Arabica::DOM::Node<std::string>& element) { // namelist if (HAS_ATTR(element, "namelist")) { if (_dataModel) { - std::vector<std::string> names = tokenizeIdRefs(ATTR(element, "namelist")); - for (int i = 0; i < names.size(); i++) { - Data namelistValue = _dataModel.getStringAsData(names[i]); - sendReq.namelist[names[i]] = namelistValue; - sendReq.data.compound[names[i]] = namelistValue; + std::list<std::string> names = tokenizeIdRefs(ATTR(element, "namelist")); + for (std::list<std::string>::const_iterator nameIter = names.begin(); nameIter != names.end(); nameIter++) { + Data namelistValue = _dataModel.getStringAsData(*nameIter); + sendReq.namelist[*nameIter] = namelistValue; + sendReq.data.compound[*nameIter] = namelistValue; } } else { LOG(ERROR) << "Namelist attribute at send requires datamodel to be defined"; @@ -1054,9 +1054,9 @@ void InterpreterImpl::invoke(const Arabica::DOM::Node<std::string>& element) { // namelist if (HAS_ATTR(element, "namelist")) { - std::vector<std::string> names = tokenizeIdRefs(ATTR(element, "namelist")); - for (int i = 0; i < names.size(); i++) { - invokeReq.namelist[names[i]] = _dataModel.evalAsString(names[i]); + std::list<std::string> names = tokenizeIdRefs(ATTR(element, "namelist")); + for (std::list<std::string>::const_iterator nameIter = names.begin(); nameIter != names.end(); nameIter++) { + invokeReq.namelist[*nameIter] = _dataModel.evalAsString(*nameIter); } } @@ -1235,10 +1235,11 @@ bool InterpreterImpl::hasConditionMatch(const Arabica::DOM::Node<std::string>& c void InterpreterImpl::executeContent(const NodeList<std::string>& content, bool rethrow) { for (unsigned int i = 0; i < content.getLength(); i++) { - if (content.item(i).getNodeType() != Node_base::ELEMENT_NODE) + const Arabica::DOM::Node<std::string>& node = content.item(i); + if (node.getNodeType() != Node_base::ELEMENT_NODE) continue; try { - executeContent(content.item(i), true); + executeContent(node, true); } CATCH_AND_DISTRIBUTE2("Error when executing content", content.item(i)); } @@ -1246,10 +1247,11 @@ void InterpreterImpl::executeContent(const NodeList<std::string>& content, bool void InterpreterImpl::executeContent(const NodeSet<std::string>& content, bool rethrow) { for (unsigned int i = 0; i < content.size(); i++) { - if (content[i].getNodeType() != Node_base::ELEMENT_NODE) + const Arabica::DOM::Node<std::string>& node = content[i]; + if (node.getNodeType() != Node_base::ELEMENT_NODE) continue; try { - executeContent(content[i], true); + executeContent(node, true); } CATCH_AND_DISTRIBUTE2("Error when executing content", content[i]); } @@ -1598,9 +1600,9 @@ NEXT_ANCESTOR: return ancestor; } -Arabica::XPath::NodeSet<std::string> InterpreterImpl::getStates(const std::vector<std::string>& stateIds) { +Arabica::XPath::NodeSet<std::string> InterpreterImpl::getStates(const std::list<std::string>& stateIds) { Arabica::XPath::NodeSet<std::string> states; - std::vector<std::string>::const_iterator tokenIter = stateIds.begin(); + std::list<std::string>::const_iterator tokenIter = stateIds.begin(); while(tokenIter != stateIds.end()) { states.push_back(getState(*tokenIter)); tokenIter++; @@ -1717,18 +1719,32 @@ NodeSet<std::string> InterpreterImpl::getTargetStates(const Arabica::DOM::Node<s } std::string targetId = ((Arabica::DOM::Element<std::string>)transition).getAttribute("target"); - - std::vector<std::string> targetIds = InterpreterImpl::tokenizeIdRefs(ATTR(transition, "target")); - for (int i = 0; i < targetIds.size(); i++) { - Arabica::DOM::Node<std::string> state = getState(targetIds[i]); + std::list<std::string> targetIds = InterpreterImpl::tokenizeIdRefs(ATTR(transition, "target")); + for (std::list<std::string>::const_iterator targetIter = targetIds.begin(); targetIter != targetIds.end(); targetIter++) { + Arabica::DOM::Node<std::string> state = getState(*targetIter); assert(HAS_ATTR(state, "id")); targetStates.push_back(state); } return targetStates; } -std::vector<std::string> InterpreterImpl::tokenizeIdRefs(const std::string& idRefs) { - std::vector<std::string> ids; +std::list<std::string> InterpreterImpl::tokenizeIdRefs(const std::string& idRefs) { + std::list<std::string> ids; + + // appr. 3x faster than stringstream + size_t start = 0; + for (int i = 0; i < idRefs.size(); i++) { + if (isspace(idRefs[i])) { + if (i > 0 && start < i - 1) { + ids.push_back(idRefs.substr(start, i - start)); + } + while(isspace(idRefs[++i])); // skip whitespaces + start = i; + } else if (i + 1 == idRefs.size()) { + ids.push_back(idRefs.substr(start, i + 1 - start)); + } + } + #if 0 if (idRefs.length() > 0) { @@ -1740,11 +1756,13 @@ std::vector<std::string> InterpreterImpl::tokenizeIdRefs(const std::string& idRe } #endif +#if 0 // this version is somewhat fatser than the one above std::stringstream ss (idRefs); std::string item; while(ss >> item) ids.push_back(item); +#endif return ids; } diff --git a/src/uscxml/Interpreter.h b/src/uscxml/Interpreter.h index 5cc9053..d2e63e9 100644 --- a/src/uscxml/Interpreter.h +++ b/src/uscxml/Interpreter.h @@ -236,7 +236,7 @@ public: } Arabica::DOM::Node<std::string> getState(const std::string& stateId); - Arabica::XPath::NodeSet<std::string> getStates(const std::vector<std::string>& stateIds); + Arabica::XPath::NodeSet<std::string> getStates(const std::list<std::string>& stateIds); Arabica::DOM::Document<std::string>& getDocument() { return _document; @@ -286,7 +286,7 @@ public: static bool isCompound(const Arabica::DOM::Node<std::string>& state); static bool isDescendant(const Arabica::DOM::Node<std::string>& s1, const Arabica::DOM::Node<std::string>& s2); - static std::vector<std::string> tokenizeIdRefs(const std::string& idRefs); + static std::list<std::string> tokenizeIdRefs(const std::string& idRefs); static std::string spaceNormalize(const std::string& text); bool isInEmbeddedDocument(const Arabica::DOM::Node<std::string>& node); @@ -540,7 +540,7 @@ public: Arabica::DOM::Node<std::string> getState(const std::string& stateId) { return _impl->getState(stateId); } - Arabica::XPath::NodeSet<std::string> getStates(const std::vector<std::string>& stateIds) { + Arabica::XPath::NodeSet<std::string> getStates(const std::list<std::string>& stateIds) { return _impl->getStates(stateIds); } @@ -628,7 +628,7 @@ public: return InterpreterImpl::isDescendant(s1, s2); } - static std::vector<std::string> tokenizeIdRefs(const std::string& idRefs) { + static std::list<std::string> tokenizeIdRefs(const std::string& idRefs) { return InterpreterImpl::tokenizeIdRefs(idRefs); } static std::string spaceNormalize(const std::string& text) { diff --git a/src/uscxml/Message.cpp b/src/uscxml/Message.cpp index c79e08a..26cf640 100644 --- a/src/uscxml/Message.cpp +++ b/src/uscxml/Message.cpp @@ -61,6 +61,64 @@ Blob::Blob(void* _data, size_t _size, const std::string& _mimeType, bool adopt) size = _size; } +#if 0 +// there used to work base64 encoded images in a browser - can't check extensively just now +static const std::string base64_chars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + +std::string Blob::base64() { + + int in_len = size; + char const* bytes_to_encode = data; + + std::string ret; + int i = 0; + int j = 0; + unsigned char char_array_3[3]; + unsigned char char_array_4[4]; + + while (in_len--) { + char_array_3[i++] = *(bytes_to_encode++); + if (i == 3) { + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for(i = 0; (i <4) ; i++) + ret += base64_chars[char_array_4[i]]; + i = 0; + } + } + + if (i) { + for(j = i; j < 3; j++) + char_array_3[j] = '\0'; + + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for (j = 0; (j < i + 1); j++) + ret += base64_chars[char_array_4[j]]; + + while((i++ < 3)) + ret += '='; + + } + + return ret; + +} +#else +std::string Blob::base64() { + return base64Encode((char* const)data, size); +} +#endif + Data::Data(const char* _data, size_t _size, const std::string& mimeType, bool adopt) { binary = boost::shared_ptr<Blob>(new Blob((void*)_data, _size, mimeType, adopt)); } diff --git a/src/uscxml/Message.h b/src/uscxml/Message.h index 5de9a56..5f6703e 100644 --- a/src/uscxml/Message.h +++ b/src/uscxml/Message.h @@ -55,9 +55,7 @@ public: return uscxml::md5(data, size); } - std::string base64() { - return base64Encode((char* const)data, size); - } + std::string base64(); Blob* fromBase64(const std::string base64) { std::string decoded = base64Decode(base64); diff --git a/src/uscxml/interpreter/InterpreterDraft6.cpp b/src/uscxml/interpreter/InterpreterDraft6.cpp index c9c00ef..772ad96 100644 --- a/src/uscxml/interpreter/InterpreterDraft6.cpp +++ b/src/uscxml/interpreter/InterpreterDraft6.cpp @@ -467,9 +467,8 @@ bool InterpreterDraft6::isEnabledTransition(const Node<std::string>& transition, return false; } - std::vector<std::string> eventNames = tokenizeIdRefs(eventName); - - std::vector<std::string>::iterator eventIter = eventNames.begin(); + std::list<std::string> eventNames = tokenizeIdRefs(eventName); + std::list<std::string>::iterator eventIter = eventNames.begin(); while(eventIter != eventNames.end()) { if(nameMatch(*eventIter, event) && hasConditionMatch(transition)) { return true; diff --git a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp index 947c0c2..9827b91 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp +++ b/src/uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDataModel.cpp @@ -400,9 +400,10 @@ Data JSCDataModel::getValueAsData(const JSValueRef value) { if (!isNumeric(property.c_str(), 10)) isArray = false; propertySet.insert(property); - JSStringRelease(stringValue); + //JSStringRelease(stringValue); // JSPropertyNameArrayRelease does the job it seems free(buf); } + JSPropertyNameArrayRelease(properties); std::set<std::string>::iterator propIter = propertySet.begin(); while(propIter != propertySet.end()) { if (isArray) { @@ -537,14 +538,14 @@ void JSCDataModel::assign(const Element<std::string>& assignElem, throw Event("error.execution", Event::PLATFORM); // flags on attribute are ignored? - if (key.compare("_sessionid") == 0) - return; //throw Event("error.execution", Event::PLATFORM); + if (key.compare("_sessionid") == 0) // test 322 + throw Event("error.execution", Event::PLATFORM); if (key.compare("_name") == 0) - return; //throw Event("error.execution", Event::PLATFORM); - if (key.compare("_ioprocessors") == 0) - return; //throw Event("error.execution", Event::PLATFORM); + throw Event("error.execution", Event::PLATFORM); + if (key.compare("_ioprocessors") == 0) // test 326 + throw Event("error.execution", Event::PLATFORM); if (key.compare("_invokers") == 0) - return; //throw Event("error.execution", Event::PLATFORM); + throw Event("error.execution", Event::PLATFORM); if (HAS_ATTR(assignElem, "expr")) { evalAsValue(key + " = " + ATTR(assignElem, "expr")); diff --git a/src/uscxml/server/HTTPServer.cpp b/src/uscxml/server/HTTPServer.cpp index 358c819..6b24cd8 100644 --- a/src/uscxml/server/HTTPServer.cpp +++ b/src/uscxml/server/HTTPServer.cpp @@ -92,17 +92,24 @@ HTTPServer::HTTPServer(unsigned short port, unsigned short wsPort, SSLConfig* ss evhttp_set_allowed_methods(_http, allowedMethods); // allow all methods - if (_port > 0) + if (_port > 0) { _httpHandle = evhttp_bind_socket_with_handle(_http, INADDR_ANY, _port); - if (_httpHandle) - LOG(INFO) << "HTTP server listening on tcp/" << _port; + if (_httpHandle) { + LOG(INFO) << "HTTP server listening on tcp/" << _port; + } else { + LOG(ERROR) << "HTTP server cannot bind to tcp/" << _wsPort; + } + } _wsPort = wsPort; - if (_wsPort > 0) + if (_wsPort > 0) { _wsHandle = evws_bind_socket(_evws, _wsPort); - if (_wsHandle) - LOG(INFO) << "WebSocket server listening on tcp/" << _wsPort; - + if (_wsHandle) { + LOG(INFO) << "WebSocket server listening on tcp/" << _wsPort; + } else { + LOG(ERROR) << "WebSocket server cannot bind to tcp/" << _wsPort; + } + } #if (defined EVENT_SSL_FOUND && defined OPENSSL_FOUND && defined OPENSSL_HAS_ELIPTIC_CURVES) _sslHandle = NULL; _https = NULL; @@ -136,11 +143,15 @@ HTTPServer::HTTPServer(unsigned short port, unsigned short wsPort, SSLConfig* ss evhttp_set_bevcb(_https, sslBufferEventCallback, ctx); evhttp_set_gencb(_https, sslGeneralBufferEventCallback, NULL); - if (_sslPort > 0) + if (_sslPort > 0) { _sslHandle = evhttp_bind_socket_with_handle(_https, INADDR_ANY, _sslPort); - if (_sslHandle) - LOG(INFO) << "HTTPS server listening on tcp/" << _wsPort; + if (_sslHandle) { + LOG(INFO) << "HTTPS server listening on tcp/" << _wsPort; + } else { + LOG(ERROR) << "HTTPS server cannot bind to tcp/" << _wsPort; + } + } } #endif diff --git a/src/uscxml/util/Base64.h b/src/uscxml/util/Base64.h index 7dfc83c..a07d24e 100644 --- a/src/uscxml/util/Base64.h +++ b/src/uscxml/util/Base64.h @@ -36,9 +36,7 @@ extern "C" { } base64_decodestate; USCXML_API void base64_init_decodestate(base64_decodestate* state_in); - USCXML_API int base64_decode_value(char value_in); - USCXML_API int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in); /// ENDCODE @@ -54,11 +52,8 @@ extern "C" { } base64_encodestate; USCXML_API void base64_init_encodestate(base64_encodestate* state_in); - USCXML_API char base64_encode_value(char value_in); - USCXML_API int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in); - USCXML_API int base64_encode_blockend(char* code_out, base64_encodestate* state_in); #ifdef __cplusplus diff --git a/src/uscxml/util/Base64.hpp b/src/uscxml/util/Base64.hpp index a106a12..e3cbe03 100644 --- a/src/uscxml/util/Base64.hpp +++ b/src/uscxml/util/Base64.hpp @@ -12,7 +12,7 @@ extern "C" { namespace uscxml { -USCXML_API inline std::string base64Encode(const char* data, unsigned int len) { +USCXML_API inline std::string base64Encode(const char* data, unsigned int len, bool withBlockEnd = true) { base64_encodestate* ctx = (base64_encodestate*)malloc(sizeof(base64_encodestate)); base64_init_encodestate(ctx); @@ -22,10 +22,15 @@ USCXML_API inline std::string base64Encode(const char* data, unsigned int len) { * be approximated with this formula: */ + int written = 0; char* out = (char*)malloc(len * 1.4 + 814); - base64_encode_block(data, len, out, ctx); + written += base64_encode_block(data, len, out, ctx); + if (withBlockEnd) { + written += base64_encode_blockend(out + written, ctx); + written--; // drop the newline + } + std::string result(out, written); free(ctx); - std::string result(out); free(out); return result; } @@ -42,5 +47,8 @@ USCXML_API inline std::string base64Decode(const std::string& data) { return result; } +// USCXML_API std::string base64Decode(const std::string& data); +// USCXML_API std::string base64Encode(const char* data, unsigned int len); + } #endif /* end of include guard: BASE64_H_5FKG12HF */ diff --git a/src/uscxml/util/MD5.c b/src/uscxml/util/MD5.c index 1bf05e4..f553c9c 100644 --- a/src/uscxml/util/MD5.c +++ b/src/uscxml/util/MD5.c @@ -52,6 +52,7 @@ */ #include "MD5.h" +#include <string.h> #undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ #ifdef ARCH_IS_BIG_ENDIAN diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index eff801c..4c906fd 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -35,6 +35,11 @@ if (OPENSCENEGRAPH_FOUND AND OFF) set_target_properties(test-osg PROPERTIES FOLDER "Tests") endif() +add_executable(test-base64 src/test-base64.cpp) +target_link_libraries(test-base64 uscxml) +add_test(test-base64 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-base64) +set_target_properties(test-base64 PROPERTIES FOLDER "Tests") + add_executable(test-eventdelay src/test-eventdelay.cpp) target_link_libraries(test-eventdelay uscxml) add_test(test-eventdelay ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-eventdelay) @@ -130,11 +135,11 @@ foreach( W3C_TEST ${W3C_TESTS} ) string(REGEX MATCH "[^//]+/[^//]+.scxml" TEST_NAME ${W3C_TEST}) #message("TEST_NAME: ${TEST_NAME}") if (NOT TEST_NAME MATCHES ".*sub.*") - if (RUN_W3C_ECMA_TESTS AND TEST_NAME MATCHES "^ecma\\/.*") + if (BUILD_TESTS_W3C_ECMA AND TEST_NAME MATCHES "^ecma\\/.*") add_test(${TEST_NAME} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-w3c ${W3C_TEST}) set_tests_properties(${TEST_NAME} PROPERTIES FAIL_REGULAR_EXPRESSION "TEST FAILED") endif() - if (RUN_W3C_XPATH_TESTS AND TEST_NAME MATCHES "^xpath\\/.*") + if (BUILD_TESTS_W3C_XPATH AND TEST_NAME MATCHES "^xpath\\/.*") add_test(${TEST_NAME} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test-w3c ${W3C_TEST}) set_tests_properties(${TEST_NAME} PROPERTIES FAIL_REGULAR_EXPRESSION "TEST FAILED") endif() diff --git a/test/samples/uscxml/test-performance.scxml b/test/samples/uscxml/test-performance.scxml index 4d2d4c4..d8e75da 100644 --- a/test/samples/uscxml/test-performance.scxml +++ b/test/samples/uscxml/test-performance.scxml @@ -1,6 +1,6 @@ <scxml datamodel="ecmascript"> <datamodel> - <data id="iterations">10000</data> + <data id="iterations">100000</data> </datamodel> <state id="start"> <transition target="loop" /> diff --git a/test/samples/w3c/update-txml.sh b/test/samples/w3c/update-txml.sh index 3c7255b..074318d 100755 --- a/test/samples/w3c/update-txml.sh +++ b/test/samples/w3c/update-txml.sh @@ -1,7 +1,7 @@ #!/bin/bash wget -rl1 -Atxml,txt,xsl http://www.w3.org/Voice/2013/scxml-irp/ -find ./www.w3.org -name *.txml -exec cp {} ./txml \; -find ./www.w3.org -name *.txt -exec cp {} ./txml \; -find ./www.w3.org -name *.xsl -exec cp {} . \; +find ./www.w3.org -name "*.txml" -exec cp {} ./txml \; +find ./www.w3.org -name "*.txt" -exec cp {} ./txml \; +find ./www.w3.org -name "*.xsl" -exec cp {} . \; rm -rf www.w3.org
\ No newline at end of file diff --git a/test/src/test-base64.cpp b/test/src/test-base64.cpp new file mode 100644 index 0000000..1267b7b --- /dev/null +++ b/test/src/test-base64.cpp @@ -0,0 +1,18 @@ +#include "uscxml/util/Base64.hpp" +#include <assert.h> + +#define SOURCE_LEN 10 + +int main(int argc, char** argv) { + std::string data; + std::string base64CPP; + std::string base64C; + + char buffer[SOURCE_LEN]; + for (int i = 0; i < SOURCE_LEN; i++) { + buffer[i] = (char)55; + } + + base64C = uscxml::base64Encode(buffer, SOURCE_LEN); + +}
\ No newline at end of file diff --git a/test/src/test-predicates.cpp b/test/src/test-predicates.cpp index b3e46fe..ed155b4 100644 --- a/test/src/test-predicates.cpp +++ b/test/src/test-predicates.cpp @@ -43,12 +43,66 @@ int main(int argc, char** argv) { assert(Interpreter::isDescendant(compoundChild1, compoundState)); - std::string idrefs("id1 \nid2 \tid3"); - std::vector<std::string> tokenizedIdrefs = Interpreter::tokenizeIdRefs(idrefs); - assert(tokenizedIdrefs.size() == 3); - assert(tokenizedIdrefs[0].compare("id1") == 0); - assert(tokenizedIdrefs[1].compare("id2") == 0); - assert(tokenizedIdrefs[2].compare("id3") == 0); + { + std::string idrefs("id1"); + std::list<std::string> tokenizedIdrefs = Interpreter::tokenizeIdRefs(idrefs); + assert(tokenizedIdrefs.size() == 1); + assert(tokenizedIdrefs.front().compare("id1") == 0); + } + + { + std::string idrefs(" id1"); + std::list<std::string> tokenizedIdrefs = Interpreter::tokenizeIdRefs(idrefs); + assert(tokenizedIdrefs.size() == 1); + assert(tokenizedIdrefs.front().compare("id1") == 0); + } + + { + std::string idrefs(" id1 "); + std::list<std::string> tokenizedIdrefs = Interpreter::tokenizeIdRefs(idrefs); + assert(tokenizedIdrefs.size() == 1); + assert(tokenizedIdrefs.front().compare("id1") == 0); + } + + { + std::string idrefs(" \tid1\n "); + std::list<std::string> tokenizedIdrefs = Interpreter::tokenizeIdRefs(idrefs); + assert(tokenizedIdrefs.size() == 1); + assert(tokenizedIdrefs.front().compare("id1") == 0); + } + + { + std::string idrefs("id1 id2 id3"); + std::list<std::string> tokenizedIdrefs = Interpreter::tokenizeIdRefs(idrefs); + assert(tokenizedIdrefs.size() == 3); + assert(tokenizedIdrefs.front().compare("id1") == 0); + tokenizedIdrefs.pop_front(); + assert(tokenizedIdrefs.front().compare("id2") == 0); + tokenizedIdrefs.pop_front(); + assert(tokenizedIdrefs.front().compare("id3") == 0); + } + + { + std::string idrefs("\t id1 \nid2\n\n id3\t"); + std::list<std::string> tokenizedIdrefs = Interpreter::tokenizeIdRefs(idrefs); + assert(tokenizedIdrefs.size() == 3); + assert(tokenizedIdrefs.front().compare("id1") == 0); + tokenizedIdrefs.pop_front(); + assert(tokenizedIdrefs.front().compare("id2") == 0); + tokenizedIdrefs.pop_front(); + assert(tokenizedIdrefs.front().compare("id3") == 0); + } + + { + std::string idrefs("id1 \nid2 \tid3"); + std::list<std::string> tokenizedIdrefs = Interpreter::tokenizeIdRefs(idrefs); + assert(tokenizedIdrefs.size() == 3); + assert(tokenizedIdrefs.front().compare("id1") == 0); + tokenizedIdrefs.pop_front(); + assert(tokenizedIdrefs.front().compare("id2") == 0); + tokenizedIdrefs.pop_front(); + assert(tokenizedIdrefs.front().compare("id3") == 0); + } std::string transEvents; transEvents = "error"; |