[lightspark] 03/08: Imported Upstream version 0.7.2+git20150512
Gabriele Giacone
gg0-guest at moszumanska.debian.org
Tue May 12 19:02:51 UTC 2015
This is an automated email from the git hooks/post-receive script.
gg0-guest pushed a commit to branch master
in repository lightspark.
commit 0be6438bad09c20b3e6576433cdd39d526aeee7f
Author: Gabriele Giacone <1o5g4r8o at gmail.com>
Date: Tue May 12 15:04:59 2015 +0200
Imported Upstream version 0.7.2+git20150512
---
CMakeLists.txt | 79 +-
ChangeLog | 10 +
README | 21 +-
conf/FindFFMpeg.cmake | 6 +-
conf/FindFreetype.cmake | 6 +-
conf/FindLLVM.cmake | 33 +-
debian/control | 2 +-
docs/man/lightspark.1 | 28 +-
src/CMakeLists.txt | 27 +
src/allclasses.cpp | 30 +
src/allclasses.h | 72 +
src/asobject.cpp | 461 ++++-
src/asobject.h | 66 +-
src/backends/decoder.cpp | 193 +-
src/backends/decoder.h | 26 +-
src/backends/graphics.cpp | 92 +-
src/backends/graphics.h | 28 +-
src/backends/input.cpp | 15 +
src/backends/input.h | 1 +
src/backends/netutils.cpp | 629 +-----
src/backends/netutils.h | 125 +-
src/backends/rendering.cpp | 6 +-
src/backends/rtmputils.cpp | 6 +-
src/backends/rtmputils.h | 3 +-
src/backends/security.cpp | 9 +-
src/backends/streamcache.cpp | 499 +++++
src/backends/streamcache.h | 197 ++
src/backends/urlutils.cpp | 255 ++-
src/backends/urlutils.h | 20 +-
src/backends/xml_support.cpp | 83 +-
src/backends/xml_support.h | 8 +-
src/compat.h | 1 +
src/main.cpp | 8 +-
src/parsing/amf3_generator.cpp | 165 +-
src/parsing/amf3_generator.h | 32 +
src/parsing/tags.cpp | 101 +-
src/parsing/tags.h | 29 +-
src/parsing/tags_stub.cpp | 6 -
src/platforms/engineutils.cpp | 30 +
src/platforms/engineutils.h | 11 +-
src/plugin/npscriptobject.cpp | 7 +-
src/plugin/plugin.cpp | 87 +-
src/plugin/plugin.h | 12 +-
src/scripting/abc.cpp | 289 ++-
src/scripting/abc.h | 44 +-
src/scripting/abc_codesynt.cpp | 25 +-
src/scripting/abc_fast_interpreter.cpp | 87 +-
src/scripting/abc_interpreter.cpp | 103 +-
src/scripting/abc_opcodes.cpp | 429 ++--
src/scripting/abc_optimizer.cpp | 6 +-
src/scripting/abctypes.h | 5 +-
src/scripting/argconv.h | 8 +-
src/scripting/class.cpp | 30 +-
src/scripting/class.h | 126 +-
.../flash/accessibility/flashaccessibility.cpp | 42 +-
.../flash/accessibility/flashaccessibility.h | 19 +-
src/scripting/flash/concurrent/Condition.cpp | 81 +
.../flash/concurrent/Condition.h} | 30 +-
.../Mutex.cpp} | 45 +-
.../flash/concurrent/Mutex.h} | 31 +-
src/scripting/flash/desktop/flashdesktop.cpp | 5 +-
src/scripting/flash/display/BitmapData.cpp | 137 +-
src/scripting/flash/display/BitmapData.h | 3 +
src/scripting/flash/display/DisplayObject.cpp | 47 +-
src/scripting/flash/display/DisplayObject.h | 5 +-
src/scripting/flash/display/Graphics.cpp | 923 +++++++++
src/scripting/flash/display/Graphics.h | 103 +
src/scripting/flash/display/GraphicsBitmapFill.cpp | 70 +
.../display/GraphicsBitmapFill.h} | 48 +-
.../GraphicsEndFill.cpp} | 32 +-
.../flash/display/GraphicsEndFill.h} | 26 +-
.../flash/display/GraphicsGradientFill.cpp | 96 +
src/scripting/flash/display/GraphicsGradientFill.h | 55 +
src/scripting/flash/display/GraphicsPath.cpp | 173 ++
.../UInteger.h => flash/display/GraphicsPath.h} | 54 +-
src/scripting/flash/display/GraphicsShaderFill.cpp | 73 +
.../GraphicsShaderFill.h} | 33 +-
src/scripting/flash/display/GraphicsSolidFill.cpp | 63 +
.../GraphicsSolidFill.h} | 29 +-
src/scripting/flash/display/GraphicsStroke.cpp | 109 +
.../UInteger.h => flash/display/GraphicsStroke.h} | 50 +-
.../flash/display/GraphicsTrianglePath.cpp | 74 +
.../display/GraphicsTrianglePath.h} | 47 +-
.../flash/display/IGraphicsData.h} | 25 +-
.../flash/display/IGraphicsFill.h} | 23 +-
.../flash/display/IGraphicsPath.h} | 20 +-
.../flash/display/IGraphicsStroke.h} | 20 +-
src/scripting/flash/display/TokenContainer.cpp | 23 +-
src/scripting/flash/display/TokenContainer.h | 4 +-
src/scripting/flash/display/flashdisplay.cpp | 1006 +++------
src/scripting/flash/display/flashdisplay.h | 101 +-
src/scripting/flash/errors/flasherrors.cpp | 21 +-
src/scripting/flash/events/flashevents.cpp | 238 ++-
src/scripting/flash/events/flashevents.h | 76 +-
src/scripting/flash/external/ExternalInterface.cpp | 8 +-
.../flashfilesystem.cpp} | 29 +-
.../flashfilesystem.h} | 22 +-
src/scripting/flash/filters/flashfilters.cpp | 321 ++-
src/scripting/flash/filters/flashfilters.h | 111 +-
src/scripting/flash/geom/flashgeom.cpp | 46 +-
src/scripting/flash/geom/flashgeom.h | 23 +-
src/scripting/flash/media/flashmedia.cpp | 151 +-
src/scripting/flash/media/flashmedia.h | 34 +-
.../NetStreamPlayOptions.cpp} | 41 +-
.../flashsensors.h => net/NetStreamPlayOptions.h} | 34 +-
.../NetStreamPlayTransitions.cpp} | 37 +-
.../flash/net/NetStreamPlayTransitions.h} | 24 +-
src/scripting/flash/net/URLRequestHeader.cpp | 3 +-
src/scripting/flash/net/URLStream.cpp | 12 +-
src/scripting/flash/net/URLStream.h | 1 +
src/scripting/flash/net/XMLSocket.cpp | 3 +-
src/scripting/flash/net/flashnet.cpp | 369 +++-
src/scripting/flash/net/flashnet.h | 65 +-
src/scripting/flash/printing/flashprinting.cpp | 69 +
.../flashprinting.h} | 27 +-
src/scripting/flash/sensors/flashsensors.cpp | 3 +-
src/scripting/flash/sensors/flashsensors.h | 2 +-
src/scripting/flash/system/flashsystem.cpp | 139 +-
src/scripting/flash/system/flashsystem.h | 24 +-
src/scripting/flash/text/flashtext.cpp | 629 +++++-
src/scripting/flash/text/flashtext.h | 89 +-
src/scripting/flash/text/flashtextengine.cpp | 333 ++-
src/scripting/flash/text/flashtextengine.h | 123 +-
.../flashaccessibility.cpp => ui/ContextMenu.cpp} | 35 +-
.../{sensors/flashsensors.h => ui/ContextMenu.h} | 33 +-
src/scripting/flash/ui/ContextMenuBuiltInItems.cpp | 57 +
.../ContextMenuBuiltInItems.h} | 31 +-
.../flash/ui/ContextMenuItem.cpp} | 36 +-
.../flash/ui/ContextMenuItem.h} | 26 +-
src/scripting/flash/ui/Keyboard.cpp | 9 +-
src/scripting/flash/ui/Mouse.cpp | 75 +
.../rtmputils.h => scripting/flash/ui/Mouse.h} | 28 +-
.../flash/utils/{flashutils.cpp => ByteArray.cpp} | 1085 ++--------
src/scripting/flash/utils/ByteArray.h | 156 ++
src/scripting/flash/utils/Dictionary.cpp | 344 ++++
src/scripting/flash/utils/Dictionary.h | 64 +
src/scripting/flash/utils/IntervalManager.cpp | 106 +
.../IntervalManager.h} | 35 +-
src/scripting/flash/utils/IntervalRunner.cpp | 72 +
.../UInteger.h => flash/utils/IntervalRunner.h} | 55 +-
src/scripting/flash/utils/Proxy.cpp | 251 +++
src/scripting/flash/utils/Proxy.h | 61 +
src/scripting/flash/utils/Timer.cpp | 185 ++
.../{toplevel/UInteger.h => flash/utils/Timer.h} | 60 +-
src/scripting/flash/utils/flashutils.cpp | 1892 +----------------
src/scripting/flash/utils/flashutils.h | 243 +--
src/scripting/flash/xml/flashxml.cpp | 10 +-
src/scripting/toplevel/ASString.cpp | 119 +-
src/scripting/toplevel/ASString.h | 7 +
src/scripting/toplevel/Array.cpp | 370 +++-
src/scripting/toplevel/Array.h | 30 +-
src/scripting/toplevel/Boolean.cpp | 22 +-
src/scripting/toplevel/Date.cpp | 28 +-
src/scripting/toplevel/Date.h | 4 +
src/scripting/toplevel/Error.cpp | 49 +-
src/scripting/toplevel/Integer.cpp | 65 +-
src/scripting/toplevel/Integer.h | 3 +
src/scripting/toplevel/JSON.cpp | 774 +++++++
src/scripting/toplevel/JSON.h | 51 +
src/scripting/toplevel/Math.cpp | 4 +-
src/scripting/toplevel/Number.cpp | 227 +-
src/scripting/toplevel/Number.h | 9 +-
src/scripting/toplevel/RegExp.cpp | 12 +-
src/scripting/toplevel/UInteger.cpp | 54 +-
src/scripting/toplevel/UInteger.h | 3 +
src/scripting/toplevel/Vector.cpp | 148 +-
src/scripting/toplevel/Vector.h | 26 +-
src/scripting/toplevel/XML.cpp | 2164 ++++++++++++++------
src/scripting/toplevel/XML.h | 103 +-
src/scripting/toplevel/XMLList.cpp | 633 ++++--
src/scripting/toplevel/XMLList.h | 39 +-
src/scripting/toplevel/toplevel.cpp | 281 ++-
src/scripting/toplevel/toplevel.h | 66 +-
src/swf.cpp | 58 +-
src/swf.h | 3 +
src/swftypes.cpp | 73 +-
src/swftypes.h | 25 +-
src/threading.cpp | 27 +
src/threading.h | 10 +
src/tiny_string.cpp | 398 ++++
src/tiny_string.h | 353 +---
tests/encodeURI_test.mxml | 67 +
tests/make-tamarin | 121 +-
tests/methodNamespace_test.mxml | 141 ++
tests/quit.as | 2 +
tests/tests | 109 +-
tools/langref_parser | 13 +-
tools/mergeABCtoSWF | 134 ++
tools/pygil | 24 +-
189 files changed, 15747 insertions(+), 7560 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 33dbb85..7e8c08b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -78,7 +78,7 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
# GCC 4.6+ is required, GCC_VERSION macro taken from GCC manual
INCLUDE(CheckCSourceCompiles)
-IF(CMAKE_COMPILER_IS_GNUCC)
+IF(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
CHECK_C_SOURCE_COMPILES("
#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
#if GCC_VERSION < 40600
@@ -88,7 +88,7 @@ IF(CMAKE_COMPILER_IS_GNUCC)
IF(NOT GCC_IS_4_6)
MESSAGE(FATAL_ERROR "GCC 4.6+ is required.")
ENDIF(NOT GCC_IS_4_6)
-ENDIF(CMAKE_COMPILER_IS_GNUCC)
+ENDIF(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
# Find put the path of the gnash executable, if available
FIND_PROGRAM(GNASH_EXE_PATH NAMES gnash)
@@ -114,31 +114,31 @@ SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/conf)
INCLUDE(Pack)
# If we're gcc, then use nasm to get fastpath. If MSVC, just use inline asm to get around
# CMake issues
-IF(CMAKE_COMPILER_IS_GNUCC)
+IF(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
INCLUDE(CMakeASM-NASMCompiler)
-ENDIF(CMAKE_COMPILER_IS_GNUCC)
+ENDIF(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
IF(${CMAKE_SYSTEM_PROCESSOR} MATCHES "^i[3-6]86$|^x86$")
SET(i386 1)
SET(LIB_SUFFIX "" CACHE STRING "Choose the suffix of the lib folder (if any) : None 32")
# nasm for assembly optimizations
- IF(CMAKE_COMPILER_IS_GNUCC)
+ IF(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
ENABLE_LANGUAGE(ASM-NASM)
- ENDIF(CMAKE_COMPILER_IS_GNUCC)
+ ENDIF(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
ELSEIF(${CMAKE_SYSTEM_PROCESSOR} MATCHES "unknown" AND ${CMAKE_SYSTEM} MATCHES "GNU-0.3")
# GNU Hurd is i386
SET(i386 1)
SET(LIB_SUFFIX "" CACHE STRING "Choose the suffix of the lib folder (if any) : None 32")
# nasm for assembly optimizations
- IF(CMAKE_COMPILER_IS_GNUCC)
+ IF(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
ENABLE_LANGUAGE(ASM-NASM)
ENDIF ()
ELSEIF(${CMAKE_SYSTEM_PROCESSOR} MATCHES "^x86_64$|^amd64$")
SET(x86_64 1)
SET(LIB_SUFFIX "" CACHE STRING "Choose the suffix of the lib folder (if any) : None 64")
# nasm for assembly optimizations
- IF(CMAKE_COMPILER_IS_GNUCC)
+ IF(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
ENABLE_LANGUAGE(ASM-NASM)
- ENDIF(CMAKE_COMPILER_IS_GNUCC)
+ ENDIF(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
ELSEIF(${CMAKE_SYSTEM_PROCESSOR} MATCHES "ppc")
SET(ppc 1)
SET(LIB_SUFFIX "" CACHE STRING "Choose the suffix of the lib folder (if any) : None ppc")
@@ -238,6 +238,15 @@ ENDIF(${LLVM_STRING_VERSION} VERSION_EQUAL 3.0)
IF(${LLVM_STRING_VERSION} VERSION_GREATER 3.0)
ADD_DEFINITIONS(-DLLVM_31)
ENDIF(${LLVM_STRING_VERSION} VERSION_GREATER 3.0)
+IF(${LLVM_STRING_VERSION} VERSION_GREATER 3.3)
+ ADD_DEFINITIONS(-DLLVM_34)
+ENDIF(${LLVM_STRING_VERSION} VERSION_GREATER 3.3)
+IF(${LLVM_STRING_VERSION} VERSION_GREATER 3.4)
+ ADD_DEFINITIONS(-DLLVM_35)
+ENDIF(${LLVM_STRING_VERSION} VERSION_GREATER 3.4)
+IF(NOT (${LLVM_STRING_VERSION} VERSION_LESS 3.6))
+ ADD_DEFINITIONS(-DLLVM_36)
+ENDIF(NOT (${LLVM_STRING_VERSION} VERSION_LESS 3.6))
INCLUDE(FindZLIB REQUIRED)
INCLUDE(FindFreetype REQUIRED)
IF(NOT(ENABLE_GLES2))
@@ -287,12 +296,17 @@ ENDIF(AUDIO_BACKEND)
IF(ENABLE_LIBAVCODEC)
pkg_check_modules(FFMPEG libavcodec libavutil libavformat)
+ pkg_check_modules(LIBAVRESAMPLE libavresample)
IF(NOT(FFMPEG_FOUND))
INCLUDE(FindFFMpeg REQUIRED)
ENDIF(NOT(FFMPEG_FOUND))
# Compatibility checks for ffmpeg deprecated functions
INCLUDE(CheckFunctionExists REQUIRED)
- SET(CMAKE_REQUIRED_FLAGS ${LIBAVCODEC_CFLAGS})
+ INCLUDE(CheckCSourceCompiles)
+ SET(FFMPEG_FLAGS "${LIBAVCODEC_CFLAGS} ${LIBAVRESAMPLE_FLAGS}")
+ SET(FFMPEG_INCLUDE_DIRS "${FFMPEG_INCLUDE_DIRS} ${LIBAVRESAMPLE_INCLUDE_DIRS}")
+ SET(FFMPEG_LIBRARIES "${FFMPEG_LIBRARIES};${LIBAVRESAMPLE_LIBRARIES}")
+ SET(CMAKE_REQUIRED_FLAGS ${FFMPEG_FLAGS})
SET(CMAKE_REQUIRED_INCLUDES ${FFMPEG_INCLUDE_DIRS})
SET(CMAKE_REQUIRED_LIBRARIES ${FFMPEG_LIBRARIES})
CHECK_FUNCTION_EXISTS(avcodec_decode_video2 HAVE_AVCODEC_DECODE_VIDEO2)
@@ -303,7 +317,8 @@ IF(ENABLE_LIBAVCODEC)
CHECK_FUNCTION_EXISTS(avcodec_open2 HAVE_AVCODEC_OPEN2)
CHECK_FUNCTION_EXISTS(avformat_close_input HAVE_AVFORMAT_CLOSE_INPUT)
CHECK_FUNCTION_EXISTS(avformat_find_stream_info HAVE_AVFORMAT_FIND_STREAM_INFO)
-
+ CHECK_C_SOURCE_COMPILES("#include <libavcodec/avcodec.h>\nint main() { enum AVCodecID c; return 0; }" HAVE_AVCODECID)
+
SET(CMAKE_REQUIRED_FLAGS)
SET(CMAKE_REQUIRED_INCLUDES)
SET(CMAKE_REQUIRED_LIBRARIES)
@@ -331,6 +346,12 @@ IF(ENABLE_LIBAVCODEC)
IF(HAVE_AVFORMAT_FIND_STREAM_INFO)
ADD_DEFINITIONS(-DHAVE_AVFORMAT_FIND_STREAM_INFO)
ENDIF(HAVE_AVFORMAT_FIND_STREAM_INFO)
+ IF(HAVE_AVCODECID)
+ ADD_DEFINITIONS(-DHAVE_AVCODECID)
+ ENDIF(HAVE_AVCODECID)
+ IF(LIBAVRESAMPLE_FOUND)
+ ADD_DEFINITIONS(-DHAVE_LIBAVRESAMPLE)
+ ENDIF(LIBAVRESAMPLE_FOUND)
ADD_DEFINITIONS(-DENABLE_LIBAVCODEC)
ENDIF(ENABLE_LIBAVCODEC)
@@ -372,7 +393,7 @@ IF(ENABLE_LIBAVCODEC)
SET(OPTIONAL_LIBRARIES ${OPTIONAL_LIBRARIES} ${FFMPEG_LIBRARIES})
ENDIF(ENABLE_LIBAVCODEC)
-IF(CMAKE_COMPILER_IS_GNUCC)
+IF(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
IF(MINGW)
SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed,--no-undefined -mthreads ${CMAKE_EXE_LINKER_FLAGS}")
SET(CMAKE_SHARED_LINKER_FLAGS "-Wl,--as-needed,--no-undefined,--enable-stdcall-fixup -mthreads ${CMAKE_SHARED_LINKER_FLAGS}")
@@ -382,7 +403,13 @@ IF(CMAKE_COMPILER_IS_GNUCC)
ENDIF()
SET(CMAKE_EXE_LINKER_FLAGS_RELEASE "-s")
SET(CMAKE_SHARED_LINKER_FLAGS_RELEASE "-s")
-ENDIF(CMAKE_COMPILER_IS_GNUCC)
+ENDIF(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+IF(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+ SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -Wl,--no-undefined ${CMAKE_EXE_LINKER_FLAGS}")
+ SET(CMAKE_SHARED_LINKER_FLAGS "-Wl,--as-needed,-z,noexecstack,--no-undefined ${CMAKE_SHARED_LINKER_FLAGS}")
+ SET(CMAKE_EXE_LINKER_FLAGS_RELEASE "-s")
+ SET(CMAKE_SHARED_LINKER_FLAGS_RELEASE "-s")
+ENDIF(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
LINK_DIRECTORIES(${LLVM_LIB_DIR})
@@ -413,13 +440,13 @@ IF(ENABLE_MEMORY_USAGE_PROFILING)
ENDIF(ENABLE_MEMORY_USAGE_PROFILING)
# Compiler defaults flags for different profiles
-IF(CMAKE_COMPILER_IS_GNUCC)
+IF(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
IF(MINGW)
SET(CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} -mms-bitfields -mthreads -fexceptions -Wall -Wnon-virtual-dtor -Woverloaded-virtual -pipe -std=c++0x -Wdisabled-optimization -Wextra -Wno-unused-parameter -Wno-invalid-offsetof")
ELSE()
SET(CMAKE_CXX_FLAGS
- "${CMAKE_CXX_FLAGS} -Wall -Wnon-virtual-dtor -Woverloaded-virtual -pipe -fvisibility=hidden -fvisibility-inlines-hidden -std=c++0x -Wdisabled-optimization -Wextra -Wno-unused-parameter -Wno-invalid-offsetof")
+ "${CMAKE_CXX_FLAGS} -Wall -Wnon-virtual-dtor -Woverloaded-virtual -pipe -fvisibility=hidden -fvisibility-inlines-hidden -std=c++11 -Wdisabled-optimization -Wextra -Wno-unused-parameter -Wno-invalid-offsetof")
ENDIF()
SET(CMAKE_CXX_FLAGS_DEBUG "-g -O0 -DEXPENSIVE_DEBUG")
SET(CMAKE_CXX_FLAGS_PROFILE "-g -pg -O2")
@@ -427,7 +454,18 @@ IF(CMAKE_COMPILER_IS_GNUCC)
SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-g -O2 -DNDEBUG")
SET(CMAKE_CXX_FLAGS_LEANDEBUG "-g -O2")
ADD_DEFINITIONS(-DLS_DATADIR="${LSDATADIR}" -DGNASH_PATH="${GNASH_EXE_PATH}" -DPRIVATELIBDIR="${PRIVATELIBDIR}")
-ENDIF(CMAKE_COMPILER_IS_GNUCC)
+ENDIF(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+IF(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+ SET(CMAKE_CXX_FLAGS
+ "${CMAKE_CXX_FLAGS} -Wall -Wnon-virtual-dtor -Woverloaded-virtual -pipe -fvisibility=hidden -fvisibility-inlines-hidden -std=c++11 -Wdisabled-optimization -Wextra -Wno-unused-parameter -Wno-invalid-offsetof")
+ SET(CMAKE_CXX_FLAGS_DEBUG "-g -O0 -DEXPENSIVE_DEBUG")
+ SET(CMAKE_CXX_FLAGS_PROFILE "-g -pg -O2")
+ SET(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG")
+ SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-g -O2 -DNDEBUG")
+ SET(CMAKE_CXX_FLAGS_LEANDEBUG "-g -O2")
+ ADD_DEFINITIONS(-DLS_DATADIR="${LSDATADIR}" -DGNASH_PATH="${GNASH_EXE_PATH}" -DPRIVATELIBDIR="${PRIVATELIBDIR}")
+ ADD_DEFINITIONS(-DUSE_CLANG)
+ENDIF(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
IF(MSVC)
ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS -DVPCOMPAT -DPTW32_STATIC_LIB -DPCRE_STATIC)
@@ -445,11 +483,16 @@ IF(HAVE_ATOMIC)
ENDIF(HAVE_ATOMIC)
# Setting the output directories, so we can build all profiles without mixmatching
-IF(CMAKE_COMPILER_IS_GNUCC)
+IF(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+ SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${CMAKE_SYSTEM_PROCESSOR}/${CMAKE_BUILD_TYPE}/bin")
+ SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${CMAKE_SYSTEM_PROCESSOR}/${CMAKE_BUILD_TYPE}/lib${LIB_SUFFIX}")
+ #SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/objs/${CMAKE_SYSTEM_PROCESSOR}/${CMAKE_BUILD_TYPE}/lib${LIB_SUFFIX}" CACHE PATH "Static libraries output directory")
+ENDIF(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+IF(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${CMAKE_SYSTEM_PROCESSOR}/${CMAKE_BUILD_TYPE}/bin")
SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${CMAKE_SYSTEM_PROCESSOR}/${CMAKE_BUILD_TYPE}/lib${LIB_SUFFIX}")
#SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/objs/${CMAKE_SYSTEM_PROCESSOR}/${CMAKE_BUILD_TYPE}/lib${LIB_SUFFIX}" CACHE PATH "Static libraries output directory")
-ENDIF(CMAKE_COMPILER_IS_GNUCC)
+ENDIF(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
#Install icons and desktop file
if(UNIX)
diff --git a/ChangeLog b/ChangeLog
index 3920617..fb7831b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,15 @@
lightspark: An open source flash player implementation
+Version NEXT:
+
+ * Support LLVM up to version 3.6
+ * fix event dispatcher handling
+ * several fixes for object initialization
+ * partially implement AMF0 decoding
+ * complete rework of XML subsystem
+ * Support embedded audio
+ * Implement JSON parsing
+
Version 0.7.2:
* Improved image support: alpha in palettes, abbreviated JPEGs
diff --git a/README b/README
index ec64d4a..957ac80 100644
--- a/README
+++ b/README
@@ -35,15 +35,20 @@ DEBUG MODE:
To enable debug mode change the cmake command like this:
4b) cmake -DCMAKE_BUILD_TYPE=Debug
-CMAKE_BUILD_TYPE available: Debug Release RelWithDebInfo Profile Sound
-support may be disabled using the following option: -DENABLE_SOUND=0
-The audio backend can be set using -DAUDIO_BACKEND=<pulseaudio|sdl>
-(default is pulseaudio)
+CMAKE_BUILD_TYPE available: Debug LeanDebug Release RelWithDebInfo Profile
+
+Sound support may be disabled using the following option:
+-DENABLE_SOUND=0 The audio backend can be set using
+-DAUDIO_BACKEND=<pulseaudio|sdl> (default is pulseaudio)
EXECUTION
=========
Using `make install`, lightspark is installed in the system wide
+
+Browser plugin
+--------------
+
Firefox plugin path and Firefox should show it in the about:plugins
list and in the Tools->Add-ons->Plugins window.
@@ -57,6 +62,14 @@ Firefox is not able to deal very well with multiple plugins for the
same MIME type. If you only see a black box where a flash app should
be try to remove any other flash plugin you have installed.
+Command line
+------------
+
+The command line version of Lightspark can play a local SWF file.
+Execution: lightspark file.swf
+
+Type `lightspark` to see all command line options.
+
Keyboard shortcuts
------------------
diff --git a/conf/FindFFMpeg.cmake b/conf/FindFFMpeg.cmake
index 2b4dd98..8246c15 100644
--- a/conf/FindFFMpeg.cmake
+++ b/conf/FindFFMpeg.cmake
@@ -23,7 +23,11 @@ FIND_LIBRARY(FFMPEG_AVFORMAT_LIBRARY NAMES
avformat
)
-SET(FFMPEG_LIBRARY ${FFMPEG_AVCODEC_LIBRARY} ${FFMPEG_AVUTIL_LIBRARY} ${FFMPEG_AVFORMAT_LIBRARY})
+FIND_LIBRARY(FFMPEG_AVRESAMPLE_LIBRARY NAMES
+ avresample
+)
+
+SET(FFMPEG_LIBRARY ${FFMPEG_AVCODEC_LIBRARY} ${FFMPEG_AVUTIL_LIBRARY} ${FFMPEG_AVFORMAT_LIBRARY} ${FFMPEG_AVRESAMPLE_LIBRARY})
MARK_AS_ADVANCED(FFMPEG_LIBRARY)
# handle the QUIETLY and REQUIRED arguments and set FFMPEG_FOUND to TRUE if
diff --git a/conf/FindFreetype.cmake b/conf/FindFreetype.cmake
index a04d185..001ce35 100644
--- a/conf/FindFreetype.cmake
+++ b/conf/FindFreetype.cmake
@@ -52,9 +52,13 @@ FIND_PATH(FREETYPE_INCLUDE_DIR_ft2build ft2build.h
/sw/include
/opt/local/include
/usr/freeware/include
+ PATH_SUFFIXES freetype2
)
-FIND_PATH(FREETYPE_INCLUDE_DIR_freetype2 freetype/config/ftheader.h
+FIND_PATH(FREETYPE_INCLUDE_DIR_freetype2
+ NAMES
+ freetype/config/ftheader.h
+ config/ftheader.h
HINTS
$ENV{FREETYPE_DIR}/include/freetype2
PATHS
diff --git a/conf/FindLLVM.cmake b/conf/FindLLVM.cmake
index 7bd52e2..51b776c 100644
--- a/conf/FindLLVM.cmake
+++ b/conf/FindLLVM.cmake
@@ -51,6 +51,9 @@ else (LLVM_INCLUDE_DIR)
/usr/lib/llvm-2.8/bin
/usr/lib/llvm-2.9/bin
/usr/lib/llvm-3.0/bin
+ /usr/lib/llvm-3.1/bin
+ /usr/lib/llvm-3.2/bin
+ /usr/lib/llvm-3.3/bin
)
find_program(LLVM_GCC_EXECUTABLE
@@ -147,6 +150,7 @@ else (LLVM_INCLUDE_DIR)
exec_program(${LLVM_CONFIG_EXECUTABLE} ARGS --libdir OUTPUT_VARIABLE LLVM_LIB_DIR )
#MESSAGE(STATUS "LLVM lib dir: " ${LLVM_LIB_DIR})
exec_program(${LLVM_CONFIG_EXECUTABLE} ARGS --includedir OUTPUT_VARIABLE LLVM_INCLUDE_DIR )
+ #MESSAGE(STATUS "LLVM include dir: " ${LLVM_INCLUDE_DIR})
INCLUDE(CheckIncludeFileCXX)
set(CMAKE_REQUIRED_INCLUDES ${LLVM_INCLUDE_DIR})
@@ -158,7 +162,7 @@ else (LLVM_INCLUDE_DIR)
ENDIF(HAVE_SUPPORT_TARGETSELECT_H)
set(CMAKE_REQUIRED_INCLUDES ${LLVM_INCLUDE_DIR})
- set(CMAKE_REQUIRED_DEFINITIONS -D__STDC_LIMIT_MACROS=1 -D__STDC_CONSTANT_MACROS=1)
+ set(CMAKE_REQUIRED_DEFINITIONS -D__STDC_LIMIT_MACROS=1 -D__STDC_CONSTANT_MACROS=1 -std=c++11)
check_include_file_cxx("llvm/IRBuilder.h" HAVE_IRBUILDER_H)
unset(CMAKE_REQUIRED_INCLUDES)
MESSAGE(STATUS "HAVE_IRBUILDER_H: " ${HAVE_IRBUILDER_H})
@@ -168,23 +172,48 @@ else (LLVM_INCLUDE_DIR)
set(CMAKE_REQUIRED_INCLUDES ${LLVM_INCLUDE_DIR})
check_include_file_cxx("llvm/DataLayout.h" HAVE_DATALAYOUT_H)
+ check_include_file_cxx("llvm/IR/DataLayout.h" HAVE_IR_DATALAYOUT_H)
+ check_include_file_cxx("llvm/IR/Verifier.h" HAVE_IR_VERIFIER_H)
unset(CMAKE_REQUIRED_INCLUDES)
MESSAGE(STATUS "HAVE_DATALAYOUT_H: " ${HAVE_DATALAYOUT_H})
+ MESSAGE(STATUS "HAVE_IR_DATALAYOUT_H: " ${HAVE_IR_DATALAYOUT_H})
+ MESSAGE(STATUS "HAVE_IR_VERIFIER_H: " ${HAVE_IR_VERIFIER_H})
IF(HAVE_DATALAYOUT_H)
ADD_DEFINITIONS(-DHAVE_DATALAYOUT_H)
ENDIF(HAVE_DATALAYOUT_H)
+ IF(HAVE_IR_DATALAYOUT_H)
+ ADD_DEFINITIONS(-DHAVE_IR_DATALAYOUT_H)
+ ENDIF(HAVE_IR_DATALAYOUT_H)
+ IF(HAVE_IR_VERIFIER_H)
+ ADD_DEFINITIONS(-DHAVE_IR_VERIFIER_H)
+ ENDIF(HAVE_IR_VERIFIER_H)
exec_program(${LLVM_CONFIG_EXECUTABLE} ARGS --cxxflags OUTPUT_VARIABLE LLVM_COMPILE_FLAGS )
MESSAGE(STATUS "LLVM CXX flags: " ${LLVM_COMPILE_FLAGS})
exec_program(${LLVM_CONFIG_EXECUTABLE} ARGS --ldflags OUTPUT_VARIABLE LLVM_LDFLAGS )
MESSAGE(STATUS "LLVM LD flags: " ${LLVM_LDFLAGS})
- FIND_LLVM_LIBS( ${LLVM_CONFIG_EXECUTABLE} "core ipa ipo instrumentation bitreader bitwriter linker" LLVM_LIBS_CORE LLVM_LIBS_CORE_OBJECTS )
+ exec_program( ${LLVM_CONFIG_EXECUTABLE} ARGS --system-libs OUTPUT_VARIABLE LLVM_SYSTEM_LIBS RETURN_VALUE LLVM_SYSTEM_LIBS_FAILED)
+ if(LLVM_SYSTEM_LIBS_FAILED)
+ SET(LLVM_SYSTEM_LIBS "")
+ endif(LLVM_SYSTEM_LIBS_FAILED)
+ FIND_LLVM_LIBS( ${LLVM_CONFIG_EXECUTABLE} "core ipa ipo instrumentation bitreader bitwriter linker" LLVM_LIBS_CORE_ONLY LLVM_LIBS_CORE_OBJECTS )
+ SET(LLVM_LIBS_CORE ${LLVM_LIBS_CORE_ONLY} ${LLVM_SYSTEM_LIBS})
+ UNSET(LLVM_LIBS_CORE_ONLY)
+ UNSET(LLVM_SYSTEM_LIBS_FAILED)
MESSAGE(STATUS "LLVM core libs: " ${LLVM_LIBS_CORE})
+ IF(${LLVM_STRING_VERSION} VERSION_GREATER 3.5)
+ IF(APPLE AND UNIVERSAL)
+ FIND_LLVM_LIBS( ${LLVM_CONFIG_EXECUTABLE} "engine native x86 PowerPC ARM" LLVM_LIBS_JIT LLVM_LIBS_JIT_OBJECTS )
+ ELSE(APPLE AND UNIVERSAL)
+ FIND_LLVM_LIBS( ${LLVM_CONFIG_EXECUTABLE} "engine native" LLVM_LIBS_JIT LLVM_LIBS_JIT_OBJECTS )
+ ENDIF(APPLE AND UNIVERSAL)
+ ELSE(${LLVM_STRING_VERSION} VERSION_GREATER 3.5)
IF(APPLE AND UNIVERSAL)
FIND_LLVM_LIBS( ${LLVM_CONFIG_EXECUTABLE} "jit native x86 PowerPC ARM" LLVM_LIBS_JIT LLVM_LIBS_JIT_OBJECTS )
ELSE(APPLE AND UNIVERSAL)
FIND_LLVM_LIBS( ${LLVM_CONFIG_EXECUTABLE} "jit native" LLVM_LIBS_JIT LLVM_LIBS_JIT_OBJECTS )
ENDIF(APPLE AND UNIVERSAL)
+ ENDIF(${LLVM_STRING_VERSION} VERSION_GREATER 3.5)
MESSAGE(STATUS "LLVM JIT libs: " ${LLVM_LIBS_JIT})
MESSAGE(STATUS "LLVM JIT objs: " ${LLVM_LIBS_JIT_OBJECTS})
diff --git a/debian/control b/debian/control
index 6dfcb9b..0ef2874 100644
--- a/debian/control
+++ b/debian/control
@@ -2,7 +2,7 @@ Source: lightspark
Section: utils
Priority: optional
Maintainer: Alessandro Pignotti <a.pignotti at sssup.it>
-Build-Depends: g++ (>=4.5), gnash, cmake, cdbs, nasm, debhelper (>= 7), llvm-3.0-dev, libgl1-mesa-dev, libxext-dev, libcurl4-gnutls-dev | libcurl4-openssl-dev, libxml2-dev, zlib1g-dev, libavcodec-dev, libpcre3-dev, libglew1.5-dev, libboost-filesystem-dev, libboost-system-dev, libxml++2.6-dev (>= 2.33.1), libcairo2-dev, libgtk2.0-dev, libjpeg8-dev, libavformat-dev, libpango1.0-dev, libpulse-dev, librtmp-dev, liblzma-dev
+Build-Depends: g++ (>=4.5), gnash, cmake, cdbs, nasm, debhelper (>= 7), llvm-dev, libgl1-mesa-dev, libxext-dev, libcurl4-gnutls-dev | libcurl4-openssl-dev, libxml2-dev, zlib1g-dev, libavcodec-dev, libpcre3-dev, libglew1.5-dev, libboost-filesystem-dev, libboost-system-dev, libxml++2.6-dev (>= 2.33.1), libcairo2-dev, libgtk2.0-dev, libjpeg8-dev, libavformat-dev, libavresample-dev, libpango1.0-dev, libpulse-dev, librtmp-dev, liblzma-dev, libfreetype6-dev, libpng-dev
Standards-Version: 3.8.4
Homepage: http://lightspark.sf.net
Vcs-git: git://github.com/alexp-sssup/lightspark.git
diff --git a/docs/man/lightspark.1 b/docs/man/lightspark.1
index 83f3526..ee38e95 100644
--- a/docs/man/lightspark.1
+++ b/docs/man/lightspark.1
@@ -2,7 +2,7 @@
.\" First parameter, NAME, should be all caps
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
.\" other parameters are allowed: see man(7), man(1)
-.TH LIGHTSPARK 1 "May 29, 2010"
+.TH LIGHTSPARK 1 "November 9, 2013"
.\" Please adjust this date whenever revising the manpage.
.\"
.\" Some roff macros, for reference:
@@ -19,15 +19,15 @@
lightspark \- a free Flash player
.SH SYNOPSIS
.B lightspark
-[\-\-url|\-u http://loader.url/file.swf] [\-\-disable-interpreter|\-ni] [\-\-enable\-jit|\-j] [\-\-log\-level|\-l 0-4] [\-\-parameters\-file|\-p params-file] [\-\-version|\-v] file.swf
+[\-\-url|\-u http://loader.url/file.swf] [\-\-air] [\-\-disable-interpreter|\-ni] [\-\-enable-fast-interpreter|\-fi] [\-\-enable\-jit|\-j] [\-\-log\-level|\-l 0-4] [\-\-parameters\-file|\-p params-file] [\-\-profiling-output|\-o] [\-\-security-sandbox|\-s <sandbox type>] [\-\-exit-on-error] [\-\-HTTP-cookies <cookie>] [\-\-version|\-v] file.swf
.SH DESCRIPTION
.B Lightspark
is a free, modern Flash Player implementation, this documents the options accepted by the standalone version of the program.
.PP
.\" TeX users may be more comfortable with the \fB<whatever>\fP and
-.\" \fI<whatever>\fP escape sequences to invode bold face and italics,
+.\" \fI<whatever>\fP escape sequences to invoke bold face and italics,
.\" respectively.
-The player is currently in Beta, support for any particular SWF file is not guaranteed
+The player is currently in Beta, support for any particular SWF file is not guaranteed.
.PP
You might wish to see the project website at http://lightspark.sf.net or our
technical blog at http://allievi.sssup.it/techblog
@@ -41,6 +41,10 @@ Pretends to be loading the file from an url
.IP
Disable the ActionScript interpreter
.HP
+\fB\-\-enable-fast-interpreter\fP
+.IP
+Enable an experimental optimized ActionScript interpreter
+.HP
\fB\-\-enable-jit\fP, \fB\-j\fP
.IP
Enable the ActionScript JIT compilation engine
@@ -56,6 +60,22 @@ Load flash parameters from file. Every odd line will be interpreted as a paramet
\fB\-\-profiling-output\fP profiling-file, \fB\-o\fP profiling-file
.IP
Output profiling data to profiling-file in a callgrind/KCachegrind compatible format
+.HP
+\fB\-\-security-sandbox\fP type, \fB\-s\fP type
+.IP
+Run a Flash file in a given sandbox to control access to network and local files. The possible types are: remote (default), local-with-filesystem, local-with-networking, local-trusted.
+.HP
+\fB\-\-exit-on-error\fP
+.IP
+Exit as soon as the first error is encountered.
+.HP
+\fB\-\-HTTP-cookies\fP cookie
+.IP
+Set cookie to be used in HTTP requests.
+.HP
+\fB\-\-air\fP
+.IP
+Run as an AIR application: grant permission to access both local files and network, and enable AIR APIs.
.HP
\fB\-\-version\fP, \fB\-v\fP
.IP
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index e86fb44..2f9c824 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -47,6 +47,7 @@ SET(LIBSPARK_SOURCES
backends/rendering_context.cpp
backends/rtmputils.cpp
backends/security.cpp
+ backends/streamcache.cpp
backends/urlutils.cpp
backends/xml_support.cpp
parsing/amf3_generator.cpp
@@ -65,6 +66,8 @@ SET(LIBSPARK_SOURCES
scripting/abc_opcodes.cpp
scripting/abctypes.cpp
scripting/flash/accessibility/flashaccessibility.cpp
+ scripting/flash/concurrent/Mutex.cpp
+ scripting/flash/concurrent/Condition.cpp
scripting/flash/desktop/flashdesktop.cpp
scripting/flash/display/BitmapContainer.cpp
scripting/flash/display/BitmapData.cpp
@@ -72,22 +75,45 @@ SET(LIBSPARK_SOURCES
scripting/flash/display/IBitmapDrawable.cpp
scripting/flash/display/flashdisplay.cpp
scripting/flash/display/TokenContainer.cpp
+ scripting/flash/display/Graphics.cpp
+ scripting/flash/display/GraphicsBitmapFill.cpp
+ scripting/flash/display/GraphicsEndFill.cpp
+ scripting/flash/display/GraphicsGradientFill.cpp
+ scripting/flash/display/GraphicsPath.cpp
+ scripting/flash/display/GraphicsShaderFill.cpp
+ scripting/flash/display/GraphicsSolidFill.cpp
+ scripting/flash/display/GraphicsStroke.cpp
+ scripting/flash/display/GraphicsTrianglePath.cpp
scripting/flash/events/flashevents.cpp
scripting/flash/external/ExternalInterface.cpp
scripting/flash/filters/flashfilters.cpp
+ scripting/flash/filesystem/flashfilesystem.cpp
scripting/flash/geom/flashgeom.cpp
scripting/flash/media/flashmedia.cpp
scripting/flash/net/flashnet.cpp
scripting/flash/net/URLRequestHeader.cpp
scripting/flash/net/URLStream.cpp
scripting/flash/net/XMLSocket.cpp
+ scripting/flash/net/NetStreamPlayOptions.cpp
+ scripting/flash/net/NetStreamPlayTransitions.cpp
+ scripting/flash/printing/flashprinting.cpp
scripting/flash/errors/flasherrors.cpp
scripting/flash/sensors/flashsensors.cpp
scripting/flash/system/flashsystem.cpp
scripting/flash/text/flashtext.cpp
scripting/flash/text/flashtextengine.cpp
scripting/flash/utils/flashutils.cpp
+ scripting/flash/utils/ByteArray.cpp
+ scripting/flash/utils/Dictionary.cpp
+ scripting/flash/utils/Proxy.cpp
+ scripting/flash/utils/Timer.cpp
+ scripting/flash/utils/IntervalManager.cpp
+ scripting/flash/utils/IntervalRunner.cpp
scripting/flash/ui/Keyboard.cpp
+ scripting/flash/ui/Mouse.cpp
+ scripting/flash/ui/ContextMenu.cpp
+ scripting/flash/ui/ContextMenuItem.cpp
+ scripting/flash/ui/ContextMenuBuiltInItems.cpp
scripting/flash/xml/flashxml.cpp
scripting/toplevel/Array.cpp
scripting/toplevel/ASString.cpp
@@ -95,6 +121,7 @@ SET(LIBSPARK_SOURCES
scripting/toplevel/Date.cpp
scripting/toplevel/Error.cpp
scripting/toplevel/Integer.cpp
+ scripting/toplevel/JSON.cpp
scripting/toplevel/Math.cpp
scripting/toplevel/Number.cpp
scripting/toplevel/RegExp.cpp
diff --git a/src/allclasses.cpp b/src/allclasses.cpp
index 8b9a47c..e3c559f 100644
--- a/src/allclasses.cpp
+++ b/src/allclasses.cpp
@@ -19,24 +19,50 @@
#include "scripting/toplevel/ASString.h"
#include "scripting/toplevel/Date.h"
+#include "scripting/toplevel/JSON.h"
#include "scripting/toplevel/Math.h"
#include "scripting/toplevel/RegExp.h"
#include "scripting/toplevel/Vector.h"
#include "scripting/toplevel/XML.h"
#include "scripting/toplevel/XMLList.h"
#include "scripting/flash/accessibility/flashaccessibility.h"
+#include "scripting/flash/concurrent/Mutex.h"
+#include "scripting/flash/concurrent/Condition.h"
#include "scripting/flash/desktop/flashdesktop.h"
#include "scripting/flash/display/flashdisplay.h"
#include "scripting/flash/display/BitmapData.h"
+#include "scripting/flash/display/Graphics.h"
+#include "scripting/flash/display/GraphicsBitmapFill.h"
+#include "scripting/flash/display/GraphicsEndFill.h"
+#include "scripting/flash/display/GraphicsGradientFill.h"
+#include "scripting/flash/display/GraphicsPath.h"
+#include "scripting/flash/display/GraphicsShaderFill.h"
+#include "scripting/flash/display/GraphicsSolidFill.h"
+#include "scripting/flash/display/GraphicsStroke.h"
+#include "scripting/flash/display/GraphicsTrianglePath.h"
+#include "scripting/flash/display/IGraphicsData.h"
+#include "scripting/flash/display/IGraphicsFill.h"
+#include "scripting/flash/display/IGraphicsPath.h"
+#include "scripting/flash/display/IGraphicsStroke.h"
#include "scripting/flash/events/flashevents.h"
+#include "scripting/flash/filesystem/flashfilesystem.h"
#include "scripting/flash/filters/flashfilters.h"
#include "scripting/flash/net/flashnet.h"
#include "scripting/flash/net/URLRequestHeader.h"
#include "scripting/flash/net/URLStream.h"
#include "scripting/flash/net/XMLSocket.h"
+#include "scripting/flash/net/NetStreamPlayOptions.h"
+#include "scripting/flash/net/NetStreamPlayTransitions.h"
+#include "scripting/flash/printing/flashprinting.h"
#include "scripting/flash/system/flashsystem.h"
#include "scripting/flash/sensors/flashsensors.h"
#include "scripting/flash/utils/flashutils.h"
+#include "scripting/flash/utils/ByteArray.h"
+#include "scripting/flash/utils/Dictionary.h"
+#include "scripting/flash/utils/Proxy.h"
+#include "scripting/flash/utils/Timer.h"
+#include "scripting/flash/utils/IntervalManager.h"
+#include "scripting/flash/utils/IntervalRunner.h"
#include "scripting/flash/geom/flashgeom.h"
#include "scripting/flash/external/ExternalInterface.h"
#include "scripting/flash/media/flashmedia.h"
@@ -45,6 +71,10 @@
#include "scripting/flash/text/flashtext.h"
#include "scripting/flash/text/flashtextengine.h"
#include "scripting/flash/ui/Keyboard.h"
+#include "scripting/flash/ui/Mouse.h"
+#include "scripting/flash/ui/ContextMenu.h"
+#include "scripting/flash/ui/ContextMenuItem.h"
+#include "scripting/flash/ui/ContextMenuBuiltInItems.h"
using namespace lightspark;
diff --git a/src/allclasses.h b/src/allclasses.h
index dbb3a2c..27fc777 100644
--- a/src/allclasses.h
+++ b/src/allclasses.h
@@ -28,6 +28,7 @@ REGISTER_CLASS_NAME(Date,"")
REGISTER_CLASS_NAME2(Global,"global","")
REGISTER_CLASS_NAME2(IFunction,"Function","")
REGISTER_CLASS_NAME2(Integer,"int","")
+REGISTER_CLASS_NAME(JSON,"")
REGISTER_CLASS_NAME(Math,"")
REGISTER_CLASS_NAME(Namespace,"")
REGISTER_CLASS_NAME(Number,"")
@@ -52,9 +53,14 @@ REGISTER_CLASS_NAME(XMLList,"")
REGISTER_CLASS_NAME(Vector,"__AS3__.vec")
//Accessibility
+REGISTER_CLASS_NAME(Accessibility,"flash.accessibility")
REGISTER_CLASS_NAME(AccessibilityProperties,"flash.accessibility")
REGISTER_CLASS_NAME(AccessibilityImplementation,"flash.accessibility")
+//Concurrent
+REGISTER_CLASS_NAME(ASMutex,"flash.concurrent")
+REGISTER_CLASS_NAME(ASCondition,"flash.concurrent")
+
//Desktop (AIR)
REGISTER_CLASS_NAME(NativeApplication,"flash.desktop")
@@ -69,6 +75,20 @@ REGISTER_CLASS_NAME(DisplayObjectContainer,"flash.display")
REGISTER_CLASS_NAME(FrameLabel,"flash.display")
REGISTER_CLASS_NAME(GradientType,"flash.display")
REGISTER_CLASS_NAME(Graphics,"flash.display")
+REGISTER_CLASS_NAME(GraphicsBitmapFill,"flash.display")
+REGISTER_CLASS_NAME(GraphicsEndFill,"flash.display")
+REGISTER_CLASS_NAME(GraphicsGradientFill,"flash.display")
+REGISTER_CLASS_NAME(GraphicsPath,"flash.display")
+REGISTER_CLASS_NAME(GraphicsPathCommand,"flash.display")
+REGISTER_CLASS_NAME(GraphicsPathWinding,"flash.display")
+REGISTER_CLASS_NAME(GraphicsShaderFill,"flash.display")
+REGISTER_CLASS_NAME(GraphicsSolidFill,"flash.display")
+REGISTER_CLASS_NAME(GraphicsStroke,"flash.display")
+REGISTER_CLASS_NAME(GraphicsTrianglePath,"flash.display")
+REGISTER_CLASS_NAME(IGraphicsData,"flash.display")
+REGISTER_CLASS_NAME(IGraphicsFill,"flash.display")
+REGISTER_CLASS_NAME(IGraphicsPath,"flash.display")
+REGISTER_CLASS_NAME(IGraphicsStroke,"flash.display")
REGISTER_CLASS_NAME(IBitmapDrawable,"flash.display")
REGISTER_CLASS_NAME(InteractiveObject,"flash.display")
REGISTER_CLASS_NAME(InterpolationMethod,"flash.display")
@@ -91,6 +111,7 @@ REGISTER_CLASS_NAME(StageQuality,"flash.display")
//Events
REGISTER_CLASS_NAME(AsyncErrorEvent,"flash.events")
+REGISTER_CLASS_NAME(ContextMenuEvent,"flash.events")
REGISTER_CLASS_NAME(DRMErrorEvent,"flash.events")
REGISTER_CLASS_NAME(DRMStatusEvent,"flash.events")
REGISTER_CLASS_NAME(DataEvent,"flash.events")
@@ -100,6 +121,7 @@ REGISTER_CLASS_NAME(EventDispatcher,"flash.events")
REGISTER_CLASS_NAME(EventPhase,"flash.events")
REGISTER_CLASS_NAME(FocusEvent,"flash.events")
REGISTER_CLASS_NAME(FullScreenEvent,"flash.events")
+REGISTER_CLASS_NAME(GestureEvent,"flash.events")
REGISTER_CLASS_NAME(HTTPStatusEvent,"flash.events")
REGISTER_CLASS_NAME(IEventDispatcher,"flash.events")
REGISTER_CLASS_NAME(IOErrorEvent,"flash.events")
@@ -107,6 +129,7 @@ REGISTER_CLASS_NAME(InvokeEvent,"flash.events")
REGISTER_CLASS_NAME(KeyboardEvent,"flash.events")
REGISTER_CLASS_NAME(MouseEvent,"flash.events")
REGISTER_CLASS_NAME(NetStatusEvent,"flash.events")
+REGISTER_CLASS_NAME(PressAndTapGestureEvent,"flash.events")
REGISTER_CLASS_NAME(ProgressEvent,"flash.events")
REGISTER_CLASS_NAME(SecurityErrorEvent,"flash.events")
REGISTER_CLASS_NAME(StageVideoEvent,"flash.events")
@@ -114,14 +137,32 @@ REGISTER_CLASS_NAME(StageVideoAvailabilityEvent,"flash.events")
REGISTER_CLASS_NAME(StatusEvent,"flash.events")
REGISTER_CLASS_NAME(TextEvent,"flash.events")
REGISTER_CLASS_NAME(TimerEvent,"flash.events")
+REGISTER_CLASS_NAME(TouchEvent,"flash.events")
+REGISTER_CLASS_NAME(TransformGestureEvent,"flash.events")
+REGISTER_CLASS_NAME(UncaughtErrorEvent,"flash.events")
+REGISTER_CLASS_NAME(UncaughtErrorEvents,"flash.events")
+REGISTER_CLASS_NAME(VideoEvent,"flash.events")
//External interface (browser interaction)
REGISTER_CLASS_NAME(ExternalInterface,"flash.external")
+//filesystem
+REGISTER_CLASS_NAME(FileStream,"flash.filesystem")
+
//Filters
REGISTER_CLASS_NAME(BitmapFilter,"flash.filters")
+REGISTER_CLASS_NAME(BitmapFilterQuality,"flash.filters")
REGISTER_CLASS_NAME(DropShadowFilter,"flash.filters")
REGISTER_CLASS_NAME(GlowFilter,"flash.filters")
+REGISTER_CLASS_NAME(GradientGlowFilter,"flash.filters")
+REGISTER_CLASS_NAME(BevelFilter,"flash.filters")
+REGISTER_CLASS_NAME(ColorMatrixFilter,"flash.filters")
+REGISTER_CLASS_NAME(BlurFilter,"flash.filters")
+REGISTER_CLASS_NAME(ConvolutionFilter,"flash.filters")
+REGISTER_CLASS_NAME(DisplacementMapFilter,"flash.filters")
+REGISTER_CLASS_NAME(GradientBevelFilter,"flash.filters")
+REGISTER_CLASS_NAME(ShaderFilter,"flash.filters")
+
//Geom
REGISTER_CLASS_NAME(ColorTransform,"flash.geom")
@@ -130,6 +171,8 @@ REGISTER_CLASS_NAME(Point,"flash.geom")
REGISTER_CLASS_NAME2(Rectangle,"Rectangle","flash.geom")
REGISTER_CLASS_NAME(Transform,"flash.geom")
REGISTER_CLASS_NAME(Vector3D,"flash.geom")
+REGISTER_CLASS_NAME(Matrix3D,"flash.geom")
+REGISTER_CLASS_NAME(PerspectiveProjection,"flash.geom")
//Media
REGISTER_CLASS_NAME(Sound,"flash.media")
@@ -142,11 +185,18 @@ REGISTER_CLASS_NAME(Video,"flash.media")
REGISTER_CLASS_NAME(VideoStatus,"flash.media")
//Net
+REGISTER_CLASS_NAME(LocalConnection,"flash.net")
REGISTER_CLASS_NAME(NetConnection,"flash.net")
+REGISTER_CLASS_NAME(NetGroup,"flash.net")
REGISTER_CLASS_NAME(NetStream,"flash.net")
+REGISTER_CLASS_NAME(NetStreamAppendBytesAction,"flash.net")
+REGISTER_CLASS_NAME(NetStreamPlayTransitions,"flash.net")
+REGISTER_CLASS_NAME(NetStreamPlayOptions,"flash.net")
REGISTER_CLASS_NAME(ObjectEncoding,"flash.net")
REGISTER_CLASS_NAME(Responder,"flash.net")
REGISTER_CLASS_NAME(SharedObject,"flash.net")
+REGISTER_CLASS_NAME(SharedObjectFlushStatus,"flash.net")
+REGISTER_CLASS_NAME(ASSocket,"flash.net")
REGISTER_CLASS_NAME(URLLoader,"flash.net")
REGISTER_CLASS_NAME(URLLoaderDataFormat,"flash.net")
REGISTER_CLASS_NAME(URLRequest,"flash.net")
@@ -156,6 +206,13 @@ REGISTER_CLASS_NAME(URLStream,"flash.net")
REGISTER_CLASS_NAME(URLVariables,"flash.net")
REGISTER_CLASS_NAME(XMLSocket,"flash.net")
+REGISTER_CLASS_NAME(DRMManager,"flash.net.drm")
+
+//Printing
+REGISTER_CLASS_NAME(PrintJob,"flash.printing")
+REGISTER_CLASS_NAME(PrintJobOptions,"flash.printing")
+REGISTER_CLASS_NAME(PrintJobOrientation,"flash.printing")
+
//Errors
REGISTER_CLASS_NAME(EOFError,"flash.errors")
REGISTER_CLASS_NAME(IOError,"flash.errors")
@@ -175,6 +232,7 @@ REGISTER_CLASS_NAME(LoaderContext,"flash.system")
REGISTER_CLASS_NAME(Security,"flash.system")
REGISTER_CLASS_NAME(SecurityDomain,"flash.system")
REGISTER_CLASS_NAME(System,"flash.system")
+REGISTER_CLASS_NAME(ASWorker,"flash.system")
//Text
REGISTER_CLASS_NAME2(ASFont,"Font","flash.text")
@@ -189,18 +247,28 @@ REGISTER_CLASS_NAME(TextFieldAutoSize,"flash.text")
REGISTER_CLASS_NAME(TextFieldType,"flash.text")
REGISTER_CLASS_NAME(TextFormat,"flash.text")
REGISTER_CLASS_NAME(TextFormatAlign,"flash.text")
+REGISTER_CLASS_NAME(TextInteractionMode,"flash.text")
REGISTER_CLASS_NAME(TextLineMetrics,"flash.text")
REGISTER_CLASS_NAME(StaticText,"flash.text")
REGISTER_CLASS_NAME(StyleSheet,"flash.text")
//Text engine
REGISTER_CLASS_NAME(ContentElement,"flash.text.engine")
+REGISTER_CLASS_NAME(EastAsianJustifier,"flash.text.engine")
REGISTER_CLASS_NAME(ElementFormat,"flash.text.engine")
REGISTER_CLASS_NAME(FontDescription,"flash.text.engine")
+REGISTER_CLASS_NAME(FontMetrics,"flash.text.engine")
+REGISTER_CLASS_NAME(FontLookup,"flash.text.engine")
REGISTER_CLASS_NAME(FontWeight,"flash.text.engine")
+REGISTER_CLASS_NAME(Kerning,"flash.text.engine")
+REGISTER_CLASS_NAME(LineJustification,"flash.text.engine")
+REGISTER_CLASS_NAME(SpaceJustifier,"flash.text.engine")
+REGISTER_CLASS_NAME(TextBaseline,"flash.text.engine")
REGISTER_CLASS_NAME(TextBlock,"flash.text.engine")
REGISTER_CLASS_NAME(TextElement,"flash.text.engine")
+REGISTER_CLASS_NAME(TextJustifier,"flash.text.engine")
REGISTER_CLASS_NAME(TextLine,"flash.text.engine")
+REGISTER_CLASS_NAME(TextLineValidity,"flash.text.engine")
//Utils
REGISTER_CLASS_NAME(ByteArray,"flash.utils")
@@ -216,6 +284,10 @@ REGISTER_CLASS_NAME(Timer,"flash.utils")
REGISTER_CLASS_NAME(Keyboard,"flash.ui")
REGISTER_CLASS_NAME(KeyboardType,"flash.ui")
REGISTER_CLASS_NAME(KeyLocation,"flash.ui")
+REGISTER_CLASS_NAME(Mouse,"flash.ui")
+REGISTER_CLASS_NAME(ContextMenu,"flash.ui")
+REGISTER_CLASS_NAME(ContextMenuItem,"flash.ui")
+REGISTER_CLASS_NAME(ContextMenuBuiltInItems,"flash.ui")
//XML
REGISTER_CLASS_NAME(XMLDocument,"flash.xml")
diff --git a/src/asobject.cpp b/src/asobject.cpp
index f11f461..3253e27 100644
--- a/src/asobject.cpp
+++ b/src/asobject.cpp
@@ -24,6 +24,7 @@
#include <limits>
#include "compat.h"
#include "parsing/amf3_generator.h"
+#include "scripting/argconv.h"
#include "scripting/toplevel/ASString.h"
#include "scripting/toplevel/Date.h"
#include "scripting/toplevel/XML.h"
@@ -37,7 +38,13 @@ string ASObject::toDebugString()
{
check();
string ret;
- if(getClass())
+ if(this->is<Class_base>())
+ {
+ ret = "[class ";
+ ret+=this->as<Class_base>()->class_name.getQualifiedName().raw_buf();
+ ret+="]";
+ }
+ else if(getClass())
{
ret="[object ";
ret+=getClass()->class_name.name.raw_buf();
@@ -47,11 +54,9 @@ string ASObject::toDebugString()
ret = "Undefined";
else if(this->is<Null>())
ret = "Null";
- else if(this->is<Class_base>())
+ else if(this->is<Template_base>())
{
- ret = "[class ";
- ret+=this->as<Class_base>()->class_name.getQualifiedName().raw_buf();
- ret+="]";
+ ret = "[templated class]";
}
else
{
@@ -60,6 +65,33 @@ string ASObject::toDebugString()
return ret;
}
+void ASObject::setProxyProperty(const multiname &name)
+{
+ if (this->proxyMultiName)
+ this->proxyMultiName->ns.clear();
+ else
+ this->proxyMultiName = new (getVm()->vmDataMemory) multiname(getVm()->vmDataMemory);
+ this->proxyMultiName->isAttribute = name.isAttribute;
+ this->proxyMultiName->ns.reserve(name.ns.size());
+ for(unsigned int i=0;i<name.ns.size();i++)
+ {
+ this->proxyMultiName->ns.push_back(name.ns[i]);
+ }
+
+}
+
+void ASObject::applyProxyProperty(multiname &name)
+{
+ if (!this->proxyMultiName)
+ return;
+ name.isAttribute = this->proxyMultiName->isAttribute;
+ name.ns.clear();
+ name.ns.reserve(this->proxyMultiName->ns.size());
+ for(unsigned int i=0;i<this->proxyMultiName->ns.size();i++)
+ {
+ name.ns.push_back(this->proxyMultiName->ns[i]);
+ }
+}
tiny_string ASObject::toString()
{
check();
@@ -85,6 +117,14 @@ tiny_string ASObject::toString()
}
}
+tiny_string ASObject::toLocaleString()
+{
+ _NR<ASObject> str = executeASMethod("toLocaleString", {""}, NULL, 0);
+ if (str.isNull())
+ return "";
+ return str->toString();
+}
+
TRISTATE ASObject::isLess(ASObject* r)
{
check();
@@ -105,7 +145,7 @@ int variables_map::getNextEnumerable(unsigned int start) const
++it;
}
- while(it->second.kind!=DYNAMIC_TRAIT)
+ while(it->second.kind!=DYNAMIC_TRAIT || !it->second.isenumerable)
{
++i;
++it;
@@ -141,14 +181,15 @@ _R<ASObject> ASObject::nextValue(uint32_t index)
void ASObject::sinit(Class_base* c)
{
c->setDeclaredMethodByQName("hasOwnProperty",AS3,Class<IFunction>::getFunction(hasOwnProperty),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("setPropertyIsEnumerable",AS3,Class<IFunction>::getFunction(setPropertyIsEnumerable),NORMAL_METHOD,true);
c->prototype->setVariableByQName("toString","",Class<IFunction>::getFunction(_toString),DYNAMIC_TRAIT);
- c->prototype->setVariableByQName("toLocaleString","",Class<IFunction>::getFunction(_toString),DYNAMIC_TRAIT);
+ c->prototype->setVariableByQName("toLocaleString","",Class<IFunction>::getFunction(_toLocaleString),DYNAMIC_TRAIT);
c->prototype->setVariableByQName("valueOf","",Class<IFunction>::getFunction(valueOf),DYNAMIC_TRAIT);
c->prototype->setVariableByQName("hasOwnProperty","",Class<IFunction>::getFunction(hasOwnProperty),DYNAMIC_TRAIT);
c->prototype->setVariableByQName("isPrototypeOf","",Class<IFunction>::getFunction(isPrototypeOf),DYNAMIC_TRAIT);
c->prototype->setVariableByQName("propertyIsEnumerable","",Class<IFunction>::getFunction(propertyIsEnumerable),DYNAMIC_TRAIT);
-
+
}
void ASObject::buildTraits(ASObject* o)
@@ -166,6 +207,8 @@ bool ASObject::isEqual(ASObject* r)
{
case T_NULL:
case T_UNDEFINED:
+ if (!this->isConstructed() && !this->is<Class_base>())
+ return true;
return false;
case T_NUMBER:
case T_INTEGER:
@@ -190,6 +233,8 @@ bool ASObject::isEqual(ASObject* r)
return x->toString()==toString();
}
}
+ if (r->is<ObjectConstructor>())
+ return this == r->getClass();
LOG(LOG_CALLS,_("Equal comparison between type ")<<getObjectType()<< _(" and type ") << r->getObjectType());
if(classdef)
@@ -215,7 +260,7 @@ uint16_t ASObject::toUInt16()
int32_t ASObject::toInt()
{
- return 0;
+ return toPrimitive()->toInt();
}
/* Implements ECMA's ToPrimitive (9.1) and [[DefaultValue]] (8.6.2.6) */
@@ -328,6 +373,46 @@ _R<ASObject> ASObject::call_toString()
return _MR(ret);
}
+bool ASObject::has_toJSON()
+{
+ multiname toJSONName(NULL);
+ toJSONName.name_type=multiname::NAME_STRING;
+ toJSONName.name_s_id=getSys()->getUniqueStringId("toJSON");
+ toJSONName.ns.push_back(nsNameAndKind("",NAMESPACE));
+ toJSONName.ns.push_back(nsNameAndKind(AS3,NAMESPACE));
+ toJSONName.isAttribute = false;
+ return ASObject::hasPropertyByMultiname(toJSONName, true, true);
+}
+
+tiny_string ASObject::call_toJSON()
+{
+ multiname toJSONName(NULL);
+ toJSONName.name_type=multiname::NAME_STRING;
+ toJSONName.name_s_id=getSys()->getUniqueStringId("toJSON");
+ toJSONName.ns.push_back(nsNameAndKind("",NAMESPACE));
+ toJSONName.ns.push_back(nsNameAndKind(AS3,NAMESPACE));
+ toJSONName.isAttribute = false;
+ assert(ASObject::hasPropertyByMultiname(toJSONName, true, true));
+
+ _NR<ASObject> o=getVariableByMultiname(toJSONName,SKIP_IMPL);
+ assert_and_throw(o->is<IFunction>());
+ IFunction* f=o->as<IFunction>();
+
+ incRef();
+ ASObject *ret=f->call(this,NULL,0);
+ tiny_string res;
+ if (ret->is<ASString>())
+ {
+ res += "\"";
+ res += ret->toString();
+ res += "\"";
+ }
+ else
+ res = ret->toString();
+
+ return res;
+}
+
bool ASObject::isPrimitive() const
{
// ECMA 3, section 4.3.2, T_INTEGER and T_UINTEGER are added
@@ -336,7 +421,10 @@ bool ASObject::isPrimitive() const
type==T_STRING || type==T_BOOLEAN || type==T_INTEGER ||
type==T_UINTEGER;
}
-
+bool ASObject::isConstructed() const
+{
+ return traitsInitialized && constructIndicator;
+}
variables_map::variables_map(MemoryAccount* m):
Variables(std::less<mapType::key_type>(), reporter_allocator<mapType::value_type>(m)),slots_vars(m)
{
@@ -376,13 +464,14 @@ bool ASObject::hasPropertyByMultiname(const multiname& name, bool considerDynami
if(classdef && classdef->borrowedVariables.findObjVar(name, NO_CREATE_TRAIT, DECLARED_TRAIT)!=NULL)
return true;
+ NS_KIND nskind;
//Check prototype inheritance chain
if(getClass() && considerPrototype)
{
Prototype* proto = getClass()->prototype.getPtr();
while(proto)
{
- if(proto->getObj()->findGettable(name) != NULL)
+ if(proto->getObj()->findGettable(name,nskind) != NULL)
return true;
proto=proto->prevPrototype.getPtr();
}
@@ -470,7 +559,7 @@ bool ASObject::deleteVariableByMultiname(const multiname& name)
return true;
}
//Only dynamic traits are deletable
- if (obj->kind != DYNAMIC_TRAIT)
+ if (obj->kind != DYNAMIC_TRAIT && obj->kind != INSTANCE_TRAIT)
return false;
assert(obj->getter==NULL && obj->setter==NULL && obj->var!=NULL);
@@ -537,7 +626,20 @@ void ASObject::setVariableByMultiname(const multiname& name, ASObject* o, CONST_
}
}
- //Do not lookup in the prototype chain. This is tested behaviour
+ //Do not set variables in prototype chain. Still have to do
+ //lookup to throw a correct error in case a named function
+ //exists in prototype chain. See Tamarin test
+ //ecma3/Boolean/ecma4_sealedtype_1_rt
+ if(!obj && cls && cls->isSealed)
+ {
+ variable *protoObj = cls->findSettableInPrototype(name);
+ if (protoObj &&
+ ((protoObj->var && protoObj->var->is<Function>()) ||
+ protoObj->setter))
+ {
+ throwError<ReferenceError>(kCannotAssignToMethodError, name.normalizedName(), cls ? cls->getQualifiedClassName() : "");
+ }
+ }
if(!obj)
{
@@ -595,24 +697,26 @@ void ASObject::setVariableByQName(uint32_t nameId, const nsNameAndKind& ns, ASOb
}
void ASObject::initializeVariableByMultiname(const multiname& name, ASObject* o, multiname* typemname,
- ABCContext* context, TRAIT_KIND traitKind)
+ ABCContext* context, TRAIT_KIND traitKind, bool bOverwrite)
{
check();
-
- variable* obj=findSettable(name);
- if(obj)
+ if (!bOverwrite)
{
- //Initializing an already existing variable
- LOG(LOG_NOT_IMPLEMENTED,"Variable " << name << "already initialized");
- o->decRef();
- return;
+ variable* obj=findSettable(name);
+ if(obj)
+ {
+ //Initializing an already existing variable
+ LOG(LOG_NOT_IMPLEMENTED,"Variable " << name << " already initialized");
+ if (o != NULL)
+ o->decRef();
+ return;
+ }
}
-
- Variables.initializeVar(name, o, typemname, context, traitKind);
+ Variables.initializeVar(name, o, typemname, context, traitKind,this);
}
variable::variable(TRAIT_KIND _k, ASObject* _v, multiname* _t, const Type* _type)
- : var(_v),typeUnion(NULL),setter(NULL),getter(NULL),kind(_k),traitState(NO_STATE)
+ : var(_v),typeUnion(NULL),setter(NULL),getter(NULL),kind(_k),traitState(NO_STATE),isenumerable(true)
{
if(_type)
{
@@ -731,7 +835,7 @@ variable* variables_map::findObjVar(const multiname& mname, TRAIT_KIND createKin
return &inserted->second;
}
-const variable* variables_map::findObjVar(const multiname& mname, uint32_t traitKinds) const
+const variable* variables_map::findObjVar(const multiname& mname, uint32_t traitKinds, NS_KIND &nskind) const
{
uint32_t name=mname.normalizedNameId();
assert(!mname.ns.empty());
@@ -746,6 +850,7 @@ const variable* variables_map::findObjVar(const multiname& mname, uint32_t trait
const nsNameAndKind& ns=ret->first.ns;
if(ns==*nsIt)
{
+ nskind = ns.getImpl().kind;
if(ret->second.kind & traitKinds)
return &ret->second;
else
@@ -764,29 +869,86 @@ const variable* variables_map::findObjVar(const multiname& mname, uint32_t trait
return NULL;
}
-void variables_map::initializeVar(const multiname& mname, ASObject* obj, multiname* typemname, ABCContext* context, TRAIT_KIND traitKind)
+void variables_map::initializeVar(const multiname& mname, ASObject* obj, multiname* typemname, ABCContext* context, TRAIT_KIND traitKind, ASObject* mainObj)
{
const Type* type = NULL;
/* If typename is a builtin type, we coerce obj.
* It it's not it must be a user defined class,
- * so we only allow Null and Undefined (which are both coerced to Null) */
-
- type = Type::getBuiltinType(typemname);
+ * so we try to find the class it is derived from and create an apropriate uninitialized instance */
+ if (type == NULL)
+ type = Type::getBuiltinType(typemname);
+ if (type == NULL)
+ type = Type::getTypeFromMultiname(typemname,context);
if(type==NULL)
{
- assert_and_throw(obj->is<Null>() || obj->is<Undefined>());
- if(obj->is<Undefined>())
+ if (obj == NULL) // create dynamic object
+ {
+ obj = getSys()->getUndefinedRef();
+ }
+ else
{
- //Casting undefined to an object (of unknown class)
- //results in Null
- obj->decRef();
- obj = getSys()->getNullRef();
+ assert_and_throw(obj->is<Null>() || obj->is<Undefined>());
+ if(obj->is<Undefined>())
+ {
+ //Casting undefined to an object (of unknown class)
+ //results in Null
+ obj->decRef();
+ obj = getSys()->getNullRef();
+ }
}
}
else
- obj = type->coerce(obj);
-
- assert(traitKind==DECLARED_TRAIT || traitKind==CONSTANT_TRAIT);
+ {
+ if (obj == NULL) // create dynamic object
+ {
+ if (type == Type::anyType)
+ {
+ // type could not be found, so it's stored as an uninitialized variable
+ LOG(LOG_CALLS,"add uninitialized var:"<<mname);
+ uninitializedVar v;
+ mainObj->incRef();
+ v.mainObj = mainObj;
+ v.mname = &mname;
+ v.traitKind = traitKind;
+ v.typemname = typemname;
+ context->addUninitializedVar(v);
+ obj = getSys()->getUndefinedRef();
+ obj = type->coerce(obj);
+ }
+ else if(mainObj->is<Class_base>() &&
+ mainObj->as<Class_base>()->class_name.getQualifiedName() == typemname->qualifiedString())
+ {
+ // avoid recursive construction
+ obj = getSys()->getNullRef();
+ }
+ else if (type != Class_object::getClass() &&
+ dynamic_cast<const Class_base*>(type))
+ {
+ if (!((Class_base*)type)->super)
+ {
+ // super type could not be found, so the class is stored as an uninitialized variable
+ LOG(LOG_CALLS,"add uninitialized class var:"<<mname);
+ uninitializedVar v;
+ mainObj->incRef();
+ v.mainObj = mainObj;
+ v.mname = &mname;
+ v.traitKind = traitKind;
+ v.typemname = typemname;
+ context->addUninitializedVar(v);
+ obj = getSys()->getUndefinedRef();
+ obj = type->coerce(obj);
+ }
+ else
+ obj = ((Class_base*)type)->getInstance(false,NULL,0);
+ }
+ else
+ {
+ obj = getSys()->getUndefinedRef();
+ obj = type->coerce(obj);
+ }
+ }
+ }
+ assert(traitKind==DECLARED_TRAIT || traitKind==CONSTANT_TRAIT || traitKind == INSTANCE_TRAIT);
uint32_t name=mname.normalizedNameId();
Variables.insert(make_pair(varName(name, mname.ns[0]), variable(traitKind, obj, typemname, type)));
@@ -826,6 +988,16 @@ ASFUNCTIONBODY(ASObject,_toString)
return Class<ASString>::getInstanceS(ret);
}
+ASFUNCTIONBODY(ASObject,_toLocaleString)
+{
+ if (!obj->has_toString())
+ throwError<TypeError>(kCallNotFoundError, "toString", obj->getClassName());
+
+ _R<ASObject> res = obj->call_toString();
+ res->incRef();
+ return res.getPtr();
+}
+
ASFUNCTIONBODY(ASObject,hasOwnProperty)
{
assert_and_throw(argslen==1);
@@ -867,7 +1039,8 @@ ASFUNCTIONBODY(ASObject,isPrototypeOf)
ASFUNCTIONBODY(ASObject,propertyIsEnumerable)
{
- assert_and_throw(argslen==1);
+ if (argslen == 0)
+ return abstract_b(false);
multiname name(NULL);
name.name_type=multiname::NAME_STRING;
name.name_s_id=getSys()->getUniqueStringId(args[0]->toString());
@@ -886,16 +1059,41 @@ ASFUNCTIONBODY(ASObject,propertyIsEnumerable)
return abstract_b(true);
return abstract_b(false);
}
+ASFUNCTIONBODY(ASObject,setPropertyIsEnumerable)
+{
+ tiny_string propname;
+ bool isEnum;
+ ARG_UNPACK(propname) (isEnum, true);
+ multiname name(NULL);
+ name.name_type=multiname::NAME_STRING;
+ name.name_s_id=getSys()->getUniqueStringId(args[0]->toString());
+ name.ns.push_back(nsNameAndKind("",NAMESPACE));
+ name.isAttribute=false;
+ variable* v =obj->Variables.findObjVar(name, NO_CREATE_TRAIT,DYNAMIC_TRAIT);
+ if (v)
+ v->isenumerable = isEnum;
+ return NULL;
+}
ASFUNCTIONBODY(ASObject,_constructor)
{
return NULL;
}
+ASFUNCTIONBODY(ASObject,_constructorNotInstantiatable)
+{
+ throwError<ArgumentError>(kCantInstantiateError, obj->getClassName());
+ return NULL;
+}
+
void ASObject::initSlot(unsigned int n, const multiname& name)
{
Variables.initSlot(n,name.name_s_id,name.ns[0]);
}
+void ASObject::appendSlot(const multiname& name)
+{
+ Variables.appendSlot(name.name_s_id,name.ns[0]);
+}
int32_t ASObject::getVariableByMultiname_i(const multiname& name)
{
@@ -906,9 +1104,9 @@ int32_t ASObject::getVariableByMultiname_i(const multiname& name)
return ret->toInt();
}
-const variable* ASObject::findGettableImpl(const variables_map& map, const multiname& name)
+const variable* ASObject::findGettableImpl(const variables_map& map, const multiname& name, NS_KIND &nskind)
{
- const variable* ret=map.findObjVar(name,DECLARED_TRAIT|DYNAMIC_TRAIT);
+ const variable* ret=map.findObjVar(name,DECLARED_TRAIT|DYNAMIC_TRAIT,nskind);
if(ret)
{
//It seems valid for a class to redefine only the setter, so if we can't find
@@ -919,20 +1117,20 @@ const variable* ASObject::findGettableImpl(const variables_map& map, const multi
return ret;
}
-const variable* ASObject::findGettable(const multiname& name) const
+const variable* ASObject::findGettable(const multiname& name, NS_KIND &nskind) const
{
- return findGettableImpl(Variables,name);
+ return findGettableImpl(Variables,name,nskind);
}
-const variable* ASObject::findVariableByMultiname(const multiname& name, GET_VARIABLE_OPTION opt, Class_base* cls)
+const variable* ASObject::findVariableByMultiname(const multiname& name, GET_VARIABLE_OPTION opt, Class_base* cls, NS_KIND &nskind)
{
//Get from the current object without considering borrowed properties
- const variable* var=findGettable(name);
+ const variable* var=findGettable(name,nskind);
if(!var && cls)
{
//Look for borrowed traits before
- var=cls->findBorrowedGettable(name);
+ var=cls->findBorrowedGettable(name,nskind);
}
if(!var && cls)
@@ -941,7 +1139,7 @@ const variable* ASObject::findVariableByMultiname(const multiname& name, GET_VAR
Prototype* proto = cls->prototype.getPtr();
while(proto)
{
- var = proto->getObj()->findGettable(name);
+ var = proto->getObj()->findGettable(name,nskind);
if(var)
break;
proto = proto->prevPrototype.getPtr();
@@ -954,10 +1152,24 @@ _NR<ASObject> ASObject::getVariableByMultiname(const multiname& name, GET_VARIAB
{
check();
assert(!cls || classdef->isSubClass(cls));
- const variable* obj=findVariableByMultiname(name, opt, cls);
+ NS_KIND nskind;
+ const variable* obj=findVariableByMultiname(name, opt, cls,nskind);
if(!obj)
return NullRef;
+ if (this->is<Class_base>() &&
+ (!obj->var ||
+ (obj->var->getObjectType() != T_UNDEFINED &&
+ obj->var->getObjectType() != T_NULL &&
+ obj->var->getObjectType() != T_FUNCTION )))
+ {
+ LOG(LOG_CALLS,"accessing class:"<<name<<" "<< this->as<Class_base>()->getQualifiedClassName()<<" "<<nskind);
+ if (obj->kind == INSTANCE_TRAIT &&
+ nskind != NAMESPACE &&
+ nskind != PACKAGE_INTERNAL_NAMESPACE &&
+ nskind != STATIC_PROTECTED_NAMESPACE)
+ throwError<TypeError>(kCallOfNonFunctionError,name.normalizedName());
+ }
if(obj->getter)
{
@@ -1080,6 +1292,9 @@ void variables_map::dumpVariables()
case CONSTANT_TRAIT:
kind="Declared: ";
break;
+ case INSTANCE_TRAIT:
+ kind="Declared (instance)";
+ break;
case DYNAMIC_TRAIT:
kind="Dynamic: ";
break;
@@ -1112,8 +1327,8 @@ void variables_map::destroyContents()
Variables.clear();
}
-ASObject::ASObject(MemoryAccount* m):Variables(m),classdef(NULL),
- type(T_OBJECT),traitsInitialized(false),implEnable(true)
+ASObject::ASObject(MemoryAccount* m):Variables(m),classdef(NULL),proxyMultiName(NULL),
+ type(T_OBJECT),traitsInitialized(false),constructIndicator(false),implEnable(true)
{
#ifndef NDEBUG
//Stuff only used in debugging
@@ -1121,8 +1336,8 @@ ASObject::ASObject(MemoryAccount* m):Variables(m),classdef(NULL),
#endif
}
-ASObject::ASObject(Class_base* c):Variables((c)?c->memoryAccount:NULL),classdef(NULL),
- type(T_OBJECT),traitsInitialized(false),implEnable(true)
+ASObject::ASObject(Class_base* c):Variables((c)?c->memoryAccount:NULL),classdef(NULL),proxyMultiName(NULL),
+ type(T_OBJECT),traitsInitialized(false),constructIndicator(false),implEnable(true)
{
setClass(c);
#ifndef NDEBUG
@@ -1131,8 +1346,8 @@ ASObject::ASObject(Class_base* c):Variables((c)?c->memoryAccount:NULL),classdef(
#endif
}
-ASObject::ASObject(const ASObject& o):Variables((o.classdef)?o.classdef->memoryAccount:NULL),classdef(NULL),
- type(o.type),traitsInitialized(false),implEnable(true)
+ASObject::ASObject(const ASObject& o):Variables((o.classdef)?o.classdef->memoryAccount:NULL),classdef(NULL),proxyMultiName(NULL),
+ type(o.type),traitsInitialized(false),constructIndicator(false),implEnable(true)
{
if(o.classdef)
setClass(o.classdef);
@@ -1169,6 +1384,9 @@ void ASObject::finalize()
classdef->decRef();
classdef=NULL;
}
+ if (proxyMultiName)
+ delete proxyMultiName;
+ proxyMultiName = NULL;
}
ASObject::~ASObject()
@@ -1446,6 +1664,139 @@ ASObject *ASObject::describeType() const
return Class<XML>::getInstanceS(root);
}
+tiny_string ASObject::toJSON(std::vector<ASObject *> &path, IFunction *replacer, const tiny_string &spaces,const tiny_string& filter)
+{
+ if (has_toJSON())
+ {
+ return call_toJSON();
+ }
+
+ tiny_string newline = (spaces.empty() ? "" : "\n");
+ tiny_string res;
+ if (this->isPrimitive())
+ {
+ switch(this->type)
+ {
+ case T_STRING:
+ {
+ res += "\"";
+ tiny_string sub = this->toString();
+ for (CharIterator it=sub.begin(); it!=sub.end(); it++)
+ {
+ switch (*it)
+ {
+ case '\b':
+ res += "\\b";
+ break;
+ case '\f':
+ res += "\\f";
+ break;
+ case '\n':
+ res += "\\n";
+ break;
+ case '\r':
+ res += "\\r";
+ break;
+ case '\t':
+ res += "\\t";
+ break;
+ case '\"':
+ res += "\\\"";
+ break;
+ case '\\':
+ res += "\\\\";
+ break;
+ default:
+ if (*it < 0x20 || *it > 0xff)
+ {
+ char hexstr[7];
+ sprintf(hexstr,"\\u%04x",*it);
+ res += hexstr;
+ }
+ else
+ res += *it;
+ break;
+ }
+ }
+ res += "\"";
+ break;
+ }
+ case T_UNDEFINED:
+ res += "null";
+ break;
+ default:
+ res += this->toString();
+ break;
+ }
+ }
+ else
+ {
+ res += "{";
+ const variables_map::const_var_iterator beginIt = Variables.Variables.begin();
+ const variables_map::const_var_iterator endIt = Variables.Variables.end();
+ bool bfirst = true;
+ for(variables_map::const_var_iterator varIt=beginIt; varIt != endIt; ++varIt)
+ {
+ // check for cylic reference
+ if (varIt->second.var->getObjectType() != T_UNDEFINED &&
+ varIt->second.var->getObjectType() != T_NULL &&
+ varIt->second.var->getObjectType() != T_BOOLEAN &&
+ (varIt->second.var == this ||
+ std::find(path.begin(),path.end(), varIt->second.var) != path.end() ||
+ std::find(path.begin(),path.end(), this) != path.end() ))
+ throwError<TypeError>(kJSONCyclicStructure);
+
+ if (replacer != NULL)
+ {
+ if (!bfirst)
+ res += ",";
+ res += newline+spaces;
+ res += "\"";
+ res += getSys()->getStringFromUniqueId(varIt->first.nameId);
+ res += "\"";
+ res += ":";
+ if (!spaces.empty())
+ res += " ";
+ ASObject* params[2];
+
+ params[0] = Class<ASString>::getInstanceS(getSys()->getStringFromUniqueId(varIt->first.nameId));
+ params[1] = varIt->second.var;
+ params[1]->incRef();
+ ASObject *funcret=replacer->call(getSys()->getNullRef(), params, 2);
+ LOG(LOG_ERROR,"funcall:"<<res<<"|"<<funcret);
+ if (funcret)
+ res += funcret->toString();
+ else
+ res += varIt->second.var->toJSON(path,replacer,spaces+spaces,filter);
+ bfirst = false;
+ }
+ else if (filter.empty() || filter.find(tiny_string(" ")+getSys()->getStringFromUniqueId(varIt->first.nameId)+" ") != tiny_string::npos)
+ {
+ if (!bfirst)
+ res += ",";
+ res += newline+spaces;
+ res += "\"";
+ res += getSys()->getStringFromUniqueId(varIt->first.nameId);
+ res += "\"";
+ res += ":";
+ if (!spaces.empty())
+ res += " ";
+ res += varIt->second.var->toJSON(path,replacer,spaces+spaces,filter);
+ bfirst = false;
+ }
+ if (varIt->second.var->getObjectType() != T_UNDEFINED &&
+ varIt->second.var->getObjectType() != T_NULL &&
+ varIt->second.var->getObjectType() != T_BOOLEAN)
+ path.push_back(varIt->second.var);
+ }
+ if (!bfirst)
+ res += newline+spaces.substr_bytes(0,spaces.numBytes()/2);
+
+ res += "}";
+ }
+ return res;
+}
+
bool ASObject::hasprop_prototype()
{
variable* var=Variables.findObjVar(BUILTIN_STRINGS::PROTOTYPE,nsNameAndKind(BUILTIN_NAMESPACES::EMPTY_NS),
@@ -1491,7 +1842,7 @@ void ASObject::setprop_prototype(_NR<ASObject>& o)
ret->setVar(obj);
}
-tiny_string ASObject::getClassName()
+tiny_string ASObject::getClassName() const
{
if (getClass())
return getClass()->getQualifiedClassName();
diff --git a/src/asobject.h b/src/asobject.h
index 2064223..958007a 100644
--- a/src/asobject.h
+++ b/src/asobject.h
@@ -122,6 +122,25 @@
REGISTER_GETTER(c,name); \
REGISTER_SETTER(c,name)
+#define CLASS_DYNAMIC_NOT_FINAL 0
+#define CLASS_FINAL 1
+#define CLASS_SEALED 2
+
+// TODO: Every class should have a constructor
+#define CLASS_SETUP_NO_CONSTRUCTOR(c, superClass, attributes) \
+ c->setSuper(Class<superClass>::getRef()); \
+ c->setConstructor(NULL); \
+ c->isFinal = ((attributes) & CLASS_FINAL) != 0; \
+ c->isSealed = ((attributes) & CLASS_SEALED) != 0
+
+#define CLASS_SETUP(c, superClass, constructor, attributes) \
+ CLASS_SETUP_NO_CONSTRUCTOR(c, superClass, attributes); \
+ c->setConstructor(Class<IFunction>::getFunction(constructor));
+
+#define CLASS_SETUP_CONSTRUCTOR_LENGTH(c, superClass, constructor, ctorlength, attributes) \
+ CLASS_SETUP_NO_CONSTRUCTOR(c, superClass, attributes); \
+ c->setConstructor(Class<IFunction>::getFunction((constructor), (ctorlength)));
+
namespace lightspark
{
@@ -134,7 +153,7 @@ class Loader;
class Type;
class ABCContext;
-enum TRAIT_KIND { NO_CREATE_TRAIT=0, DECLARED_TRAIT=1, DYNAMIC_TRAIT=2, CONSTANT_TRAIT=9 /* constants are also declared traits */ };
+enum TRAIT_KIND { NO_CREATE_TRAIT=0, DECLARED_TRAIT=1, DYNAMIC_TRAIT=2, INSTANCE_TRAIT=5, CONSTANT_TRAIT=9 /* constants are also declared traits */ };
enum TRAIT_STATE { NO_STATE=0, HAS_GETTER_SETTER=1, TYPE_RESOLVED=2 };
struct variable
@@ -150,8 +169,9 @@ struct variable
IFunction* getter;
TRAIT_KIND kind;
TRAIT_STATE traitState;
+ bool isenumerable:1;
variable(TRAIT_KIND _k)
- : var(NULL),typeUnion(NULL),setter(NULL),getter(NULL),kind(_k),traitState(NO_STATE) {}
+ : var(NULL),typeUnion(NULL),setter(NULL),getter(NULL),kind(_k),traitState(NO_STATE),isenumerable(true) {}
variable(TRAIT_KIND _k, ASObject* _v, multiname* _t, const Type* type);
void setVar(ASObject* v);
/*
@@ -201,9 +221,9 @@ public:
/**
* Const version of findObjVar, useful when looking for getters
*/
- const variable* findObjVar(const multiname& mname, uint32_t traitKinds) const;
+ const variable* findObjVar(const multiname& mname, uint32_t traitKinds, NS_KIND &nskind) const;
//Initialize a new variable specifying the type (TODO: add support for const)
- void initializeVar(const multiname& mname, ASObject* obj, multiname* typemname, ABCContext* context, TRAIT_KIND traitKind);
+ void initializeVar(const multiname& mname, ASObject* obj, multiname *typemname, ABCContext* context, TRAIT_KIND traitKind, ASObject* mainObj);
void killObjVar(const multiname& mname);
ASObject* getSlot(unsigned int n)
{
@@ -221,6 +241,10 @@ public:
*/
void setSlotNoCoerce(unsigned int n,ASObject* o);
void initSlot(unsigned int n, uint32_t nameId, const nsNameAndKind& ns);
+ void appendSlot(uint32_t nameId, const nsNameAndKind& ns)
+ {
+ initSlot(slots_vars.size()+1, nameId, ns);
+ }
int size() const
{
return Variables.size();
@@ -251,20 +275,22 @@ friend class IFunction; //Needed for clone
private:
variables_map Variables;
Class_base* classdef;
- const variable* findGettable(const multiname& name) const DLL_LOCAL;
+ const variable* findGettable(const multiname& name, NS_KIND &nskind) const DLL_LOCAL;
variable* findSettable(const multiname& name, bool* has_getter=NULL) DLL_LOCAL;
+ multiname* proxyMultiName;
protected:
ASObject(MemoryAccount* m);
ASObject(const ASObject& o);
virtual ~ASObject();
SWFOBJECT_TYPE type;
bool traitsInitialized:1;
+ bool constructIndicator:1;
void serializeDynamicProperties(ByteArray* out, std::map<tiny_string, uint32_t>& stringMap,
std::map<const ASObject*, uint32_t>& objMap,
std::map<const Class_base*, uint32_t> traitsMap) const;
void setClass(Class_base* c);
static variable* findSettableImpl(variables_map& map, const multiname& name, bool* has_getter);
- static const variable* findGettableImpl(const variables_map& map, const multiname& name);
+ static const variable* findGettableImpl(const variables_map& map, const multiname& name, NS_KIND &nskind);
public:
ASObject(Class_base* c);
#ifndef NDEBUG
@@ -274,11 +300,16 @@ public:
bool implEnable:1;
Class_base* getClass() const { return classdef; }
ASFUNCTION(_constructor);
+ // constructor for subclasses that can't be instantiated.
+ // Throws ArgumentError.
+ ASFUNCTION(_constructorNotInstantiatable);
ASFUNCTION(_toString);
+ ASFUNCTION(_toLocaleString);
ASFUNCTION(hasOwnProperty);
ASFUNCTION(valueOf);
ASFUNCTION(isPrototypeOf);
ASFUNCTION(propertyIsEnumerable);
+ ASFUNCTION(setPropertyIsEnumerable);
void check() const;
static void s_incRef(ASObject* o)
{
@@ -313,7 +344,7 @@ public:
* Helper method using the get the raw variable struct instead of calling the getter.
* It is used by getVariableByMultiname and by early binding code
*/
- const variable* findVariableByMultiname(const multiname& name, GET_VARIABLE_OPTION opt, Class_base* cls);
+ const variable* findVariableByMultiname(const multiname& name, GET_VARIABLE_OPTION opt, Class_base* cls, NS_KIND &nskind);
/*
* Gets a variable of this object. It looks through all classes (beginning at cls),
* then the prototype chain, and then instance variables.
@@ -348,7 +379,7 @@ public:
* Called by ABCVm::buildTraits to create DECLARED_TRAIT or CONSTANT_TRAIT and set their type
*/
void initializeVariableByMultiname(const multiname& name, ASObject* o, multiname* typemname,
- ABCContext* context, TRAIT_KIND traitKind);
+ ABCContext* context, TRAIT_KIND traitKind,bool bOverwrite);
/*
* Called by ABCVm::initProperty (implementation of ABC instruction), it is allowed to set CONSTANT_TRAIT
*/
@@ -375,6 +406,7 @@ public:
Variables.setSlotNoCoerce(n,o);
}
void initSlot(unsigned int n, const multiname& name);
+ void appendSlot(const multiname& name);
unsigned int numVariables() const;
tiny_string getNameAt(int i) const
{
@@ -387,6 +419,7 @@ public:
}
/* Implements ECMA's 9.8 ToString operation, but returns the concrete value */
tiny_string toString();
+ tiny_string toLocaleString();
virtual int32_t toInt();
virtual uint32_t toUInt();
uint16_t toUInt16();
@@ -396,6 +429,9 @@ public:
_R<ASObject> toPrimitive(TP_HINT hint = NO_HINT);
bool isPrimitive() const;
+ bool isInitialized() const {return traitsInitialized;}
+ virtual bool isConstructed() const;
+
/* helper functions for calling the "valueOf" and
* "toString" AS-functions which may be members of this
* object */
@@ -403,9 +439,11 @@ public:
_R<ASObject> call_valueOf();
bool has_toString();
_R<ASObject> call_toString();
+ bool has_toJSON();
+ tiny_string call_toJSON();
/* Helper function for calling getClass()->getQualifiedClassName() */
- virtual tiny_string getClassName();
+ virtual tiny_string getClassName() const;
ASFUNCTION(generator);
@@ -441,6 +479,7 @@ public:
virtual ASObject *describeType() const;
+ virtual tiny_string toJSON(std::vector<ASObject *> &path, IFunction *replacer, const tiny_string &spaces,const tiny_string& filter);
/* returns true if the current object is of type T */
template<class T> bool is() const { return dynamic_cast<const T*>(this); }
/* returns this object casted to the given type.
@@ -451,6 +490,15 @@ public:
/* Returns a debug string identifying this object */
virtual std::string toDebugString();
+
+ /* stores proxy namespace settings for internal usage */
+ void setProxyProperty(const multiname& name);
+ /* applies proxy namespace settings to name for internal usage */
+ void applyProxyProperty(multiname &name);
+
+ void dumpVariables() { Variables.dumpVariables(); }
+
+ void setConstructIndicator() { constructIndicator = true; }
};
class Number;
diff --git a/src/backends/decoder.cpp b/src/backends/decoder.cpp
index 18e72e0..3c360d4 100755
--- a/src/backends/decoder.cpp
+++ b/src/backends/decoder.cpp
@@ -295,6 +295,8 @@ bool FFMpegVideoDecoder::decodePacket(AVPacket* pkt, uint32_t time)
#else
int ret=avcodec_decode_video(codecContext, frameIn, &frameOk, pkt->data, pkt->size);
#endif
+ if (ret < 0)
+ return false;
assert_and_throw(ret==(int)pkt->size);
if(frameOk)
@@ -451,19 +453,7 @@ void AudioDecoder::skipAll()
#ifdef ENABLE_LIBAVCODEC
FFMpegAudioDecoder::FFMpegAudioDecoder(LS_AUDIO_CODEC audioCodec, uint8_t* initdata, uint32_t datalen):ownedContext(true)
{
- CodecID codecId;
- switch(audioCodec)
- {
- case AAC:
- codecId=CODEC_ID_AAC;
- break;
- case MP3:
- codecId=CODEC_ID_MP3;
- break;
- default:
- ::abort();
- }
- AVCodec* codec=avcodec_find_decoder(codecId);
+ AVCodec* codec=avcodec_find_decoder(LSToFFMpegCodec(audioCodec));
assert(codec);
codecContext=avcodec_alloc_context3(codec);
@@ -490,7 +480,33 @@ FFMpegAudioDecoder::FFMpegAudioDecoder(LS_AUDIO_CODEC audioCodec, uint8_t* initd
#endif
}
-FFMpegAudioDecoder::FFMpegAudioDecoder(AVCodecContext* _c):codecContext(_c)
+FFMpegAudioDecoder::FFMpegAudioDecoder(LS_AUDIO_CODEC lscodec, int sampleRate, int channels, bool):ownedContext(true)
+{
+ status=INIT;
+
+ CodecID codecId = LSToFFMpegCodec(lscodec);
+ AVCodec* codec=avcodec_find_decoder(codecId);
+ assert(codec);
+ codecContext=avcodec_alloc_context3(codec);
+ codecContext->codec_id = codecId;
+ codecContext->sample_rate = sampleRate;
+ codecContext->channels = channels;
+
+#ifdef HAVE_AVCODEC_OPEN2
+ if(avcodec_open2(codecContext, codec, NULL)<0)
+#else
+ if(avcodec_open(codecContext, codec)<0)
+#endif //HAVE_AVCODEC_ALLOC_CONTEXT3
+ return;
+
+ if(fillDataAndCheckValidity())
+ status=VALID;
+#if HAVE_AVCODEC_DECODE_AUDIO4
+ frameIn=avcodec_alloc_frame();
+#endif
+}
+
+FFMpegAudioDecoder::FFMpegAudioDecoder(AVCodecContext* _c):ownedContext(false),codecContext(_c)
{
status=INIT;
AVCodec* codec=avcodec_find_decoder(codecContext->codec_id);
@@ -520,6 +536,21 @@ FFMpegAudioDecoder::~FFMpegAudioDecoder()
#endif
}
+CodecID FFMpegAudioDecoder::LSToFFMpegCodec(LS_AUDIO_CODEC LSCodec)
+{
+ switch(LSCodec)
+ {
+ case AAC:
+ return CODEC_ID_AAC;
+ case MP3:
+ return CODEC_ID_MP3;
+ case ADPCM:
+ return CODEC_ID_ADPCM_SWF;
+ default:
+ return CODEC_ID_NONE;
+ }
+}
+
bool FFMpegAudioDecoder::fillDataAndCheckValidity()
{
if(codecContext->sample_rate!=0)
@@ -556,8 +587,25 @@ uint32_t FFMpegAudioDecoder::decodeData(uint8_t* data, int32_t datalen, uint32_t
#if HAVE_AVCODEC_DECODE_AUDIO3 || HAVE_AVCODEC_DECODE_AUDIO4
AVPacket pkt;
av_init_packet(&pkt);
- pkt.data=data;
- pkt.size=datalen;
+
+ // If some data was left unprocessed on previous call,
+ // concatenate.
+ std::vector<uint8_t> combinedBuffer;
+ if (overflowBuffer.empty())
+ {
+ pkt.data=data;
+ pkt.size=datalen;
+ }
+ else
+ {
+ combinedBuffer.assign(overflowBuffer.begin(), overflowBuffer.end());
+ if (datalen > 0)
+ combinedBuffer.insert(combinedBuffer.end(), data, data+datalen);
+ pkt.data = &combinedBuffer[0];
+ pkt.size = combinedBuffer.size();
+ overflowBuffer.clear();
+ }
+
#if HAVE_AVCODEC_DECODE_AUDIO4
avcodec_get_frame_defaults(frameIn);
int frameOk=0;
@@ -566,21 +614,36 @@ uint32_t FFMpegAudioDecoder::decodeData(uint8_t* data, int32_t datalen, uint32_t
ret=-1;
else
{
- //This is suboptimal but equivalent to what libavcodec
- //does for the compatibility version of avcodec_decode_audio3
- memcpy(curTail.samples, frameIn->extended_data[0], frameIn->linesize[0]);
- maxLen=frameIn->linesize[0];
+ if (frameIn->format != AV_SAMPLE_FMT_S16)
+ {
+ maxLen = resampleFrameToS16(curTail);
+ }
+ else
+ {
+ //This is suboptimal but equivalent to what libavcodec
+ //does for the compatibility version of avcodec_decode_audio3
+ memcpy(curTail.samples, frameIn->extended_data[0], frameIn->linesize[0]);
+ maxLen=frameIn->linesize[0];
+ }
}
#else
int32_t ret=avcodec_decode_audio3(codecContext, curTail.samples, &maxLen, &pkt);
#endif
+
+ if (ret > 0)
+ {
+ pkt.data += ret;
+ pkt.size -= ret;
+
+ if (pkt.size > 0)
+ {
+ overflowBuffer.assign(pkt.data, pkt.data+pkt.size);
+ }
+ }
+
#else
int32_t ret=avcodec_decode_audio2(codecContext, curTail.samples, &maxLen, data, datalen);
#endif
- assert_and_throw(ret==datalen);
-
- if(status==INIT && fillDataAndCheckValidity())
- status=VALID;
curTail.len=maxLen;
assert(!(curTail.len&0x80000000));
@@ -588,6 +651,10 @@ uint32_t FFMpegAudioDecoder::decodeData(uint8_t* data, int32_t datalen, uint32_t
curTail.current=curTail.samples;
curTail.time=time;
samplesBuffer.commitLast();
+
+ if(status==INIT && fillDataAndCheckValidity())
+ status=VALID;
+
return maxLen;
}
@@ -604,10 +671,17 @@ uint32_t FFMpegAudioDecoder::decodePacket(AVPacket* pkt, uint32_t time)
ret=-1;
else
{
- //This is suboptimal but equivalent to what libavcodec
- //does for the compatibility version of avcodec_decode_audio3
- memcpy(curTail.samples, frameIn->extended_data[0], frameIn->linesize[0]);
- maxLen=frameIn->linesize[0];
+ if (frameIn->format != AV_SAMPLE_FMT_S16)
+ {
+ maxLen = resampleFrameToS16(curTail);
+ }
+ else
+ {
+ //This is suboptimal but equivalent to what libavcodec
+ //does for the compatibility version of avcodec_decode_audio3
+ memcpy(curTail.samples, frameIn->extended_data[0], frameIn->linesize[0]);
+ maxLen=frameIn->linesize[0];
+ }
}
#elif HAVE_AVCODEC_DECODE_AUDIO3
int ret=avcodec_decode_audio3(codecContext, curTail.samples, &maxLen, pkt);
@@ -639,6 +713,61 @@ uint32_t FFMpegAudioDecoder::decodePacket(AVPacket* pkt, uint32_t time)
samplesBuffer.commitLast();
return maxLen;
}
+#if HAVE_AVCODEC_DECODE_AUDIO4
+int FFMpegAudioDecoder::resampleFrameToS16(FrameSamples& curTail)
+{
+ int maxLen;
+#ifdef HAVE_LIBAVRESAMPLE
+ AVAudioResampleContext * avr = avresample_alloc_context();
+ av_opt_set_int(avr, "in_channel_layout", frameIn->channel_layout, 0);
+ av_opt_set_int(avr, "out_channel_layout", frameIn->channel_layout, 0);
+ av_opt_set_int(avr, "in_sample_rate", frameIn->sample_rate, 0);
+ av_opt_set_int(avr, "out_sample_rate", frameIn->sample_rate, 0);
+ av_opt_set_int(avr, "in_sample_fmt", frameIn->format, 0);
+ av_opt_set_int(avr, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);
+ avresample_open(avr);
+
+ uint8_t *output;
+ int out_linesize;
+ int out_samples = avresample_available(avr) + av_rescale_rnd(avresample_get_delay(avr) + frameIn->linesize[0], frameIn->sample_rate, frameIn->sample_rate, AV_ROUND_UP);
+ av_samples_alloc(&output, &out_linesize, frameIn->nb_samples, out_samples, AV_SAMPLE_FMT_S16, 0);
+ maxLen = avresample_convert(avr, &output, out_linesize, out_samples, frameIn->extended_data, frameIn->linesize[0], frameIn->nb_samples)*4;
+ memcpy(curTail.samples, output, maxLen);
+ av_freep(&output);
+ avresample_free(&avr);
+#else
+ LOG(LOG_ERROR, "unexpected sample format and can't resample, recompile with libavresample");
+ memset(curTail.samples, 0, frameIn->linesize[0]);
+ maxLen = frameIn->linesize[0];
+#endif
+ return maxLen;
+}
+#endif
+
+uint32_t FFMpegAudioDecoder::decodeStreamSomePackets(std::istream& s, uint32_t time)
+{
+ const size_t BUF_SIZE = 4096;
+ uint32_t ret;
+ uint8_t inbuf[BUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
+ s.read((char*)inbuf, BUF_SIZE);
+ if (s.gcount() == 0)
+ return 0;
+
+ ret = decodeData(inbuf, s.gcount(), time);
+
+ // Keep the overflowBuffer from growing without bounds
+ size_t overflowSize = overflowBuffer.size();
+ while (overflowSize > BUF_SIZE)
+ {
+ ret = decodeData(NULL, 0, time);
+ if (overflowBuffer.size() == overflowSize)
+ break;
+ overflowSize = overflowBuffer.size();
+ }
+
+ return ret;
+}
+
#endif //ENABLE_LIBAVCODEC
StreamDecoder::~StreamDecoder()
@@ -721,7 +850,13 @@ FFMpegStreamDecoder::FFMpegStreamDecoder(std::istream& s)
if(videoFound)
{
//Pass the frame rate from the container, the once from the codec is often wrong
- double frameRate=av_q2d(formatCtx->streams[videoIndex]->r_frame_rate);
+ AVStream *stream = formatCtx->streams[videoIndex];
+#if LIBAVUTIL_VERSION_MAJOR < 54
+ AVRational rateRational = stream->r_frame_rate;
+#else
+ AVRational rateRational = stream->avg_frame_rate;
+#endif
+ double frameRate=av_q2d(rateRational);
customVideoDecoder=new FFMpegVideoDecoder(formatCtx->streams[videoIndex]->codec,frameRate);
videoDecoder=customVideoDecoder;
}
diff --git a/src/backends/decoder.h b/src/backends/decoder.h
index cddf058..2abbcbe 100644
--- a/src/backends/decoder.h
+++ b/src/backends/decoder.h
@@ -28,6 +28,24 @@ extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
+#ifdef HAVE_LIBAVRESAMPLE
+#include <libavresample/avresample.h>
+#endif
+#include <libavutil/opt.h>
+#include <libavutil/mathematics.h>
+#ifndef AVCODEC_MAX_AUDIO_FRAME_SIZE
+#define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audio
+#endif
+#ifdef HAVE_AVCODECID
+#define CodecID AVCodecID
+#define CODEC_ID_NONE AV_CODEC_ID_NONE
+#define CODEC_ID_H264 AV_CODEC_ID_H264
+#define CODEC_ID_FLV1 AV_CODEC_ID_FLV1
+#define CODEC_ID_VP6F AV_CODEC_ID_VP6F
+#define CODEC_ID_AAC AV_CODEC_ID_AAC
+#define CODEC_ID_MP3 AV_CODEC_ID_MP3
+#define CODEC_ID_ADPCM_SWF AV_CODEC_ID_ADPCM_SWF
+#endif
#define MAX_AUDIO_FRAME_SIZE AVCODEC_MAX_AUDIO_FRAME_SIZE
}
#else
@@ -40,7 +58,8 @@ namespace lightspark
{
enum LS_VIDEO_CODEC { H264=0, H263, VP6 };
-enum LS_AUDIO_CODEC { LINEAR_PCM_PLATFORM_ENDIAN=0, ADPCM=1, MP3=2, LINEAR_PCM_LE=3, AAC=10 };
+// "Audio coding formats" from Chapter 11 in SWF documentation
+enum LS_AUDIO_CODEC { CODEC_NONE=-1, LINEAR_PCM_PLATFORM_ENDIAN=0, ADPCM=1, MP3=2, LINEAR_PCM_LE=3, AAC=10 };
class Decoder
{
@@ -277,12 +296,16 @@ class FFMpegAudioDecoder: public AudioDecoder
private:
bool ownedContext;
AVCodecContext* codecContext;
+ std::vector<uint8_t> overflowBuffer;
bool fillDataAndCheckValidity();
+ CodecID LSToFFMpegCodec(LS_AUDIO_CODEC lscodec);
#if HAVE_AVCODEC_DECODE_AUDIO4
AVFrame* frameIn;
+ int resampleFrameToS16(FrameSamples& curTail);
#endif
public:
FFMpegAudioDecoder(LS_AUDIO_CODEC codec, uint8_t* initdata, uint32_t datalen);
+ FFMpegAudioDecoder(LS_AUDIO_CODEC codec, int sampleRate, int channels, bool);
/*
Specialized constructor used by FFMpegStreamDecoder
*/
@@ -293,6 +316,7 @@ public:
*/
uint32_t decodePacket(AVPacket* pkt, uint32_t time);
uint32_t decodeData(uint8_t* data, int32_t datalen, uint32_t time);
+ uint32_t decodeStreamSomePackets(std::istream& s, uint32_t time);
};
#endif
diff --git a/src/backends/graphics.cpp b/src/backends/graphics.cpp
index b8a79a2..f6ac15c 100644
--- a/src/backends/graphics.cpp
+++ b/src/backends/graphics.cpp
@@ -458,10 +458,20 @@ bool CairoTokenRenderer::cairoPathFromTokens(cairo_t* cr, const std::vector<Geom
cairo_stroke(stroke_cr);
const LINESTYLE2& style = tokens[i].lineStyle;
- const RGBA& color = style.Color;
cairo_set_operator(stroke_cr, CAIRO_OPERATOR_OVER);
- cairo_set_source_rgba(stroke_cr, color.rf(), color.gf(), color.bf(), color.af());
+ if (style.HasFillFlag)
+ {
+ cairo_pattern_t* pattern = FILLSTYLEToCairo(style.FillType, scaleCorrection);
+ if (pattern)
+ {
+ cairo_set_source(stroke_cr, pattern);
+ cairo_pattern_destroy(pattern);
+ }
+ } else {
+ const RGBA& color = style.Color;
+ cairo_set_source_rgba(stroke_cr, color.rf(), color.gf(), color.bf(), color.af());
+ }
// TODO: EndCapStyle
if (style.StartCapStyle == 0)
@@ -838,12 +848,6 @@ void CairoPangoRenderer::pangoLayoutFromData(PangoLayout* layout, const TextData
pango_layout_set_width(layout,PANGO_SCALE*tData.width);
pango_layout_set_wrap(layout,PANGO_WRAP_WORD);//I think this is what Adobe does
}
- //In case autoSize is NONE, we also have the height
- if(tData.autoSize == TextData::AUTO_SIZE::AS_NONE)
- {
- pango_layout_set_width(layout,PANGO_SCALE*tData.width);
- pango_layout_set_height(layout,PANGO_SCALE*tData.height);//TODO:Not sure what Pango does if the text is too long to fit
- }
/* setup font description */
desc = pango_font_description_new();
@@ -870,9 +874,19 @@ void CairoPangoRenderer::executeDraw(cairo_t* cr)
cairo_paint(cr);
}
+ /* text scroll position */
+ int32_t translateX = textData.scrollH;
+ int32_t translateY = 0;
+ if (textData.scrollV > 1)
+ {
+ translateY = -PANGO_PIXELS(lineExtents(layout, textData.scrollV-1).y);
+ }
+
/* draw the text */
cairo_set_source_rgb (cr, textData.textColor.Red/255., textData.textColor.Green/255., textData.textColor.Blue/255.);
+ cairo_translate(cr, translateX, translateY);
pango_cairo_show_layout(cr, layout);
+ cairo_translate(cr, -translateX, -translateY);
if(textData.border)
{
@@ -917,6 +931,68 @@ bool CairoPangoRenderer::getBounds(const TextData& _textData, uint32_t& w, uint3
return (h!=0) && (w!=0);
}
+PangoRectangle CairoPangoRenderer::lineExtents(PangoLayout *layout, int lineNumber)
+{
+ PangoRectangle rect;
+ memset(&rect, 0, sizeof(PangoRectangle));
+ int i = 0;
+ PangoLayoutIter* lineIter = pango_layout_get_iter(layout);
+ do
+ {
+ if (i == lineNumber)
+ {
+ pango_layout_iter_get_line_extents(lineIter, NULL, &rect);
+ break;
+ }
+
+ i++;
+ } while (pango_layout_iter_next_line(lineIter));
+ pango_layout_iter_free(lineIter);
+
+ return rect;
+}
+
+std::vector<LineData> CairoPangoRenderer::getLineData(const TextData& _textData)
+{
+ //TODO:check locking
+ Locker l(pangoMutex);
+ cairo_surface_t* cairoSurface=cairo_image_surface_create_for_data(NULL, CAIRO_FORMAT_ARGB32, 0, 0, 0);
+ cairo_t *cr=cairo_create(cairoSurface);
+
+ PangoLayout* layout;
+ layout = pango_cairo_create_layout(cr);
+ pangoLayoutFromData(layout, _textData);
+
+ int XOffset = _textData.scrollH;
+ int YOffset = PANGO_PIXELS(lineExtents(layout, _textData.scrollV-1).y);
+ std::vector<LineData> data;
+ data.reserve(pango_layout_get_line_count(layout));
+ PangoLayoutIter* lineIter = pango_layout_get_iter(layout);
+ do
+ {
+ PangoRectangle rect;
+ pango_layout_iter_get_line_extents(lineIter, NULL, &rect);
+ PangoLayoutLine* line = pango_layout_iter_get_line(lineIter);
+ data.emplace_back(PANGO_PIXELS(rect.x) - XOffset,
+ PANGO_PIXELS(rect.y) - YOffset,
+ PANGO_PIXELS(rect.width),
+ PANGO_PIXELS(rect.height),
+ _textData.text.bytePosToIndex(line->start_index),
+ _textData.text.substr_bytes(line->start_index, line->length).numChars(),
+ PANGO_PIXELS(PANGO_ASCENT(rect)),
+ PANGO_PIXELS(PANGO_DESCENT(rect)),
+ PANGO_PIXELS(PANGO_LBEARING(rect)),
+ 0); // FIXME
+ } while (pango_layout_iter_next_line(lineIter));
+ pango_layout_iter_free(lineIter);
+
+ g_object_unref(layout);
+ cairo_destroy(cr);
+ cairo_surface_destroy(cairoSurface);
+
+ return data;
+}
+
void CairoPangoRenderer::applyCairoMask(cairo_t* cr, int32_t xOffset, int32_t yOffset) const
{
assert(false);
diff --git a/src/backends/graphics.h b/src/backends/graphics.h
index 63ba009..674a967 100644
--- a/src/backends/graphics.h
+++ b/src/backends/graphics.h
@@ -344,7 +344,7 @@ class TextData
{
public:
/* the default values are from the spec for flash.text.TextField and flash.text.TextFormat */
- TextData() : width(100), height(100), textWidth(0), textHeight(0), font("Times New Roman"), background(false), backgroundColor(0xFFFFFF),
+ TextData() : width(100), height(100), textWidth(0), textHeight(0), font("Times New Roman"), scrollH(0), scrollV(1), background(false), backgroundColor(0xFFFFFF),
border(false), borderColor(0x000000), multiline(false), textColor(0x000000),
autoSize(AS_NONE), fontSize(12), wordWrap(false) {}
uint32_t width;
@@ -353,6 +353,8 @@ public:
uint32_t textHeight;
tiny_string text;
tiny_string font;
+ int32_t scrollH; // pixels, 0-based
+ int32_t scrollV; // lines, 1-based
bool background;
RGB backgroundColor;
bool border;
@@ -365,6 +367,28 @@ public:
bool wordWrap;
};
+class LineData {
+public:
+ LineData(int32_t x, int32_t y, int32_t _width,
+ int32_t _height, int32_t _firstCharOffset, int32_t _length,
+ number_t _ascent, number_t _descent, number_t _leading,
+ number_t _indent):
+ extents(x, x+_width, y, y+_height),
+ firstCharOffset(_firstCharOffset), length(_length),
+ ascent(_ascent), descent(_descent), leading(_leading),
+ indent(_indent) {}
+ // position and size
+ RECT extents;
+ // Offset of the first character on this line
+ int32_t firstCharOffset;
+ // length of the line in characters
+ int32_t length;
+ number_t ascent;
+ number_t descent;
+ number_t leading;
+ number_t indent;
+};
+
class CairoPangoRenderer : public CairoRenderer
{
static StaticMutex pangoMutex;
@@ -375,6 +399,7 @@ class CairoPangoRenderer : public CairoRenderer
TextData textData;
static void pangoLayoutFromData(PangoLayout* layout, const TextData& tData);
void applyCairoMask(cairo_t* cr, int32_t offsetX, int32_t offsetY) const;
+ static PangoRectangle lineExtents(PangoLayout *layout, int lineNumber);
public:
CairoPangoRenderer(const TextData& _textData, const MATRIX& _m,
int32_t _x, int32_t _y, int32_t _w, int32_t _h, float _s, float _a, const std::vector<MaskData>& _ms)
@@ -385,6 +410,7 @@ public:
@param w,h,tw,th are the (text)width and (text)height of the textData.
*/
static bool getBounds(const TextData& _textData, uint32_t& w, uint32_t& h, uint32_t& tw, uint32_t& th);
+ static std::vector<LineData> getLineData(const TextData& _textData);
};
class InvalidateQueue
diff --git a/src/backends/input.cpp b/src/backends/input.cpp
index 96ea76c..fd3591d 100644
--- a/src/backends/input.cpp
+++ b/src/backends/input.cpp
@@ -141,6 +141,12 @@ bool InputThread::worker(GdkEvent *event)
ret=TRUE;
break;
}
+ case GDK_LEAVE_NOTIFY:
+ {
+ handleMouseLeave();
+ ret=TRUE;
+ break;
+ }
default:
//#ifdef EXPENSIVE_DEBUG
// LOG(LOG_INFO, "GDKTYPE " << event->type);
@@ -292,6 +298,15 @@ void InputThread::handleScrollEvent(uint32_t x, uint32_t y, GdkScrollDirection d
_MR(Class<MouseEvent>::getInstanceS("mouseWheel",localX,localY,true,buttonState,NullRef,delta)));
}
+void InputThread::handleMouseLeave()
+{
+ if(m_sys->currentVm == NULL)
+ return;
+
+ m_sys->currentVm->addEvent(m_sys->mainClip->getStage(),
+ _MR(Class<Event>::getInstanceS("mouseLeave")));
+}
+
void InputThread::initKeyTable()
{
int i = 0;
diff --git a/src/backends/input.h b/src/backends/input.h
index c1897f8..f02711f 100644
--- a/src/backends/input.h
+++ b/src/backends/input.h
@@ -78,6 +78,7 @@ private:
void handleMouseUp(uint32_t x, uint32_t y, unsigned int buttonState);
void handleMouseMove(uint32_t x, uint32_t y, unsigned int buttonState);
void handleScrollEvent(uint32_t x, uint32_t y, GdkScrollDirection direction, unsigned int buttonState);
+ void handleMouseLeave();
void initKeyTable();
bool handleKeyboardShortcuts(const GdkEventKey *keyevent);
diff --git a/src/backends/netutils.cpp b/src/backends/netutils.cpp
index 408c14b..1c397aa 100644
--- a/src/backends/netutils.cpp
+++ b/src/backends/netutils.cpp
@@ -24,6 +24,7 @@
#include "backends/config.h"
#include "backends/netutils.h"
#include "backends/rtmputils.h"
+#include "backends/streamcache.h"
#include "compat.h"
#include <string>
#include <algorithm>
@@ -165,25 +166,26 @@ StandaloneDownloadManager::~StandaloneDownloadManager()
* \return A pointer to a newly created \c Downloader for the given URL.
* \see DownloadManager::destroy()
*/
-Downloader* StandaloneDownloadManager::download(const URLInfo& url, bool cached, ILoadable* owner)
+Downloader* StandaloneDownloadManager::download(const URLInfo& url, _R<StreamCache> cache, ILoadable* owner)
{
+ bool cached = dynamic_cast<FileStreamCache *>(cache.getPtr()) != NULL;
LOG(LOG_INFO, _("NET: STANDALONE: DownloadManager::download '") << url.getParsedURL()
<< "'" << (cached ? _(" - cached") : ""));
ThreadedDownloader* downloader;
if(url.getProtocol() == "file")
{
LOG(LOG_INFO, _("NET: STANDALONE: DownloadManager: local file"));
- downloader=new LocalDownloader(url.getPath(), cached, owner);
+ downloader=new LocalDownloader(url.getPath(), cache, owner);
}
else if(url.getProtocol().substr(0, 4) == "rtmp")
{
LOG(LOG_INFO, _("NET: STANDALONE: DownloadManager: RTMP stream"));
- downloader=new RTMPDownloader(url.getParsedURL(), url.getStream(), owner);
+ downloader=new RTMPDownloader(url.getParsedURL(), cache, url.getStream(), owner);
}
else
{
LOG(LOG_INFO, _("NET: STANDALONE: DownloadManager: remote file"));
- downloader=new CurlDownloader(url.getParsedURL(), cached, owner);
+ downloader=new CurlDownloader(url.getParsedURL(), cache, owner);
}
downloader->enableFencingWaiting();
addDownloader(downloader);
@@ -201,7 +203,8 @@ Downloader* StandaloneDownloadManager::download(const URLInfo& url, bool cached,
* \return A pointer to a newly created \c Downloader for the given URL.
* \see DownloadManager::destroy()
*/
-Downloader* StandaloneDownloadManager::downloadWithData(const URLInfo& url, const std::vector<uint8_t>& data,
+Downloader* StandaloneDownloadManager::downloadWithData(const URLInfo& url, _R<StreamCache> cache,
+ const std::vector<uint8_t>& data,
const std::list<tiny_string>& headers, ILoadable* owner)
{
LOG(LOG_INFO, _("NET: STANDALONE: DownloadManager::downloadWithData '") << url.getParsedURL());
@@ -209,14 +212,14 @@ Downloader* StandaloneDownloadManager::downloadWithData(const URLInfo& url, cons
if(url.getProtocol() == "file")
{
LOG(LOG_INFO, _("NET: STANDALONE: DownloadManager: local file - Ignoring data field"));
- downloader=new LocalDownloader(url.getPath(), false, owner);
+ downloader=new LocalDownloader(url.getPath(), cache, owner);
}
else if(url.getProtocol() == "rtmpe")
throw RunTimeException("RTMPE does not support additional data");
else
{
LOG(LOG_INFO, _("NET: STANDALONE: DownloadManager: remote file"));
- downloader=new CurlDownloader(url.getParsedURL(), data, headers, owner);
+ downloader=new CurlDownloader(url.getParsedURL(), cache, data, headers, owner);
}
downloader->enableFencingWaiting();
addDownloader(downloader);
@@ -229,20 +232,15 @@ Downloader* StandaloneDownloadManager::downloadWithData(const URLInfo& url, cons
*
* Constructor for the Downloader class. Can only be called from derived classes.
* \param[in] _url The URL for the Downloader.
- * \param[in] _cached Whether or not to cache this download.
+ * \param[in] _cache StreamCache instance for caching this download.
*/
-Downloader::Downloader(const tiny_string& _url, bool _cached, ILoadable* o):
- cacheOpened(0),dataAvailable(0),terminated(0),hasTerminated(false),cacheHasOpened(false), //LOCKING
- waitingForCache(false),waitingForData(false),waitingForTermination(false), //STATUS
- forceStop(true),failed(false),finished(false), //FLAGS
+Downloader::Downloader(const tiny_string& _url, _R<StreamCache> _cache, ILoadable* o):
url(_url),originalURL(url), //PROPERTIES
- buffer(NULL),stableBuffer(NULL), //BUFFERING
+ cache(_cache), //CACHING
owner(o), //PROGRESS
- cachePos(0),cacheSize(0),keepCache(false),cached(_cached), //CACHING
redirected(false),requestStatus(0), //HTTP REDIR, STATUS & HEADERS
- length(0),receivedLength(0) //DOWNLOADED DATA
+ length(0) //DOWNLOADED DATA
{
- setg(NULL,NULL,NULL);
}
/**
@@ -252,18 +250,13 @@ Downloader::Downloader(const tiny_string& _url, bool _cached, ILoadable* o):
* \param[in] _url The URL for the Downloader.
* \param[in] data Additional data to send to the host
*/
-Downloader::Downloader(const tiny_string& _url, const std::vector<uint8_t>& _data, const std::list<tiny_string>& h, ILoadable* o):
- cacheOpened(0),dataAvailable(0),terminated(0),hasTerminated(false),cacheHasOpened(false), //LOCKING
- waitingForCache(false),waitingForData(false),waitingForTermination(false), //STATUS
- forceStop(true),failed(false),finished(false), //FLAGS
+Downloader::Downloader(const tiny_string& _url, _R<StreamCache> _cache, const std::vector<uint8_t>& _data, const std::list<tiny_string>& h, ILoadable* o):
url(_url),originalURL(url), //PROPERTIES
- buffer(NULL),stableBuffer(NULL), //BUFFERING
+ cache(_cache), //CACHING
owner(o), //PROGRESS
- cachePos(0),cacheSize(0),keepCache(false),cached(false), //CACHING
redirected(false),requestStatus(0),requestHeaders(h),data(_data),//HTTP REDIR, STATUS & HEADERS
- length(0),receivedLength(0) //DOWNLOADED DATA
+ length(0) //DOWNLOADED DATA
{
- setg(NULL,NULL,NULL);
}
/**
@@ -275,263 +268,6 @@ Downloader::Downloader(const tiny_string& _url, const std::vector<uint8_t>& _dat
*/
Downloader::~Downloader()
{
- waitForTermination();
-
- Mutex::Lock l(mutex);
-
- if(cached)
- {
- if(cache.is_open())
- cache.close();
- if(!keepCache && cacheFilename != "")
- unlink(cacheFilename.raw_buf());
- }
- if(buffer != NULL)
- {
- free(buffer);
- }
- if(stableBuffer != NULL && stableBuffer!=buffer)
- {
- free(stableBuffer);
- }
-}
-
-/**
- * \brief Called by the streambuf API
- *
- * Called by the streambuf API when there is no more data to read.
- * Waits for the mutex at start and releases the mutex when finished.
- * \throw RunTimeException Cache file could not be read
- */
-Downloader::int_type Downloader::underflow()
-{
- Mutex::Lock l(mutex);
- //Let's see if the other buffer contains new data
- syncBuffers();
- if(egptr()-gptr()>0)
- {
- //There is data already
- return *(uint8_t*)gptr();
- }
- const unsigned int startOffset=getOffset();
- const unsigned int startReceivedLength=receivedLength;
- assert(startOffset<=startReceivedLength);
- //If we have read all available data
- if(startReceivedLength==startOffset)
- {
- //The download has failed or has finished
- if(failed || finished)
- return EOF;
- //We haven't reached the end of the download, more bytes should follow
- else
- {
- waitForData_locked();
- syncBuffers();
-
- //Check if we haven't failed or finished (and there wasn't any new data)
- if(failed || (finished && startReceivedLength==receivedLength))
- return EOF;
- }
- }
-
- //We should have an initialized buffer here since there is some data
- assert_and_throw(buffer != NULL);
- //Temporary pointers to new streambuf read positions
- char* begin;
- char* cur;
- char* end;
- //Index in the buffer pointing to the data to be returned
- uint32_t index;
-
- if(cached)
- {
- waitForCache();
-
- size_t newCacheSize = receivedLength-(cachePos+cacheSize);
- if(newCacheSize > cacheMaxSize)
- newCacheSize = cacheMaxSize;
-
- //Move the start of our new window to the end of our last window
- cachePos = cachePos+cacheSize;
- cacheSize = newCacheSize;
- //Seek to the start of our new window
- cache.seekg(cachePos);
- //Read into our buffer window
- cache.read((char*)stableBuffer, cacheSize);
- if(cache.fail())
- {
- throw RunTimeException(_("Downloader::underflow: reading from cache file failed"));
- }
-
- begin=(char*)stableBuffer;
- cur=(char*)stableBuffer;
- end=(char*)stableBuffer+cacheSize;
- index=0;
-
- }
- else
- {
- begin=(char*)stableBuffer;
- cur=(char*)stableBuffer+startOffset;
- end=(char*)stableBuffer+receivedLength;
- index=startOffset;
- }
-
- //If we've failed, don't bother any more
- if(failed)
- return EOF;
-
- //Set our new iterators in the buffer (begin, cursor, end)
- setg(begin, cur, end);
-
- //Cast to unsigned, otherwise 0xff would become eof
- return (unsigned char)stableBuffer[index];
-}
-
-/**
- * Internal function to synchronize oldBuffer and buffer
- *
- * \pre Must be called from a function called by the streambuf API
- */
-void Downloader::syncBuffers()
-{
- if(stableBuffer!=buffer)
- {
- //The buffer have been changed
- free(stableBuffer);
- stableBuffer=buffer;
- //Remember the relative positions of the input pointers
- intptr_t curPos = (intptr_t) (gptr()-eback());
- intptr_t curLen = (intptr_t) (egptr()-eback());
- //Do some pointer arithmetic to point the input pointers to the right places in the new buffer
- setg((char*)stableBuffer,(char*)(stableBuffer+curPos),(char*)(stableBuffer+curLen));
- }
-}
-
-/**
- * \brief Called by the streambuf API
- *
- * Called by the streambuf API to seek to an absolute position
- * Mutex must be locked on entry.
- * \throw RunTimeException Cache file could not be read
- */
-Downloader::pos_type Downloader::seekpos(pos_type pos, std::ios_base::openmode mode)
-{
- assert_and_throw(mode==std::ios_base::in);
- assert_and_throw(buffer && stableBuffer);
-
- syncBuffers();
-
- // read from stream until we have enough data
- uint32_t tmplen = receivedLength;
- while (!hasTerminated && pos > receivedLength)
- {
- waitForData_locked();
- syncBuffers();
- if (tmplen == receivedLength)
- break; // no new data read
- tmplen = receivedLength;
- }
-
- if(cached)
- {
- waitForCache();
-
- //The requested position is inside our current window
- if(pos >= cachePos && pos <= cachePos+cacheSize)
- {
- //Just move our cursor to the correct position in our window
- setg((char*)stableBuffer, (char*)stableBuffer+pos-cachePos, (char*)stableBuffer+cacheSize);
- }
- //The requested position is outside our current window
- else if(pos <= receivedLength)
- {
- cachePos = pos;
- cacheSize = receivedLength-pos;
- if(cacheSize > cacheMaxSize)
- cacheSize = cacheMaxSize;
-
- //Seek to the requested position
- cache.seekg(cachePos);
- //Read into our window
- cache.read((char*)stableBuffer, cacheSize);
- if(cache.fail())
- throw RunTimeException(_("Downloader::seekpos: reading from cache file failed"));
-
- //Our window starts at position pos
- setg((char*) stableBuffer, (char*) stableBuffer, ((char*) stableBuffer)+cacheSize);
- }
- //The requested position is bigger then our current amount of available data
- else if(pos > receivedLength)
- return -1;
- }
- else
- {
- //The requested position is valid
- if(pos <= receivedLength)
- setg((char*)stableBuffer,(char*)stableBuffer+pos,(char*)stableBuffer+receivedLength);
- //The requested position is bigger then our current amount of available data
- else
- return -1;
- }
-
- return pos;
-}
-
-/**
- * \brief Called by the streambuf API
- *
- * Called by the streambuf API to seek to a relative position
- * Waits for the mutex at start and releases the mutex when finished.
- */
-Downloader::pos_type Downloader::seekoff(off_type off, std::ios_base::seekdir dir, std::ios_base::openmode mode)
-{
- assert_and_throw(mode==std::ios_base::in);
- assert_and_throw(buffer != NULL);
-
- Mutex::Lock l(mutex);
- if (off != 0)
- {
- switch (dir)
- {
- case std::ios_base::beg:
- seekpos(off,mode);
- break;
- case std::ios_base::cur:
- {
- pos_type tmp = getOffset();
- seekpos(tmp+off,mode);
- break;
- }
- case std::ios_base::end:
- l.release();
- waitForTermination();
- l.acquire();
- if (finished)
- seekpos(length+off,mode);
- break;
- default:
- break;
- }
- }
-
- return getOffset();
-}
-
-/**
- * \brief Get the position of the read cursor in the (virtual) downloaded data
- *
- * Get the position of the read cursor in the (virtual) downloaded data.
- * If downloading to memory this method returns the position of the read cursor in the buffer.
- * If downloading to a cache file, this method returns the position of the read cursor in the buffer
- * + the position of the buffer window into the cache file.
- */
-Downloader::pos_type Downloader::getOffset() const
-{
- pos_type ret = gptr()-eback();
- if(cached)
- ret+=cachePos;
- return ret;
}
/**
@@ -541,28 +277,13 @@ Downloader::pos_type Downloader::getOffset() const
* signals \c dataAvailable if it is being waited for.
* It also signals \c terminated to mark the end of the download.
* A download should finish be either calling \c setFailed() or \c setFinished(), not both.
- * \post \c failed == \c true & \c finished == \c true
* \post \c length == \c receivedLength
- * \post Signals \c dataAvailable if it is being waited for (\c waitingForData == \c true).
- * \post \c waitingForTermination == \c false
- * \post Signals \c terminated
*/
void Downloader::setFailed()
{
- failed=true;
- finished = true;
+ cache->markFinished(true);
//Set the final length
- length = receivedLength;
-
- //If we are waiting for data to become available, signal dataAvailable
- if(waitingForData)
- {
- waitingForData = false;
- dataAvailable.signal();
- }
-
- waitingForTermination = false;
- terminated.signal();
+ length = cache->getReceivedLength();
}
/**
@@ -572,139 +293,13 @@ void Downloader::setFailed()
* signals \c dataAvailable if it is being waited for.
* It also signals \c terminated to mark the end of the download.
* A download should finish be either calling \c setFailed() or \c setFinished(), not both.
- * \post \c finished == \ctrue
* \post \c length == \c receivedLength
- * \post Signals \c dataAvailable if it is being waited for (\c waitingForData == true).
- * \post \c waitingForTermination == \c false
- * \post Signals \c terminated
*/
void Downloader::setFinished()
{
- finished=true;
+ cache->markFinished();
//Set the final length
- length = receivedLength;
-
- //If we are waiting for data to become available, signal dataAvailable
- if(waitingForData)
- {
- waitingForData = false;
- dataAvailable.signal();
- }
-
- waitingForTermination = false;
- terminated.signal();
-}
-
-/**
- * \brief (Re)allocates the buffer
- *
- * (Re)allocates the buffer to a given size
- * Waits for mutex at start and releases mutex when finished.
- * \post \c buffer is (re)allocated
- * mutex must be locked on entry
- */
-void Downloader::allocateBuffer(size_t size)
-{
- //Create buffer
- if(buffer == NULL)
- {
- buffer = (uint8_t*) calloc(size, sizeof(uint8_t));
- stableBuffer = buffer;
- setg((char*)buffer,(char*)buffer,(char*)buffer);
- }
- //If the buffer already exists, reallocate
- else
- {
- assert(!cached);
- intptr_t curLen = receivedLength;
- //We have to extend the buffer, so create a new one
- if(stableBuffer!=buffer)
- {
- //We're already filling a different buffer from the one used to read
- //Extend it!
- buffer = (uint8_t*)realloc(buffer,size);
- }
- else
- {
- //Create a different buffer
- buffer = (uint8_t*) calloc(size, sizeof(uint8_t));
- //Copy the stableBuffer into this
- memcpy(buffer,stableBuffer,curLen);
- }
- //Synchronization of the buffers will be done at the first chance
- }
-}
-
-/**
- * \brief Creates & opens a temporary cache file
- *
- * Creates a temporary cache file in /tmp and calls \c openExistingCache() with that file.
- * Waits for mutex at start and releases mutex when finished.
- * \throw RunTimeException Temporary file could not be created
- * \throw RunTimeException Called when the downloader isn't cached or when the cache is already open
- * \see Downloader::openExistingCache()
- * mutex must be hold prior calling
- */
-void Downloader::openCache()
-{
- //Only act if the downloader is cached and the cache hasn't been opened yet
- if(cached && !cache.is_open())
- {
- //Create a temporary file(name)
- std::string cacheFilenameS = Config::getConfig()->getCacheDirectory() + "/" + Config::getConfig()->getCachePrefix() + "XXXXXX";
- char* cacheFilenameC = g_newa(char,cacheFilenameS.length()+1);
- strncpy(cacheFilenameC, cacheFilenameS.c_str(), cacheFilenameS.length());
- cacheFilenameC[cacheFilenameS.length()] = '\0';
- //char cacheFilenameC[30] = "/tmp/lightsparkdownloadXXXXXX";
- //strcpy(cacheFilenameC, "/tmp/lightsparkdownloadXXXXXX");
- int fd = g_mkstemp(cacheFilenameC);
- if(fd == -1)
- throw RunTimeException(_("Downloader::openCache: cannot create temporary file"));
- //We are using fstream to read/write to the cache, so we don't need this FD
- close(fd);
-
- //Let the openExistingCache function handle the rest
- openExistingCache(tiny_string(cacheFilenameC, true));
- }
- else
- throw RunTimeException(_("Downloader::openCache: downloader isn't cached or called twice"));
-}
-
-/**
- * \brief Opens an existing cache file
- *
- * Opens an existing cache file, allocates the buffer and signals \c cacheOpened.
- * Waits for mutex at start and releases mutex when finished.
- * \post \c cacheFilename is set
- * \post \c cache file is opened
- * \post \c buffer is initialized
- * \post \c cacheOpened is signalled
- * \throw RunTimeException File could not be opened
- * \throw RunTimeException Called when the downloader isn't cached or when the cache is already open
- * \see Downloader::allocateBuffer()
- * mutex must be hold on entering
- */
-void Downloader::openExistingCache(tiny_string filename)
-{
- //Only act if the downloader is cached and the cache hasn't been opened yet
- if(cached && !cache.is_open())
- {
- //Save the filename
- cacheFilename = filename;
-
- //Open the cache file
- cache.open(cacheFilename.raw_buf(), std::fstream::binary | std::fstream::in | std::fstream::out);
- if(!cache.is_open())
- throw RunTimeException(_("Downloader::openCache: cannot open temporary cache file"));
-
- allocateBuffer(cacheMaxSize);
-
- LOG(LOG_INFO, _("NET: Downloading to cache file: ") << cacheFilename);
-
- cacheOpened.signal();
- }
- else
- throw RunTimeException(_("Downloader::openCache: downloader isn't cached or called twice"));
+ length = cache->getReceivedLength();
}
/**
@@ -712,27 +307,14 @@ void Downloader::openExistingCache(tiny_string filename)
*
* Sets the expected length of the download.
* Can be called multiple times if the length isn't known up front (reallocating the buffer on the fly).
- * Waits for mutex at start and releases mutex when finished.
- * \post \c buffer is (re)allocated
- * mutex must be hold prior calling
*/
void Downloader::setLength(uint32_t _length)
{
//Set the length
length=_length;
- //The first call to this function should open the cache
- if(cached)
- {
- if(!cache.is_open())
- openCache();
- }
- else
- {
- if(buffer == NULL)
- LOG(LOG_INFO, _("NET: Downloading to memory"));
- allocateBuffer(length);
- }
+ cache->reserve(length);
+
notifyOwnerAboutBytesTotal();
}
@@ -752,39 +334,9 @@ void Downloader::append(uint8_t* buf, uint32_t added)
if(added==0)
return;
- Mutex::Lock l(mutex);
-
- //If the added data would overflow the buffer, grow it
- if((receivedLength+added)>length)
- {
- uint32_t newLength;
- assert(length>=receivedLength);
- //If reallocating the buffer ask for a minimum amount of space
- if((receivedLength+added)-length > bufferMinGrowth)
- newLength = receivedLength + added;
- else
- newLength = length + bufferMinGrowth;
- assert(newLength>=receivedLength+added);
-
- setLength(newLength);
- }
-
- if(cached)
- {
- //Seek to where we last wrote data
- cache.seekp(receivedLength);
- cache.write((char*) buf, added);
- }
- else
- memcpy(buffer+receivedLength, buf, added);
-
- receivedLength += added;
-
- if(waitingForData)
- {
- waitingForData = false;
- dataAvailable.signal();
- }
+ cache->append((unsigned char *)buf, added);
+ if (cache->getReceivedLength() > length)
+ setLength(cache->getReceivedLength());
notifyOwnerAboutBytesLoaded();
}
@@ -824,8 +376,6 @@ void Downloader::parseHeaders(const char* _headers, bool _setLength)
*/
void Downloader::parseHeader(std::string header, bool _setLength)
{
- Mutex::Lock l(mutex);
-
if(header.substr(0, 9) == "HTTP/1.1 " || header.substr(0, 9) == "HTTP/1.0 ")
{
std::string status = header.substr(9, 3);
@@ -891,83 +441,8 @@ void Downloader::parseHeader(std::string header, bool _setLength)
*/
void Downloader::stop()
{
- failed = true;
- finished = true;
- length = receivedLength;
-
- waitingForData = false;
- dataAvailable.signal();
-
- waitingForTermination = false;
- terminated.signal();
-}
-
-/**
- * \brief Wait for the cache file to be opened
- *
- * If \c !cacheHasOpened: wait for the \c cacheOpened signal and set \c cacheHasOpened to \c true
- * Waits for the mutex at start and releases the mutex when finished.
- * \post \c cacheOpened signals has been handled
- * \post \c cacheHasOpened = true
- * mutex must be locked on entry
- */
-void Downloader::waitForCache()
-{
- if(!cacheHasOpened)
- {
- waitingForCache = true;
-
- mutex.unlock();
- cacheOpened.wait();
- mutex.lock();
-
- cacheHasOpened = true;
- }
-}
-
-/**
- * \brief Wait for data to become available
- *
- * Wait for data to become available.
- * Waits for the mutex at start and releases the mutex when finished.
- * \post \c dataAvailable signal has been handled
- */
-void Downloader::waitForData_locked()
-{
- waitingForData = true;
- mutex.unlock();
- dataAvailable.wait();
- mutex.lock();
-}
-
-/**
- * \brief Wait for termination of the downloader
- *
- * If \c getSys()->isShuttingDown(), calls \c setFailed() and returns.
- * Otherwise if \c !hasTerminated: wait for the \c terminated signal and set \c hasTerminated to \c true
- * Waits for the mutex at start and releases the mutex when finished.
- * \post \c terminated signal has been handled
- * \post \c hasTerminated = true
- */
-void Downloader::waitForTermination()
-{
- Mutex::Lock l(mutex);
- if(getSys()->isShuttingDown())
- {
- setFailed();
- return;
- }
-
- if(!hasTerminated)
- {
- waitingForTermination = true;
-
- l.release();
- terminated.wait();
- l.acquire();
-
- hasTerminated = true;
- }
+ cache->markFinished(true);
+ length = cache->getReceivedLength();
}
void Downloader::notifyOwnerAboutBytesTotal() const
@@ -979,7 +454,7 @@ void Downloader::notifyOwnerAboutBytesTotal() const
void Downloader::notifyOwnerAboutBytesLoaded() const
{
if(owner)
- owner->setBytesLoaded(receivedLength);
+ owner->setBytesLoaded(cache->getReceivedLength());
}
void ThreadedDownloader::enableFencingWaiting()
@@ -1010,8 +485,8 @@ void ThreadedDownloader::waitFencing()
* \param[in] _url The URL for the Downloader.
* \param[in] _cached Whether or not to cache this download.
*/
-ThreadedDownloader::ThreadedDownloader(const tiny_string& url, bool cached, ILoadable* o):
- Downloader(url, cached, o),fenceState(false)
+ThreadedDownloader::ThreadedDownloader(const tiny_string& url, _R <StreamCache> cache, ILoadable* o):
+ Downloader(url, cache, o),fenceState(false)
{
}
@@ -1022,9 +497,10 @@ ThreadedDownloader::ThreadedDownloader(const tiny_string& url, bool cached, ILoa
* \param[in] _url The URL for the Downloader.
* \param[in] data Additional data to send to the host
*/
-ThreadedDownloader::ThreadedDownloader(const tiny_string& url, const std::vector<uint8_t>& data,
+ThreadedDownloader::ThreadedDownloader(const tiny_string& url, _R<StreamCache> cache,
+ const std::vector<uint8_t>& data,
const std::list<tiny_string>& headers, ILoadable* o):
- Downloader(url, data, headers, o),fenceState(false)
+ Downloader(url, cache, data, headers, o),fenceState(false)
{
}
@@ -1046,8 +522,8 @@ ThreadedDownloader::~ThreadedDownloader()
* \param[in] _url The URL for the Downloader.
* \param[in] _cached Whether or not to cache this download.
*/
-CurlDownloader::CurlDownloader(const tiny_string& _url, bool _cached, ILoadable* o):
- ThreadedDownloader(_url, _cached, o)
+CurlDownloader::CurlDownloader(const tiny_string& _url, _R<StreamCache> _cache, ILoadable* o):
+ ThreadedDownloader(_url, _cache, o)
{
}
@@ -1057,9 +533,10 @@ CurlDownloader::CurlDownloader(const tiny_string& _url, bool _cached, ILoadable*
* \param[in] _url The URL for the Downloader.
* \param[in] data Additional data to send to the host
*/
-CurlDownloader::CurlDownloader(const tiny_string& _url, const std::vector<uint8_t>& _data,
+CurlDownloader::CurlDownloader(const tiny_string& _url, _R<StreamCache> _cache,
+ const std::vector<uint8_t>& _data,
const std::list<tiny_string>& _headers, ILoadable* o):
- ThreadedDownloader(_url, _data, _headers, o)
+ ThreadedDownloader(_url, _cache, _data, _headers, o)
{
}
@@ -1180,7 +657,7 @@ void CurlDownloader::execute()
int CurlDownloader::progress_callback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow)
{
CurlDownloader* th=static_cast<CurlDownloader*>(clientp);
- return th->threadAborting || th->failed;
+ return th->threadAborting || th->cache->hasFailed();
}
/**
@@ -1224,7 +701,8 @@ size_t CurlDownloader::write_header(void *buffer, size_t size, size_t nmemb, voi
* \param[in] _url The URL for the Downloader.
* \param[in] _cached Whether or not to cache this download.
*/
-LocalDownloader::LocalDownloader(const tiny_string& _url, bool _cached, ILoadable* o):ThreadedDownloader(_url, _cached, o)
+LocalDownloader::LocalDownloader(const tiny_string& _url, _R<StreamCache> _cache, ILoadable* o):
+ ThreadedDownloader(_url, _cache, o)
{
}
@@ -1256,18 +734,14 @@ void LocalDownloader::execute()
LOG(LOG_INFO, _("NET: LocalDownloader::execute: reading local file: ") << url.raw_buf());
//If the caching is selected, we override the normal behaviour and use the local file as the cache file
//This prevents unneeded copying of the file's data
- if(isCached())
- {
- Mutex::Lock l(mutex);
- //Make sure we don't delete the local file afterwards
- keepCache = true;
- openExistingCache(url);
+ FileStreamCache *fileCache = dynamic_cast<FileStreamCache *>(cache.getPtr());
+ if (fileCache)
+ {
+ fileCache->useExistingFile(url);
- cache.seekg(0, std::ios::end);
//Report that we've downloaded everything already
- length = cache.tellg();
- receivedLength = length;
+ length = fileCache->getReceivedLength();
notifyOwnerAboutBytesLoaded();
notifyOwnerAboutBytesTotal();
}
@@ -1280,7 +754,6 @@ void LocalDownloader::execute()
{
file.seekg(0, std::ios::end);
{
- Mutex::Lock l(mutex);
setLength(file.tellg());
}
file.seekg(0, std::ios::beg);
@@ -1290,7 +763,7 @@ void LocalDownloader::execute()
bool readFailed = 0;
while(!file.eof())
{
- if(file.fail() || hasFailed())
+ if(file.fail() || cache->hasFailed())
{
readFailed = 1;
break;
@@ -1329,7 +802,7 @@ DownloaderThreadBase::DownloaderThreadBase(_NR<URLRequest> request, IDownloaderT
}
}
-bool DownloaderThreadBase::createDownloader(bool cached,
+bool DownloaderThreadBase::createDownloader(_R<StreamCache> cache,
_NR<EventDispatcher> dispatcher,
ILoadable* owner,
bool checkPolicyFile)
@@ -1355,11 +828,11 @@ bool DownloaderThreadBase::createDownloader(bool cached,
if(postData.empty())
{
//This is a GET request
- downloader=getSys()->downloadManager->download(url, cached, owner);
+ downloader=getSys()->downloadManager->download(url, cache, owner);
}
else
{
- downloader=getSys()->downloadManager->downloadWithData(url, postData, requestHeaders, owner);
+ downloader=getSys()->downloadManager->downloadWithData(url, cache, postData, requestHeaders, owner);
}
return true;
diff --git a/src/backends/netutils.h b/src/backends/netutils.h
index de2789b..2f1f6fd 100644
--- a/src/backends/netutils.h
+++ b/src/backends/netutils.h
@@ -29,6 +29,7 @@
#include "swftypes.h"
#include "thread_pool.h"
#include "backends/urlutils.h"
+#include "backends/streamcache.h"
#include "smartrefs.h"
namespace lightspark
@@ -57,8 +58,9 @@ protected:
void cleanUp();
public:
virtual ~DownloadManager();
- virtual Downloader* download(const URLInfo& url, bool cached, ILoadable* owner)=0;
- virtual Downloader* downloadWithData(const URLInfo& url, const std::vector<uint8_t>& data,
+ virtual Downloader* download(const URLInfo& url, _R<StreamCache> cache, ILoadable* owner)=0;
+ virtual Downloader* downloadWithData(const URLInfo& url, _R<StreamCache> cache,
+ const std::vector<uint8_t>& data,
const std::list<tiny_string>& headers, ILoadable* owner)=0;
virtual void destroy(Downloader* downloader)=0;
void stopAll();
@@ -72,57 +74,22 @@ class DLL_PUBLIC StandaloneDownloadManager:public DownloadManager
public:
StandaloneDownloadManager();
~StandaloneDownloadManager();
- Downloader* download(const URLInfo& url, bool cached, ILoadable* owner);
- Downloader* downloadWithData(const URLInfo& url, const std::vector<uint8_t>& data,
+ Downloader* download(const URLInfo& url, _R<StreamCache> cache, ILoadable* owner);
+ Downloader* downloadWithData(const URLInfo& url, _R<StreamCache> cache,
+ const std::vector<uint8_t>& data,
const std::list<tiny_string>& headers, ILoadable* owner);
void destroy(Downloader* downloader);
};
-class DLL_PUBLIC Downloader: public std::streambuf
+class DLL_PUBLIC Downloader
{
-private:
- //Handles streambuf out-of-data events
- virtual int_type underflow();
- //Seeks to absolute position
- virtual pos_type seekoff(off_type, std::ios_base::seekdir, std::ios_base::openmode);
- //Seeks to relative position
- virtual pos_type seekpos(pos_type, std::ios_base::openmode);
- //Helper to get the current offset
- pos_type getOffset() const;
protected:
//Abstract base class, can't be constructed
- Downloader(const tiny_string& _url, bool _cached, ILoadable* o);
- Downloader(const tiny_string& _url, const std::vector<uint8_t>& data,
+ Downloader(const tiny_string& _url, _R<StreamCache> _cache, ILoadable* o);
+ Downloader(const tiny_string& _url, _R<StreamCache> _cache, const std::vector<uint8_t>& data,
const std::list<tiny_string>& headers, ILoadable* o);
- //-- LOCKING
- //Provides internal mutual exclusing
- Mutex mutex;
- //Signals the cache opening
- Semaphore cacheOpened;
- //Signals new bytes available for reading
- Semaphore dataAvailable;
- //Signals termination of the download
- Semaphore terminated;
- //True if the download is terminated
- bool hasTerminated;
- //True if cache has opened
- bool cacheHasOpened;
-
- //-- STATUS
- //True if the downloader is waiting for the cache to be opened
- bool waitingForCache;
- //True if the downloader is waiting for data
- bool waitingForData;
- void waitForData_locked();
- //True if the downloader is waiting for termination
- bool waitingForTermination;
//-- FLAGS
- //This flag forces a stop in internal code
- bool forceStop;
- //These flags specify what type of termination happened
- bool failed;
- bool finished;
//Mark the download as failed
void setFailed();
//Mark the download as finished
@@ -132,43 +99,14 @@ protected:
tiny_string url;
tiny_string originalURL;
- //-- BUFFERING
- //This will hold the whole download (non-cached) or a window into the download (cached)
- uint8_t* buffer;
- //We can't change the used buffer (for example when resizing) asynchronously. We can only do that on underflows
- uint8_t* stableBuffer;
- //Minimum growth of the buffer
- static const size_t bufferMinGrowth = 4096;
- //(Re)allocate the buffer
- void allocateBuffer(size_t size);
- //Synchronize stableBuffer and buffer
- void syncBuffers();
+ //-- CACHING
+ _R<StreamCache> cache;
//-- PROGRESS MONITORING
ILoadable* owner;
void notifyOwnerAboutBytesTotal() const;
void notifyOwnerAboutBytesLoaded() const;
- //-- CACHING
- //Cache filename
- tiny_string cacheFilename;
- //Cache fstream
- std::fstream cache;
- //Position of the cache buffer into the file
- uint32_t cachePos;
- //Size of data in the buffer
- uint32_t cacheSize;
- //Maximum size of the cache buffer
- static const size_t cacheMaxSize = 8192;
- //True if the cache file doesn't need to be deleted on destruction
- bool keepCache:1;
- //True if the file is cached to disk (default = false)
- bool cached:1;
- //Creates & opens a temporary cache file
- void openCache();
- //Opens an existing cache file
- void openExistingCache(tiny_string filename);
-
//-- HTTP REDIRECTION, STATUS & HEADERS
bool redirected:1;
void setRedirected(const tiny_string& newURL)
@@ -187,10 +125,6 @@ protected:
//-- DOWNLOADED DATA
//File length (can change in certain cases, resulting in reallocation of the buffer (non-cached))
uint32_t length;
- //Amount of data already received
- uint32_t receivedLength;
- //Append data to the internal buffer
- void append(uint8_t* buffer, uint32_t length);
//Set the length of the downloaded file, can be called multiple times to accomodate a growing file
void setLength(uint32_t _length);
public:
@@ -198,28 +132,23 @@ public:
virtual ~Downloader();
//Stop the download
void stop();
- //Wait for cache to be opened
- void waitForCache();
- //Wait for data to become available
- void waitForData() { Mutex::Lock l(mutex); waitForData_locked(); }
- //Wait for the download to terminate
- void waitForTermination();
//True if the download has failed
- bool hasFailed() { return failed; }
+ bool hasFailed() { return cache->hasFailed(); }
//True if the download has finished
//Can be used in conjunction with failed to find out if it finished successfully
- bool hasFinished() { return finished; }
-
- //True if the download is cached
- bool isCached() { return cached; }
+ bool hasFinished() { return cache->hasTerminated(); }
const tiny_string& getURL() { return url; }
+ //Wait until the downloader completes
+ void waitForTermination() { return cache->waitForTermination(); }
+
+ _R<StreamCache> getCache() { return cache; }
//Gets the total length of the downloaded file (may change)
uint32_t getLength() { return length; }
//Gets the length of downloaded data
- uint32_t getReceivedLength() { return receivedLength; }
+ uint32_t getReceivedLength() { return cache->getReceivedLength(); }
size_t getHeaderCount() { return headers.size(); }
tiny_string getHeader(const char* header) { return getHeader(tiny_string(header)); }
@@ -232,7 +161,8 @@ public:
bool isRedirected() { return redirected; }
const tiny_string& getOriginalURL() { return originalURL; }
uint16_t getRequestStatus() { return requestStatus; }
-
+ //Append data to the internal buffer
+ void append(uint8_t* buffer, uint32_t length);
};
class ThreadedDownloader : public Downloader, public IThreadJob
@@ -245,8 +175,9 @@ public:
void waitFencing();
protected:
//Abstract base class, can not be constructed
- ThreadedDownloader(const tiny_string& url, bool cached, ILoadable* o);
- ThreadedDownloader(const tiny_string& url, const std::vector<uint8_t>& data,
+ ThreadedDownloader(const tiny_string& url, _R<StreamCache> cache, ILoadable* o);
+ ThreadedDownloader(const tiny_string& url, _R<StreamCache> cache,
+ const std::vector<uint8_t>& data,
const std::list<tiny_string>& headers, ILoadable* o);
// //This class can only get destroyed by DownloadManager
// virtual ~ThreadedDownloader();
@@ -262,8 +193,8 @@ private:
void execute();
void threadAbort();
public:
- CurlDownloader(const tiny_string& _url, bool _cached, ILoadable* o);
- CurlDownloader(const tiny_string& _url, const std::vector<uint8_t>& data,
+ CurlDownloader(const tiny_string& _url, _R<StreamCache> cache, ILoadable* o);
+ CurlDownloader(const tiny_string& _url, _R<StreamCache> cache, const std::vector<uint8_t>& data,
const std::list<tiny_string>& headers, ILoadable* o);
};
@@ -280,7 +211,7 @@ private:
//Size of the reading buffer
static const size_t bufSize = 8192;
public:
- LocalDownloader(const tiny_string& _url, bool _cached, ILoadable* o);
+ LocalDownloader(const tiny_string& _url, _R<StreamCache> _cache, ILoadable* o);
};
class IDownloaderThreadListener
@@ -306,7 +237,7 @@ protected:
std::list<tiny_string> requestHeaders;
Spinlock downloaderLock;
Downloader* downloader;
- bool createDownloader(bool cached,
+ bool createDownloader(_R<StreamCache> cache,
_NR<EventDispatcher> dispatcher=NullRef,
ILoadable* owner=NULL,
bool checkPolicyFile=true);
diff --git a/src/backends/rendering.cpp b/src/backends/rendering.cpp
index 08228db..b80a320 100644
--- a/src/backends/rendering.cpp
+++ b/src/backends/rendering.cpp
@@ -46,10 +46,10 @@ using namespace std;
/* calculate FPS every second */
const Glib::TimeVal RenderThread::FPS_time(/*seconds*/1,/*microseconds*/0);
-static GStaticPrivate renderThread = G_STATIC_PRIVATE_INIT; /* TLS */
+DEFINE_AND_INITIALIZE_TLS(renderThread);
RenderThread* lightspark::getRenderThread()
{
- RenderThread* ret = (RenderThread*)g_static_private_get(&renderThread);
+ RenderThread* ret = (RenderThread*)tls_get(&renderThread);
/* If this is NULL, then you are not calling from the render thread,
* which is disallowed! (OpenGL is not threadsafe)
*/
@@ -326,7 +326,7 @@ void RenderThread::worker()
{
setTLSSys(m_sys);
/* set TLS variable for getRenderThread() */
- g_static_private_set(&renderThread, this, NULL);
+ tls_set(&renderThread, this);
ThreadProfile* profile=m_sys->allocateProfiler(RGB(200,0,0));
profile->setTag("Render");
diff --git a/src/backends/rtmputils.cpp b/src/backends/rtmputils.cpp
index 131ae48..3b6865b 100644
--- a/src/backends/rtmputils.cpp
+++ b/src/backends/rtmputils.cpp
@@ -20,6 +20,7 @@
#include "backends/rtmputils.h"
#include "logger.h"
#include "swf.h"
+#include "backends/streamcache.h"
#ifdef ENABLE_RTMP
#include <librtmp/rtmp.h>
@@ -28,8 +29,9 @@
using namespace lightspark;
using namespace std;
-RTMPDownloader::RTMPDownloader(const tiny_string& _url, const tiny_string& _stream, ILoadable* o):
- ThreadedDownloader(_url, true, o),
+RTMPDownloader::RTMPDownloader(const tiny_string& _url, _R<StreamCache> _cache,
+ const tiny_string& _stream, ILoadable* o):
+ ThreadedDownloader(_url, _cache, o),
stream(_stream)
{
}
diff --git a/src/backends/rtmputils.h b/src/backends/rtmputils.h
index 7e9de51..6082152 100644
--- a/src/backends/rtmputils.h
+++ b/src/backends/rtmputils.h
@@ -34,7 +34,8 @@ private:
void threadAbort();
tiny_string stream;
public:
- RTMPDownloader(const tiny_string& _url, const tiny_string& _stream, ILoadable* o);
+ RTMPDownloader(const tiny_string& _url, _R<StreamCache> _cache,
+ const tiny_string& _stream, ILoadable* o);
};
};
diff --git a/src/backends/security.cpp b/src/backends/security.cpp
index f460560..b43c8ca 100644
--- a/src/backends/security.cpp
+++ b/src/backends/security.cpp
@@ -1001,7 +1001,7 @@ bool URLPolicyFile::retrievePolicyFile(vector<unsigned char>& outData)
bool ok = true;
//No caching needed for this download, we don't expect very big files
- Downloader* downloader=getSys()->downloadManager->download(url, false, NULL);
+ Downloader* downloader=getSys()->downloadManager->download(url, _MR(new MemoryStreamCache), NULL);
//Wait until the file is fetched
downloader->waitForTermination();
@@ -1023,7 +1023,8 @@ bool URLPolicyFile::retrievePolicyFile(vector<unsigned char>& outData)
//Policy files must have on of the following content-types to be valid:
//text/*, application/xml or application/xhtml+xml
- tiny_string contentType = downloader->getHeader("content-type");
+ std::list<tiny_string> contenttypelist = downloader->getHeader("content-type").split(';');
+ tiny_string contentType = contenttypelist.size() == 0 ? "" : contenttypelist.front();
if(ok && (subtype == HTTP || subtype == HTTPS) &&
contentType.substr(0, 5) != "text/" &&
contentType != "application/xml" &&
@@ -1052,11 +1053,13 @@ bool URLPolicyFile::retrievePolicyFile(vector<unsigned char>& outData)
if (ok)
{
- istream s(downloader);
+ std::streambuf *sbuf = downloader->getCache()->createReader();
+ istream s(sbuf);
size_t bufLength = downloader->getLength();
size_t offset = outData.size();
outData.resize(offset+bufLength);
s.read((char*)&outData[offset], bufLength);
+ delete sbuf;
}
getSys()->downloadManager->destroy(downloader);
diff --git a/src/backends/streamcache.cpp b/src/backends/streamcache.cpp
new file mode 100644
index 0000000..6db1b58
--- /dev/null
+++ b/src/backends/streamcache.cpp
@@ -0,0 +1,499 @@
+/**************************************************************************
+ Lightspark, a free flash player implementation
+
+ Copyright (C) 2013 Antti Ajanki (antti.ajanki at iki.fi)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+**************************************************************************/
+
+#include <string.h>
+#include <unistd.h>
+#include <glib.h>
+#include "backends/streamcache.h"
+#include "backends/config.h"
+#include "exceptions.h"
+#include "logger.h"
+
+using namespace std;
+using namespace lightspark;
+
+StreamCache::StreamCache()
+ : receivedLength(0), failed(false), terminated(false)
+{
+}
+
+void StreamCache::markFinished(bool _failed)
+{
+ Locker locker(stateMutex);
+ if (terminated)
+ return;
+
+ failed = _failed;
+ terminated = true;
+ stateCond.broadcast();
+}
+
+void StreamCache::waitForData(size_t currentOffset)
+{
+ Locker locker(stateMutex);
+ while (receivedLength <= currentOffset && !terminated)
+ stateCond.wait(stateMutex);
+}
+
+void StreamCache::waitForTermination()
+{
+ Locker locker(stateMutex);
+ while (!terminated)
+ stateCond.wait(stateMutex);
+}
+
+void StreamCache::append(const unsigned char* buffer, size_t length)
+{
+ if (!buffer || length == 0 || terminated)
+ return;
+
+ handleAppend(buffer, length);
+
+ {
+ Locker locker(stateMutex);
+ receivedLength += length;
+ stateCond.broadcast();
+ }
+}
+
+class lightspark::MemoryChunk {
+public:
+ MemoryChunk(size_t len);
+ ~MemoryChunk();
+ unsigned char * const buffer;
+ const size_t capacity;
+ ACQUIRE_RELEASE_VARIABLE(size_t, used);
+};
+
+MemoryChunk::MemoryChunk(size_t len) :
+ buffer(new unsigned char[len]), capacity(len), used(0)
+{
+}
+
+MemoryChunk::~MemoryChunk()
+{
+ delete[] buffer;
+}
+
+MemoryStreamCache::MemoryStreamCache():
+ writeChunk(NULL), nextChunkSize(0)
+{
+}
+
+MemoryStreamCache::~MemoryStreamCache()
+{
+ for (auto it=chunks.begin(); it!=chunks.end(); ++it)
+ delete *it;
+}
+
+// Rounds val up to the next multiple of pow(2, s).
+static size_t nextMultipleOf2Pow(size_t val, size_t s)
+{
+ return ((size_t)((double)(val-1) / (1 << s)) + 1) << s;
+}
+
+void MemoryStreamCache::allocateChunk(size_t minLength)
+{
+ size_t len = imax(imax(minLength, minChunkSize), nextChunkSize);
+ len = nextMultipleOf2Pow(len, 12);
+ assert(len >= minLength);
+ nextChunkSize = len;
+
+ {
+ Locker locker(chunkListMutex);
+ writeChunk = new MemoryChunk(len);
+ chunks.push_back(writeChunk);
+ }
+}
+
+void MemoryStreamCache::handleAppend(const unsigned char* data, size_t length)
+{
+ assert(length > 0);
+
+ if (!writeChunk || (ACQUIRE_READ(writeChunk->used) >= writeChunk->capacity))
+ allocateChunk(length);
+
+ assert(writeChunk);
+
+ size_t used = ACQUIRE_READ(writeChunk->used);
+ if (writeChunk->capacity >= used + length)
+ {
+ // Data fits in to the current chunk
+ memcpy(writeChunk->buffer + used, data, length);
+ RELEASE_WRITE(writeChunk->used, used + length);
+ }
+ else
+ {
+ // Write as much as possible to the current buffer
+ size_t unused = writeChunk->capacity - used;
+ memcpy(writeChunk->buffer + used, data, unused);
+ RELEASE_WRITE(writeChunk->used, writeChunk->capacity);
+
+ // allocate a new chunk by a recursive call
+ handleAppend(data + unused, length - unused);
+ }
+}
+
+void MemoryStreamCache::reserve(size_t expectedLength)
+{
+ if (expectedLength <= receivedLength)
+ return;
+
+ // Set the next chunk to be large enough to hold the remaining
+ // of the stream. The memory will be actually allocated in
+ // append().
+ size_t unused = 0;
+ if (writeChunk)
+ unused = writeChunk->capacity - ACQUIRE_READ(writeChunk->used);
+
+ size_t allocated = receivedLength + unused;
+ if (expectedLength > allocated)
+ nextChunkSize = expectedLength - allocated;
+}
+
+std::streambuf *MemoryStreamCache::createReader()
+{
+ incRef();
+ return new MemoryStreamCache::Reader(_MR(this));
+}
+
+MemoryStreamCache::Reader::Reader(_R<MemoryStreamCache> b) :
+ buffer(b), chunkIndex(0), chunkStartOffset(0)
+{
+ setg(NULL, NULL, NULL);
+}
+
+/**
+ * \brief Called by the streambuf API
+ *
+ * Called by the streambuf API when there is no more data to read.
+ */
+int MemoryStreamCache::Reader::underflow()
+{
+ Locker locker(buffer->chunkListMutex);
+
+ // Wait until there is some data to be read or until terminated
+ bool hasMoreChunks = chunkIndex+1 < buffer->chunks.size();
+ bool lastChunkHasBytes = (chunkIndex+1 == buffer->chunks.size()) &&
+ ((size_t)(gptr() - eback()) < ACQUIRE_READ(buffer->chunks[chunkIndex]->used));
+ if (!buffer->hasTerminated() && !hasMoreChunks && !lastChunkHasBytes)
+ {
+ locker.release();
+ buffer->waitForData(getOffset());
+ locker.acquire();
+ }
+
+ if (chunkIndex >= buffer->chunks.size())
+ {
+ // This can only happen if the stream is terminated
+ // before any data is written.
+ assert(chunkIndex == 0);
+ assert(buffer->hasTerminated());
+ return EOF;
+ }
+
+ MemoryChunk *chunk = buffer->chunks[chunkIndex];
+ size_t used = ACQUIRE_READ(chunk->used);
+ unsigned char *cursor;
+ unsigned char *end = chunk->buffer + used;
+
+ if (gptr() == NULL)
+ {
+ // On the first call gptr() is NULL (as set in the
+ // constructor). Nothing has been read yet.
+ cursor = chunk->buffer;
+ }
+ else if ((unsigned char*)gptr() < end)
+ {
+ // Data left in this chunk
+ cursor = (unsigned char*)gptr();
+ }
+ else if (chunkIndex == buffer->chunks.size()-1)
+ {
+ // This is the last received chunk and there is no
+ // data to be read => we're finished
+ assert(buffer->hasTerminated());
+ return EOF;
+ }
+ else
+ {
+ // Move to the next chunk
+ chunkStartOffset = chunkStartOffset + used;
+ chunkIndex++;
+
+ // chunkIndex is still valid, because the case
+ // size()-1 was handled above
+ assert_and_throw(chunkIndex < buffer->chunks.size());
+
+ chunk = buffer->chunks[chunkIndex];
+ cursor = chunk->buffer;
+ end = chunk->buffer + ACQUIRE_READ(chunk->used);
+ }
+
+ setg((char *)chunk->buffer, (char *)cursor, (char *)end);
+
+ assert(cursor != end); // there is at least one byte to return
+ return (int)cursor[0];
+}
+
+/**
+ * \brief Called by the streambuf API
+ *
+ * Called by the streambuf API to seek to a relative position
+ */
+streampos MemoryStreamCache::Reader::seekoff(streamoff off, std::ios_base::seekdir dir,
+ std::ios_base::openmode mode)
+{
+ if (mode != std::ios_base::in)
+ return -1;
+
+ switch (dir)
+ {
+ case std::ios_base::beg:
+ seekpos(off, mode);
+ break;
+ case std::ios_base::cur:
+ // TODO: optimize by checking if the new
+ // offset is in the current chunk
+ seekpos(getOffset() + off, mode);
+ break;
+ case std::ios_base::end:
+ buffer->waitForTermination();
+ if (buffer->hasFailed())
+ return -1;
+
+ seekpos((streampos)buffer->getReceivedLength() + off, mode);
+ break;
+ default:
+ break;
+ }
+
+ return getOffset();
+}
+
+/**
+ * \brief Called by the streambuf API
+ *
+ * Called by the streambuf API to seek to an absolute position
+ */
+streampos MemoryStreamCache::Reader::seekpos(streampos pos, std::ios_base::openmode mode)
+{
+ if (mode != std::ios_base::in || pos < 0)
+ return -1;
+
+ if (pos >= (streampos)buffer->getReceivedLength())
+ buffer->waitForTermination();
+
+ Locker locker(buffer->chunkListMutex);
+ streampos offset = 0;
+ for (auto it=buffer->chunks.begin(); it!=buffer->chunks.end(); ++it)
+ {
+ streampos used = (streampos)ACQUIRE_READ((*it)->used);
+ if (pos >= offset + used)
+ {
+ offset += used;
+ }
+ else
+ {
+ setg((char *)(*it)->buffer,
+ (char *)((*it)->buffer + (pos - offset)),
+ (char *)((*it)->buffer + used));
+ return pos;
+ }
+ }
+
+ return -1;
+}
+
+/**
+ * Get the position of the read cursor in the (virtual) downloaded data.
+ */
+streampos MemoryStreamCache::Reader::getOffset() const
+{
+ return chunkStartOffset + (size_t)(gptr() - eback());
+}
+
+FileStreamCache::FileStreamCache()
+ : keepCache(false)
+{
+}
+
+FileStreamCache::~FileStreamCache()
+{
+ if (cache.is_open())
+ cache.close();
+ if (!keepCache && !cacheFilename.empty())
+ unlink(cacheFilename.raw_buf());
+}
+
+void FileStreamCache::handleAppend(const unsigned char* buffer, size_t length)
+{
+ if (!cache.is_open())
+ openCache();
+
+ cache.write((const char*)buffer, length);
+ cache.sync();
+}
+
+/**
+ * \brief Creates & opens a temporary cache file
+ *
+ * Creates a temporary cache file in /tmp and calls \c openExistingCache() with that file.
+ * Waits for mutex at start and releases mutex when finished.
+ * \throw RunTimeException Temporary file could not be created
+ * \throw RunTimeException Called when the cache is already open
+ * \see Downloader::openExistingCache()
+ */
+void FileStreamCache::openCache()
+{
+ if (cache.is_open())
+ {
+ markFinished(true);
+ throw RunTimeException(_("FileStreamCache::openCache called twice"));
+ }
+
+ //Create a temporary file(name)
+ std::string cacheFilenameS = Config::getConfig()->getCacheDirectory() + "/" + Config::getConfig()->getCachePrefix() + "XXXXXX";
+ char* cacheFilenameC = g_newa(char,cacheFilenameS.length()+1);
+ strncpy(cacheFilenameC, cacheFilenameS.c_str(), cacheFilenameS.length());
+ cacheFilenameC[cacheFilenameS.length()] = '\0';
+ int fd = g_mkstemp(cacheFilenameC);
+ if(fd == -1)
+ {
+ markFinished(true);
+ throw RunTimeException(_("FileStreamCache::openCache: cannot create temporary file"));
+ }
+
+ //We are using fstream to read/write to the cache, so we don't need this FD
+ close(fd);
+
+ //Let the openExistingCache function handle the rest
+ openExistingCache(tiny_string(cacheFilenameC, true));
+}
+
+/**
+ * \brief Opens an existing cache file
+ *
+ * Opens an existing cache file, allocates the buffer and signals \c cacheOpened.
+ * \post \c cacheFilename is set
+ * \post \c cache file is opened
+ * \throw RunTimeException File could not be opened
+ * \throw RunTimeException Called when the cache is already open
+ */
+void FileStreamCache::openExistingCache(const tiny_string& filename, bool forWriting)
+{
+ if (cache.is_open())
+ {
+ markFinished(true);
+ throw RunTimeException(_("FileStreamCache::openCache called twice"));
+ }
+
+ cacheFilename = filename;
+
+ //Open the cache file
+ ios_base::openmode mode;
+ if (forWriting)
+ mode = std::fstream::binary | std::fstream::out;
+ else
+ mode = std::fstream::binary | std::fstream::in;
+ cache.open(cacheFilename.raw_buf(), mode);
+ if (!cache.is_open())
+ {
+ markFinished(true);
+ throw RunTimeException(_("FileStreamCache::openCache: cannot open temporary cache file"));
+ }
+
+ LOG(LOG_INFO, _("NET: Downloading to cache file: ") << cacheFilename);
+}
+
+void FileStreamCache::useExistingFile(const tiny_string& filename)
+{
+ //Make sure we don't delete the local file afterwards
+ keepCache = true;
+
+ cacheFilename = filename;
+ openExistingCache(filename, false);
+
+ cache.seekg(0, std::ios::end);
+ receivedLength = cache.tellg();
+
+ // We already have the whole file
+ markFinished();
+}
+
+void FileStreamCache::waitForCache()
+{
+ if (cache.is_open())
+ return;
+
+ // Cache file will be opened when the first byte is received
+ waitForData(0);
+
+ // Check if the stream was terminated before anything was written
+ if (!cache.is_open())
+ throw RunTimeException(_("FileStreamCache::waitForCache: cache file is not open"));
+}
+
+std::streambuf *FileStreamCache::createReader()
+{
+ waitForCache();
+
+ incRef();
+ FileStreamCache::Reader *fbuf = new FileStreamCache::Reader(_MR(this));
+ fbuf->open(cacheFilename.raw_buf(), std::fstream::binary | std::fstream::in);
+ if (!fbuf->is_open())
+ {
+ delete fbuf;
+ throw RunTimeException(_("FileStreamCache::createReader: opening cache file for reading failed"));
+ }
+ return fbuf;
+}
+
+FileStreamCache::Reader::Reader(_R<FileStreamCache> b) : buffer(b)
+{
+}
+
+int FileStreamCache::Reader::underflow()
+{
+ if (!buffer->hasTerminated())
+ buffer->waitForData(seekoff(0, ios_base::cur, ios_base::in));
+
+ return filebuf::underflow();
+}
+
+streamsize FileStreamCache::Reader::xsgetn(char* s, streamsize n)
+{
+ streamsize read=filebuf::xsgetn(s, n);
+
+ // If not enough data was available, wait for writer
+ while (read < n)
+ {
+ buffer->waitForData(seekoff(0, ios_base::cur, ios_base::in));
+
+ streamsize b = filebuf::xsgetn(s+read, n-read);
+
+ // No more data after waiting, this must be EOF
+ if (b == 0)
+ return read;
+
+ read += b;
+ }
+
+ return read;
+}
diff --git a/src/backends/streamcache.h b/src/backends/streamcache.h
new file mode 100644
index 0000000..82a14fd
--- /dev/null
+++ b/src/backends/streamcache.h
@@ -0,0 +1,197 @@
+/**************************************************************************
+ Lightspark, a free flash player implementation
+
+ Copyright (C) 2013 Antti Ajanki (antti.ajanki at iki.fi)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+**************************************************************************/
+
+#ifndef BACKENDS_STREAMCACHE_H
+#define BACKENDS_STREAMCACHE_H 1
+
+#include <list>
+#include <istream>
+#include <fstream>
+#include <cstdint>
+#include "threading.h"
+#include "tiny_string.h"
+#include "smartrefs.h"
+#include "compat.h"
+
+namespace lightspark
+{
+
+/*
+ * A single-writer-multiple-reader buffer for downloaded streams.
+ *
+ * Writing is done by one thread by calling append(), reading is done
+ * through streambuf interface (constructred by createReader()) in a
+ * separate thread. There can be several readers in multiple threads.
+ *
+ * This is an abstract base class.
+ */
+class DLL_PUBLIC StreamCache : public RefCountable {
+protected:
+ StreamCache() DLL_LOCAL;
+
+ // stateMutex must be held while receivedLength, failed or
+ // terminated are accessed
+ Mutex stateMutex;
+ // stateCond is signalled when data is received or the stream
+ // is terminated
+ Cond stateCond;
+ // Amount of data already received
+ size_t receivedLength;
+ // Has the stream been completely downloaded or failed?
+ bool failed:1;
+ bool terminated:1;
+
+ // Wait until more than currentOffset bytes has been received
+ // or until terminated
+ void waitForData(size_t currentOffset) DLL_LOCAL;
+
+ // Derived class implements this to store received data
+ virtual void handleAppend(const unsigned char* buffer, size_t length)=0;
+
+public:
+ virtual ~StreamCache() {}
+
+ // Gets the length of downloaded data
+ size_t getReceivedLength() const { return receivedLength; }
+
+ bool hasTerminated() const { return terminated; }
+ bool hasFailed() const { return failed; }
+
+ // Wait until the writer calls markTerminated
+ void waitForTermination();
+
+ // Set the expected length of the stream.
+ // The default implementation does nothing, but the derived
+ // classes can allocate memory here.
+ virtual void reserve(size_t expectedLength) {}
+
+ // Write new data to the buffer (writer thread)
+ void append(const unsigned char* buffer, size_t length);
+
+ // Writer should call this when all of the stream has been
+ // append()'ed
+ void markFinished(bool failed=false);
+
+ // Create a streambuf for reading from this buffer (reader
+ // thread). Every call returns a new, independent streambuf.
+ // The caller must delete the returned value.
+ virtual std::streambuf *createReader()=0;
+};
+
+class MemoryChunk;
+
+/*
+ * MemoryStreamCache buffers the stream in memory.
+ */
+class DLL_PUBLIC MemoryStreamCache : public StreamCache {
+private:
+ class DLL_LOCAL Reader : public std::streambuf {
+ private:
+ _R<MemoryStreamCache> buffer;
+ // The chunk that is currently being read
+ unsigned int chunkIndex;
+ // Offset at the start of current chunk
+ size_t chunkStartOffset;
+
+ // Handles streambuf out-of-data events
+ virtual int underflow();
+ // Seeks to absolute position
+ virtual std::streampos seekoff(std::streamoff, std::ios_base::seekdir, std::ios_base::openmode);
+ // Seeks to relative position
+ virtual std::streampos seekpos(std::streampos, std::ios_base::openmode);
+ // Helper to get the current offset
+ std::streampos getOffset() const;
+ public:
+ Reader(_R<MemoryStreamCache> b);
+ };
+
+ // Stream is stored into a sequence of memory chunks. The
+ // chunks can grow, but they are never moved, so both readers
+ // and writer can safely use them. However, the mutex must be
+ // held when the container is accessed.
+ Mutex chunkListMutex;
+ std::vector<MemoryChunk *> chunks;
+
+ // The last chunk, the next write will happen here (writer thread)
+ MemoryChunk *writeChunk;
+
+ // Variables controlling the memory allocation
+ size_t nextChunkSize;
+ static const size_t minChunkSize = 4*4096;
+
+ // Allocate a new chunk, append it to chunks, update writeChunk
+ void allocateChunk(size_t minLength) DLL_LOCAL;
+
+ virtual void handleAppend(const unsigned char* buffer, size_t length) DLL_LOCAL;
+
+public:
+ MemoryStreamCache();
+ virtual ~MemoryStreamCache();
+
+ virtual void reserve(size_t expectedLength);
+
+ virtual std::streambuf *createReader();
+};
+
+/*
+ * FileStreamCache saves the stream in a temporary file.
+ */
+class DLL_PUBLIC FileStreamCache : public StreamCache {
+private:
+ /*
+ * Extends filebuf to wait for writer thread to supply more
+ * data when the end of temporary file is reached.
+ */
+ class DLL_LOCAL Reader : public std::filebuf {
+ private:
+ _R<FileStreamCache> buffer;
+ virtual int underflow();
+ virtual std::streamsize xsgetn(char* s, std::streamsize n);
+ public:
+ Reader(_R<FileStreamCache> buffer);
+ };
+
+ //Cache filename
+ tiny_string cacheFilename;
+ //Cache fstream
+ std::fstream cache;
+ //True if the cache file doesn't need to be deleted on destruction
+ bool keepCache:1;
+
+ void openCache() DLL_LOCAL;
+ void openExistingCache(const tiny_string& filename, bool forWriting=true) DLL_LOCAL;
+
+ // Block until the cache file is opened by the writer stream
+ void waitForCache() DLL_LOCAL;
+
+ virtual void handleAppend(const unsigned char* buffer, size_t length) DLL_LOCAL;
+
+public:
+ FileStreamCache();
+ virtual ~FileStreamCache();
+
+ virtual std::streambuf *createReader();
+
+ // Use an existing file as cache. Must be called before append().
+ void useExistingFile(const tiny_string& filename);
+};
+
+};
+
+#endif // BACKENDS_STREAMCACHE_H
diff --git a/src/backends/urlutils.cpp b/src/backends/urlutils.cpp
index ebeaf9c..2511948 100644
--- a/src/backends/urlutils.cpp
+++ b/src/backends/urlutils.cpp
@@ -22,15 +22,39 @@
#include "backends/urlutils.h"
#include "compat.h"
#include "scripting/toplevel/Integer.h"
+#include "scripting/toplevel/Error.h"
+#include "scripting/class.h"
#include <string>
#include <algorithm>
#include <cctype>
#include <sstream>
#include <iostream>
#include <fstream>
+#ifdef __MINGW32__
+#include <malloc.h>
+#else
+#include <alloca.h>
+#endif
using namespace lightspark;
+std::list<uint32_t> URLInfo::uriReservedAndHash =
+ {';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '#'};
+std::list<uint32_t> URLInfo::uriUnescaped =
+ {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+ 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B',
+ 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+ 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3',
+ '4', '5', '6', '7', '8', '9', '-', '_', '.', '!', '~', '*', '\'', '(',
+ ')'};
+std::list<uint32_t> URLInfo::uriReservedAndUnescapedAndHash =
+ {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+ 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B',
+ 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+ 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3',
+ '4', '5', '6', '7', '8', '9', '-', '_', '.', '!', '~', '*', '\'', '(',
+ ')', ';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '#'};
+
std::ostream& lightspark::operator<<(std::ostream& s, const URLInfo& u)
{
s << u.getParsedURL();
@@ -50,11 +74,15 @@ URLInfo::URLInfo(const tiny_string& u)
if(colonPos == std::string::npos)
invalidReason = MISSING_PROTOCOL;
- std::string protocolStr = str.substr(0, colonPos);
- std::transform(protocolStr.begin(), protocolStr.end(), protocolStr.begin(), ::tolower);
+ std::string protocolStr;
+ if (colonPos != std::string::npos)
+ {
+ protocolStr = str.substr(0, colonPos);
+ std::transform(protocolStr.begin(), protocolStr.end(), protocolStr.begin(), ::tolower);
+ }
protocol = protocolStr;
- size_t hostnamePos = colonPos+3;
+ size_t hostnamePos = colonPos != std::string::npos ? colonPos+3 : std::string::npos;
size_t portPos = std::string::npos;
size_t pathPos = std::string::npos;
size_t queryPos = std::string::npos;
@@ -93,8 +121,12 @@ URLInfo::URLInfo(const tiny_string& u)
}
//Parse the host string
- std::string hostnameStr = str.substr(hostnamePos, std::min(std::min(pathPos, portPos), queryPos)-hostnamePos);
- std::transform(hostnameStr.begin(), hostnameStr.end(), hostnameStr.begin(), ::tolower);
+ std::string hostnameStr;
+ if (hostnamePos != std::string::npos)
+ {
+ hostnameStr= str.substr(hostnamePos, std::min(std::min(pathPos, portPos), queryPos)-hostnamePos);
+ std::transform(hostnameStr.begin(), hostnameStr.end(), hostnameStr.begin(), ::tolower);
+ }
hostname = hostnameStr;
port = 0;
@@ -287,7 +319,7 @@ bool URLInfo::isSubOf(const URLInfo& url) const
}
bool URLInfo::isSubPathOf(const tiny_string& parent, const tiny_string& child)
{
- return child.substr(0, parent.numChars()) == parent;
+ return child.substr_bytes(0, parent.numBytes()) == parent;
}
bool URLInfo::isSubDomainOf(const tiny_string& parent, const tiny_string& child)
{
@@ -332,6 +364,11 @@ bool URLInfo::sameHost(const URLInfo& other) const
tiny_string URLInfo::encode(const tiny_string& u, ENCODING type)
{
+ if (type == ENCODE_URI)
+ return encodeURI(u, uriReservedAndUnescapedAndHash);
+ else if (type == ENCODE_URICOMPONENT)
+ return encodeURI(u, uriUnescaped);
+
tiny_string str;
char buf[7];
@@ -355,20 +392,6 @@ tiny_string URLInfo::encode(const tiny_string& u, ENCODING type)
//ENCODE_FORM encodes spaces as + instead of %20
else if(type == ENCODE_FORM && *i == ' ')
str += '+';
- //Additionally ENCODE_URICOMPONENT and ENCODE_URI don't encode:
- //- _ . ! ~ * ' ( )
- else if((type == ENCODE_URI || type == ENCODE_URICOMPONENT) &&
- (*i == '-' || *i == '_' || *i == '.' || *i == '!' ||
- *i == '~' || *i == '*' || *i == '\'' || *i == '(' ||
- *i == ')'))
- str += *i;
- //Additionally ENCODE_URI doesn't encode:
- //; / ? : @ & = + $ , #
- else if((type == ENCODE_URI) &&
- (*i == ';' || *i == '/' || *i == '?' || *i == ':' ||
- *i == '@' || *i == '&' || *i == '=' || *i == '+' ||
- *i == '$' || *i == ',' || *i == '#'))
- str += *i;
// ENCODE_ESCAPE doesn't encode:
//@ - _ . * + /
else if(type == ENCODE_ESCAPE &&
@@ -390,8 +413,72 @@ tiny_string URLInfo::encode(const tiny_string& u, ENCODING type)
return str;
}
-std::string URLInfo::decode(const std::string& u, ENCODING type)
+tiny_string URLInfo::encodeURI(const tiny_string& u, const std::list<uint32_t>& unescapedChars) {
+ tiny_string res;
+ CharIterator c = u.begin();
+ CharIterator end = u.end();
+ while (c != end)
+ {
+ if (std::find(unescapedChars.begin(), unescapedChars.end(), *c) == unescapedChars.end())
+ {
+ if ((*c >= 0xD800) && (*c <= 0xDFFF))
+ {
+ res += encodeSurrogatePair(c, end);
+ }
+ else
+ {
+ res += encodeSingleChar(*c);
+ }
+ }
+ else
+ {
+ res += *c;
+ }
+ ++c;
+ }
+ return res;
+}
+
+tiny_string URLInfo::encodeSurrogatePair(CharIterator& c, const CharIterator& end)
+{
+ if ((*c < 0xD800) || (*c >= 0xDC00))
+ throwError<URIError>(kInvalidURIError, "encodeURI");
+ uint32_t highSurrogate = *c;
+ ++c;
+ if ((c == end) || ((*c < 0xDC00) || (*c > 0xDFFF)))
+ throwError<URIError>(kInvalidURIError, "encodeURI");
+ uint32_t lowSurrogate = *c;
+ return encodeSingleChar((highSurrogate - 0xD800)*0x400 +
+ (lowSurrogate - 0xDC00) + 0x10000);
+}
+
+tiny_string URLInfo::encodeSingleChar(uint32_t codepoint)
{
+ char octets[6];
+ gint numOctets = g_unichar_to_utf8(codepoint, octets);
+ tiny_string encoded;
+ for (int i=0; i<numOctets; i++)
+ {
+ encoded += encodeOctet(octets[i]);
+ }
+
+ return encoded;
+}
+
+tiny_string URLInfo::encodeOctet(char c) {
+ gchar *buf = (gchar *)alloca(6);
+ g_snprintf(buf, 6, "%%%.2X", (unsigned char)c);
+ buf[5] = '\0';
+ return tiny_string(buf, true);
+}
+
+tiny_string URLInfo::decode(const std::string& u, ENCODING type)
+{
+ if (type == ENCODE_URI)
+ return decodeURI(u, uriReservedAndHash);
+ else if (type == ENCODE_URICOMPONENT)
+ return decodeURI(u, {});
+
std::string str;
//The string can only shrink
str.reserve(u.length());
@@ -419,26 +506,6 @@ std::string URLInfo::decode(const std::string& u, ENCODING type)
str += stringBuf;
i+=2;
}
- //ENCODE_URI and ENCODE_URICOMPONENT don't decode:
- //- _ . ! ~ * ' ( )
- else if((type == ENCODE_URI || type == ENCODE_URICOMPONENT) &&
- (stringBuf == "%2D" || stringBuf == "%5F" || stringBuf == "%2E" || stringBuf == "%21" ||
- stringBuf == "%7E" || stringBuf == "%2A" || stringBuf == "%27" || stringBuf == "%28" ||
- stringBuf == "%29"))
- {
- str += stringBuf;
- i+=2;
- }
- //Additionally ENCODE_URI doesn't decode:
- //; / ? : @ & = + $ , #
- else if(type == ENCODE_URI &&
- (stringBuf == "%23" || stringBuf == "%24" || stringBuf == "%26" || stringBuf == "%2B" ||
- stringBuf == "%2C" || stringBuf == "%2F" || stringBuf == "%3A" || stringBuf == "%3B" ||
- stringBuf == "%3D" || stringBuf == "%3F" || stringBuf == "%40"))
- {
- str += stringBuf;
- i+=2;
- }
//All encoded characters that weren't excluded above are now decoded
else
{
@@ -466,6 +533,112 @@ std::string URLInfo::decode(const std::string& u, ENCODING type)
return str;
}
+tiny_string URLInfo::decodeURI(const tiny_string& u, const std::list<uint32_t>& reservedChars)
+{
+ tiny_string res;
+ CharIterator c = u.begin();
+ CharIterator end = u.end();
+ while (c != end)
+ {
+ if (*c == '%')
+ {
+ CharIterator encodeBegin = c;
+ uint32_t decoded = decodeSingleChar(c, end);
+ if (std::find(reservedChars.begin(), reservedChars.end(), decoded) == reservedChars.end())
+ {
+ res += decoded;
+ }
+ else
+ {
+ CharIterator it = encodeBegin;
+ while (it != c)
+ {
+ res += *it;
+ ++it;
+ }
+ }
+ }
+ else
+ {
+ res += *c;
+ ++c;
+ }
+ }
+
+ return res;
+}
+
+uint32_t URLInfo::decodeSingleChar(CharIterator& c, const CharIterator& end)
+{
+ uint32_t decoded = decodeSingleEscapeSequence(c, end);
+ if ((decoded & 0x80) != 0) {
+ decoded = decodeRestOfUTF8Sequence(decoded, c, end);
+ }
+ return decoded;
+}
+
+uint32_t URLInfo::decodeRestOfUTF8Sequence(uint32_t firstOctet, CharIterator& c, const CharIterator& end) {
+ unsigned int numOctets = 0;
+ uint32_t mask = 0x80;
+ while ((firstOctet & mask) != 0) {
+ numOctets++;
+ mask = mask >> 1;
+ }
+ if (numOctets <= 1 || numOctets > 4)
+ throwError<URIError>(kInvalidURIError, "decodeURI");
+
+ char *octets = (char *)alloca(numOctets);
+ octets[0] = firstOctet;
+ for (unsigned int i=1; i<numOctets; i++) {
+ octets[i] = decodeSingleEscapeSequence(c, end);
+ }
+
+ if (isSurrogateUTF8Sequence(octets, numOctets))
+ {
+ LOG(LOG_NOT_IMPLEMENTED, "decodeURI: decoding surrogate pairs");
+ return REPLACEMENT_CHARACTER;
+ }
+
+ gunichar unichar = g_utf8_get_char_validated(octets, numOctets);
+ if ((unichar == (gunichar)-1) ||
+ (unichar == (gunichar)-2) ||
+ (unichar >= 0x10FFFF))
+ throwError<URIError>(kInvalidURIError, "decodeURI");
+
+ return (uint32_t)unichar;
+}
+
+uint32_t URLInfo::decodeSingleEscapeSequence(CharIterator& c, const CharIterator& end)
+{
+ if (*c != '%')
+ throwError<URIError>(kInvalidURIError, "decodeURI");
+ ++c;
+ uint32_t h1 = decodeHexDigit(c, end);
+ uint32_t h2 = decodeHexDigit(c, end);
+ return (h1 << 4) + h2;
+}
+
+bool URLInfo::isSurrogateUTF8Sequence(const char *octets, unsigned int numOctets)
+{
+ // Surrogate code points: 0xD800 - 0xDFFF
+ // UTF-8 encoded: 0xED 0xA0 0x80 - 0xED 0xBF 0xBF
+ return (numOctets == 3) &&
+ ((unsigned char)octets[0] == 0xED) &&
+ ((unsigned char)octets[1] >= 0xA0) &&
+ ((unsigned char)octets[1] <= 0xBF);
+}
+
+uint32_t URLInfo::decodeHexDigit(CharIterator& c, const CharIterator& end)
+{
+ if (c == end || !isxdigit(*c))
+ throwError<URIError>(kInvalidURIError, "decodeURI");
+
+ gint h = g_unichar_xdigit_value(*c);
+ assert((h >= 0) && (h < 16));
+ ++c;
+ return (uint32_t) h;
+}
+
bool URLInfo::isRTMP() const
{
return protocol == "rtmp" || protocol == "rtmpe" || protocol == "rtmps" ||
diff --git a/src/backends/urlutils.h b/src/backends/urlutils.h
index 7c95982..6d1f633 100644
--- a/src/backends/urlutils.h
+++ b/src/backends/urlutils.h
@@ -35,6 +35,10 @@ class DLL_PUBLIC URLInfo
{
friend std::ostream& operator<<(std::ostream& s, const URLInfo& u);
private:
+ static std::list<uint32_t> uriReservedAndHash;
+ static std::list<uint32_t> uriUnescaped;
+ static std::list<uint32_t> uriReservedAndUnescapedAndHash;
+ static const uint32_t REPLACEMENT_CHARACTER = 0xFFFD;
tiny_string url; //The URL space encoded
tiny_string parsedURL; //The URL normalized and space encoded
tiny_string protocol; //Part after
@@ -51,6 +55,16 @@ private:
INVALID_REASON invalidReason;
uint16_t port; //Part after first : after hostname
bool valid;
+ static tiny_string encodeURI(const tiny_string& u, const std::list<uint32_t>& unescapedChars);
+ static tiny_string encodeSurrogatePair(CharIterator& c, const CharIterator& end);
+ static tiny_string encodeSingleChar(uint32_t codepoint);
+ static tiny_string encodeOctet(char c);
+ static tiny_string decodeURI(const tiny_string& u, const std::list<uint32_t>& reservedChars);
+ static uint32_t decodeSingleEscapeSequence(CharIterator& c, const CharIterator& end);
+ static uint32_t decodeSingleChar(CharIterator& c, const CharIterator& end);
+ static uint32_t decodeRestOfUTF8Sequence(uint32_t firstOctet, CharIterator& c, const CharIterator& end);
+ static uint32_t decodeHexDigit(CharIterator& c, const CharIterator& end);
+ static bool isSurrogateUTF8Sequence(const char *octets, unsigned int numOctets);
public:
URLInfo():invalidReason(IS_EMPTY),valid(false) {};
URLInfo(const tiny_string& u);
@@ -109,11 +123,7 @@ public:
{
return std::string(encode(tiny_string(u), type));
}
- static tiny_string decode(const tiny_string& u, ENCODING type=ENCODE_URICOMPONENT)
- {
- return tiny_string(decode(std::string(u.raw_buf()), type));
- };
- static std::string decode(const std::string& u, ENCODING type=ENCODE_URICOMPONENT);
+ static tiny_string decode(const std::string& u, ENCODING type=ENCODE_URICOMPONENT);
};
};
diff --git a/src/backends/xml_support.cpp b/src/backends/xml_support.cpp
index 2aefaee..8d1af9d 100644
--- a/src/backends/xml_support.cpp
+++ b/src/backends/xml_support.cpp
@@ -40,6 +40,7 @@ void RecoveryDomParser::parse_memory_raw(const unsigned char* contents, size_typ
xmlSAXHandlerV1* handler=(xmlSAXHandlerV1*)calloc(1,sizeof(xmlSAXHandlerV1));
initxmlDefaultSAXHandler(handler, 0);
+ handler->comment = comment;
context_->recovery=1;
free(context_->sax);
context_->sax=(xmlSAXHandler*)handler;
@@ -60,7 +61,8 @@ void RecoveryDomParser::parse_memory_raw(const unsigned char* contents, size_typ
if(!context_->wellFormed)
LOG(LOG_ERROR, "XML data not well formed!");
- doc_ = new RecoveryDocument(context_->myDoc);
+ if (context_->myDoc)
+ doc_ = new RecoveryDocument(context_->myDoc);
// This is to indicate to release_underlying that we took the
// ownership on the doc.
context_->myDoc = 0;
@@ -74,7 +76,7 @@ void RecoveryDomParser::parse_memory_raw(const unsigned char* contents, size_typ
#endif
xmlpp::Node* XMLBase::buildFromString(const string& str,
- bool ignoreEmptyTextNodes,
+ bool ignoreEmptyTextNodes, bool *hasParent,
const string& default_ns)
{
string buf = parserQuirks(str);
@@ -86,27 +88,42 @@ xmlpp::Node* XMLBase::buildFromString(const string& str,
{
}
xmlpp::Document* doc=parser.get_document();
- if(doc && doc->get_root_node())
+ if(doc)
{
- xmlpp::Element *root = doc->get_root_node();
- // It would be better to remove empty nodes during
- // parsing, but xmlpp doesn't offer an interface.
- if (ignoreEmptyTextNodes)
- removeWhitespaceNodes(root);
- addDefaultNamespace(root, default_ns);
- return root;
+ if (!doc->get_root_node())
+ {
+ buf = removeWhitespace(str)+"<parent></parent>";
+ try
+ {
+ parser.parse_memory_raw((const unsigned char*)buf.c_str(), buf.size());
+ }
+ catch(const exception& e)
+ {
+ }
+ doc=parser.get_document();
+ }
+ if (doc && doc->get_root_node())
+ {
+ *hasParent = true;
+ xmlpp::Element *root = doc->get_root_node();
+ // It would be better to remove empty nodes during
+ // parsing, but xmlpp doesn't offer an interface.
+ if (ignoreEmptyTextNodes)
+ removeWhitespaceNodes(root);
+ addDefaultNamespace(root, default_ns);
+ return root;
+ }
}
-
- LOG(LOG_ERROR, "XML parsing failed, creating text node");
//If everything fails, create a fake document and add a single text string child
+ // see 10.3.1 in ECMA 357
if (default_ns.empty())
- buf="<a></a>";
+ buf="<parent></parent>";
else
- buf="<a xmlns=\"" + default_ns + "\"></a>";
+ buf="<parent xmlns=\"" + default_ns + "\"></parent>";
parser.parse_memory_raw((const unsigned char*)buf.c_str(), buf.size());
+ *hasParent = false;
return parser.get_document()->get_root_node()->add_child_text(str);
- // TODO: node's parent (root) should be inaccessible from AS code
}
void XMLBase::addDefaultNamespace(xmlpp::Element *root, const string& default_ns)
@@ -136,15 +153,25 @@ void XMLBase::addDefaultNamespaceRecursive(xmlNodePtr node, xmlNsPtr ns)
}
}
-xmlpp::Node* XMLBase::buildCopy(const xmlpp::Node* src)
+xmlpp::Node* XMLBase::buildCopy(const xmlpp::Node* src, bool *hasParent)
{
+ const xmlpp::ContentNode* contentnode;
const xmlpp::TextNode* textnode=dynamic_cast<const xmlpp::TextNode*>(src);
if(textnode)
{
- return buildFromString(textnode->get_content(), false);
+ return buildFromString(textnode->get_content(), false,hasParent);
+ }
+ else if ((contentnode = dynamic_cast<const xmlpp::ContentNode*>(src)))
+ {
+ // ContentNode but not TextNode => comment, PI or CData
+ // These can't be root nodes so we add a dummy root.
+ *hasParent = false;
+ xmlpp::Element* root = parser.get_document()->create_root_node("dummy_root");
+ return root->import_node(contentnode);
}
else
{
+ *hasParent = true;
return parser.get_document()->create_root_node_by_import(src);
}
}
@@ -210,3 +237,25 @@ void XMLBase::removeWhitespaceNodes(xmlpp::Element *node)
}
}
}
+tiny_string XMLBase::removeWhitespace(tiny_string val)
+{
+ bool bwhite = true;
+ uint32_t start = 0;
+ CharIterator it = val.begin();
+ CharIterator itend = val.begin();
+ while (it != val.end())
+ {
+ if (!g_unichar_isspace(*it))
+ {
+ itend=it;
+ itend++;
+ bwhite = false;
+ }
+ else if (bwhite)
+ start++;
+ it++;
+ }
+ if (bwhite)
+ return "";
+ return val.substr(start,itend);
+}
diff --git a/src/backends/xml_support.h b/src/backends/xml_support.h
index 5ef59b1..a8a6a5b 100644
--- a/src/backends/xml_support.h
+++ b/src/backends/xml_support.h
@@ -25,6 +25,7 @@
#include <libxml++/exceptions/internal_error.h>
//For xmlCreateFileParserCtxt().
#include <libxml/parserInternals.h>
+#include "tiny_string.h"
namespace lightspark
{
@@ -57,16 +58,19 @@ protected:
LSDomParser parser;
xmlpp::Node* buildFromString(const std::string& str,
bool ignoreEmptyTextnodes,
+ bool *hasParent,
const std::string& default_ns=std::string());
void addDefaultNamespace(xmlpp::Element *root, const std::string& default_ns);
void addDefaultNamespaceRecursive(xmlNodePtr node, xmlNsPtr ns);
// Set the root to be a copy of src. If src is a text node,
// create a new element node with the same content.
- xmlpp::Node* buildCopy(const xmlpp::Node* node);
- static std::string parserQuirks(const std::string& str);
+ xmlpp::Node* buildCopy(const xmlpp::Node* node, bool *hasParent);
static std::string quirkCData(const std::string& str);
static std::string quirkXMLDeclarationInMiddle(const std::string& str);
void removeWhitespaceNodes(xmlpp::Element *node);
+ tiny_string removeWhitespace(tiny_string val);
+public:
+ static std::string parserQuirks(const std::string& str);
};
};
diff --git a/src/compat.h b/src/compat.h
index 5934b65..0cc00c3 100644
--- a/src/compat.h
+++ b/src/compat.h
@@ -116,6 +116,7 @@ _CRTIMP char* __cdecl __MINGW_NOTHROW _strdup (const char*) __MINGW_ATTRIB_MAL
//Boolean type with acquire release barrier semantics
#define ACQUIRE_RELEASE_FLAG(x) std::atomic_bool x
+#define ACQUIRE_RELEASE_VARIABLE(t, x) std::atomic<t> x
#define ACQUIRE_READ(x) x.load(std::memory_order_acquire)
#define RELEASE_WRITE(x, v) x.store(v, std::memory_order_release)
diff --git a/src/main.cpp b/src/main.cpp
index d0099bd..6f8d331 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -246,6 +246,7 @@ int main(int argc, char* argv[])
#ifdef PROFILING_SUPPORT
" [--profiling-output|-o profiling-file]" <<
#endif
+ " [--version|-v]" <<
" <file.swf>");
exit(1);
}
@@ -286,7 +287,12 @@ int main(int argc, char* argv[])
{
sys->mainClip->setOrigin(url, fileName);
sys->parseParametersFromURL(sys->mainClip->getOrigin());
- sandboxType = SecurityManager::REMOTE;
+ if (sandboxType != SecurityManager::REMOTE &&
+ sys->mainClip->getOrigin().getProtocol() != "file")
+ {
+ LOG(LOG_INFO, _("Switching to remote sandbox because of remote url"));
+ sandboxType = SecurityManager::REMOTE;
+ }
}
#ifndef _WIN32
//When running in a local sandbox, set the root URL to the current working dir
diff --git a/src/parsing/amf3_generator.cpp b/src/parsing/amf3_generator.cpp
index 455cde7..0801c0a 100644
--- a/src/parsing/amf3_generator.cpp
+++ b/src/parsing/amf3_generator.cpp
@@ -26,6 +26,7 @@
#include "toplevel/XML.h"
#include <iostream>
#include <fstream>
+#include "scripting/flash/utils/ByteArray.h"
using namespace std;
using namespace lightspark;
@@ -273,6 +274,7 @@ _R<ASObject> Amf3Deserializer::parseXML(std::vector<ASObject*>& objMap, bool leg
return _MR(xmlObj);
}
+
_R<ASObject> Amf3Deserializer::parseValue(std::vector<tiny_string>& stringMap,
std::vector<ASObject*>& objMap,
std::vector<TraitsRef>& traitsMap) const
@@ -281,33 +283,144 @@ _R<ASObject> Amf3Deserializer::parseValue(std::vector<tiny_string>& stringMap,
uint8_t marker;
if(!input->readByte(marker))
throw ParseException("Not enough data to parse AMF3 object");
+ if (input->getCurrentObjectEncoding() == ObjectEncoding::AMF3)
+ {
+ switch(marker)
+ {
+ case null_marker:
+ return _MR(getSys()->getNullRef());
+ case undefined_marker:
+ return _MR(getSys()->getUndefinedRef());
+ case false_marker:
+ return _MR(abstract_b(false));
+ case true_marker:
+ return _MR(abstract_b(true));
+ case integer_marker:
+ return parseInteger();
+ case double_marker:
+ return parseDouble();
+ case string_marker:
+ return _MR(Class<ASString>::getInstanceS(parseStringVR(stringMap)));
+ case xml_doc_marker:
+ return parseXML(objMap, true);
+ case array_marker:
+ return parseArray(stringMap, objMap, traitsMap);
+ case object_marker:
+ return parseObject(stringMap, objMap, traitsMap);
+ case xml_marker:
+ return parseXML(objMap, false);
+ default:
+ LOG(LOG_ERROR,"Unsupported marker " << (uint32_t)marker);
+ throw UnsupportedException("Unsupported marker");
+ }
+
+ }
+ else
+ {
+ switch(marker)
+ {
+ case amf0_number_marker:
+ return parseDouble();
+ case amf0_boolean_marker:
+ return _MR(abstract_b(input->readByte(marker)));
+ case amf0_string_marker:
+ return _MR(Class<ASString>::getInstanceS(parseStringAMF0()));
+ case amf0_object_marker:
+ return parseObjectAMF0(stringMap,objMap,traitsMap);
+ case amf0_null_marker:
+ return _MR(getSys()->getNullRef());
+ case amf0_undefined_marker:
+ return _MR(getSys()->getUndefinedRef());
+ case amf0_reference_marker:
+ LOG(LOG_ERROR,"unimplemented marker " << (uint32_t)marker);
+ throw UnsupportedException("unimplemented marker");
+ case amf0_ecma_array_marker:
+ return parseECMAArrayAMF0(stringMap,objMap,traitsMap);
+ case amf0_strict_array_marker:
+ LOG(LOG_ERROR,"unimplemented marker " << (uint32_t)marker);
+ throw UnsupportedException("unimplemented marker");
+ case amf0_date_marker:
+ LOG(LOG_ERROR,"unimplemented marker " << (uint32_t)marker);
+ throw UnsupportedException("unimplemented marker");
+ case amf0_long_string_marker:
+ LOG(LOG_ERROR,"unimplemented marker " << (uint32_t)marker);
+ throw UnsupportedException("unimplemented marker");
+ case amf0_xml_document_marker:
+ return parseXML(objMap, false);
+ case amf0_typed_object_marker:
+ LOG(LOG_ERROR,"unimplemented marker " << (uint32_t)marker);
+ throw UnsupportedException("unimplemented marker");
+ case amf0_avmplus_object_marker:
+ input->setCurrentObjectEncoding(ObjectEncoding::AMF3);
+ return parseValue(stringMap, objMap, traitsMap);
+ default:
+ LOG(LOG_ERROR,"Unsupported marker " << (uint32_t)marker);
+ throw UnsupportedException("Unsupported marker");
+ }
+ }
+}
+tiny_string Amf3Deserializer::parseStringAMF0() const
+{
+ uint16_t strLen;
+ if(!input->readShort(strLen))
+ throw ParseException("Not enough data to parse integer");
+
+ string retStr;
+ for(uint32_t i=0;i<strLen;i++)
+ {
+ uint8_t c;
+ if(!input->readByte(c))
+ throw ParseException("Not enough data to parse string");
+ retStr.push_back(c);
+ }
+ return retStr;
+}
+_R<ASObject> Amf3Deserializer::parseECMAArrayAMF0(std::vector<tiny_string>& stringMap,
+ std::vector<ASObject*>& objMap,
+ std::vector<TraitsRef>& traitsMap) const
+{
+ uint32_t count;
+ if(!input->readUnsignedInt(count))
+ throw ParseException("Not enough data to parse AMF3 array");
+
+ _R<ASObject> ret=_MR(Class<ASObject>::getInstanceS());
- switch(marker)
+ //Read name, value pairs
+ while(count)
{
- case null_marker:
- return _MR(getSys()->getNullRef());
- case undefined_marker:
- return _MR(getSys()->getUndefinedRef());
- case false_marker:
- return _MR(abstract_b(false));
- case true_marker:
- return _MR(abstract_b(true));
- case integer_marker:
- return parseInteger();
- case double_marker:
- return parseDouble();
- case string_marker:
- return _MR(Class<ASString>::getInstanceS(parseStringVR(stringMap)));
- case xml_doc_marker:
- return parseXML(objMap, true);
- case array_marker:
- return parseArray(stringMap, objMap, traitsMap);
- case object_marker:
- return parseObject(stringMap, objMap, traitsMap);
- case xml_marker:
- return parseXML(objMap, false);
- default:
- LOG(LOG_ERROR,"Unsupported marker " << (uint32_t)marker);
- throw UnsupportedException("Unsupported marker");
+ tiny_string varName = parseStringAMF0();
+ if (varName == "")
+ throw ParseException("empty key in AMF0 ECMA array");
+ _R<ASObject> value=parseValue(stringMap, objMap, traitsMap);
+ value->incRef();
+
+ ret->setVariableByQName(varName,"",value.getPtr(),DYNAMIC_TRAIT);
+ count--;
}
+ return ret;
}
+_R<ASObject> Amf3Deserializer::parseObjectAMF0(std::vector<tiny_string>& stringMap,
+ std::vector<ASObject*>& objMap,
+ std::vector<TraitsRef>& traitsMap) const
+{
+ _R<ASObject> ret=_MR(Class<ASObject>::getInstanceS());
+
+ while (true)
+ {
+ tiny_string varName = parseStringAMF0();
+ if (varName == "")
+ {
+ uint8_t marker = 0;
+ input->readByte(marker);
+ if (marker == amf0_object_end_marker )
+ return ret;
+ throw ParseException("empty key in AMF0 object");
+ }
+ _R<ASObject> value=parseValue(stringMap, objMap, traitsMap);
+ value->incRef();
+
+ ret->setVariableByQName(varName,"",value.getPtr(),DYNAMIC_TRAIT);
+ }
+ return _R<ASObject>(getSys()->getUndefinedRef());
+}
+
diff --git a/src/parsing/amf3_generator.h b/src/parsing/amf3_generator.h
index 360685a..ae2cd69 100644
--- a/src/parsing/amf3_generator.h
+++ b/src/parsing/amf3_generator.h
@@ -50,6 +50,28 @@ enum markers_type
xml_marker = 0xb
};
+enum amf0_markers_type
+{
+ amf0_number_marker = 0x00,
+ amf0_boolean_marker = 0x01,
+ amf0_string_marker = 0x02,
+ amf0_object_marker = 0x03,
+ amf0_movieclip_marker = 0x04,
+ amf0_null_marker = 0x05,
+ amf0_undefined_marker = 0x06,
+ amf0_reference_marker = 0x07,
+ amf0_ecma_array_marker = 0x08,
+ amf0_object_end_marker = 0x09,
+ amf0_strict_array_marker = 0x0A,
+ amf0_date_marker = 0x0B,
+ amf0_long_string_marker = 0x0C,
+ amf0_unsupported_marker = 0x0D,
+ amf0_recordset_marker = 0x0E,
+ amf0_xml_document_marker = 0x0F,
+ amf0_typed_object_marker = 0x10,
+ amf0_avmplus_object_marker = 0x11
+};
+
class TraitsRef
{
public:
@@ -64,6 +86,7 @@ class Amf3Deserializer
private:
ByteArray* input;
tiny_string parseStringVR(std::vector<tiny_string>& stringMap) const;
+
_R<ASObject> parseObject(std::vector<tiny_string>& stringMap,
std::vector<ASObject*>& objMap,
std::vector<TraitsRef>& traitsMap) const;
@@ -76,6 +99,15 @@ private:
_R<ASObject> parseInteger() const;
_R<ASObject> parseDouble() const;
_R<ASObject> parseXML(std::vector<ASObject*>& objMap, bool legacyXML) const;
+
+
+ tiny_string parseStringAMF0() const;
+ _R<ASObject> parseECMAArrayAMF0(std::vector<tiny_string>& stringMap,
+ std::vector<ASObject*>& objMap,
+ std::vector<TraitsRef>& traitsMap) const;
+ _R<ASObject> parseObjectAMF0(std::vector<tiny_string>& stringMap,
+ std::vector<ASObject*>& objMap,
+ std::vector<TraitsRef>& traitsMap) const;
public:
Amf3Deserializer(ByteArray* i):input(i) {}
_R<ASObject> readObject() const;
diff --git a/src/parsing/tags.cpp b/src/parsing/tags.cpp
index 665147d..6cdb962 100644
--- a/src/parsing/tags.cpp
+++ b/src/parsing/tags.cpp
@@ -24,10 +24,16 @@
#include <list>
#include <algorithm>
#include <sstream>
+#ifdef __MINGW32__
+#include <malloc.h>
+#else
+#include <alloca.h>
+#endif
#include "scripting/abc.h"
#include "parsing/tags.h"
#include "backends/geometry.h"
#include "backends/security.h"
+#include "backends/streamcache.h"
#include "swftypes.h"
#include "logger.h"
#include "compat.h"
@@ -35,6 +41,7 @@
#include "scripting/flash/display/BitmapData.h"
#include "scripting/flash/text/flashtext.h"
#include "scripting/flash/media/flashmedia.h"
+#include "backends/audio.h"
#undef RGB
@@ -383,6 +390,7 @@ DefineSpriteTag::DefineSpriteTag(RECORDHEADER h, std::istream& in, RootMovieClip
case SYMBOL_CLASS_TAG:
case ABC_TAG:
case CONTROL_TAG:
+ case ACTION_TAG:
delete tag;
throw ParseException("Control tag inside a sprite. Should not happen.");
case FRAMELABEL_TAG:
@@ -1181,8 +1189,7 @@ void PlaceObject2Tag::execute(DisplayObjectContainer* parent) const
//TODO: support clipping
if(ClipDepth!=0)
{
- LOG(LOG_ERROR,"ClipDepth is not supported");
- return;
+ LOG(LOG_ERROR,"ClipDepth is not supported, but object is created anyway");
}
if(!PlaceFlagHasCharacter && !PlaceFlagMove)
@@ -1436,6 +1443,7 @@ ASObject* DefineButtonTag::instance(Class_base* c) const
assert_and_throw(state);
//The matrix must be set before invoking the constructor
state->setLegacyMatrix(i->PlaceMatrix);
+ state->name = "";
/*
* TODO: BlendMode, filerList, PlaceDepth, ColorTransfrom
*/
@@ -1532,7 +1540,7 @@ FileAttributesTag::FileAttributesTag(RECORDHEADER h, std::istream& in):Tag(h)
UB(24,bs);
}
-DefineSoundTag::DefineSoundTag(RECORDHEADER h, std::istream& in,RootMovieClip* root):DictionaryTag(h,root)
+DefineSoundTag::DefineSoundTag(RECORDHEADER h, std::istream& in,RootMovieClip* root):DictionaryTag(h,root),SoundData(new MemoryStreamCache)
{
LOG(LOG_TRACE,_("DefineSound Tag"));
in >> SoundId;
@@ -1542,8 +1550,13 @@ DefineSoundTag::DefineSoundTag(RECORDHEADER h, std::istream& in,RootMovieClip* r
SoundSize=UB(1,bs);
SoundType=UB(1,bs);
in >> SoundSampleCount;
- //TODO: read and parse actual sound data
- ignore(in,h.getLength()-7);
+
+ //TODO: get rid of the temporary copy
+ unsigned int soundDataLength = h.getLength()-7;
+ unsigned char *tmp = (unsigned char *)alloca(soundDataLength);
+ in.read((char *)tmp, soundDataLength);
+ SoundData->append(tmp, in.gcount());
+ SoundData->markFinished();
}
ASObject* DefineSoundTag::instance(Class_base* c) const
@@ -1556,8 +1569,82 @@ ASObject* DefineSoundTag::instance(Class_base* c) const
else
retClass=Class<Sound>::getClass();
- //TODO: use the tag sound data
- return new (retClass->memoryAccount) Sound(retClass);
+ return new (retClass->memoryAccount) Sound(retClass, SoundData,
+ AudioFormat(getAudioCodec(), getSampleRate(), getChannels()));
+}
+
+LS_AUDIO_CODEC DefineSoundTag::getAudioCodec() const
+{
+ return (LS_AUDIO_CODEC)SoundFormat;
+}
+
+int DefineSoundTag::getSampleRate() const
+{
+ switch(SoundRate)
+ {
+ case 0:
+ return 5500;
+ case 1:
+ return 11000;
+ case 2:
+ return 22000;
+ case 3:
+ return 44000;
+ }
+
+ // not reached
+ assert(false && "invalid sample rate");
+ return 0;
+}
+
+int DefineSoundTag::getChannels() const
+{
+ return (int)SoundType + 1;
+}
+
+_R<MemoryStreamCache> DefineSoundTag::getSoundData() const
+{
+ return SoundData;
+}
+
+std::streambuf *DefineSoundTag::createSoundStream() const
+{
+ return SoundData->createReader();
+}
+
+StartSoundTag::StartSoundTag(RECORDHEADER h, std::istream& in):ActionTag(h)
+{
+ LOG(LOG_TRACE,_("StartSound Tag"));
+ in >> SoundId >> SoundInfo;
+}
+
+void StartSoundTag::execute(RootMovieClip* root) const
+{
+ DefineSoundTag *soundTag = \
+ dynamic_cast<DefineSoundTag *>(root->dictionaryLookup(SoundId));
+
+ if (SoundInfo.SyncStop || SoundInfo.HasEnvelope || SoundInfo.HasLoops ||
+ SoundInfo.HasOutPoint || SoundInfo.HasInPoint)
+ {
+ LOG(LOG_NOT_IMPLEMENTED, "StartSoundTag: some modifiers not supported");
+ if (SoundInfo.SyncStop)
+ return;
+ }
+
+ play(soundTag);
+}
+
+void StartSoundTag::play(const DefineSoundTag *soundTag) const
+{
+ SoundChannel *schannel = Class<SoundChannel>::getInstanceS(
+ soundTag->getSoundData(),
+ AudioFormat(soundTag->getAudioCodec(),
+ soundTag->getSampleRate(),
+ soundTag->getChannels()));
+
+ // SoundChannel thread keeps one reference, which will be
+ // removed thread is finished
+ schannel->decRef();
}
ScriptLimitsTag::ScriptLimitsTag(RECORDHEADER h, std::istream& in):ControlTag(h)
diff --git a/src/parsing/tags.h b/src/parsing/tags.h
index 3af0f4d..40d7bb7 100644
--- a/src/parsing/tags.h
+++ b/src/parsing/tags.h
@@ -31,7 +31,7 @@
namespace lightspark
{
-enum TAGTYPE {TAG=0,DISPLAY_LIST_TAG,SHOW_TAG,CONTROL_TAG,DICT_TAG,FRAMELABEL_TAG,SYMBOL_CLASS_TAG,ABC_TAG,END_TAG};
+enum TAGTYPE {TAG=0,DISPLAY_LIST_TAG,SHOW_TAG,CONTROL_TAG,DICT_TAG,FRAMELABEL_TAG,SYMBOL_CLASS_TAG,ACTION_TAG,ABC_TAG,END_TAG};
void ignore(std::istream& i, int count);
@@ -94,6 +94,17 @@ public:
virtual void execute(RootMovieClip* root) const=0;
};
+/*
+ * Initiates an action. Action is executed after a frame is parsed.
+ */
+class ActionTag: public ControlTag
+{
+public:
+ ActionTag(RECORDHEADER h):ControlTag(h){}
+ virtual TAGTYPE getType()const{ return ACTION_TAG; }
+ virtual void execute(RootMovieClip* root) const=0;
+};
+
class DefineShapeTag: public DictionaryTag
{
protected:
@@ -212,6 +223,8 @@ public:
ASObject* instance(Class_base* c=NULL) const;
};
+class MemoryStreamCache;
+
class DefineSoundTag: public DictionaryTag
{
private:
@@ -221,16 +234,28 @@ private:
char SoundSize;
char SoundType;
UI32_SWF SoundSampleCount;
+ _R<MemoryStreamCache> SoundData;
public:
DefineSoundTag(RECORDHEADER h, std::istream& s, RootMovieClip* root);
virtual int getId() const { return SoundId; }
ASObject* instance(Class_base* c=NULL) const;
+ LS_AUDIO_CODEC getAudioCodec() const;
+ int getSampleRate() const;
+ int getChannels() const;
+ _R<MemoryStreamCache> getSoundData() const;
+ std::streambuf *createSoundStream() const;
};
-class StartSoundTag: public Tag
+class StartSoundTag: public ActionTag
{
+private:
+ UI16_SWF SoundId;
+ SOUNDINFO SoundInfo;
+
+ void play(const DefineSoundTag *soundTag) const;
public:
StartSoundTag(RECORDHEADER h, std::istream& s);
+ virtual void execute(RootMovieClip* root) const;
};
class SoundStreamHeadTag: public Tag
diff --git a/src/parsing/tags_stub.cpp b/src/parsing/tags_stub.cpp
index e1b0365..80162fd 100644
--- a/src/parsing/tags_stub.cpp
+++ b/src/parsing/tags_stub.cpp
@@ -39,12 +39,6 @@ DefineFontInfoTag::DefineFontInfoTag(RECORDHEADER h, std::istream& in):Tag(h)
skip(in);
}
-StartSoundTag::StartSoundTag(RECORDHEADER h, std::istream& in):Tag(h)
-{
- LOG(LOG_NOT_IMPLEMENTED,_("StartSound Tag"));
- skip(in);
-}
-
SoundStreamHeadTag::SoundStreamHeadTag(RECORDHEADER h, std::istream& in):Tag(h)
{
LOG(LOG_NOT_IMPLEMENTED,_("SoundStreamHead Tag"));
diff --git a/src/platforms/engineutils.cpp b/src/platforms/engineutils.cpp
index 4152b48..6efcfc7 100644
--- a/src/platforms/engineutils.cpp
+++ b/src/platforms/engineutils.cpp
@@ -99,3 +99,33 @@ void EngineData::showWindow(uint32_t w, uint32_t h)
gtk_widget_show(widget);
gtk_widget_map(widget);
}
+
+void EngineData::showMouseCursor()
+{
+ if (!widget)
+ return;
+
+ gdk_threads_enter();
+ GdkWindow* gdkwindow = gtk_widget_get_window(widget);
+ if (gdkwindow)
+ gdk_window_set_cursor(gdkwindow, NULL);
+ gdk_threads_leave();
+}
+
+void EngineData::hideMouseCursor()
+{
+ if (!widget)
+ return;
+
+ gdk_threads_enter();
+ GdkCursor* cursor = gdk_cursor_new(GDK_BLANK_CURSOR);
+ if (cursor)
+ {
+ GdkWindow* gdkwindow = gtk_widget_get_window(widget);
+ if (gdkwindow)
+ gdk_window_set_cursor(gdkwindow, cursor);
+ gdk_cursor_unref(cursor);
+ }
+ gdk_threads_leave();
+}
+
diff --git a/src/platforms/engineutils.h b/src/platforms/engineutils.h
index ee3d1ab..44cdb6e 100644
--- a/src/platforms/engineutils.h
+++ b/src/platforms/engineutils.h
@@ -99,8 +99,11 @@ public:
assert(!inputHandlerId);
inputHandler = ic;
gtk_widget_set_can_focus(widget,TRUE);
- gtk_widget_add_events(widget,GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK |
- GDK_POINTER_MOTION_MASK | GDK_EXPOSURE_MASK);
+ gtk_widget_add_events(widget,
+ GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
+ GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK |
+ GDK_POINTER_MOTION_MASK | GDK_EXPOSURE_MASK |
+ GDK_LEAVE_NOTIFY_MASK);
inputHandlerId = g_signal_connect(widget, "event", G_CALLBACK(inputDispatch), this);
}
void removeInputHandler()
@@ -141,6 +144,10 @@ public:
static void startGTKMain();
static void quitGTKMain();
+
+ /* show/hide mouse cursor, must be called from the gtk thread */
+ void showMouseCursor();
+ void hideMouseCursor();
};
};
diff --git a/src/plugin/npscriptobject.cpp b/src/plugin/npscriptobject.cpp
index e95ca66..0c528d8 100644
--- a/src/plugin/npscriptobject.cpp
+++ b/src/plugin/npscriptobject.cpp
@@ -814,8 +814,11 @@ bool NPScriptObject::callExternalHandler(NPP instance, const char* scriptString,
//SUCCESS
if(!NPVARIANT_IS_OBJECT(resultVariant))
{
- //Something very wrong happended, our forged function is not a function!
- LOG(LOG_ERROR,"Could not evaluate wrapper function in external interface");
+ std::map<const NPObject*, std::unique_ptr<ExtObject>> npObjectsMap;
+ NPVariantObject tmp(npObjectsMap, instance, resultVariant);
+ std::map<const ExtObject*, ASObject*> asObjectsMap;
+ *(result) = tmp.getASObject(asObjectsMap);
+ NPN_ReleaseVariantValue(&resultVariant);
}
else
{
diff --git a/src/plugin/plugin.cpp b/src/plugin/plugin.cpp
index e8338e0..9dd4f82 100644
--- a/src/plugin/plugin.cpp
+++ b/src/plugin/plugin.cpp
@@ -20,6 +20,7 @@
#include "version.h"
#include "backends/security.h"
+#include "backends/streamcache.h"
#include "plugin/plugin.h"
#include "logger.h"
#include "compat.h"
@@ -63,18 +64,22 @@ NPDownloadManager::NPDownloadManager(NPP _instance):instance(_instance)
* \return A pointer to a newly created \c Downloader for the given URL.
* \see DownloadManager::destroy()
*/
-lightspark::Downloader* NPDownloadManager::download(const lightspark::URLInfo& url, bool cached, lightspark::ILoadable* owner)
+lightspark::Downloader* NPDownloadManager::download(const lightspark::URLInfo& url, _R<StreamCache> cache, lightspark::ILoadable* owner)
{
// Handle RTMP requests internally, not through NPAPI
if(url.isRTMP())
{
- return StandaloneDownloadManager::download(url, cached, owner);
+ return StandaloneDownloadManager::download(url, cache, owner);
}
+ // FIXME: dynamic_cast fails because the linker doesn't find
+ // typeinfo for FileStreamCache
+ //bool cached = dynamic_cast<FileStreamCache *>(cache.getPtr()) != NULL;
+ bool cached = false;
LOG(LOG_INFO, _("NET: PLUGIN: DownloadManager::download '") << url.getParsedURL() <<
"'" << (cached ? _(" - cached") : ""));
//Register this download
- NPDownloader* downloader=new NPDownloader(url.getParsedURL(), cached, instance, owner);
+ NPDownloader* downloader=new NPDownloader(url.getParsedURL(), cache, instance, owner);
addDownloader(downloader);
return downloader;
}
@@ -88,18 +93,19 @@ lightspark::Downloader* NPDownloadManager::download(const lightspark::URLInfo& u
* \return A pointer to a newly created \c Downloader for the given URL.
* \see DownloadManager::destroy()
*/
-lightspark::Downloader* NPDownloadManager::downloadWithData(const lightspark::URLInfo& url, const std::vector<uint8_t>& data,
+lightspark::Downloader* NPDownloadManager::downloadWithData(const lightspark::URLInfo& url,
+ _R<StreamCache> cache, const std::vector<uint8_t>& data,
const std::list<tiny_string>& headers, lightspark::ILoadable* owner)
{
// Handle RTMP requests internally, not through NPAPI
if(url.isRTMP())
{
- return StandaloneDownloadManager::downloadWithData(url, data, headers, owner);
+ return StandaloneDownloadManager::downloadWithData(url, cache, data, headers, owner);
}
LOG(LOG_INFO, _("NET: PLUGIN: DownloadManager::downloadWithData '") << url.getParsedURL());
//Register this download
- NPDownloader* downloader=new NPDownloader(url.getParsedURL(), data, headers, instance, owner);
+ NPDownloader* downloader=new NPDownloader(url.getParsedURL(), cache, data, headers, instance, owner);
addDownloader(downloader);
return downloader;
}
@@ -139,7 +145,7 @@ void NPDownloadManager::destroy(lightspark::Downloader* downloader)
* \param[in] _url The URL for the Downloader.
*/
NPDownloader::NPDownloader(const lightspark::tiny_string& _url, lightspark::ILoadable* owner):
- Downloader(_url, false, owner),instance(NULL),cleanupInDestroyStream(true),state(INIT)
+ Downloader(_url, _MR(new MemoryStreamCache), owner),instance(NULL),cleanupInDestroyStream(true),state(INIT)
{
}
@@ -151,8 +157,8 @@ NPDownloader::NPDownloader(const lightspark::tiny_string& _url, lightspark::ILoa
* \param[in] _instance The netscape plugin instance
* \param[in] owner The \c LoaderInfo object that keeps track of this download
*/
-NPDownloader::NPDownloader(const lightspark::tiny_string& _url, bool _cached, NPP _instance, lightspark::ILoadable* owner):
- Downloader(_url, _cached, owner),instance(_instance),cleanupInDestroyStream(false),state(INIT)
+NPDownloader::NPDownloader(const lightspark::tiny_string& _url, _R<StreamCache> _cache, NPP _instance, lightspark::ILoadable* owner):
+ Downloader(_url, _cache, owner),instance(_instance),cleanupInDestroyStream(false),state(INIT)
{
NPN_PluginThreadAsyncCall(instance, dlStartCallback, this);
}
@@ -165,9 +171,10 @@ NPDownloader::NPDownloader(const lightspark::tiny_string& _url, bool _cached, NP
* \param[in] _instance The netscape plugin instance
* \param[in] owner The \c LoaderInfo object that keeps track of this download
*/
-NPDownloader::NPDownloader(const lightspark::tiny_string& _url, const std::vector<uint8_t>& _data,
+NPDownloader::NPDownloader(const lightspark::tiny_string& _url, _R<StreamCache> _cache,
+ const std::vector<uint8_t>& _data,
const std::list<tiny_string>& headers, NPP _instance, lightspark::ILoadable* owner):
- Downloader(_url, _data, headers, owner),instance(_instance),cleanupInDestroyStream(false),state(INIT)
+ Downloader(_url, _cache, _data, headers, owner),instance(_instance),cleanupInDestroyStream(false),state(INIT)
{
NPN_PluginThreadAsyncCall(instance, dlStartCallback, this);
}
@@ -313,36 +320,14 @@ void NS_DestroyPluginInstance(nsPluginInstanceBase * aPlugin)
//
nsPluginInstance::nsPluginInstance(NPP aInstance, int16_t argc, char** argn, char** argv) :
nsPluginInstanceBase(), mInstance(aInstance),mInitialized(FALSE),mWindow(0),
- mainDownloaderStream(NULL),mainDownloader(NULL),scriptObject(NULL),m_pt(NULL)
+ mainDownloaderStreambuf(NULL),mainDownloaderStream(NULL),
+ mainDownloader(NULL),scriptObject(NULL),m_pt(NULL)
{
LOG(LOG_INFO, "Lightspark version " << VERSION << " Copyright 2009-2013 Alessandro Pignotti and others");
setTLSSys( NULL );
m_sys=new lightspark::SystemState(0, lightspark::SystemState::FLASH);
//Files running in the plugin have REMOTE sandbox
m_sys->securityManager->setSandboxType(lightspark::SecurityManager::REMOTE);
- //Parse OBJECT/EMBED tag attributes
- string baseURL;
- for(int i=0;i<argc;i++)
- {
- if(argn[i]==NULL || argv[i]==NULL)
- continue;
- if(strcasecmp(argn[i],"flashvars")==0)
- {
- m_sys->parseParametersFromFlashvars(argv[i]);
- }
- else if(strcasecmp(argn[i],"base")==0)
- {
- baseURL = argv[i];
- //This is a directory, not a file
- baseURL += "/";
- }
- //The SWF file url should be getted from NewStream
- }
- //basedir is a qualified URL or a path relative to the HTML page
- URLInfo page(getPageURL());
- m_sys->mainClip->setBaseURL(page.goToURL(baseURL).getURL());
-
- m_sys->downloadManager=new NPDownloadManager(mInstance);
int p_major, p_minor, n_major, n_minor;
NPN_Version(&p_major, &p_minor, &n_major, &n_minor);
@@ -351,6 +336,33 @@ nsPluginInstance::nsPluginInstance(NPP aInstance, int16_t argc, char** argn, cha
(NPScriptObjectGW *) NPN_CreateObject(mInstance, &NPScriptObjectGW::npClass);
m_sys->extScriptObject = scriptObject->getScriptObject();
scriptObject->m_sys = m_sys;
+ //Parse OBJECT/EMBED tag attributes
+ string baseURL;
+ for(int i=0;i<argc;i++)
+ {
+ if(argn[i]==NULL || argv[i]==NULL)
+ continue;
+ if(strcasecmp(argn[i],"flashvars")==0)
+ {
+ m_sys->parseParametersFromFlashvars(argv[i]);
+ }
+ else if(strcasecmp(argn[i],"base")==0)
+ {
+ baseURL = argv[i];
+ //This is a directory, not a file
+ baseURL += "/";
+ }
+ else if(strcasecmp(argn[i],"name")==0)
+ {
+ m_sys->extScriptObject->setProperty(argn[i],argv[i]);
+ }
+ //The SWF file url should be getted from NewStream
+ }
+ //basedir is a qualified URL or a path relative to the HTML page
+ URLInfo page(getPageURL());
+ m_sys->mainClip->setBaseURL(page.goToURL(baseURL).getURL());
+
+ m_sys->downloadManager=new NPDownloadManager(mInstance);
}
else
LOG(LOG_ERROR, "PLUGIN: Browser doesn't support NPRuntime");
@@ -366,6 +378,8 @@ nsPluginInstance::~nsPluginInstance()
setTLSSys(m_sys);
if(mainDownloader)
mainDownloader->stop();
+ if (mainDownloaderStreambuf)
+ delete mainDownloaderStreambuf;
// Kill all stuff relating to NPScriptObject which is still running
static_cast<NPScriptObject*>(m_sys->extScriptObject)->destroy();
@@ -644,7 +658,8 @@ NPError nsPluginInstance::NewStream(NPMIMEType type, NPStream* stream, NPBool se
dl=new NPDownloader(stream->url,m_sys->mainClip->loaderInfo.getPtr());
dl->setLength(stream->end);
mainDownloader=dl;
- mainDownloaderStream.rdbuf(mainDownloader);
+ mainDownloaderStreambuf = mainDownloader->getCache()->createReader();
+ mainDownloaderStream.rdbuf(mainDownloaderStreambuf);
m_pt=new lightspark::ParseThread(mainDownloaderStream,m_sys->mainClip);
m_sys->addJob(m_pt);
}
diff --git a/src/plugin/plugin.h b/src/plugin/plugin.h
index a8a5823..4e4962f 100644
--- a/src/plugin/plugin.h
+++ b/src/plugin/plugin.h
@@ -44,8 +44,11 @@ private:
NPP instance;
public:
NPDownloadManager(NPP i);
- lightspark::Downloader* download(const lightspark::URLInfo& url, bool cached, lightspark::ILoadable* owner);
- lightspark::Downloader* downloadWithData(const lightspark::URLInfo& url, const std::vector<uint8_t>& data,
+ lightspark::Downloader* download(const lightspark::URLInfo& url,
+ _R<StreamCache> cache,
+ lightspark::ILoadable* owner);
+ lightspark::Downloader* downloadWithData(const lightspark::URLInfo& url,
+ _R<StreamCache> cache, const std::vector<uint8_t>& data,
const std::list<tiny_string>& headers, lightspark::ILoadable* owner);
void destroy(lightspark::Downloader* downloader);
};
@@ -63,8 +66,8 @@ public:
STATE state;
//Constructor used for the main file
NPDownloader(const lightspark::tiny_string& _url, lightspark::ILoadable* owner);
- NPDownloader(const lightspark::tiny_string& _url, bool _cached, NPP _instance, lightspark::ILoadable* owner);
- NPDownloader(const lightspark::tiny_string& _url, const std::vector<uint8_t>& _data,
+ NPDownloader(const lightspark::tiny_string& _url, _R<StreamCache> cache, NPP _instance, lightspark::ILoadable* owner);
+ NPDownloader(const lightspark::tiny_string& _url, _R<StreamCache> cache, const std::vector<uint8_t>& _data,
const std::list<tiny_string>& headers, NPP _instance, lightspark::ILoadable* owner);
};
@@ -135,6 +138,7 @@ private:
GdkNativeWindow mWindow;
int mX, mY;
+ std::streambuf *mainDownloaderStreambuf;
std::istream mainDownloaderStream;
NPDownloader* mainDownloader;
NPScriptObjectGW* scriptObject;
diff --git a/src/scripting/abc.cpp b/src/scripting/abc.cpp
index ef1cf30..0b96a18 100644
--- a/src/scripting/abc.cpp
+++ b/src/scripting/abc.cpp
@@ -23,12 +23,21 @@
#include "compat.h"
-#include <llvm/Module.h>
#include <llvm/ExecutionEngine/ExecutionEngine.h>
+#ifndef LLVM_36
#include <llvm/ExecutionEngine/JIT.h>
+#endif
#include <llvm/PassManager.h>
-#include <llvm/LLVMContext.h>
-#ifdef HAVE_DATALAYOUT_H
+#ifdef HAVE_IR_DATALAYOUT_H
+# include <llvm/IR/Module.h>
+# include <llvm/IR/LLVMContext.h>
+#else
+# include <llvm/Module.h>
+# include <llvm/LLVMContext.h>
+#endif
+#ifdef HAVE_IR_DATALAYOUT_H
+# include <llvm/IR/DataLayout.h>
+#elif defined HAVE_DATALAYOUT_H
# include <llvm/DataLayout.h>
#else
# include <llvm/Target/TargetData.h>
@@ -39,7 +48,11 @@
#include <llvm/Target/TargetSelect.h>
#endif
#include <llvm/Target/TargetOptions.h>
-#include <llvm/Analysis/Verifier.h>
+#ifdef HAVE_IR_VERIFIER_H
+# include <llvm/IR/Verifier.h>
+#else
+# include <llvm/Analysis/Verifier.h>
+#endif
#include <llvm/Transforms/Scalar.h>
#include "logger.h"
#include "swftypes.h"
@@ -49,24 +62,47 @@
#include "swf.h"
#include "scripting/toplevel/ASString.h"
#include "scripting/toplevel/Date.h"
+#include "scripting/toplevel/JSON.h"
#include "scripting/toplevel/Math.h"
#include "scripting/toplevel/RegExp.h"
#include "scripting/toplevel/Vector.h"
#include "scripting/toplevel/XML.h"
#include "scripting/toplevel/XMLList.h"
#include "scripting/flash/accessibility/flashaccessibility.h"
+#include "scripting/flash/concurrent/Mutex.h"
+#include "scripting/flash/concurrent/Condition.h"
#include "scripting/flash/desktop/flashdesktop.h"
#include "scripting/flash/display/flashdisplay.h"
#include "scripting/flash/display/BitmapData.h"
+#include "scripting/flash/display/Graphics.h"
+#include "scripting/flash/display/GraphicsBitmapFill.h"
+#include "scripting/flash/display/GraphicsEndFill.h"
+#include "scripting/flash/display/GraphicsGradientFill.h"
+#include "scripting/flash/display/GraphicsPath.h"
+#include "scripting/flash/display/GraphicsShaderFill.h"
+#include "scripting/flash/display/GraphicsSolidFill.h"
+#include "scripting/flash/display/GraphicsStroke.h"
+#include "scripting/flash/display/GraphicsTrianglePath.h"
+#include "scripting/flash/display/IGraphicsData.h"
+#include "scripting/flash/display/IGraphicsFill.h"
+#include "scripting/flash/display/IGraphicsPath.h"
+#include "scripting/flash/display/IGraphicsStroke.h"
#include "scripting/flash/events/flashevents.h"
+#include "scripting/flash/filesystem/flashfilesystem.h"
#include "scripting/flash/filters/flashfilters.h"
#include "scripting/flash/net/flashnet.h"
#include "scripting/flash/net/URLRequestHeader.h"
#include "scripting/flash/net/URLStream.h"
#include "scripting/flash/net/XMLSocket.h"
+#include "scripting/flash/net/NetStreamPlayOptions.h"
+#include "scripting/flash/net/NetStreamPlayTransitions.h"
+#include "scripting/flash/printing/flashprinting.h"
#include "scripting/flash/system/flashsystem.h"
#include "scripting/flash/sensors/flashsensors.h"
#include "scripting/flash/utils/flashutils.h"
+#include "scripting/flash/utils/Dictionary.h"
+#include "scripting/flash/utils/Proxy.h"
+#include "scripting/flash/utils/Timer.h"
#include "scripting/flash/geom/flashgeom.h"
#include "scripting/flash/external/ExternalInterface.h"
#include "scripting/flash/media/flashmedia.h"
@@ -75,6 +111,10 @@
#include "scripting/flash/text/flashtext.h"
#include "scripting/flash/text/flashtextengine.h"
#include "scripting/flash/ui/Keyboard.h"
+#include "scripting/flash/ui/Mouse.h"
+#include "scripting/flash/ui/ContextMenu.h"
+#include "scripting/flash/ui/ContextMenuItem.h"
+#include "scripting/flash/ui/ContextMenuBuiltInItems.h"
#include "scripting/class.h"
#include "exceptions.h"
#include "scripting/abc.h"
@@ -82,10 +122,10 @@
using namespace std;
using namespace lightspark;
-static GStaticPrivate is_vm_thread = G_STATIC_PRIVATE_INIT; /* TLS */
+DEFINE_AND_INITIALIZE_TLS(is_vm_thread);
bool lightspark::isVmThread()
{
- return g_static_private_get(&is_vm_thread);
+ return GPOINTER_TO_INT(tls_get(&is_vm_thread));
}
DoABCTag::DoABCTag(RECORDHEADER h, std::istream& in):ControlTag(h)
@@ -196,13 +236,11 @@ void ABCVm::registerClasses()
builtin->registerBuiltin("Namespace","",Class<Namespace>::getRef());
builtin->registerBuiltin("AS3","",_MR(Class<Namespace>::getInstanceS(AS3)));
builtin->registerBuiltin("Date","",Class<Date>::getRef());
+ builtin->registerBuiltin("JSON","",Class<JSON>::getRef());
builtin->registerBuiltin("RegExp","",Class<RegExp>::getRef());
builtin->registerBuiltin("QName","",Class<ASQName>::getRef());
builtin->registerBuiltin("uint","",Class<UInteger>::getRef());
builtin->registerBuiltin("Vector","__AS3__.vec",_MR(Template<Vector>::getTemplate()));
- //Some instances must be included, they are not created by AS3 code
- builtin->registerBuiltin("Vector$Object","__AS3__.vec",Template<Vector>::getTemplateInstance(Class<ASObject>::getClass()));
- builtin->registerBuiltin("Vector$Number","__AS3__.vec",Template<Vector>::getTemplateInstance(Class<Number>::getClass()));
builtin->registerBuiltin("Error","",Class<ASError>::getRef());
builtin->registerBuiltin("SecurityError","",Class<SecurityError>::getRef());
builtin->registerBuiltin("ArgumentError","",Class<ArgumentError>::getRef());
@@ -234,6 +272,10 @@ void ABCVm::registerClasses()
builtin->registerBuiltin("AccessibilityProperties","flash.accessibility",Class<AccessibilityProperties>::getRef());
builtin->registerBuiltin("AccessibilityImplementation","flash.accessibility",Class<AccessibilityImplementation>::getRef());
+ builtin->registerBuiltin("Accessibility","flash.accessibility",Class<Accessibility>::getRef());
+
+ builtin->registerBuiltin("Mutex","flash.concurrent",Class<ASMutex>::getRef());
+ builtin->registerBuiltin("Condition","flash.concurrent",Class<ASCondition>::getRef());
builtin->registerBuiltin("MovieClip","flash.display",Class<MovieClip>::getRef());
builtin->registerBuiltin("DisplayObject","flash.display",Class<DisplayObject>::getRef());
@@ -246,6 +288,20 @@ void ABCVm::registerClasses()
builtin->registerBuiltin("Shape","flash.display",Class<Shape>::getRef());
builtin->registerBuiltin("Stage","flash.display",Class<Stage>::getRef());
builtin->registerBuiltin("Graphics","flash.display",Class<Graphics>::getRef());
+ builtin->registerBuiltin("GraphicsBitmapFill","flash.display",Class<GraphicsBitmapFill>::getRef());
+ builtin->registerBuiltin("GraphicsEndFill","flash.display",Class<GraphicsEndFill>::getRef());
+ builtin->registerBuiltin("GraphicsGradientFill","flash.display",Class<GraphicsGradientFill>::getRef());
+ builtin->registerBuiltin("GraphicsPath","flash.display",Class<GraphicsPath>::getRef());
+ builtin->registerBuiltin("GraphicsPathCommand","flash.display",Class<GraphicsPathCommand>::getRef());
+ builtin->registerBuiltin("GraphicsPathWinding","flash.display",Class<GraphicsPathWinding>::getRef());
+ builtin->registerBuiltin("GraphicsShaderFill","flash.display",Class<GraphicsShaderFill>::getRef());
+ builtin->registerBuiltin("GraphicsSolidFill","flash.display",Class<GraphicsSolidFill>::getRef());
+ builtin->registerBuiltin("GraphicsStroke","flash.display",Class<GraphicsStroke>::getRef());
+ builtin->registerBuiltin("GraphicsTrianglePath","flash.display",Class<GraphicsTrianglePath>::getRef());
+ builtin->registerBuiltin("IGraphicsData","flash.display",InterfaceClass<IGraphicsData>::getRef());
+ builtin->registerBuiltin("IGraphicsFill","flash.display",InterfaceClass<IGraphicsFill>::getRef());
+ builtin->registerBuiltin("IGraphicsPath","flash.display",InterfaceClass<IGraphicsPath>::getRef());
+ builtin->registerBuiltin("IGraphicsStroke","flash.display",InterfaceClass<IGraphicsStroke>::getRef());
builtin->registerBuiltin("GradientType","flash.display",Class<GradientType>::getRef());
builtin->registerBuiltin("BlendMode","flash.display",Class<BlendMode>::getRef());
builtin->registerBuiltin("LineScaleMode","flash.display",Class<LineScaleMode>::getRef());
@@ -256,10 +312,6 @@ void ABCVm::registerClasses()
builtin->registerBuiltin("BitmapData","flash.display",Class<BitmapData>::getRef());
builtin->registerBuiltin("Bitmap","flash.display",Class<Bitmap>::getRef());
builtin->registerBuiltin("IBitmapDrawable","flash.display",InterfaceClass<IBitmapDrawable>::getRef());
- builtin->registerBuiltin("GraphicsGradientFill","flash.display",
- Class<ASObject>::getStubClass(QName("GraphicsGradientFill","flash.display")));
- builtin->registerBuiltin("GraphicsPath","flash.display",
- Class<ASObject>::getStubClass(QName("GraphicsPath","flash.display")));
builtin->registerBuiltin("MorphShape","flash.display",Class<MorphShape>::getRef());
builtin->registerBuiltin("SpreadMethod","flash.display",Class<SpreadMethod>::getRef());
builtin->registerBuiltin("InterpolationMethod","flash.display",Class<InterpolationMethod>::getRef());
@@ -270,24 +322,17 @@ void ABCVm::registerClasses()
builtin->registerBuiltin("BitmapDataChannel","flash.display",Class<BitmapDataChannel>::getRef());
builtin->registerBuiltin("BitmapFilter","flash.filters",Class<BitmapFilter>::getRef());
+ builtin->registerBuiltin("BitmapFilterQuality","flash.filters",Class<BitmapFilterQuality>::getRef());
builtin->registerBuiltin("DropShadowFilter","flash.filters",Class<DropShadowFilter>::getRef());
builtin->registerBuiltin("GlowFilter","flash.filters",Class<GlowFilter>::getRef());
- builtin->registerBuiltin("GradientGlowFilter","flash.filters",
- Class<ASObject>::getStubClass(QName("GradientGlowFilter","flash.filters"), Class<BitmapFilter>::getRef()));
- builtin->registerBuiltin("BevelFilter","flash.filters",
- Class<ASObject>::getStubClass(QName("BevelFilter","flash.filters"), Class<BitmapFilter>::getRef()));
- builtin->registerBuiltin("ColorMatrixFilter","flash.filters",
- Class<ASObject>::getStubClass(QName("ColorMatrixFilter","flash.filters"), Class<BitmapFilter>::getRef()));
- builtin->registerBuiltin("BlurFilter","flash.filters",
- Class<ASObject>::getStubClass(QName("BlurFilter","flash.filters"), Class<BitmapFilter>::getRef()));
- builtin->registerBuiltin("ConvolutionFilter","flash.filters",
- Class<ASObject>::getStubClass(QName("ConvolutionFilter","flash.filters"), Class<BitmapFilter>::getRef()));
- builtin->registerBuiltin("DisplacementMapFilter","flash.filters",
- Class<ASObject>::getStubClass(QName("DisplacementMapFilter","flash.filters"), Class<BitmapFilter>::getRef()));
- builtin->registerBuiltin("GradientBevelFilter","flash.filters",
- Class<ASObject>::getStubClass(QName("GradientBevelFilter","flash.filters"), Class<BitmapFilter>::getRef()));
- builtin->registerBuiltin("ShaderFilter","flash.filters",
- Class<ASObject>::getStubClass(QName("ShaderFilter","flash.filters"), Class<BitmapFilter>::getRef()));
+ builtin->registerBuiltin("GradientGlowFilter","flash.filters",Class<GradientGlowFilter>::getRef());
+ builtin->registerBuiltin("BevelFilter","flash.filters",Class<BevelFilter>::getRef());
+ builtin->registerBuiltin("ColorMatrixFilter","flash.filters",Class<ColorMatrixFilter>::getRef());
+ builtin->registerBuiltin("BlurFilter","flash.filters",Class<BlurFilter>::getRef());
+ builtin->registerBuiltin("ConvolutionFilter","flash.filters",Class<ConvolutionFilter>::getRef());
+ builtin->registerBuiltin("DisplacementMapFilter","flash.filters",Class<DisplacementMapFilter>::getRef());
+ builtin->registerBuiltin("GradientBevelFilter","flash.filters",Class<GradientBevelFilter>::getRef());
+ builtin->registerBuiltin("ShaderFilter","flash.filters",Class<ShaderFilter>::getRef());
builtin->registerBuiltin("AntiAliasType","flash.text",Class<AntiAliasType>::getRef());
builtin->registerBuiltin("Font","flash.text",Class<ASFont>::getRef());
@@ -303,15 +348,25 @@ void ABCVm::registerClasses()
builtin->registerBuiltin("TextFormat","flash.text",Class<TextFormat>::getRef());
builtin->registerBuiltin("TextFormatAlign","flash.text",Class<TextFormatAlign>::getRef());
builtin->registerBuiltin("TextLineMetrics","flash.text",Class<TextLineMetrics>::getRef());
+ builtin->registerBuiltin("TextInteractionMode","flash.text",Class<TextInteractionMode>::getRef());
builtin->registerBuiltin("StaticText","flash.text",Class<StaticText>::getRef());
builtin->registerBuiltin("ContentElement","flash.text.engine",Class<ContentElement>::getRef());
builtin->registerBuiltin("ElementFormat","flash.text.engine",Class<ElementFormat>::getRef());
builtin->registerBuiltin("FontDescription","flash.text.engine",Class<FontDescription>::getRef());
+ builtin->registerBuiltin("FontMetrics","flash.text.engine",Class<FontMetrics>::getRef());
+ builtin->registerBuiltin("FontLookup","flash.text.engine",Class<FontLookup>::getRef());
builtin->registerBuiltin("FontWeight","flash.text.engine",Class<FontWeight>::getRef());
+ builtin->registerBuiltin("Kerning","flash.text.engine",Class<Kerning>::getRef());
+ builtin->registerBuiltin("LineJustification","flash.text.engine",Class<LineJustification>::getRef());
+ builtin->registerBuiltin("TextBaseline","flash.text.engine",Class<TextBaseline>::getRef());
builtin->registerBuiltin("TextBlock","flash.text.engine",Class<TextBlock>::getRef());
builtin->registerBuiltin("TextElement","flash.text.engine",Class<TextElement>::getRef());
builtin->registerBuiltin("TextLine","flash.text.engine",Class<TextLine>::getRef());
+ builtin->registerBuiltin("TextLineValidity","flash.text.engine",Class<TextLineValidity>::getRef());
+ builtin->registerBuiltin("TextJustifier","flash.text.engine",Class<TextJustifier>::getRef());
+ builtin->registerBuiltin("SpaceJustifier","flash.text.engine",Class<SpaceJustifier>::getRef());
+ builtin->registerBuiltin("EastAsianJustifier","flash.text.engine",Class<EastAsianJustifier>::getRef());
builtin->registerBuiltin("XMLDocument","flash.xml",Class<XMLDocument>::getRef());
builtin->registerBuiltin("XMLNode","flash.xml",Class<XMLNode>::getRef());
@@ -323,10 +378,8 @@ void ABCVm::registerClasses()
builtin->registerBuiltin("Dictionary","flash.utils",Class<Dictionary>::getRef());
builtin->registerBuiltin("Proxy","flash.utils",Class<Proxy>::getRef());
builtin->registerBuiltin("Timer","flash.utils",Class<Timer>::getRef());
- builtin->registerBuiltin("getQualifiedClassName","flash.utils",
- _MR(Class<IFunction>::getFunction(getQualifiedClassName)));
- builtin->registerBuiltin("getQualifiedSuperclassName","flash.utils",
- _MR(Class<IFunction>::getFunction(getQualifiedSuperclassName)));
+ builtin->registerBuiltin("getQualifiedClassName","flash.utils",_MR(Class<IFunction>::getFunction(getQualifiedClassName)));
+ builtin->registerBuiltin("getQualifiedSuperclassName","flash.utils",_MR(Class<IFunction>::getFunction(getQualifiedSuperclassName)));
builtin->registerBuiltin("getDefinitionByName","flash.utils",_MR(Class<IFunction>::getFunction(getDefinitionByName)));
builtin->registerBuiltin("getTimer","flash.utils",_MR(Class<IFunction>::getFunction(getTimer)));
builtin->registerBuiltin("setInterval","flash.utils",_MR(Class<IFunction>::getFunction(setInterval)));
@@ -334,6 +387,8 @@ void ABCVm::registerClasses()
builtin->registerBuiltin("clearInterval","flash.utils",_MR(Class<IFunction>::getFunction(clearInterval)));
builtin->registerBuiltin("clearTimeout","flash.utils",_MR(Class<IFunction>::getFunction(clearTimeout)));
builtin->registerBuiltin("describeType","flash.utils",_MR(Class<IFunction>::getFunction(describeType)));
+ builtin->registerBuiltin("escapeMultiByte","flash.utils",_MR(Class<IFunction>::getFunction(escapeMultiByte)));
+ builtin->registerBuiltin("unescapeMultiByte","flash.utils",_MR(Class<IFunction>::getFunction(unescapeMultiByte)));
builtin->registerBuiltin("IExternalizable","flash.utils",InterfaceClass<IExternalizable>::getRef());
builtin->registerBuiltin("IDataInput","flash.utils",InterfaceClass<IDataInput>::getRef());
builtin->registerBuiltin("IDataOutput","flash.utils",InterfaceClass<IDataOutput>::getRef());
@@ -344,7 +399,8 @@ void ABCVm::registerClasses()
builtin->registerBuiltin("Transform","flash.geom",Class<Transform>::getRef());
builtin->registerBuiltin("Point","flash.geom",Class<Point>::getRef());
builtin->registerBuiltin("Vector3D","flash.geom",Class<Vector3D>::getRef());
- builtin->registerBuiltin("Matrix3D","flash.geom",Class<ASObject>::getStubClass(QName("Matrix3D", "flash.geom")));
+ builtin->registerBuiltin("Matrix3D","flash.geom",Class<Matrix3D>::getRef());
+ builtin->registerBuiltin("PerspectiveProjection","flash.geom",Class<PerspectiveProjection>::getRef());
builtin->registerBuiltin("EventDispatcher","flash.events",Class<EventDispatcher>::getRef());
builtin->registerBuiltin("Event","flash.events",Class<Event>::getRef());
@@ -369,13 +425,24 @@ void ABCVm::registerClasses()
builtin->registerBuiltin("DRMStatusEvent","flash.events",Class<DRMStatusEvent>::getRef());
builtin->registerBuiltin("StageVideoEvent","flash.events",Class<StageVideoEvent>::getRef());
builtin->registerBuiltin("StageVideoAvailabilityEvent","flash.events",Class<StageVideoAvailabilityEvent>::getRef());
+ builtin->registerBuiltin("TouchEvent","flash.events",Class<TouchEvent>::getRef());
+ builtin->registerBuiltin("GestureEvent","flash.events",Class<GestureEvent>::getRef());
+ builtin->registerBuiltin("PressAndTapGestureEvent","flash.events",Class<PressAndTapGestureEvent>::getRef());
+ builtin->registerBuiltin("TransformGestureEvent","flash.events",Class<TransformGestureEvent>::getRef());
+ builtin->registerBuiltin("ContextMenuEvent","flash.events",Class<ContextMenuEvent>::getRef());
+ builtin->registerBuiltin("UncaughtErrorEvent","flash.events",Class<UncaughtErrorEvent>::getRef());
+ builtin->registerBuiltin("UncaughtErrorEvents","flash.events",Class<UncaughtErrorEvents>::getRef());
+ builtin->registerBuiltin("VideoEvent","flash.events",Class<VideoEvent>::getRef());
builtin->registerBuiltin("navigateToURL","flash.net",_MR(Class<IFunction>::getFunction(navigateToURL)));
builtin->registerBuiltin("sendToURL","flash.net",_MR(Class<IFunction>::getFunction(sendToURL)));
- builtin->registerBuiltin("LocalConnection","flash.net",Class<ASObject>::getStubClass(QName("LocalConnection","flash.net")));
+ builtin->registerBuiltin("LocalConnection","flash.net",Class<LocalConnection>::getRef());
builtin->registerBuiltin("NetConnection","flash.net",Class<NetConnection>::getRef());
+ builtin->registerBuiltin("NetGroup","flash.net",Class<NetGroup>::getRef());
builtin->registerBuiltin("NetStream","flash.net",Class<NetStream>::getRef());
- builtin->registerBuiltin("NetStreamPlayOptions","flash.net",Class<ASObject>::getStubClass(QName("NetStreamPlayOptions","flash.net")));
+ builtin->registerBuiltin("NetStreamAppendBytesAction","flash.net",Class<NetStreamAppendBytesAction>::getRef());
+ builtin->registerBuiltin("NetStreamPlayOptions","flash.net",Class<NetStreamPlayOptions>::getRef());
+ builtin->registerBuiltin("NetStreamPlayTransitions","flash.net",Class<NetStreamPlayTransitions>::getRef());
builtin->registerBuiltin("URLLoader","flash.net",Class<URLLoader>::getRef());
builtin->registerBuiltin("URLStream","flash.net",Class<URLStream>::getRef());
builtin->registerBuiltin("URLLoaderDataFormat","flash.net",Class<URLLoaderDataFormat>::getRef());
@@ -384,13 +451,17 @@ void ABCVm::registerClasses()
builtin->registerBuiltin("URLRequestMethod","flash.net",Class<URLRequestMethod>::getRef());
builtin->registerBuiltin("URLVariables","flash.net",Class<URLVariables>::getRef());
builtin->registerBuiltin("SharedObject","flash.net",Class<SharedObject>::getRef());
+ builtin->registerBuiltin("SharedObjectFlushStatus","flash.net",Class<SharedObjectFlushStatus>::getRef());
builtin->registerBuiltin("ObjectEncoding","flash.net",Class<ObjectEncoding>::getRef());
- builtin->registerBuiltin("Socket","flash.net",Class<ASObject>::getStubClass(QName("Socket","flash.net")));
+ builtin->registerBuiltin("Socket","flash.net",Class<ASSocket>::getRef());
builtin->registerBuiltin("Responder","flash.net",Class<Responder>::getRef());
builtin->registerBuiltin("XMLSocket","flash.net",Class<XMLSocket>::getRef());
builtin->registerBuiltin("registerClassAlias","flash.net",_MR(Class<IFunction>::getFunction(registerClassAlias)));
builtin->registerBuiltin("getClassByAlias","flash.net",_MR(Class<IFunction>::getFunction(getClassByAlias)));
+ builtin->registerBuiltin("DRMManager","flash.net.drm",Class<DRMManager>::getRef());
+
+
builtin->registerBuiltin("fscommand","flash.system",_MR(Class<IFunction>::getFunction(fscommand)));
builtin->registerBuiltin("Capabilities","flash.system",Class<Capabilities>::getRef());
builtin->registerBuiltin("Security","flash.system",Class<Security>::getRef());
@@ -398,6 +469,7 @@ void ABCVm::registerClasses()
builtin->registerBuiltin("SecurityDomain","flash.system",Class<SecurityDomain>::getRef());
builtin->registerBuiltin("LoaderContext","flash.system",Class<LoaderContext>::getRef());
builtin->registerBuiltin("System","flash.system",Class<System>::getRef());
+ builtin->registerBuiltin("Worker","flash.system",Class<ASWorker>::getRef());
builtin->registerBuiltin("SoundTransform","flash.media",Class<SoundTransform>::getRef());
builtin->registerBuiltin("Video","flash.media",Class<Video>::getRef());
@@ -411,8 +483,10 @@ void ABCVm::registerClasses()
builtin->registerBuiltin("Keyboard","flash.ui",Class<Keyboard>::getRef());
builtin->registerBuiltin("KeyboardType","flash.ui",Class<KeyboardType>::getRef());
builtin->registerBuiltin("KeyLocation","flash.ui",Class<KeyLocation>::getRef());
- builtin->registerBuiltin("ContextMenu","flash.ui",Class<ASObject>::getStubClass(QName("ContextMenu","flash.ui")));
- builtin->registerBuiltin("ContextMenuItem","flash.ui",Class<ASObject>::getStubClass(QName("ContextMenuItem","flash.ui")));
+ builtin->registerBuiltin("ContextMenu","flash.ui",Class<ContextMenu>::getRef());
+ builtin->registerBuiltin("ContextMenuItem","flash.ui",Class<ContextMenuItem>::getRef());
+ builtin->registerBuiltin("ContextMenuBuiltInItems","flash.ui",Class<ContextMenuBuiltInItems>::getRef());
+ builtin->registerBuiltin("Mouse","flash.ui",Class<Mouse>::getRef());
builtin->registerBuiltin("Accelerometer", "flash.sensors",Class<Accelerometer>::getRef());
@@ -424,15 +498,15 @@ void ABCVm::registerClasses()
builtin->registerBuiltin("ScriptTimeoutError","flash.errors",Class<ScriptTimeoutError>::getRef());
builtin->registerBuiltin("StackOverflowError","flash.errors",Class<StackOverflowError>::getRef());
- builtin->registerBuiltin("PrintJob","flash.printing",
- Class<ASObject>::getStubClass(QName("PrintJob","flash.printing"), Class<EventDispatcher>::getRef()));
- builtin->registerBuiltin("PrintJobOptions","flash.printing",Class<ASObject>::getStubClass(QName("PrintJobOptions","flash.printing")));
- builtin->registerBuiltin("PrintJobOrientation","flash.printing",Class<ASObject>::getStubClass(QName("PrintJobOrientation","flash.printing")));
+ builtin->registerBuiltin("PrintJob","flash.printing",Class<PrintJob>::getRef());
+ builtin->registerBuiltin("PrintJobOptions","flash.printing",Class<PrintJobOptions>::getRef());
+ builtin->registerBuiltin("PrintJobOrientation","flash.printing",Class<PrintJobOrientation>::getRef());
builtin->registerBuiltin("isNaN","",_MR(Class<IFunction>::getFunction(isNaN)));
builtin->registerBuiltin("isFinite","",_MR(Class<IFunction>::getFunction(isFinite)));
builtin->registerBuiltin("isXMLName","",_MR(Class<IFunction>::getFunction(_isXMLName)));
+
//If needed add AIR definitions
if(getSys()->flashMode==SystemState::AIR)
{
@@ -440,10 +514,12 @@ void ABCVm::registerClasses()
builtin->registerBuiltin("InvokeEvent","flash.events",Class<InvokeEvent>::getRef());
- builtin->registerBuiltin("FileStream","flash.filesystem",
- Class<ASObject>::getStubClass(QName("FileStream","flash.filestream")));
+ builtin->registerBuiltin("FileStream","flash.filesystem",Class<FileStream>::getRef());
}
+ Class_object::getRef()->getClass()->prototype = _MNR(new_objectPrototype());
+ Class_object::getRef()->getClass()->initStandardProps();
+
getSys()->systemDomain->registerGlobalScope(builtin);
}
@@ -623,6 +699,8 @@ multiname* ABCContext::s_getMultiname(ABCContext* th, ASObject* n, ASObject* n2,
*/
multiname* ABCContext::getMultinameImpl(ASObject* n, ASObject* n2, unsigned int midx)
{
+ if (constant_pool.multiname_count == 0)
+ return NULL;
multiname* ret;
multiname_info* m=&constant_pool.multinames[midx];
@@ -701,6 +779,16 @@ multiname* ABCContext::getMultinameImpl(ASObject* n, ASObject* n2, unsigned int
{
multiname_info* p=&constant_pool.multinames[m->param_types[i]];
name += "$";
+ tiny_string nsname;
+ if (p->ns < constant_pool.namespaces.size())
+ {
+ // TODO there's no documentation about how to handle derived classes
+ // We just prepend the namespace to the template class, so we can find it when needed
+ namespace_info nsi = constant_pool.namespaces[p->ns];
+ nsname = getString(nsi.name);
+ if (nsname != "")
+ name += nsname+"$";
+ }
name += getString(p->name);
}
ret->ns.push_back(nsNameAndKind(this, td->ns));
@@ -740,10 +828,16 @@ multiname* ABCContext::getMultinameImpl(ASObject* n, ASObject* n2, unsigned int
if (n->is<ASQName>())
{
ASQName *qname = n->as<ASQName>();
+ // don't overwrite any static parts
+ if (!m->dynamic)
+ m->dynamic=new (getVm()->vmDataMemory) multiname(getVm()->vmDataMemory);
+ ret=m->dynamic;
+ ret->isAttribute=m->cached->isAttribute;
ret->ns.clear();
ret->ns.push_back(nsNameAndKind(qname->getURI(),NAMESPACE));
}
-
+ else
+ n->applyProxyProperty(*ret);
ret->setName(n);
n->decRef();
break;
@@ -754,9 +848,8 @@ multiname* ABCContext::getMultinameImpl(ASObject* n, ASObject* n2, unsigned int
assert(n && !n2);
assert_and_throw(n->classdef==Class<Namespace>::getClass());
Namespace* tmpns=static_cast<Namespace*>(n);
- //TODO: What is the right kind?
ret->ns.clear();
- ret->ns.push_back(nsNameAndKind(tmpns->uri,NAMESPACE));
+ ret->ns.push_back(nsNameAndKind(tmpns->uri,tmpns->nskind));
n->decRef();
break;
}
@@ -767,7 +860,7 @@ multiname* ABCContext::getMultinameImpl(ASObject* n, ASObject* n2, unsigned int
assert_and_throw(n2->classdef==Class<Namespace>::getClass());
Namespace* tmpns=static_cast<Namespace*>(n2);
ret->ns.clear();
- ret->ns.push_back(nsNameAndKind(tmpns->uri,NAMESPACE));
+ ret->ns.push_back(nsNameAndKind(tmpns->uri,tmpns->nskind));
ret->setName(n);
n->decRef();
n2->decRef();
@@ -1254,7 +1347,7 @@ Class_inherit* ABCVm::findClassInherit(const string& s, RootMovieClip* root)
Class_inherit* derived_class_tmp=static_cast<Class_inherit*>(derived_class);
if(derived_class_tmp->isBinded())
{
- LOG(LOG_ERROR, "Class already binded to a tag. Not binding");
+ LOG(LOG_ERROR, "Class already binded to a tag. Not binding:"<<s<< " class:"<<derived_class_tmp->getQualifiedClassName());
return NULL;
}
return derived_class_tmp;
@@ -1450,6 +1543,19 @@ void ABCContext::runScriptInit(unsigned int i, ASObject* g)
ret->decRef();
entry->decRef();
+
+ // initialize vars where type was not known during script init
+ // this may happen for variables of private classes defined in this script
+ LOG(LOG_CALLS,"initialize uninitialized vars");
+ auto it = uninitializedVars.begin();
+ while (it != uninitializedVars.end())
+ {
+ uninitializedVar v = *it;
+ v.mainObj->initializeVariableByMultiname(*v.mname,NULL,v.typemname,this,v.traitKind,true);
+ v.mainObj->decRef();
+ uninitializedVars.pop_front();
+ it = uninitializedVars.begin();
+ }
LOG(LOG_CALLS, "Finished script init for script " << i );
}
@@ -1460,13 +1566,15 @@ void ABCVm::Run(ABCVm* th)
while(getVm()!=th);
/* set TLS variable for isVmThread() */
- g_static_private_set(&is_vm_thread,(void*)1,NULL);
+ tls_set(&is_vm_thread, GINT_TO_POINTER(1));
if(th->m_sys->useJit)
{
#ifdef LLVM_31
llvm::TargetOptions Opts;
+#ifndef LLVM_34
Opts.JITExceptionHandling = true;
+#endif
#else
llvm::JITExceptionHandling = true;
#endif
@@ -1479,7 +1587,11 @@ void ABCVm::Run(ABCVm* th)
#endif
llvm::InitializeNativeTarget();
th->module=new llvm::Module(llvm::StringRef("abc jit"),th->llvm_context());
+#ifdef LLVM_36
+ llvm::EngineBuilder eb(std::unique_ptr<llvm::Module>(th->module));
+#else
llvm::EngineBuilder eb(th->module);
+#endif
eb.setEngineKind(llvm::EngineKind::JIT);
#ifdef LLVM_31
eb.setTargetOptions(Opts);
@@ -1489,11 +1601,17 @@ void ABCVm::Run(ABCVm* th)
assert_and_throw(th->ex);
th->FPM=new llvm::FunctionPassManager(th->module);
-#ifdef HAVE_DATALAYOUT_H
+#ifdef LLVM_36
+ th->FPM->add(new llvm::DataLayoutPass());
+#else
+#ifdef LLVM_35
+ th->FPM->add(new llvm::DataLayoutPass(*th->ex->getDataLayout()));
+#elif defined HAVE_DATALAYOUT_H || defined HAVE_IR_DATALAYOUT_H
th->FPM->add(new llvm::DataLayout(*th->ex->getDataLayout()));
#else
th->FPM->add(new llvm::TargetData(*th->ex->getTargetData()));
#endif
+#endif
#ifdef EXPENSIVE_DEBUG
//This is pretty heavy, do not enable in release
th->FPM->add(llvm::createVerifierPass());
@@ -1848,8 +1966,13 @@ ASObject* ABCContext::getConstant(int kind, int index)
case 0x06: //Double
return abstract_d(constant_pool.doubles[index]);
case 0x08: //Namespace
+ {
assert_and_throw(constant_pool.namespaces[index].name);
- return Class<Namespace>::getInstanceS(getString(constant_pool.namespaces[index].name));
+ Namespace* ret = Class<Namespace>::getInstanceS(getString(constant_pool.namespaces[index].name));
+ if (constant_pool.namespaces[index].kind != 0)
+ ret->nskind =(NS_KIND)(int)(constant_pool.namespaces[index].kind);
+ return ret;
+ }
case 0x0a: //False
return abstract_b(false);
case 0x0b: //True
@@ -1864,6 +1987,23 @@ ASObject* ABCContext::getConstant(int kind, int index)
}
}
+void ABCContext::addUninitializedVar(uninitializedVar &v)
+{
+ auto it = uninitializedVars.begin();
+ bool bfound = false;
+ while (it != uninitializedVars.end())
+ {
+ if (it->mainObj == v.mainObj && it->mname == v.mname)
+ {
+ bfound = true;
+ break;
+ }
+ it++;
+ }
+ if (!bfound)
+ uninitializedVars.push_back(v);
+}
+
void ABCContext::buildTrait(ASObject* obj, const traits_info* t, bool isBorrowed, int scriptid)
{
multiname* mname=getMultiname(t->name,NULL);
@@ -1873,7 +2013,7 @@ void ABCContext::buildTrait(ASObject* obj, const traits_info* t, bool isBorrowed
LOG(LOG_CALLS,_("Next slot has flags ") << (t->kind>>4));
if(t->kind&traits_info::Metadata)
- {
+ {
for(unsigned int i=0;i<t->metadata_count;i++)
{
metadata_info& minfo = metadata[t->metadata[i]];
@@ -1894,10 +2034,10 @@ void ABCContext::buildTrait(ASObject* obj, const traits_info* t, bool isBorrowed
return;
ASObject* ret;
+ QName className(getSys()->getStringFromUniqueId(mname->name_s_id),mname->ns[0].getImpl().name);
//check if this class has the 'interface' flag, i.e. it is an interface
if((instances[t->classi].flags)&0x04)
{
- QName className(getSys()->getStringFromUniqueId(mname->name_s_id),mname->ns[0].getImpl().name);
MemoryAccount* memoryAccount = getSys()->allocateMemoryAccount(className.name);
Class_inherit* ci=new (getSys()->unaccountedMemory) Class_inherit(className, memoryAccount);
@@ -1938,13 +2078,27 @@ void ABCContext::buildTrait(ASObject* obj, const traits_info* t, bool isBorrowed
//do interfaces have cinit methods?
//TODO: call them, set constructor property, do something
if(classes[t->classi].cinit != 0)
- LOG(LOG_NOT_IMPLEMENTED,"Interface cinit (static)");
+ {
+ method_info* m=&methods[classes[t->classi].cinit];
+ if (m->body)
+ LOG(LOG_NOT_IMPLEMENTED,"Interface cinit (static):"<<className);
+ }
if(instances[t->classi].init != 0)
- LOG(LOG_NOT_IMPLEMENTED,"Interface cinit (constructor)");
+ {
+ method_info* m=&methods[instances[t->classi].init];
+ if (m->body)
+ LOG(LOG_NOT_IMPLEMENTED,"Interface cinit (constructor):"<<className);
+ }
ret = ci;
}
else
- ret=getSys()->getUndefinedRef();
+ {
+ MemoryAccount* memoryAccount = getSys()->allocateMemoryAccount(className.name);
+ Class_inherit* c=new (getSys()->unaccountedMemory) Class_inherit(className, memoryAccount);
+ root->applicationDomain->classesBeingDefined.insert(make_pair(mname, c));
+ ret=c;
+ }
+
obj->setVariableByQName(mname->name_s_id,mname->ns[0],ret,DECLARED_TRAIT);
@@ -1957,7 +2111,7 @@ void ABCContext::buildTrait(ASObject* obj, const traits_info* t, bool isBorrowed
case traits_info::Setter:
case traits_info::Method:
{
- //methods can also be defined at toplevel (not only traits_info::Function!)
+ //methods can also be defined at toplevel (not only traits_info::Function!)
if(kind == traits_info::Getter)
LOG(LOG_CALLS,"Getter trait: " << *mname << _(" #") << t->method);
else if(kind == traits_info::Setter)
@@ -2020,10 +2174,12 @@ void ABCContext::buildTrait(ASObject* obj, const traits_info* t, bool isBorrowed
LOG(LOG_CALLS,_("Const ") << *mname <<_(" type ")<< *tname<< " = " << ret->toDebugString());
- obj->initializeVariableByMultiname(*mname, ret, tname, this, CONSTANT_TRAIT);
+ obj->initializeVariableByMultiname(*mname, ret, tname, this, CONSTANT_TRAIT,false);
if(t->slot_id)
obj->initSlot(t->slot_id, *mname);
+ //else // slot_id 0 seems to mean appending new slot
+ // obj->appendSlot(*mname);
break;
}
case traits_info::Slot:
@@ -2038,20 +2194,21 @@ void ABCContext::buildTrait(ASObject* obj, const traits_info* t, bool isBorrowed
if(t->vindex)
{
ret=getConstant(t->vkind,t->vindex);
- LOG(LOG_CALLS,_("Slot ") << t->slot_id << ' ' << *mname <<_(" type ")<<*tname<< " = " << ret->toDebugString() );
+ LOG(LOG_CALLS,_("Slot ") << t->slot_id << ' ' << *mname <<_(" type ")<<*tname<< " = " << ret->toDebugString() <<" "<<isBorrowed);
}
else
{
- LOG(LOG_CALLS,_("Slot ")<< t->slot_id<< _(" vindex 0 ") << *mname <<_(" type ")<<*tname);
- //The Undefined is coerced to the right type by the initializeVar..
- ret = getSys()->getUndefinedRef();
+ LOG(LOG_CALLS,_("Slot ")<< t->slot_id<< _(" vindex 0 ") << *mname <<_(" type ")<<*tname<<" "<<isBorrowed);
+ ret = NULL;
}
- obj->initializeVariableByMultiname(*mname, ret, tname, this, DECLARED_TRAIT);
+ obj->initializeVariableByMultiname(*mname, ret, tname, this, isBorrowed ? INSTANCE_TRAIT : DECLARED_TRAIT,false);
if(t->slot_id)
obj->initSlot(t->slot_id, *mname);
-
+ //else // slot_id 0 seems to mean appending new slot
+ // obj->appendSlot(*mname);
+
break;
}
default:
diff --git a/src/scripting/abc.h b/src/scripting/abc.h
index c5677cf..2a74073 100644
--- a/src/scripting/abc.h
+++ b/src/scripting/abc.h
@@ -142,6 +142,15 @@ struct typed_opcode_handler
ARGS_TYPE type;
};
+struct uninitializedVar
+{
+ uninitializedVar():mname(NULL),mainObj(NULL),typemname(NULL),traitKind(NO_CREATE_TRAIT) {}
+ const multiname* mname;
+ ASObject* mainObj;
+ multiname* typemname;
+ TRAIT_KIND traitKind;
+};
+
class ABCContext
{
friend class ABCVm;
@@ -174,6 +183,9 @@ public:
uint32_t namespaceBaseId;
std::vector<bool> hasRunScriptInit;
+ // list of vars that have to be initialized after script init is done
+ std::list<uninitializedVar> uninitializedVars;
+ void addUninitializedVar(uninitializedVar& v);
/**
Construct and insert in the a object a given trait
@param obj the tarhget object
@@ -195,8 +207,6 @@ public:
bool isinstance(ASObject* obj, multiname* name);
- std::map<const multiname*, Class_base*> classesBeingDefined;
-
#ifdef PROFILING_SUPPORT
void dumpProfilingData(std::ostream& f) const;
#endif
@@ -246,6 +256,28 @@ private:
_R<ApplicationDomain> appDomain = getCurrentApplicationDomain(th);
appDomain->writeToDomainMemory<T>(addr, val);
}
+
+ static void loadNumber(call_context* th)
+ {
+ ASObject* arg1=th->runtime_stack_pop();
+ number_t addr=arg1->toNumber();
+ arg1->decRef();
+ _R<ApplicationDomain> appDomain = getCurrentApplicationDomain(th);
+ number_t ret=appDomain->readFromDomainMemory<number_t>(addr);
+ th->runtime_stack_push(abstract_d(ret));
+ }
+ static void storeNumber(call_context* th)
+ {
+ ASObject* arg1=th->runtime_stack_pop();
+ ASObject* arg2=th->runtime_stack_pop();
+ number_t addr=arg1->toNumber();
+ arg1->decRef();
+ number_t val=arg2->toNumber();
+ arg2->decRef();
+ _R<ApplicationDomain> appDomain = getCurrentApplicationDomain(th);
+ appDomain->writeToDomainMemory<number_t>(addr, val);
+ }
+
static void callSuper(call_context* th, int n, int m, method_info** called_mi, bool keepReturn);
static void callProperty(call_context* th, int n, int m, method_info** called_mi, bool keepReturn);
static void callImpl(call_context* th, ASObject* f, ASObject* obj, ASObject** args, int m, method_info** called_mi, bool keepReturn);
@@ -299,6 +331,7 @@ private:
static void decLocal_i(call_context* th, int n);
static void decLocal(call_context* th, int n);
static void coerce(call_context* th, int n);
+ static void checkDeclaredTraits(ASObject* obj);
static ASObject* getProperty(ASObject* obj, multiname* name);
static int32_t getProperty_i(ASObject* obj, multiname* name);
static void setProperty(ASObject* value,ASObject* obj, multiname* name);
@@ -380,6 +413,7 @@ private:
static uint32_t decrement_i(ASObject*);
static bool strictEquals(ASObject*,ASObject*);
static ASObject* esc_xattr(ASObject* o);
+ static ASObject* esc_xelem(ASObject* o);
static bool instanceOf(ASObject* value, ASObject* type);
static Namespace* pushNamespace(call_context* th, int n);
static void dxns(call_context* th, int n);
@@ -390,7 +424,10 @@ private:
//Internal utilities
static void method_reset(method_info* th);
- static void newClassRecursiveLink(Class_base* target, Class_base* c);
+
+ static void SetAllClassLinks();
+ static void AddClassLinks(Class_base* target);
+ static bool newClassRecursiveLink(Class_base* target, Class_base* c);
static ASObject* constructFunction(call_context* th, IFunction* f, ASObject** args, int argslen);
void parseRPCMessage(_R<ByteArray> message, _NR<ASObject> client, _NR<Responder> responder);
@@ -405,6 +442,7 @@ private:
static typed_opcode_handler opcode_table_voidptr[];
static typed_opcode_handler opcode_table_bool_t[];
+
//Synchronization
Mutex event_queue_mutex;
Cond sem_event_cond;
diff --git a/src/scripting/abc_codesynt.cpp b/src/scripting/abc_codesynt.cpp
index 2018be3..bb8e9a5 100644
--- a/src/scripting/abc_codesynt.cpp
+++ b/src/scripting/abc_codesynt.cpp
@@ -25,18 +25,29 @@
#endif
#include "compat.h"
-#include <llvm/Module.h>
-#include <llvm/DerivedTypes.h>
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/PassManager.h>
-#include <llvm/Constants.h>
-#ifdef HAVE_IRBUILDER_H
+#ifdef HAVE_IR_DATALAYOUT_H
+# include <llvm/IR/Constants.h>
+# include <llvm/IR/DerivedTypes.h>
+# include <llvm/IR/Module.h>
+# include <llvm/IR/LLVMContext.h>
+#else
+# include <llvm/Constants.h>
+# include <llvm/DerivedTypes.h>
+# include <llvm/Module.h>
+# include <llvm/LLVMContext.h>
+#endif
+#ifdef HAVE_IR_DATALAYOUT_H
+# include <llvm/IR/IRBuilder.h>
+#elif defined HAVE_IRBUILDER_H
# include <llvm/IRBuilder.h>
#else
# include <llvm/Support/IRBuilder.h>
#endif
-#include <llvm/LLVMContext.h>
-#ifdef HAVE_DATALAYOUT_H
+#ifdef HAVE_IR_DATALAYOUT_H
+# include <llvm/IR/DataLayout.h>
+#elif defined HAVE_DATALAYOUT_H
# include <llvm/DataLayout.h>
#else
# include <llvm/Target/TargetData.h>
@@ -279,7 +290,7 @@ void ABCVm::registerFunctions()
llvm::FunctionType* FT=NULL;
//Create types
-#ifdef HAVE_DATALAYOUT_H
+#if defined HAVE_DATALAYOUT_H || defined HAVE_IR_DATALAYOUT_H
ptr_type=ex->getDataLayout()->getIntPtrType(llvm_context());
#else
ptr_type=ex->getTargetData()->getIntPtrType(llvm_context());
diff --git a/src/scripting/abc_fast_interpreter.cpp b/src/scripting/abc_fast_interpreter.cpp
index e49334e..f3a48e9 100644
--- a/src/scripting/abc_fast_interpreter.cpp
+++ b/src/scripting/abc_fast_interpreter.cpp
@@ -75,6 +75,12 @@ ASObject* ABCVm::executeFunctionFast(const SyntheticFunction* function, call_con
switch(opcode)
{
+ case 0x01:
+ {
+ //bkpt
+ LOG(LOG_CALLS, _("bkpt") );
+ break;
+ }
case 0x02:
{
//nop
@@ -565,6 +571,20 @@ ASObject* ABCVm::executeFunctionFast(const SyntheticFunction* function, call_con
loadIntN<uint32_t>(context);
break;
}
+ case 0x38:
+ {
+ //lf32
+ LOG(LOG_CALLS, "lf32");
+ loadNumber(context);
+ break;
+ }
+ case 0x39:
+ {
+ //lf32
+ LOG(LOG_CALLS, "lf64");
+ loadNumber(context);
+ break;
+ }
case 0x3a:
{
//si8
@@ -802,7 +822,12 @@ ASObject* ABCVm::executeFunctionFast(const SyntheticFunction* function, call_con
//getlocal
uint32_t i=data->uints[0];
instructionPointer+=4;
- assert_and_throw(context->locals[i]);
+ if (!context->locals[i])
+ {
+ LOG(LOG_CALLS, _("getLocal ") << i << " not set, pushing Undefined");
+ context->runtime_stack_push(getSys()->getUndefinedRef());
+ break;
+ }
context->locals[i]->incRef();
LOG(LOG_CALLS, _("getLocal ") << i << _(": ") << context->locals[i]->toDebugString() );
context->runtime_stack_push(context->locals[i]);
@@ -896,6 +921,27 @@ ASObject* ABCVm::executeFunctionFast(const SyntheticFunction* function, call_con
setSlot(v1, v2, t);
break;
}
+ case 0x6e:
+ {
+ //getglobalSlot
+ uint32_t t=data->uints[0];
+ instructionPointer+=4;
+
+ Global* globalscope = getGlobalScope(context);
+ context->runtime_stack_push(globalscope->getSlot(t));
+ break;
+ }
+ case 0x6f:
+ {
+ //setglobalSlot
+ uint32_t t=data->uints[0];
+ instructionPointer+=4;
+
+ Global* globalscope = getGlobalScope(context);
+ ASObject* obj=context->runtime_stack_pop();
+ globalscope->setSlot(t,obj);
+ break;
+ }
case 0x70:
{
//convert_s
@@ -905,16 +951,12 @@ ASObject* ABCVm::executeFunctionFast(const SyntheticFunction* function, call_con
}
case 0x71:
{
- //FIXME: Properly escape as described in ECMA-357 section 10.2
- //esc_xelem
ASObject* val=context->runtime_stack_pop();
- context->runtime_stack_push(convert_s(val));
+ context->runtime_stack_push(esc_xelem(val));
break;
}
case 0x72:
{
- //FIXME: Properly escape as described in ECMA-357 section 10.2
- //esc_xattr
ASObject* val=context->runtime_stack_pop();
context->runtime_stack_push(esc_xattr(val));
break;
@@ -946,6 +988,18 @@ ASObject* ABCVm::executeFunctionFast(const SyntheticFunction* function, call_con
context->runtime_stack_push(abstract_b(convert_b(val)));
break;
}
+ case 0x77:
+ {
+ //convert_o
+ ASObject* val=context->runtime_stack_pop();
+ if (val->is<Null>())
+ throwError<TypeError>(kConvertNullToObjectError);
+ if (val->is<Undefined>())
+ throwError<TypeError>(kConvertUndefinedToObjectError);
+
+ context->runtime_stack_push(val);
+ break;
+ }
case 0x78:
{
//checkfilter
@@ -1362,7 +1416,12 @@ ASObject* ABCVm::executeFunctionFast(const SyntheticFunction* function, call_con
{
//getlocal_n
int i=opcode&3;
- assert_and_throw(context->locals[i]);
+ if (!context->locals[i])
+ {
+ LOG(LOG_CALLS, _("getLocal ") << i << " not set, pushing Undefined");
+ context->runtime_stack_push(getSys()->getUndefinedRef());
+ break;
+ }
LOG(LOG_CALLS, "getLocal " << i << ": " << context->locals[i]->toDebugString() );
context->locals[i]->incRef();
context->runtime_stack_push(context->locals[i]);
@@ -1382,6 +1441,20 @@ ASObject* ABCVm::executeFunctionFast(const SyntheticFunction* function, call_con
context->locals[i]=obj;
break;
}
+ case 0xf2:
+ {
+ //bkptline
+ LOG(LOG_CALLS, _("bkptline") );
+ instructionPointer+=4;
+ break;
+ }
+ case 0xf3:
+ {
+ //timestamp
+ LOG(LOG_CALLS, _("timestamp") );
+ instructionPointer+=4;
+ break;
+ }
//lightspark custom opcodes
case 0xfb:
{
diff --git a/src/scripting/abc_interpreter.cpp b/src/scripting/abc_interpreter.cpp
index c6af09d..366bc54 100644
--- a/src/scripting/abc_interpreter.cpp
+++ b/src/scripting/abc_interpreter.cpp
@@ -73,6 +73,12 @@ ASObject* ABCVm::executeFunction(const SyntheticFunction* function, call_context
context->exec_pos = code.tellg();
switch(opcode)
{
+ case 0x01:
+ {
+ //bkpt
+ LOG(LOG_CALLS, _("bkpt") );
+ break;
+ }
case 0x02:
{
//nop
@@ -663,6 +669,20 @@ ASObject* ABCVm::executeFunction(const SyntheticFunction* function, call_context
loadIntN<uint32_t>(context);
break;
}
+ case 0x38:
+ {
+ //lf32
+ LOG(LOG_CALLS, "lf32");
+ loadNumber(context);
+ break;
+ }
+ case 0x39:
+ {
+ //lf32
+ LOG(LOG_CALLS, "lf64");
+ loadNumber(context);
+ break;
+ }
case 0x3a:
{
//si8
@@ -684,6 +704,20 @@ ASObject* ABCVm::executeFunction(const SyntheticFunction* function, call_context
storeIntN<uint32_t>(context);
break;
}
+ case 0x3d:
+ {
+ //sf32
+ LOG(LOG_CALLS, "sf32");
+ storeNumber(context);
+ break;
+ }
+ case 0x3e:
+ {
+ //sf32
+ LOG(LOG_CALLS, "sf64");
+ storeNumber(context);
+ break;
+ }
case 0x40:
{
//newfunction
@@ -909,7 +943,12 @@ ASObject* ABCVm::executeFunction(const SyntheticFunction* function, call_context
//getlocal
u30 i;
code >> i;
- assert_and_throw(context->locals[i]);
+ if (!context->locals[i])
+ {
+ LOG(LOG_CALLS, _("getLocal ") << i << " not set, pushing Undefined");
+ context->runtime_stack_push(getSys()->getUndefinedRef());
+ break;
+ }
context->locals[i]->incRef();
LOG(LOG_CALLS, _("getLocal ") << i << _(": ") << context->locals[i]->toDebugString() );
context->runtime_stack_push(context->locals[i]);
@@ -1003,6 +1042,27 @@ ASObject* ABCVm::executeFunction(const SyntheticFunction* function, call_context
setSlot(v1, v2, t);
break;
}
+ case 0x6e:
+ {
+ //getglobalSlot
+ u30 t;
+ code >> t;
+
+ Global* globalscope = getGlobalScope(context);
+ context->runtime_stack_push(globalscope->getSlot(t));
+ break;
+ }
+ case 0x6f:
+ {
+ //setglobalSlot
+ u30 t;
+ code >> t;
+
+ Global* globalscope = getGlobalScope(context);
+ ASObject* obj=context->runtime_stack_pop();
+ globalscope->setSlot(t,obj);
+ break;
+ }
case 0x70:
{
//convert_s
@@ -1012,16 +1072,12 @@ ASObject* ABCVm::executeFunction(const SyntheticFunction* function, call_context
}
case 0x71:
{
- //FIXME: Properly escape as described in ECMA-357 section 10.2
- //esc_xelem
ASObject* val=context->runtime_stack_pop();
- context->runtime_stack_push(convert_s(val));
+ context->runtime_stack_push(esc_xelem(val));
break;
}
case 0x72:
{
- //FIXME: Properly escape as described in ECMA-357 section 10.2
- //esc_xattr
ASObject* val=context->runtime_stack_pop();
context->runtime_stack_push(esc_xattr(val));
break;
@@ -1053,6 +1109,18 @@ ASObject* ABCVm::executeFunction(const SyntheticFunction* function, call_context
context->runtime_stack_push(abstract_b(convert_b(val)));
break;
}
+ case 0x77:
+ {
+ //convert_o
+ ASObject* val=context->runtime_stack_pop();
+ if (val->is<Null>())
+ throwError<TypeError>(kConvertNullToObjectError);
+ if (val->is<Undefined>())
+ throwError<TypeError>(kConvertUndefinedToObjectError);
+
+ context->runtime_stack_push(val);
+ break;
+ }
case 0x78:
{
//checkfilter
@@ -1244,7 +1312,7 @@ ASObject* ABCVm::executeFunction(const SyntheticFunction* function, call_context
ASObject* v1=context->runtime_stack_pop();
ASObject* v2=context->runtime_stack_pop();
- ASObject* ret=abstract_i(urShift(v1, v2));
+ ASObject* ret=abstract_ui(urShift(v1, v2));
context->runtime_stack_push(ret);
break;
}
@@ -1457,7 +1525,12 @@ ASObject* ABCVm::executeFunction(const SyntheticFunction* function, call_context
{
//getlocal_n
int i=opcode&3;
- assert_and_throw(context->locals[i]);
+ if (!context->locals[i])
+ {
+ LOG(LOG_CALLS, _("getLocal ") << i << " not set, pushing Undefined");
+ context->runtime_stack_push(getSys()->getUndefinedRef());
+ break;
+ }
LOG(LOG_CALLS, _("getLocal ") << i << _(": ") << context->locals[i]->toDebugString() );
context->locals[i]->incRef();
context->runtime_stack_push(context->locals[i]);
@@ -1507,6 +1580,20 @@ ASObject* ABCVm::executeFunction(const SyntheticFunction* function, call_context
code >> t;
break;
}
+ case 0xf2:
+ {
+ //bkptline
+ LOG(LOG_CALLS, _("bkptline") );
+ u30 t;
+ code >> t;
+ break;
+ }
+ case 0xf3:
+ {
+ //timestamp
+ LOG(LOG_CALLS, _("timestamp") );
+ break;
+ }
default:
LOG(LOG_ERROR,_("Not interpreted instruction @") << code.tellg());
LOG(LOG_ERROR,_("dump ") << hex << (unsigned int)opcode << dec);
diff --git a/src/scripting/abc_opcodes.cpp b/src/scripting/abc_opcodes.cpp
index 1cc8c23..ab18b5e 100644
--- a/src/scripting/abc_opcodes.cpp
+++ b/src/scripting/abc_opcodes.cpp
@@ -27,6 +27,7 @@
#include "scripting/toplevel/RegExp.h"
#include "scripting/toplevel/XML.h"
#include "scripting/toplevel/XMLList.h"
+#include "scripting/flash/utils/Proxy.h"
using namespace std;
using namespace lightspark;
@@ -52,7 +53,7 @@ int32_t ABCVm::bitAnd_oi(ASObject* val1, int32_t val2)
void ABCVm::setProperty(ASObject* value,ASObject* obj,multiname* name)
{
- LOG(LOG_CALLS,_("setProperty ") << *name << ' ' << obj);
+ LOG(LOG_CALLS,_("setProperty ") << *name << ' ' << obj->toDebugString()<<" " << value->toString());
//Do not allow to set contant traits
obj->setVariableByMultiname(*name,value,ASObject::CONST_NOT_ALLOWED);
@@ -140,12 +141,9 @@ void ABCVm::coerce_a()
ASObject* ABCVm::checkfilter(ASObject* o)
{
- Class_base* xmlClass=Class<XML>::getClass();
- Class_base* xmlListClass=Class<XMLList>::getClass();
-
- if (o->getClass()!=xmlClass && o->getClass()!=xmlListClass)
- throw Class<TypeError>::getInstanceS();
-
+ LOG(LOG_CALLS, _("checkfilter") );
+ if (!o->is<XML>() && !o->is<XMLList>())
+ throwError<TypeError>(kFilterError, o->getClassName());
return o;
}
@@ -289,14 +287,29 @@ void ABCVm::callProperty(call_context* th, int n, int m, method_info** called_mi
LOG(LOG_CALLS, (keepReturn ? "callProperty " : "callPropVoid") << *name << ' ' << m);
ASObject* obj=th->runtime_stack_pop();
- if(obj->classdef)
- LOG(LOG_CALLS,obj->classdef->class_name);
+ checkDeclaredTraits(obj);
+
+ if(obj->is<Null>())
+ throwError<TypeError>(kConvertNullToObjectError);
+ if (obj->is<Undefined>())
+ throwError<TypeError>(kConvertUndefinedToObjectError);
//We should skip the special implementation of get
_NR<ASObject> o=obj->getVariableByMultiname(*name, ASObject::SKIP_IMPL);
name->resetNameIfObject();
-
- if(!o.isNull())
+ if(o.isNull() && obj->is<Class_base>())
+ {
+ // check super classes
+ _NR<Class_base> tmpcls = obj->as<Class_base>()->super;
+ while (tmpcls && !tmpcls.isNull())
+ {
+ o=tmpcls->getVariableByMultiname(*name, ASObject::SKIP_IMPL);
+ if(!o.isNull())
+ break;
+ tmpcls = tmpcls->super;
+ }
+ }
+ if(!o.isNull() && !(obj->classdef && obj->classdef->isSubClass(Class<Proxy>::getClass())))
{
o->incRef();
callImpl(th, o.getPtr(), obj, args, m, called_mi, keepReturn);
@@ -311,54 +324,76 @@ void ABCVm::callProperty(call_context* th, int n, int m, method_info** called_mi
callPropertyName.name_type=multiname::NAME_STRING;
callPropertyName.name_s_id=getSys()->getUniqueStringId("callProperty");
callPropertyName.ns.push_back(nsNameAndKind(flash_proxy,NAMESPACE));
- _NR<ASObject> o=obj->getVariableByMultiname(callPropertyName,ASObject::SKIP_IMPL);
+ _NR<ASObject> oproxy=obj->getVariableByMultiname(callPropertyName,ASObject::SKIP_IMPL);
- if(!o.isNull())
+ if(!oproxy.isNull())
{
- assert_and_throw(o->getObjectType()==T_FUNCTION);
-
- IFunction* f=static_cast<IFunction*>(o.getPtr());
- //Create a new array
- ASObject** proxyArgs=g_newa(ASObject*, m+1);
- //Well, I don't how to pass multiname to an as function. I'll just pass the name as a string
- proxyArgs[0]=Class<ASString>::getInstanceS(getSys()->getStringFromUniqueId(name->name_s_id));
- for(int i=0;i<m;i++)
- proxyArgs[i+1]=args[i];
-
- //We now suppress special handling
- LOG(LOG_CALLS,_("Proxy::callProperty"));
- f->incRef();
- obj->incRef();
- ASObject* ret=f->call(obj,proxyArgs,m+1);
- //call getMethodInfo only after the call, so it's updated
- if(called_mi)
- *called_mi=f->getMethodInfo();
- f->decRef();
- if(keepReturn)
- th->runtime_stack_push(ret);
+ assert_and_throw(oproxy->getObjectType()==T_FUNCTION);
+ if(!o.isNull())
+ {
+ o->incRef();
+ callImpl(th, o.getPtr(), obj, args, m, called_mi, keepReturn);
+ }
else
- ret->decRef();
-
- obj->decRef();
+ {
+ IFunction* f=static_cast<IFunction*>(oproxy.getPtr());
+ //Create a new array
+ ASObject** proxyArgs=g_newa(ASObject*, m+1);
+ ASObject* namearg = Class<ASString>::getInstanceS(name->normalizedName());
+ namearg->setProxyProperty(*name);
+ proxyArgs[0]=namearg;
+ for(int i=0;i<m;i++)
+ proxyArgs[i+1]=args[i];
+
+ //We now suppress special handling
+ LOG(LOG_CALLS,_("Proxy::callProperty"));
+ f->incRef();
+ obj->incRef();
+ ASObject* ret=f->call(obj,proxyArgs,m+1);
+ //call getMethodInfo only after the call, so it's updated
+ if(called_mi)
+ *called_mi=f->getMethodInfo();
+ f->decRef();
+ if(keepReturn)
+ th->runtime_stack_push(ret);
+ else
+ ret->decRef();
+
+ obj->decRef();
+ }
LOG(LOG_CALLS,_("End of calling ") << *name);
return;
}
}
+ obj->decRef();
+ for(int i=0;i<m;i++)
+ args[i]->decRef();
+ //LOG(LOG_NOT_IMPLEMENTED,"callProperty: " << name->qualifiedString() << " not found on " << obj->toDebugString());
+ throwError<TypeError>(kCallNotFoundError, name->qualifiedString(), obj->getClassName());
- LOG(LOG_NOT_IMPLEMENTED,"callProperty: " << name->normalizedName() << " not found on " << obj->toDebugString());
if(keepReturn)
th->runtime_stack_push(getSys()->getUndefinedRef());
- obj->decRef();
- for(int i=0;i<m;i++)
- args[i]->decRef();
}
LOG(LOG_CALLS,_("End of calling ") << *name);
}
+void ABCVm::checkDeclaredTraits(ASObject* obj)
+{
+ if(!obj->isInitialized() &&
+ !obj->is<Null>() &&
+ !obj->is<Undefined>() &&
+ !obj->is<IFunction>() &&
+ !obj->is<Function_object>() &&
+ !obj->is<Class_base>() &&
+ obj->getClass() &&
+ (obj->getClass() != Class_object::getClass()))
+ obj->getClass()->setupDeclaredTraits(obj);
+}
int32_t ABCVm::getProperty_i(ASObject* obj, multiname* name)
{
LOG(LOG_CALLS, _("getProperty_i ") << *name );
+ checkDeclaredTraits(obj);
//TODO: implement exception handling to find out if no integer can be returned
int32_t ret=obj->getVariableByMultiname_i(*name);
@@ -369,14 +404,18 @@ int32_t ABCVm::getProperty_i(ASObject* obj, multiname* name)
ASObject* ABCVm::getProperty(ASObject* obj, multiname* name)
{
- LOG(LOG_CALLS, _("getProperty ") << *name << ' ' << obj);
-
+ LOG(LOG_CALLS, _("getProperty ") << *name << ' ' << obj << ' '<<obj->isInitialized());
+ checkDeclaredTraits(obj);
+
_NR<ASObject> prop=obj->getVariableByMultiname(*name);
ASObject *ret;
if(prop.isNull())
{
- LOG(LOG_NOT_IMPLEMENTED,"getProperty: " << name->normalizedName() << " not found on " << obj->toDebugString());
+ if (obj->getClass() && obj->getClass()->isSealed)
+ throwError<ReferenceError>(kReadSealedError, name->normalizedName(), obj->getClass()->getQualifiedClassName());
+ if (Log::getLevel() >= LOG_NOT_IMPLEMENTED && obj->getClassName() != "Object")
+ LOG(LOG_NOT_IMPLEMENTED,"getProperty: " << name->normalizedName() << " not found on " << obj->toDebugString());
ret = getSys()->getUndefinedRef();
}
else
@@ -588,34 +627,36 @@ ASObject* ABCVm::constructFunction(call_context* th, IFunction* f, ASObject** ar
if(f->inClass)
throwError<TypeError>(kCannotCallMethodAsConstructor, "");
- assert(f->is<SyntheticFunction>());
- SyntheticFunction* sf=f->as<SyntheticFunction>();
- assert(sf->prototype);
- ASObject* ret=new_functionObject(sf->prototype);
+ assert(f->prototype);
+ ASObject* ret=new_functionObject(f->prototype);
#ifndef NDEBUG
ret->initialized=false;
#endif
- if (sf->mi->body)
+ if (f->is<SyntheticFunction>())
{
- LOG(LOG_CALLS,_("Building method traits"));
- for(unsigned int i=0;i<sf->mi->body->trait_count;i++)
- th->context->buildTrait(ret,&sf->mi->body->traits[i],false);
+ SyntheticFunction* sf=f->as<SyntheticFunction>();
+ if (sf->mi->body)
+ {
+ LOG(LOG_CALLS,_("Building method traits"));
+ for(unsigned int i=0;i<sf->mi->body->trait_count;i++)
+ th->context->buildTrait(ret,&sf->mi->body->traits[i],false);
+ }
}
#ifndef NDEBUG
ret->initialized=true;
#endif
- sf->incRef();
- ret->setVariableByQName("constructor","",sf,DYNAMIC_TRAIT);
+ f->incRef();
+ ret->setVariableByQName("constructor","",f,DYNAMIC_TRAIT);
ret->incRef();
- sf->incRef();
- ASObject* ret2=sf->call(ret,args,argslen);
- sf->decRef();
+ f->incRef();
+ ASObject* ret2=f->call(ret,args,argslen);
+ f->decRef();
//ECMA: "return ret2 if it is an object, else ret"
- if(ret2 && !ret2->is<Undefined>())
+ if(ret2 && !ret2->isPrimitive())
{
ret->decRef();
ret = ret2;
@@ -655,15 +696,6 @@ void ABCVm::construct(call_context* th, int m)
break;
}
- case T_UNDEFINED:
- case T_NULL:
- {
- //Inc ref count to make up for decremnt later
- obj->incRef();
- ret=obj;
- break;
- }
-
case T_FUNCTION:
{
ret = constructFunction(th, obj->as<IFunction>(), args, m);
@@ -707,7 +739,7 @@ void ABCVm::constructGenericType(call_context* th, int m)
/* Instantiate the template to obtain a class */
- std::vector<Type*> t(m);
+ std::vector<const Type*> t(m);
for(int i=0;i<m;++i)
{
if(args[i]->is<Class_base>())
@@ -1311,6 +1343,7 @@ void ABCVm::getLex(call_context* th, int n)
if(!it->considerDynamic)
opt=(ASObject::GET_VARIABLE_OPTION)(opt | ASObject::SKIP_IMPL);
+ checkDeclaredTraits(it->object.getPtr());
_NR<ASObject> prop=it->object->getVariableByMultiname(*name, opt);
if(!prop.isNull())
{
@@ -1326,7 +1359,8 @@ void ABCVm::getLex(call_context* th, int n)
o=getCurrentApplicationDomain(th)->getVariableAndTargetByMultiname(*name, target);
if(o==NULL)
{
- LOG(LOG_NOT_IMPLEMENTED,"getLex: " << *name<< " not found, pushing Undefined");
+ LOG(LOG_NOT_IMPLEMENTED,"getLex: " << *name<< " not found");
+ throwError<ReferenceError>(kUndefinedVarError);
th->runtime_stack_push(getSys()->getUndefinedRef());
name->resetNameIfObject();
return;
@@ -1419,7 +1453,8 @@ ASObject* ABCVm::findPropStrict(call_context* th, multiname* name)
ret=target;
else
{
- LOG(LOG_NOT_IMPLEMENTED,"findPropStrict: " << *name << " not found, pushing Undefined");
+ LOG(LOG_NOT_IMPLEMENTED,"findPropStrict: " << *name << " not found");
+ throwError<ReferenceError>(kUndefinedVarError);
return getSys()->getUndefinedRef();
}
}
@@ -1464,7 +1499,7 @@ bool ABCVm::lessEquals(ASObject* obj1, ASObject* obj2)
void ABCVm::initProperty(ASObject* obj, ASObject* value, multiname* name)
{
- LOG(LOG_CALLS, _("initProperty ") << *name << ' ' << obj);
+ checkDeclaredTraits(obj);
//Allow to set contant traits
obj->setVariableByMultiname(*name,value,ASObject::CONST_ALLOWED);
@@ -1482,12 +1517,16 @@ void ABCVm::callSuper(call_context* th, int n, int m, method_info** called_mi, b
LOG(LOG_CALLS,(keepReturn ? "callSuper " : "callSuperVoid ") << *name << ' ' << m);
ASObject* obj=th->runtime_stack_pop();
+ if(obj->is<Null>())
+ throwError<TypeError>(kConvertNullToObjectError);
+ if (obj->is<Undefined>())
+ throwError<TypeError>(kConvertUndefinedToObjectError);
assert_and_throw(th->inClass);
assert_and_throw(th->inClass->super);
assert_and_throw(obj->getClass());
assert_and_throw(obj->getClass()->isSubClass(th->inClass));
- _NR<ASObject> f = obj->getVariableByMultiname(*name,ASObject::NONE,th->inClass->super.getPtr());
+ _NR<ASObject> f = obj->getVariableByMultiname(*name, ASObject::SKIP_IMPL,th->inClass->super.getPtr());
name->resetNameIfObject();
if(!f.isNull())
{
@@ -1496,7 +1535,11 @@ void ABCVm::callSuper(call_context* th, int n, int m, method_info** called_mi, b
}
else
{
- LOG(LOG_ERROR,_("Calling an undefined function ") << getSys()->getStringFromUniqueId(name->name_s_id));
+ obj->decRef();
+ for(int i=0;i<m;i++)
+ args[i]->decRef();
+ //LOG(LOG_ERROR,_("Calling an undefined function ") << getSys()->getStringFromUniqueId(name->name_s_id));
+ throwError<ReferenceError>(kCallNotFoundError, name->qualifiedString(), obj->getClassName());
if(keepReturn)
th->runtime_stack_push(getSys()->getUndefinedRef());
}
@@ -1723,6 +1766,7 @@ void ABCVm::constructProp(call_context* th, int n, int m)
ASObject* obj=th->runtime_stack_pop();
+ checkDeclaredTraits(obj);
_NR<ASObject> o=obj->getVariableByMultiname(*name);
if(o.isNull())
@@ -1810,62 +1854,77 @@ void ABCVm::newObject(call_context* th, int n)
void ABCVm::getDescendants(call_context* th, int n)
{
multiname* name=th->context->getMultiname(n,th);
- LOG(LOG_CALLS,"getDescendants " << *name);
ASObject* obj=th->runtime_stack_pop();
+ LOG(LOG_CALLS,"getDescendants " << *name << " " <<name->isAttribute<< " "<<obj->getClassName());
//The name must be a QName
assert_and_throw(name->name_type==multiname::NAME_STRING);
XML::XMLVector ret;
//TODO: support multiname and namespaces
+ XMLList* targetobject = NULL;
if(obj->getClass()==Class<XML>::getClass())
{
XML* xmlObj=Class<XML>::cast(obj);
- xmlObj->getDescendantsByQName(getSys()->getStringFromUniqueId(name->name_s_id), "", ret);
+ targetobject = xmlObj->getChildrenlist();
+ tiny_string ns_uri = "";
+ if (name->ns.size() > 0)
+ {
+ ns_uri = name->ns[0].getImpl().name;
+ if (ns_uri.empty() && name->ns.size() == 1)
+ ns_uri="*";
+ }
+ xmlObj->getDescendantsByQName(getSys()->getStringFromUniqueId(name->name_s_id), ns_uri,name->isAttribute, ret);
}
else if(obj->getClass()==Class<XMLList>::getClass())
{
XMLList* xmlObj=Class<XMLList>::cast(obj);
- xmlObj->getDescendantsByQName(getSys()->getStringFromUniqueId(name->name_s_id), "", ret);
+ tiny_string ns_uri = "";
+ if (name->ns.size() > 0)
+ {
+ ns_uri = name->ns[0].getImpl().name;
+ if (ns_uri.empty() && name->ns.size() == 1)
+ ns_uri="*";
+ }
+ targetobject = xmlObj;
+ xmlObj->getDescendantsByQName(getSys()->getStringFromUniqueId(name->name_s_id), ns_uri,name->isAttribute, ret);
}
else if(obj->getClass()->isSubClass(Class<Proxy>::getClass()))
{
- _NR<ASObject> o=obj->getVariableByMultiname(*name, ASObject::SKIP_IMPL);
+ multiname callPropertyName(NULL);
+ callPropertyName.name_type=multiname::NAME_STRING;
+ callPropertyName.name_s_id=getSys()->getUniqueStringId("callProperty");
+ callPropertyName.ns.push_back(nsNameAndKind(flash_proxy,NAMESPACE));
+ _NR<ASObject> o=obj->getVariableByMultiname(callPropertyName,ASObject::SKIP_IMPL);
+
if(!o.isNull())
{
- o->incRef();
- multiname callPropertyName(NULL);
- callPropertyName.name_type=multiname::NAME_STRING;
- callPropertyName.name_s_id=getSys()->getUniqueStringId("callProperty");
- callPropertyName.ns.push_back(nsNameAndKind(flash_proxy,NAMESPACE));
- _NR<ASObject> o=obj->getVariableByMultiname(callPropertyName,ASObject::SKIP_IMPL);
-
- if(!o.isNull())
- {
- assert_and_throw(o->getObjectType()==T_FUNCTION);
-
- IFunction* f=static_cast<IFunction*>(o.getPtr());
- //Create a new array
- ASObject** proxyArgs=g_newa(ASObject*, 1);
- //Well, I don't how to pass multiname to an as function. I'll just pass the name as a string
- proxyArgs[0]=Class<ASString>::getInstanceS(getSys()->getStringFromUniqueId(name->name_s_id));
-
- //We now suppress special handling
- LOG(LOG_CALLS,_("Proxy::callProperty"));
- f->incRef();
- obj->incRef();
- ASObject* ret=f->call(obj,proxyArgs,1);
- f->decRef();
- th->runtime_stack_push(ret);
-
- obj->decRef();
- LOG(LOG_CALLS,_("End of calling ") << *name);
- return;
- }
- else
- {
- tiny_string objName = obj->getClassName();
- obj->decRef();
- throwError<TypeError>(kDescendentsError, objName);
- }
+ assert_and_throw(o->getObjectType()==T_FUNCTION);
+
+ IFunction* f=static_cast<IFunction*>(o.getPtr());
+ //Create a new array
+ ASObject** proxyArgs=g_newa(ASObject*, 2);
+ proxyArgs[0]=Class<ASString>::getInstanceS("descendants");
+ ASObject* namearg = Class<ASString>::getInstanceS(name->normalizedName());
+ namearg->setProxyProperty(*name);
+ proxyArgs[1]=namearg;
+ LOG(LOG_ERROR,"Proxy::getDescend:"<<namearg->toDebugString()<<*name);
+
+ //We now suppress special handling
+ LOG(LOG_CALLS,_("Proxy::callProperty"));
+ f->incRef();
+ obj->incRef();
+ ASObject* ret=f->call(obj,proxyArgs,2);
+ f->decRef();
+ th->runtime_stack_push(ret);
+
+ obj->decRef();
+ LOG(LOG_CALLS,_("End of calling ") << *name);
+ return;
+ }
+ else
+ {
+ tiny_string objName = obj->getClassName();
+ obj->decRef();
+ throwError<TypeError>(kDescendentsError, objName);
}
}
else
@@ -1874,7 +1933,7 @@ void ABCVm::getDescendants(call_context* th, int n)
obj->decRef();
throwError<TypeError>(kDescendentsError, objName);
}
- XMLList* retObj=Class<XMLList>::getInstanceS(ret);
+ XMLList* retObj=Class<XMLList>::getInstanceS(ret,targetobject,*name);
th->runtime_stack_push(retObj);
obj->decRef();
}
@@ -1922,18 +1981,42 @@ ASObject* ABCVm::nextName(ASObject* index, ASObject* obj)
ret->incRef();
return ret.getPtr();
}
+std::vector<Class_base*> classesToLinkInterfaces;
+void ABCVm::SetAllClassLinks()
+{
+ for (unsigned int i = 0; i < classesToLinkInterfaces.size(); i++)
+ {
+ Class_base* cls = classesToLinkInterfaces[i];
+ if (!cls)
+ continue;
+ if (ABCVm::newClassRecursiveLink(cls, cls))
+ classesToLinkInterfaces[i] = NULL;
+ }
+}
+void ABCVm::AddClassLinks(Class_base* target)
+{
+ classesToLinkInterfaces.push_back(target);
+}
-void ABCVm::newClassRecursiveLink(Class_base* target, Class_base* c)
+bool ABCVm::newClassRecursiveLink(Class_base* target, Class_base* c)
{
if(c->super)
- newClassRecursiveLink(target, c->super.getPtr());
-
- const vector<Class_base*>& interfaces=c->getInterfaces();
+ {
+ if (!newClassRecursiveLink(target, c->super.getPtr()))
+ return false;
+ }
+ bool bAllDefined = false;
+ const vector<Class_base*>& interfaces=c->getInterfaces(&bAllDefined);
+ if (!bAllDefined)
+ {
+ return false;
+ }
for(unsigned int i=0;i<interfaces.size();i++)
{
LOG(LOG_CALLS,_("Linking with interface ") << interfaces[i]->class_name);
interfaces[i]->linkInterface(target);
}
+ return true;
}
void ABCVm::newClass(call_context* th, int n)
@@ -1947,25 +2030,46 @@ void ABCVm::newClass(call_context* th, int n)
assert_and_throw(mname->ns.size()==1);
QName className(getSys()->getStringFromUniqueId(mname->name_s_id),mname->ns[0].getImpl().name);
- //Check if this class has been already defined
- _NR<ApplicationDomain> domain = getCurrentApplicationDomain(th);
- ASObject* target;
- ASObject* oldDefinition=domain->getVariableAndTargetByMultiname(*mname, target);
- if(oldDefinition && oldDefinition->getObjectType()==T_CLASS)
- {
- LOG(LOG_CALLS,_("Class ") << className << _(" already defined. Pushing previous definition"));
- baseClass->decRef();
- oldDefinition->incRef();
- th->runtime_stack_push(oldDefinition);
- return;
- }
- MemoryAccount* memoryAccount = getSys()->allocateMemoryAccount(className.name);
- Class_inherit* ret=new (getSys()->unaccountedMemory) Class_inherit(className, memoryAccount);
+ Class_inherit* ret = NULL;
+ auto i = th->context->root->applicationDomain->classesBeingDefined.cbegin();
+ while (i != th->context->root->applicationDomain->classesBeingDefined.cend())
+ {
+ if(i->first->qualifiedString() == mname->qualifiedString())
+ {
+ ret = (Class_inherit*)i->second;
+ ret->incRef();
+ break;
+ }
+ i++;
+ }
- //Add the class to the ones being currently defined in this context
- th->context->classesBeingDefined.insert(make_pair(mname, ret));
+ if (ret == NULL)
+ {
+ //Check if this class has been already defined
+ _NR<ApplicationDomain> domain = getCurrentApplicationDomain(th);
+ ASObject* target;
+ ASObject* oldDefinition=domain->getVariableAndTargetByMultiname(*mname, target);
+ if(oldDefinition && oldDefinition->getObjectType()==T_CLASS)
+ {
+ LOG(LOG_CALLS,_("Class ") << className << _(" already defined. Pushing previous definition"));
+ baseClass->decRef();
+ oldDefinition->incRef();
+ th->runtime_stack_push(oldDefinition);
+ // ensure that this interface is linked to all previously defined classes implementing this interface
+ if (th->context->instances[n].isInterface())
+ ABCVm::SetAllClassLinks();
+ return;
+ }
+
+ MemoryAccount* memoryAccount = getSys()->allocateMemoryAccount(className.name);
+ ret=new (getSys()->unaccountedMemory) Class_inherit(className, memoryAccount);
+ LOG(LOG_CALLS,"add classes defined:"<<*mname<<" "<<th->context);
+ //Add the class to the ones being currently defined in this context
+ th->context->root->applicationDomain->classesBeingDefined.insert(make_pair(mname, ret));
+ }
+
ret->isFinal = th->context->instances[n].isFinal();
ret->isSealed = th->context->instances[n].isSealed();
@@ -2036,6 +2140,13 @@ void ABCVm::newClass(call_context* th, int n)
if(ret->super)
ret->prototype->prevPrototype=ret->super->prototype;
ret->addPrototypeGetter();
+ if (constructor->body)
+ ret->constructorprop = _NR<ObjectConstructor>(new_objectConstructor(ret,ret->constructor->length));
+ else
+ ret->constructorprop = _NR<ObjectConstructor>(new_objectConstructor(ret,0));
+
+ ret->constructorprop->incRef();
+ ret->addConstructorGetter();
//add implemented interfaces
for(unsigned int i=0;i<th->context->instances[n].interface_count;i++)
@@ -2056,9 +2167,16 @@ void ABCVm::newClass(call_context* th, int n)
if(!th->context->instances[n].isInterface())
{
//Link all the interfaces for this class and all the bases
- newClassRecursiveLink(ret, ret);
+ if (!newClassRecursiveLink(ret, ret))
+ {
+ // remember classes where not all interfaces are defined yet
+ ABCVm::AddClassLinks(ret);
+ }
}
-
+ // ensure that this interface is linked to all previously defined classes implementing this interface
+ if (th->context->instances[n].isInterface())
+ ABCVm::SetAllClassLinks();
+
LOG(LOG_CALLS,_("Calling Class init ") << ret);
ret->incRef();
//Class init functions are called with global as this
@@ -2079,17 +2197,17 @@ void ABCVm::newClass(call_context* th, int n)
cinit->decRef();
//Remove the class to the ones being currently defined in this context
- th->context->classesBeingDefined.erase(mname);
+ th->context->root->applicationDomain->classesBeingDefined.erase(mname);
throw;
}
assert_and_throw(ret2->is<Undefined>());
ret2->decRef();
- LOG(LOG_CALLS,_("End of Class init ") << ret);
+ LOG(LOG_CALLS,_("End of Class init ") << *mname <<" " <<ret);
th->runtime_stack_push(ret);
cinit->decRef();
//Remove the class to the ones being currently defined in this context
- th->context->classesBeingDefined.erase(mname);
+ th->context->root->applicationDomain->classesBeingDefined.erase(mname);
}
void ABCVm::swap()
@@ -2188,6 +2306,7 @@ void ABCVm::callImpl(call_context* th, ASObject* f, ASObject* obj, ASObject** ar
//we silently ignore calling undefined functions
if(f->is<Undefined>())
{
+ LOG(LOG_NOT_IMPLEMENTED,"calling undefined function:"<<obj->toDebugString());
if(keepReturn)
th->runtime_stack_push(f);
else
@@ -2264,22 +2383,28 @@ void ABCVm::newArray(call_context* th, int n)
ASObject* ABCVm::esc_xattr(ASObject* o)
{
- /* TODO: implement correct escaping according to E4X
- * For now we just cut the string at the first \0 byte, which is wrong
- * but suppresses more errors */
- tiny_string t = o->toString();
- LOG(LOG_NOT_IMPLEMENTED,"esc_xattr on " << t);
+ tiny_string t;
+ if (o->is<XML>())
+ t = o->as<XML>()->toXMLString_internal();
+ else if (o->is<XMLList>())
+ t = o->as<XMLList>()->toXMLString_internal();
+ else
+ t = XML::encodeToXML(o->toString(),true);
o->decRef();
- auto i=t.begin();
- for(;i!=t.end();++i)
- {
- if(*i == '\0')
- break;
- }
- if(i == t.end())
- return Class<ASString>::getInstanceS(t);
+ return Class<ASString>::getInstanceS(t);
+}
+
+ASObject* ABCVm::esc_xelem(ASObject* o)
+{
+ tiny_string t;
+ if (o->is<XML>())
+ t = o->as<XML>()->toXMLString_internal();
+ else if (o->is<XMLList>())
+ t = o->as<XMLList>()->toXMLString_internal();
else
- return Class<ASString>::getInstanceS(t.substr(0,i));
+ t = XML::encodeToXML(o->toString(),false);
+ o->decRef();
+ return Class<ASString>::getInstanceS(t);
}
/* This should walk prototype chain of value, trying to find type. See ECMA.
diff --git a/src/scripting/abc_optimizer.cpp b/src/scripting/abc_optimizer.cpp
index c19dd17..2be09f3 100644
--- a/src/scripting/abc_optimizer.cpp
+++ b/src/scripting/abc_optimizer.cpp
@@ -179,7 +179,8 @@ EARLY_BIND_STATUS ABCVm::earlyBindForScopeStack(ostream& out, const SyntheticFun
return CANNOT_BIND;
}
- const variable* var=it->object->findVariableByMultiname(*name, ASObject::XML_STRICT, it->object->getClass());
+ NS_KIND nskind;
+ const variable* var=it->object->findVariableByMultiname(*name, ASObject::XML_STRICT, it->object->getClass(),nskind);
if(var)
{
found=true;
@@ -964,7 +965,8 @@ void ABCVm::optimizeFunction(SyntheticFunction* function)
const Class_base* objType=dynamic_cast<const Class_base*>(baseData.type);
if(objType)
{
- const variable* var=objType->findBorrowedGettable(*name);
+ NS_KIND nskind;
+ const variable* var=objType->findBorrowedGettable(*name,nskind);
if(var && var->var && var->var->getObjectType()==T_FUNCTION)
{
SyntheticFunction* calledFunc=dynamic_cast<SyntheticFunction*>(var->var);
diff --git a/src/scripting/abctypes.h b/src/scripting/abctypes.h
index f70280a..0cca5b1 100644
--- a/src/scripting/abctypes.h
+++ b/src/scripting/abctypes.h
@@ -122,8 +122,9 @@ struct multiname_info
u30 type_definition;
std::vector<u30> param_types;
multiname* cached;
- multiname_info():cached(NULL){}
- ~multiname_info(){delete cached;}
+ multiname* dynamic;
+ multiname_info():cached(NULL),dynamic(NULL){}
+ ~multiname_info(){delete cached;if (dynamic) {delete dynamic;};}
bool isAttributeName() const;
};
diff --git a/src/scripting/argconv.h b/src/scripting/argconv.h
index 78b51bd..22cce31 100644
--- a/src/scripting/argconv.h
+++ b/src/scripting/argconv.h
@@ -215,15 +215,17 @@ inline ASObject* lightspark::ArgumentConversion<RGB>::toAbstract(const RGB& val)
return abstract_ui(val.toUInt());
}
-#define ARG_UNPACK ArgUnpack(args,argslen)
+#define ARG_UNPACK ArgUnpack(args,argslen,false)
+#define ARG_UNPACK_MORE_ALLOWED ArgUnpack(args,argslen,true)
class ArgUnpack
{
private:
ASObject* const * args;
int argslen;
+ bool moreAllowed;
public:
- ArgUnpack(ASObject* const * _args, int _argslen) : args(_args), argslen(_argslen) {}
+ ArgUnpack(ASObject* const * _args, int _argslen, bool _moreAllowed) : args(_args), argslen(_argslen), moreAllowed(_moreAllowed) {}
template<class T> ArgUnpack& operator()(T& v)
{
@@ -251,7 +253,7 @@ public:
}
~ArgUnpack()
{
- if(argslen > 0)
+ if(argslen > 0 && !moreAllowed)
LOG(LOG_NOT_IMPLEMENTED,"Not all arguments were unpacked");
}
};
diff --git a/src/scripting/class.cpp b/src/scripting/class.cpp
index 18d9741..6ba15d9 100644
--- a/src/scripting/class.cpp
+++ b/src/scripting/class.cpp
@@ -48,6 +48,13 @@ Function_object* lightspark::new_functionObject(_NR<ASObject> p)
return new (c->memoryAccount) Function_object(c, p);
}
+ObjectConstructor* lightspark::new_objectConstructor(Class_base* cls,uint32_t length)
+{
+ return new (cls->memoryAccount) ObjectConstructor(cls, length);
+}
+
+
+
Class_inherit::Class_inherit(const QName& name, MemoryAccount* m):Class_base(name, m),tag(NULL),bindedToRoot(false)
{
this->incRef(); //create on reference for the classes map
@@ -71,7 +78,6 @@ ASObject* Class_inherit::getInstance(bool construct, ASObject* const* args, cons
realClass=this;
ASObject* ret=NULL;
- assert_and_throw(!bindedToRoot);
if(tag)
{
ret=tag->instance(realClass);
@@ -172,3 +178,25 @@ ASObject* Class<ASObject>::getInstance(bool construct, ASObject* const* args, co
handleConstruction(ret,args,argslen,true);
return ret;
}
+Class<ASObject>* Class<ASObject>::getClass()
+{
+ uint32_t classId=ClassName<ASObject>::id;
+ Class<ASObject>* ret=NULL;
+ Class_base** retAddr=&getSys()->builtinClasses[classId];
+ if(*retAddr==NULL)
+ {
+ //Create the class
+ QName name(ClassName<ASObject>::name,ClassName<ASObject>::ns);
+ MemoryAccount* memoryAccount = getSys()->allocateMemoryAccount(name.name);
+ ret=new (getSys()->unaccountedMemory) Class<ASObject>(name, memoryAccount);
+ ret->incRef();
+ *retAddr=ret;
+ ret->prototype = _MNR(new_objectPrototype());
+ ASObject::sinit(ret);
+ ret->initStandardProps();
+ }
+ else
+ ret=static_cast<Class<ASObject>*>(*retAddr);
+
+ return ret;
+}
diff --git a/src/scripting/class.h b/src/scripting/class.h
index 3d14643..f98ab08 100644
--- a/src/scripting/class.h
+++ b/src/scripting/class.h
@@ -72,6 +72,7 @@ ASObject* new_asobject();
Prototype* new_objectPrototype();
Prototype* new_functionPrototype(Class_base* functionClass, _NR<Prototype> p);
Function_object* new_functionObject(_NR<ASObject> p);
+ObjectConstructor* new_objectConstructor(Class_base* cls,uint32_t length);
template<class T,std::size_t N>
struct newWithOptionalClass
@@ -149,13 +150,7 @@ public:
ret->prototype = _MNR(new_objectPrototype());
T::sinit(ret);
- ret->setDeclaredMethodByQName("toString",AS3,Class<IFunction>::getFunction(Class_base::_toString),NORMAL_METHOD,false);
- ret->incRef();
- ret->prototype->setVariableByQName("constructor","",ret,DYNAMIC_TRAIT);
- if(ret->super)
- ret->prototype->prevPrototype=ret->super->prototype;
- ret->addPrototypeGetter();
- ret->addLengthGetter();
+ ret->initStandardProps();
}
else
ret=static_cast<Class<T>*>(*retAddr);
@@ -241,54 +236,7 @@ public:
Class<ASObject>* c=Class<ASObject>::getClass();
return c->getInstance(true,NULL,0);
}
- /* This creates a stub class, i.e. a class with given name but without
- * any implementation.
- */
- static _R<Class<ASObject>> getStubClass(const QName& name, _R<Class_base> superClass=Class<ASObject>::getRef())
- {
- MemoryAccount* memoryAccount = getSys()->allocateMemoryAccount(name.name);
- Class<ASObject>* ret = new (getSys()->unaccountedMemory) Class<ASObject>(name, memoryAccount);
-
- ret->setSuper(superClass);
- ret->prototype = _MNR(new_objectPrototype());
- ret->prototype->prevPrototype=ret->super->prototype;
- ret->incRef();
- ret->prototype->setVariableByQName("constructor","",ret,DYNAMIC_TRAIT);
- ret->addPrototypeGetter();
- ret->addLengthGetter();
-
- ret->setDeclaredMethodByQName("toString",AS3,Class<IFunction>::getFunction(Class_base::_toString),NORMAL_METHOD,false);
- getSys()->customClasses.insert(ret);
- ret->incRef();
- return _MR(ret);
- }
- static Class<ASObject>* getClass()
- {
- uint32_t classId=ClassName<ASObject>::id;
- Class<ASObject>* ret=NULL;
- Class_base** retAddr=&getSys()->builtinClasses[classId];
- if(*retAddr==NULL)
- {
- //Create the class
- QName name(ClassName<ASObject>::name,ClassName<ASObject>::ns);
- MemoryAccount* memoryAccount = getSys()->allocateMemoryAccount(name.name);
- ret=new (getSys()->unaccountedMemory) Class<ASObject>(name, memoryAccount);
- ret->incRef();
- *retAddr=ret;
- ret->prototype = _MNR(new_objectPrototype());
- ASObject::sinit(ret);
-
- ret->setDeclaredMethodByQName("toString",AS3,Class<IFunction>::getFunction(Class_base::_toString),NORMAL_METHOD,false);
- ret->incRef();
- ret->prototype->setVariableByQName("constructor","",ret,DYNAMIC_TRAIT);
- ret->addPrototypeGetter();
- ret->addLengthGetter();
- }
- else
- ret=static_cast<Class<ASObject>*>(*retAddr);
-
- return ret;
- }
+ static Class<ASObject>* getClass();
static _R<Class<ASObject>> getRef()
{
Class<ASObject>* ret = getClass();
@@ -331,7 +279,7 @@ void lookupAndLink(Class_base* c, const tiny_string& name, const tiny_string& in
template<class T>
class InterfaceClass: public Class_base
{
- virtual ~InterfaceClass() {}
+ virtual ~InterfaceClass() { }
void buildInstanceTraits(ASObject*) const {}
ASObject* getInstance(bool, ASObject* const*, unsigned int, Class_base* realClass)
{
@@ -343,7 +291,7 @@ class InterfaceClass: public Class_base
assert(argslen == 1);
return args[0];
}
- InterfaceClass(const QName& name, MemoryAccount* m):Class_base(name, m) {}
+ InterfaceClass(const QName& name, MemoryAccount* m):Class_base(name, m) { }
public:
static InterfaceClass<T>* getClass()
{
@@ -383,9 +331,9 @@ class TemplatedClass : public Class<T>
private:
/* the Template<T>* this class was generated from */
const Template_base* templ;
- std::vector<Type*> types;
+ std::vector<const Type*> types;
public:
- TemplatedClass(const QName& name, const std::vector<Type*>& _types, Template_base* _templ, MemoryAccount* m)
+ TemplatedClass(const QName& name, const std::vector<const Type*>& _types, Template_base* _templ, MemoryAccount* m)
: Class<T>(name, m), templ(_templ), types(_types)
{
}
@@ -417,10 +365,14 @@ public:
return templ;
}
- const std::vector<Type*> getTypes() const
+ std::vector<const Type*> getTypes() const
{
return types;
}
+ void addType(const Type* type)
+ {
+ types.push_back(type);
+ }
ASObject* coerce(ASObject* o) const
{
@@ -429,8 +381,8 @@ public:
o->decRef();
return getSys()->getNullRef();
}
- else if ((o->is<Vector>() && o->as<Vector>()->sameType(types)) ||
- o->is<Null>())
+ else if ((o->is<Vector>() && o->as<Vector>()->sameType(this->class_name)) ||
+ o->is<Null>())
{
// Vector.<x> can be coerced to Vector.<y>
// only if x and y are the same type
@@ -440,7 +392,7 @@ public:
{
o->decRef();
throwError<TypeError>(kCheckTypeFailedError, o->getClassName(),
- Class<T>::getQualifiedClassName());
+ Class<T>::getQualifiedClassName());
return NULL; // not reached
}
}
@@ -453,7 +405,7 @@ class Template : public Template_base
public:
Template(QName name) : Template_base(name) {};
- QName getQName(const std::vector<Type*>& types)
+ QName getQName(const std::vector<const Type*>& types)
{
//This is the naming scheme that the ABC compiler uses,
//and we need to stay in sync here
@@ -466,7 +418,7 @@ public:
return ret;
}
- Class_base* applyType(const std::vector<Type*>& types)
+ Class_base* applyType(const std::vector<const Type*>& types)
{
QName instantiatedQName = getQName(types);
@@ -484,21 +436,61 @@ public:
ret->addPrototypeGetter();
}
else
+ {
+ TemplatedClass<T>* tmp = static_cast<TemplatedClass<T>*>(it->second);
+ if (tmp->getTypes().size() == 0)
+ tmp->addType(types[0]);
+ ret= tmp;
+ }
+
+ ret->incRef();
+ return ret;
+ }
+ Class_base* applyTypeByQName(const QName& qname)
+ {
+ const std::vector<const Type*> types;
+ std::map<QName, Class_base*>::iterator it=getSys()->instantiatedTemplates.find(qname);
+ Class<T>* ret=NULL;
+ if(it==getSys()->instantiatedTemplates.end()) //This class is not yet in the map, create it
+ {
+ MemoryAccount* memoryAccount = getSys()->allocateMemoryAccount(qname.name);
+ ret=new (getSys()->unaccountedMemory) TemplatedClass<T>(qname,types,this,memoryAccount);
+ getSys()->instantiatedTemplates.insert(std::make_pair(qname,ret));
+ ret->prototype = _MNR(new_objectPrototype());
+ T::sinit(ret);
+ if(ret->super)
+ ret->prototype->prevPrototype=ret->super->prototype;
+ ret->addPrototypeGetter();
+ }
+ else
ret=static_cast<TemplatedClass<T>*>(it->second);
ret->incRef();
return ret;
}
- static Ref<Class_base> getTemplateInstance(Type* type)
+ static Ref<Class_base> getTemplateInstance(const Type* type)
{
- std::vector<Type*> t(1,type);
+ std::vector<const Type*> t(1,type);
Template<T>* templ=getTemplate();
Ref<Class_base> ret=_MR(templ->applyType(t));
templ->decRef();
return ret;
}
+ static Ref<Class_base> getTemplateInstance(const QName& qname, ABCContext* context)
+ {
+ Template<T>* templ=getTemplate();
+ Ref<Class_base> ret=_MR(templ->applyTypeByQName(qname));
+ ret->context = context;
+ templ->decRef();
+ return ret;
+ }
+ static T* getInstanceS(const Type* type)
+ {
+ return static_cast<T*>(getTemplateInstance(type).getPtr()->getInstance(true,NULL,0));
+ }
+
static Template<T>* getTemplate(const QName& name)
{
std::map<QName, Template_base*>::iterator it=getSys()->templates.find(name);
diff --git a/src/scripting/flash/accessibility/flashaccessibility.cpp b/src/scripting/flash/accessibility/flashaccessibility.cpp
index ebc460d..4d6a361 100644
--- a/src/scripting/flash/accessibility/flashaccessibility.cpp
+++ b/src/scripting/flash/accessibility/flashaccessibility.cpp
@@ -23,25 +23,37 @@
using namespace lightspark;
+AccessibilityProperties::AccessibilityProperties(Class_base* c):
+ ASObject(c), forceSimple(false), noAutoLabeling(false), silent(false)
+{
+}
+
void AccessibilityProperties::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASObject>::getRef());
- REGISTER_GETTER_SETTER(c,name);
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED);
+ REGISTER_GETTER_SETTER(c, description);
+ REGISTER_GETTER_SETTER(c, forceSimple);
+ REGISTER_GETTER_SETTER(c, name);
+ REGISTER_GETTER_SETTER(c, noAutoLabeling);
+ REGISTER_GETTER_SETTER(c, shortcut);
+ REGISTER_GETTER_SETTER(c, silent);
}
ASFUNCTIONBODY(AccessibilityProperties,_constructor)
{
- LOG(LOG_NOT_IMPLEMENTED, _("AccessibilityProperties class is unimplemented."));
return NULL;
}
-ASFUNCTIONBODY_GETTER_SETTER(AccessibilityProperties,name);
+ASFUNCTIONBODY_GETTER_SETTER(AccessibilityProperties, description);
+ASFUNCTIONBODY_GETTER_SETTER(AccessibilityProperties, forceSimple);
+ASFUNCTIONBODY_GETTER_SETTER(AccessibilityProperties, name);
+ASFUNCTIONBODY_GETTER_SETTER(AccessibilityProperties, noAutoLabeling);
+ASFUNCTIONBODY_GETTER_SETTER(AccessibilityProperties, shortcut);
+ASFUNCTIONBODY_GETTER_SETTER(AccessibilityProperties, silent);
void AccessibilityImplementation::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASObject>::getRef());
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED);
}
ASFUNCTIONBODY(AccessibilityImplementation,_constructor)
@@ -49,3 +61,19 @@ ASFUNCTIONBODY(AccessibilityImplementation,_constructor)
LOG(LOG_NOT_IMPLEMENTED, _("AccessibilityImplementation class is unimplemented."));
return NULL;
}
+
+
+void Accessibility::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, ASObject, _constructorNotInstantiatable, CLASS_FINAL);
+ c->setVariableByQName("active","",abstract_b(false),CONSTANT_TRAIT);
+}
+
+ASFUNCTIONBODY(Accessibility,updateProperties)
+{
+ Accessibility* th=obj->as<Accessibility>();
+ LOG(LOG_NOT_IMPLEMENTED, "Accessibility is not supported.");
+ ARG_UNPACK (th->properties);
+
+ return NULL;
+}
diff --git a/src/scripting/flash/accessibility/flashaccessibility.h b/src/scripting/flash/accessibility/flashaccessibility.h
index 19d00b8..b462e75 100644
--- a/src/scripting/flash/accessibility/flashaccessibility.h
+++ b/src/scripting/flash/accessibility/flashaccessibility.h
@@ -28,9 +28,14 @@ namespace lightspark
class AccessibilityProperties : public ASObject
{
private:
- ASPROPERTY_GETTER_SETTER(tiny_string,name);
+ ASPROPERTY_GETTER_SETTER(tiny_string, description);
+ ASPROPERTY_GETTER_SETTER(bool, forceSimple);
+ ASPROPERTY_GETTER_SETTER(tiny_string, name);
+ ASPROPERTY_GETTER_SETTER(bool, noAutoLabeling);
+ ASPROPERTY_GETTER_SETTER(tiny_string, shortcut);
+ ASPROPERTY_GETTER_SETTER(bool, silent);
public:
- AccessibilityProperties(Class_base* c):ASObject(c){}
+ AccessibilityProperties(Class_base* c);
static void sinit(Class_base*);
ASFUNCTION(_constructor);
};
@@ -43,5 +48,15 @@ public:
ASFUNCTION(_constructor);
};
+class Accessibility : public ASObject
+{
+private:
+ _NR<AccessibilityProperties> properties;
+public:
+ Accessibility(Class_base* c):ASObject(c),properties(NULL){}
+ static void sinit(Class_base*);
+ ASFUNCTION(updateProperties);
+};
+
}
#endif /* SCRIPTING_FLASH_ACCESSIBILITY_FLASHACCESSIBILITY_H */
diff --git a/src/scripting/flash/concurrent/Condition.cpp b/src/scripting/flash/concurrent/Condition.cpp
new file mode 100644
index 0000000..6f49d17
--- /dev/null
+++ b/src/scripting/flash/concurrent/Condition.cpp
@@ -0,0 +1,81 @@
+/**************************************************************************
+ Lightspark, a free flash player implementation
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+**************************************************************************/
+
+#include "scripting/flash/concurrent/Condition.h"
+#include "scripting/flash/errors/flasherrors.h"
+#include "scripting/class.h"
+#include "scripting/argconv.h"
+
+using namespace std;
+using namespace lightspark;
+
+ASCondition::ASCondition(Class_base* c):ASObject(c)
+{
+
+}
+void ASCondition::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_FINAL);
+ c->setVariableByQName("isSupported","",abstract_b(false),CONSTANT_TRAIT);
+ c->setDeclaredMethodByQName("notify","",Class<IFunction>::getFunction(_notify),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("notifyAll","",Class<IFunction>::getFunction(_notifyAll),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("wait","",Class<IFunction>::getFunction(_wait),NORMAL_METHOD,true);
+ REGISTER_GETTER(c,mutex);
+}
+
+ASFUNCTIONBODY_GETTER(ASCondition,mutex);
+
+ASFUNCTIONBODY(ASCondition,_constructor)
+{
+ ASCondition* th=obj->as<ASCondition>();
+ _NR<ASObject> arg;
+ ARG_UNPACK(arg);
+ if (arg->is<Null>())
+ throwError<ArgumentError>(kNullPointerError);
+
+ if (!arg->is<ASMutex>())
+ throwError<ArgumentError>(kInvalidArgumentError) ;
+ arg->incRef();
+ th->mutex = _NR<ASMutex>(arg->as<ASMutex>());
+
+ return NULL;
+}
+ASFUNCTIONBODY(ASCondition,_notify)
+{
+ LOG(LOG_NOT_IMPLEMENTED,"condition notify not implemented");
+ ASCondition* th=obj->as<ASCondition>();
+ if (!th->mutex->getLockCount())
+ throwError<ASError>(kConditionCannotNotify) ;
+ return NULL;
+}
+ASFUNCTIONBODY(ASCondition,_notifyAll)
+{
+ LOG(LOG_NOT_IMPLEMENTED,"condition notifyAll not implemented");
+ ASCondition* th=obj->as<ASCondition>();
+ if (!th->mutex->getLockCount())
+ throwError<ASError>(kConditionCannotNotifyAll) ;
+ return NULL;
+}
+ASFUNCTIONBODY(ASCondition,_wait)
+{
+ LOG(LOG_NOT_IMPLEMENTED,"condition wait not implemented");
+ ASCondition* th=obj->as<ASCondition>();
+ if (!th->mutex->getLockCount())
+ throwError<ASError>(kConditionCannotWait) ;
+ return abstract_b(true);
+}
+
diff --git a/src/backends/rtmputils.h b/src/scripting/flash/concurrent/Condition.h
similarity index 66%
copy from src/backends/rtmputils.h
copy to src/scripting/flash/concurrent/Condition.h
index 7e9de51..31498e6 100644
--- a/src/backends/rtmputils.h
+++ b/src/scripting/flash/concurrent/Condition.h
@@ -1,8 +1,6 @@
/**************************************************************************
Lightspark, a free flash player implementation
- Copyright (C) 2011-2013 Alessandro Pignotti (a.pignotti at sssup.it)
-
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
@@ -17,25 +15,27 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
-#ifndef BACKENDS_RTMPUTILS_H
-#define BACKENDS_RTMPUTILS_H 1
+#ifndef FLASH_CONCURRENT_CONDITION_H
+#define FLASH_CONCURRENT_CONDITION_H
-#include "backends/netutils.h"
+#include "asobject.h"
+#include "scripting/flash/events/flashevents.h"
+#include "scripting/flash/concurrent/Mutex.h"
namespace lightspark
{
-class ILoadable;
-
-class RTMPDownloader: public ThreadedDownloader
+class ASCondition: public ASObject
{
-private:
- void execute();
- void threadAbort();
- tiny_string stream;
+ ASPROPERTY_GETTER(_NR<ASMutex>,mutex);
public:
- RTMPDownloader(const tiny_string& _url, const tiny_string& _stream, ILoadable* o);
+ ASCondition(Class_base* c);
+ static void sinit(Class_base*);
+ ASFUNCTION(_constructor);
+ ASFUNCTION(_notify);
+ ASFUNCTION(_notifyAll);
+ ASFUNCTION(_wait);
};
-};
-#endif /* BACKENDS_RTMPUTILS_H */
+}
+#endif // FLASH_CONCURRENT_CONDITION_H
diff --git a/src/scripting/flash/accessibility/flashaccessibility.cpp b/src/scripting/flash/concurrent/Mutex.cpp
similarity index 53%
copy from src/scripting/flash/accessibility/flashaccessibility.cpp
copy to src/scripting/flash/concurrent/Mutex.cpp
index ebc460d..3dc2902 100644
--- a/src/scripting/flash/accessibility/flashaccessibility.cpp
+++ b/src/scripting/flash/concurrent/Mutex.cpp
@@ -1,8 +1,6 @@
/**************************************************************************
Lightspark, a free flash player implementation
- Copyright (C) 2009-2013 Alessandro Pignotti (a.pignotti at sssup.it)
-
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
@@ -17,35 +15,46 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
-#include "scripting/flash/accessibility/flashaccessibility.h"
+#include "scripting/flash/concurrent/Mutex.h"
#include "scripting/class.h"
#include "scripting/argconv.h"
+using namespace std;
using namespace lightspark;
-void AccessibilityProperties::sinit(Class_base* c)
+ASMutex::ASMutex(Class_base* c):ASObject(c),lockcount(0)
+{
+
+}
+void ASMutex::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASObject>::getRef());
- REGISTER_GETTER_SETTER(c,name);
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_FINAL);
+ c->setDeclaredMethodByQName("lock","",Class<IFunction>::getFunction(_lock),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("unlock","",Class<IFunction>::getFunction(_unlock),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("tryLock","",Class<IFunction>::getFunction(_trylock),NORMAL_METHOD,true);
}
-ASFUNCTIONBODY(AccessibilityProperties,_constructor)
+ASFUNCTIONBODY(ASMutex,_constructor)
{
- LOG(LOG_NOT_IMPLEMENTED, _("AccessibilityProperties class is unimplemented."));
return NULL;
}
-
-ASFUNCTIONBODY_GETTER_SETTER(AccessibilityProperties,name);
-
-void AccessibilityImplementation::sinit(Class_base* c)
+ASFUNCTIONBODY(ASMutex,_lock)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASObject>::getRef());
+ ASMutex* th=obj->as<ASMutex>();
+ th->mutex.lock();
+ th->lockcount++;
+ return NULL;
}
-
-ASFUNCTIONBODY(AccessibilityImplementation,_constructor)
+ASFUNCTIONBODY(ASMutex,_unlock)
{
- LOG(LOG_NOT_IMPLEMENTED, _("AccessibilityImplementation class is unimplemented."));
+ ASMutex* th=obj->as<ASMutex>();
+ th->mutex.unlock();
+ th->lockcount--;
return NULL;
}
+ASFUNCTIONBODY(ASMutex,_trylock)
+{
+ ASMutex* th=obj->as<ASMutex>();
+ return abstract_b(th->mutex.trylock());
+}
+
diff --git a/src/backends/rtmputils.h b/src/scripting/flash/concurrent/Mutex.h
similarity index 68%
copy from src/backends/rtmputils.h
copy to src/scripting/flash/concurrent/Mutex.h
index 7e9de51..a642fd9 100644
--- a/src/backends/rtmputils.h
+++ b/src/scripting/flash/concurrent/Mutex.h
@@ -1,8 +1,6 @@
/**************************************************************************
Lightspark, a free flash player implementation
- Copyright (C) 2011-2013 Alessandro Pignotti (a.pignotti at sssup.it)
-
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
@@ -17,25 +15,30 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
-#ifndef BACKENDS_RTMPUTILS_H
-#define BACKENDS_RTMPUTILS_H 1
+#ifndef FLASH_CONCURRENT_MUTEX_H
+#define FLASH_CONCURRENT_MUTEX_H
-#include "backends/netutils.h"
+#include "asobject.h"
+#include "scripting/flash/events/flashevents.h"
namespace lightspark
{
-class ILoadable;
-
-class RTMPDownloader: public ThreadedDownloader
+class ASMutex: public ASObject
{
private:
- void execute();
- void threadAbort();
- tiny_string stream;
+ RecMutex mutex;
+ int lockcount;
+
public:
- RTMPDownloader(const tiny_string& _url, const tiny_string& _stream, ILoadable* o);
+ ASMutex(Class_base* c);
+ static void sinit(Class_base*);
+ ASFUNCTION(_constructor);
+ ASFUNCTION(_lock);
+ ASFUNCTION(_unlock);
+ ASFUNCTION(_trylock);
+ int getLockCount() { return lockcount; }
};
-};
-#endif /* BACKENDS_RTMPUTILS_H */
+}
+#endif // FLASH_CONCURRENT_MUTEX_H
diff --git a/src/scripting/flash/desktop/flashdesktop.cpp b/src/scripting/flash/desktop/flashdesktop.cpp
index ebf14e4..4e031da 100644
--- a/src/scripting/flash/desktop/flashdesktop.cpp
+++ b/src/scripting/flash/desktop/flashdesktop.cpp
@@ -27,9 +27,7 @@ using namespace lightspark;
void NativeApplication::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASObject>::getRef());
-
+ CLASS_SETUP(c, EventDispatcher, _constructor, CLASS_FINAL | CLASS_SEALED);
c->setDeclaredMethodByQName("nativeApplication", "", Class<IFunction>::getFunction(_getNativeApplication), GETTER_METHOD, false);
c->setDeclaredMethodByQName("addEventListener", "", Class<IFunction>::getFunction(addEventListener), NORMAL_METHOD, true);
}
@@ -40,6 +38,7 @@ void NativeApplication::buildTraits(ASObject* o)
ASFUNCTIONBODY(NativeApplication,_constructor)
{
+ EventDispatcher::_constructor(obj, NULL, 0);
return NULL;
}
diff --git a/src/scripting/flash/display/BitmapData.cpp b/src/scripting/flash/display/BitmapData.cpp
index 6adaed3..fa06fc2 100644
--- a/src/scripting/flash/display/BitmapData.cpp
+++ b/src/scripting/flash/display/BitmapData.cpp
@@ -24,6 +24,8 @@
#include "scripting/flash/geom/flashgeom.h"
#include "scripting/toplevel/Vector.h"
#include "scripting/flash/errors/flasherrors.h"
+#include "scripting/flash/utils/ByteArray.h"
+#include "scripting/flash/filters/flashfilters.h"
#include "backends/rendering_context.h"
using namespace lightspark;
@@ -55,8 +57,7 @@ BitmapData::BitmapData(Class_base* c, uint32_t width, uint32_t height)
void BitmapData::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASObject>::getRef());
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED);
c->addImplementedInterface(InterfaceClass<IBitmapDrawable>::getClass());
c->setDeclaredMethodByQName("draw","",Class<IFunction>::getFunction(draw),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("dispose","",Class<IFunction>::getFunction(dispose),NORMAL_METHOD,true);
@@ -80,6 +81,9 @@ void BitmapData::sinit(Class_base* c)
c->setDeclaredMethodByQName("getVector","",Class<IFunction>::getFunction(getVector),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("setPixels","",Class<IFunction>::getFunction(setPixels),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("setVector","",Class<IFunction>::getFunction(setVector),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("colorTransform","",Class<IFunction>::getFunction(colorTransform),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("compare","",Class<IFunction>::getFunction(compare),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("applyFilter","",Class<IFunction>::getFunction(applyFilter),NORMAL_METHOD,true);
// properties
c->setDeclaredMethodByQName("height","",Class<IFunction>::getFunction(_getHeight),GETTER_METHOD,true);
@@ -111,8 +115,8 @@ void BitmapData::notifyUsers() const
ASFUNCTIONBODY(BitmapData,_constructor)
{
- uint32_t width;
- uint32_t height;
+ int32_t width;
+ int32_t height;
bool transparent;
uint32_t fillColor;
BitmapData* th = obj->as<BitmapData>();
@@ -124,6 +128,10 @@ ASFUNCTIONBODY(BitmapData,_constructor)
//If the bitmap is already initialized, just return
if(width==0 || height==0 || !th->pixels->isEmpty())
return NULL;
+ if(width<0 || height<0)
+ throw Class<ArgumentError>::getInstanceS("invalid height or width", kInvalidArgumentError);
+ if(width>8191 || height>8191)
+ throw Class<ArgumentError>::getInstanceS("invalid height or width", kInvalidArgumentError);
uint32_t *pixelArray=new uint32_t[width*height];
uint32_t c=GUINT32_TO_BE(fillColor); // fromRGB expects big endian data
@@ -561,11 +569,11 @@ ASFUNCTIONBODY(BitmapData,histogram)
}
}
- Vector *result = Class<Vector>::getInstanceS(Class<Vector>::getClass());
+ Vector *result = Template<Vector>::getInstanceS(Template<Vector>::getTemplateInstance(Class<Number>::getClass()).getPtr());
int channelOrder[4] = {2, 1, 0, 3}; // red, green, blue, alpha
for (int j=0; j<4; j++)
{
- Vector *histogram = Class<Vector>::getInstanceS(Class<Number>::getClass());
+ Vector *histogram = Template<Vector>::getInstanceS(Class<Number>::getClass());
for (int level=0; level<256; level++)
{
histogram->append(abstract_d(counts[channelOrder[j]][level]));
@@ -654,7 +662,7 @@ ASFUNCTIONBODY(BitmapData,getVector)
if (rect.isNull())
throwError<TypeError>(kNullPointerError, "rect");
- Vector *result = Class<Vector>::getInstanceS(Class<UInteger>::getClass());
+ Vector *result = Template<Vector>::getInstanceS(Class<UInteger>::getClass());
vector<uint32_t> pixelvec = th->pixels->getPixelVector(rect->getRect());
vector<uint32_t>::const_iterator it;
for (it=pixelvec.begin(); it!=pixelvec.end(); ++it)
@@ -728,3 +736,118 @@ ASFUNCTIONBODY(BitmapData,setVector)
return NULL;
}
+
+ASFUNCTIONBODY(BitmapData,colorTransform)
+{
+ BitmapData* th = obj->as<BitmapData>();
+
+ _NR<Rectangle> inputRect;
+ _NR<ColorTransform> inputColorTransform;
+ ARG_UNPACK (inputRect) (inputColorTransform);
+
+ if (inputRect.isNull())
+ throwError<TypeError>(kNullPointerError, "rect");
+ if (inputColorTransform.isNull())
+ throwError<TypeError>(kNullPointerError, "inputVector");
+
+ RECT rect;
+ th->pixels->clipRect(inputRect->getRect(), rect);
+
+ vector<uint32_t> pixelvec = th->pixels->getPixelVector(rect);
+
+ unsigned int i = 0;
+ for (int32_t y=rect.Ymin; y<rect.Ymax; y++)
+ {
+ for (int32_t x=rect.Xmin; x<rect.Xmax; x++)
+ {
+
+ uint32_t pixel = pixelvec[i];
+
+ int a, r, g, b;
+ a = ((pixel >> 24 )&0xff) * inputColorTransform->alphaMultiplier + inputColorTransform->alphaOffset;
+ if (a > 255) a = 255;
+ if (a < 0) a = 0;
+ r = ((pixel >> 16 )&0xff) * inputColorTransform->redMultiplier + inputColorTransform->redOffset;
+ if (r > 255) r = 255;
+ if (r < 0) r = 0;
+ g = ((pixel >> 8 )&0xff) * inputColorTransform->greenMultiplier + inputColorTransform->greenOffset;
+ if (g > 255) g = 255;
+ if (g < 0) g = 0;
+ b = ((pixel )&0xff) * inputColorTransform->blueMultiplier + inputColorTransform->blueOffset;
+ if (b > 255) b = 255;
+ if (b < 0) b = 0;
+
+ pixel = (a<<24) | (r<<16) | (g<<8) | b;
+
+ th->pixels->setPixel(x, y, pixel, th->transparent);
+ i++;
+ }
+ }
+
+ return NULL;
+}
+ASFUNCTIONBODY(BitmapData,compare)
+{
+ BitmapData* th = obj->as<BitmapData>();
+
+ _NR<BitmapData> otherBitmapData;
+ ARG_UNPACK (otherBitmapData);
+
+ if (otherBitmapData.isNull())
+ throwError<TypeError>(kNullPointerError, "otherBitmapData");
+
+ if (th->getWidth() != otherBitmapData->getWidth())
+ return abstract_d(-3);
+ if (th->getHeight() != otherBitmapData->getHeight())
+ return abstract_d(-4);
+ RECT rect;
+ rect.Xmin = 0;
+ rect.Xmax = th->getWidth();
+ rect.Ymin = 0;
+ rect.Ymax = th->getHeight();
+
+ vector<uint32_t> pixelvec = th->pixels->getPixelVector(rect);
+ vector<uint32_t> otherpixelvec = otherBitmapData->pixels->getPixelVector(rect);
+
+ BitmapData* res = Class<BitmapData>::getInstanceS(rect.Xmax,rect.Ymax);
+ unsigned int i = 0;
+ bool different = false;
+ for (int32_t y=rect.Ymin; y<rect.Ymax; y++)
+ {
+ for (int32_t x=rect.Xmin; x<rect.Xmax; x++)
+ {
+
+ uint32_t pixel = pixelvec[i];
+ uint32_t otherpixel = otherpixelvec[i];
+ if (pixel == otherpixel)
+ res->pixels->setPixel(x, y, 0, true);
+ else if ((pixel & 0x00FFFFFF) == (otherpixel & 0x00FFFFFF))
+ {
+ different = true;
+ res->pixels->setPixel(x, y, ((pixel & 0xFF000000) - (otherpixel & 0xFF000000)) | 0x00FFFFFF , true);
+ }
+ else
+ {
+ different = true;
+ res->pixels->setPixel(x, y, ((pixel & 0x00FFFFFF) - (otherpixel & 0x00FFFFFF)), true);
+ }
+ i++;
+ }
+ }
+ if (!different)
+ return abstract_d(0);
+ return res;
+}
+
+ASFUNCTIONBODY(BitmapData,applyFilter)
+{
+ BitmapData* th = obj->as<BitmapData>();
+
+ _NR<BitmapData> sourceBitmapData;
+ _NR<Rectangle> sourceRect;
+ _NR<Point> destPoint;
+ _NR<BitmapFilter> filter;
+ ARG_UNPACK (sourceBitmapData)(sourceRect)(destPoint)(filter);
+ LOG(LOG_NOT_IMPLEMENTED,"BitmapData.applyFilter not implemented");
+ return NULL;
+}
diff --git a/src/scripting/flash/display/BitmapData.h b/src/scripting/flash/display/BitmapData.h
index 89ffd03..9291752 100644
--- a/src/scripting/flash/display/BitmapData.h
+++ b/src/scripting/flash/display/BitmapData.h
@@ -81,6 +81,9 @@ public:
ASFUNCTION(getVector);
ASFUNCTION(setPixels);
ASFUNCTION(setVector);
+ ASFUNCTION(colorTransform);
+ ASFUNCTION(compare);
+ ASFUNCTION(applyFilter);
};
};
diff --git a/src/scripting/flash/display/DisplayObject.cpp b/src/scripting/flash/display/DisplayObject.cpp
index a4937f1..0e964c0 100644
--- a/src/scripting/flash/display/DisplayObject.cpp
+++ b/src/scripting/flash/display/DisplayObject.cpp
@@ -118,8 +118,7 @@ void DisplayObject::finalize()
void DisplayObject::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<EventDispatcher>::getRef());
+ CLASS_SETUP(c, EventDispatcher, _constructorNotInstantiatable, CLASS_SEALED);
c->setDeclaredMethodByQName("loaderInfo","",Class<IFunction>::getFunction(_getLoaderInfo),GETTER_METHOD,true);
c->setDeclaredMethodByQName("width","",Class<IFunction>::getFunction(_getWidth),GETTER_METHOD,true);
c->setDeclaredMethodByQName("width","",Class<IFunction>::getFunction(_setWidth),SETTER_METHOD,true);
@@ -142,7 +141,7 @@ void DisplayObject::sinit(Class_base* c)
c->setDeclaredMethodByQName("parent","",Class<IFunction>::getFunction(_getParent),GETTER_METHOD,true);
c->setDeclaredMethodByQName("root","",Class<IFunction>::getFunction(_getRoot),GETTER_METHOD,true);
c->setDeclaredMethodByQName("blendMode","",Class<IFunction>::getFunction(_getBlendMode),GETTER_METHOD,true);
- c->setDeclaredMethodByQName("blendMode","",Class<IFunction>::getFunction(undefinedFunction),SETTER_METHOD,true);
+ c->setDeclaredMethodByQName("blendMode","",Class<IFunction>::getFunction(_setBlendMode),SETTER_METHOD,true);
c->setDeclaredMethodByQName("scale9Grid","",Class<IFunction>::getFunction(_getScale9Grid),GETTER_METHOD,true);
c->setDeclaredMethodByQName("scale9Grid","",Class<IFunction>::getFunction(undefinedFunction),SETTER_METHOD,true);
c->setDeclaredMethodByQName("stage","",Class<IFunction>::getFunction(_getStage),GETTER_METHOD,true);
@@ -306,7 +305,7 @@ void DisplayObject::extractValuesFromMatrix()
bool DisplayObject::skipRender() const
{
- return visible==false || clippedAlpha()==0.0;
+ return visible==false || clippedAlpha()==0.0 || ClipDepth;
}
void DisplayObject::defaultRender(RenderContext& ctxt) const
@@ -634,14 +633,6 @@ ASFUNCTIONBODY(DisplayObject,_getBounds)
return ret;
}
-ASFUNCTIONBODY(DisplayObject,_constructor)
-{
- //DisplayObject* th=static_cast<DisplayObject*>(obj->implementation);
- EventDispatcher::_constructor(obj,NULL,0);
-
- return NULL;
-}
-
ASFUNCTIONBODY(DisplayObject,_getLoaderInfo)
{
DisplayObject* th=static_cast<DisplayObject*>(obj);
@@ -676,8 +667,36 @@ ASFUNCTIONBODY(DisplayObject,_getScale9Grid)
ASFUNCTIONBODY(DisplayObject,_getBlendMode)
{
- //DisplayObject* th=static_cast<DisplayObject*>(obj);
- return getSys()->getUndefinedRef();
+ DisplayObject* th=static_cast<DisplayObject*>(obj);
+ return Class<ASString>::getInstanceS(th->blendMode);
+}
+ASFUNCTIONBODY(DisplayObject,_setBlendMode)
+{
+ DisplayObject* th=static_cast<DisplayObject*>(obj);
+ tiny_string val;
+ ARG_UNPACK(val);
+
+ if (
+ val != "add" &&
+ val != "alpha" &&
+ val != "darken" &&
+ val != "difference" &&
+ val != "erase" &&
+ val != "hardlight" &&
+ val != "invert" &&
+ val != "invert" &&
+ val != "layer" &&
+ val != "lighten" &&
+ val != "multiply" &&
+ val != "normal" &&
+ val != "overlay" &&
+ val != "screen" &&
+ val != "subtract"
+ )
+ val = "normal";
+ LOG(LOG_NOT_IMPLEMENTED, "blendmode is set but is not respected during drawing:"<<val);
+ th->blendMode = val;
+ return NULL;
}
ASFUNCTIONBODY(DisplayObject,localToGlobal)
diff --git a/src/scripting/flash/display/DisplayObject.h b/src/scripting/flash/display/DisplayObject.h
index b5ae7f4..1bc2392 100644
--- a/src/scripting/flash/display/DisplayObject.h
+++ b/src/scripting/flash/display/DisplayObject.h
@@ -58,6 +58,7 @@ private:
number_t rotation;
number_t sx,sy;
float alpha;
+ tiny_string blendMode;
public:
UI16_SWF Ratio;
UI16_SWF ClipDepth;
@@ -179,7 +180,6 @@ public:
number_t getNominalHeight();
static void sinit(Class_base* c);
static void buildTraits(ASObject* o);
- ASFUNCTION(_constructor);
ASFUNCTION(_getVisible);
ASFUNCTION(_setVisible);
ASFUNCTION(_getStage);
@@ -207,6 +207,7 @@ public:
ASFUNCTION(_getParent);
ASFUNCTION(_getRoot);
ASFUNCTION(_getBlendMode);
+ ASFUNCTION(_setBlendMode);
ASFUNCTION(_getScale9Grid);
ASFUNCTION(_setRotation);
ASFUNCTION(_getMouseX);
@@ -218,5 +219,5 @@ public:
ASFUNCTION(hitTestObject);
ASFUNCTION(hitTestPoint);
};
-};
+}
#endif /* SCRIPTING_FLASH_DISPLAY_DISPLAYOBJECT_H */
diff --git a/src/scripting/flash/display/Graphics.cpp b/src/scripting/flash/display/Graphics.cpp
new file mode 100644
index 0000000..663c576
--- /dev/null
+++ b/src/scripting/flash/display/Graphics.cpp
@@ -0,0 +1,923 @@
+/**************************************************************************
+ Lightspark, a free flash player implementation
+
+ Copyright (C) 2009-2013 Alessandro Pignotti (a.pignotti at sssup.it)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+**************************************************************************/
+
+#include "scripting/flash/display/Graphics.h"
+#include "scripting/flash/display/TokenContainer.h"
+#include "scripting/flash/display/BitmapData.h"
+#include "scripting/flash/display/flashdisplay.h"
+#include "scripting/flash/display/IGraphicsData.h"
+#include "scripting/toplevel/Array.h"
+#include "scripting/toplevel/Vector.h"
+#include "scripting/toplevel/Number.h"
+#include "scripting/toplevel/ASString.h"
+#include "scripting/flash/geom/flashgeom.h"
+#include "scripting/argconv.h"
+#include "swf.h"
+
+using namespace std;
+using namespace lightspark;
+
+void Graphics::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED | CLASS_FINAL);
+ c->setDeclaredMethodByQName("clear","",Class<IFunction>::getFunction(clear),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("copyFrom","",Class<IFunction>::getFunction(copyFrom),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("drawRect","",Class<IFunction>::getFunction(drawRect),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("drawRoundRect","",Class<IFunction>::getFunction(drawRoundRect),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("drawCircle","",Class<IFunction>::getFunction(drawCircle),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("drawEllipse","",Class<IFunction>::getFunction(drawEllipse),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("drawPath","",Class<IFunction>::getFunction(drawPath),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("drawTriangles","",Class<IFunction>::getFunction(drawTriangles),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("drawGraphicsData","",Class<IFunction>::getFunction(drawGraphicsData),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("moveTo","",Class<IFunction>::getFunction(moveTo),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("curveTo","",Class<IFunction>::getFunction(curveTo),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("cubicCurveTo","",Class<IFunction>::getFunction(cubicCurveTo),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("lineTo","",Class<IFunction>::getFunction(lineTo),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("lineBitmapStyle","",Class<IFunction>::getFunction(lineBitmapStyle),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("lineGradientStyle","",Class<IFunction>::getFunction(lineGradientStyle),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("lineStyle","",Class<IFunction>::getFunction(lineStyle),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("beginFill","",Class<IFunction>::getFunction(beginFill),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("beginGradientFill","",Class<IFunction>::getFunction(beginGradientFill),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("beginBitmapFill","",Class<IFunction>::getFunction(beginBitmapFill),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("endFill","",Class<IFunction>::getFunction(endFill),NORMAL_METHOD,true);
+}
+
+void Graphics::buildTraits(ASObject* o)
+{
+}
+
+//TODO: Add spinlock
+void Graphics::checkAndSetScaling()
+{
+ if(owner->scaling != 1.0f)
+ {
+ owner->scaling = 1.0f;
+ owner->tokens.clear();
+ }
+}
+
+ASFUNCTIONBODY(Graphics,_constructor)
+{
+ return NULL;
+}
+
+ASFUNCTIONBODY(Graphics,clear)
+{
+ Graphics* th=static_cast<Graphics*>(obj);
+ th->checkAndSetScaling();
+ th->owner->tokens.clear();
+ th->owner->owner->requestInvalidation(getSys());
+ return NULL;
+}
+
+ASFUNCTIONBODY(Graphics,moveTo)
+{
+ Graphics* th=static_cast<Graphics*>(obj);
+ th->checkAndSetScaling();
+ assert_and_throw(argslen==2);
+
+ int32_t x=args[0]->toInt();
+ int32_t y=args[1]->toInt();
+
+ th->owner->tokens.emplace_back(GeomToken(MOVE, Vector2(x, y)));
+ return NULL;
+}
+
+ASFUNCTIONBODY(Graphics,lineTo)
+{
+ Graphics* th=static_cast<Graphics*>(obj);
+ assert_and_throw(argslen==2);
+ th->checkAndSetScaling();
+
+ int x=args[0]->toInt();
+ int y=args[1]->toInt();
+
+ th->owner->tokens.emplace_back(GeomToken(STRAIGHT, Vector2(x, y)));
+ th->owner->owner->requestInvalidation(getSys());
+
+ return NULL;
+}
+
+ASFUNCTIONBODY(Graphics,curveTo)
+{
+ Graphics* th=static_cast<Graphics*>(obj);
+ assert_and_throw(argslen==4);
+ th->checkAndSetScaling();
+
+ int controlX=args[0]->toInt();
+ int controlY=args[1]->toInt();
+
+ int anchorX=args[2]->toInt();
+ int anchorY=args[3]->toInt();
+
+ th->owner->tokens.emplace_back(GeomToken(CURVE_QUADRATIC,
+ Vector2(controlX, controlY),
+ Vector2(anchorX, anchorY)));
+ th->owner->owner->requestInvalidation(getSys());
+
+ return NULL;
+}
+
+ASFUNCTIONBODY(Graphics,cubicCurveTo)
+{
+ Graphics* th=static_cast<Graphics*>(obj);
+ assert_and_throw(argslen==6);
+ th->checkAndSetScaling();
+
+ int control1X=args[0]->toInt();
+ int control1Y=args[1]->toInt();
+
+ int control2X=args[2]->toInt();
+ int control2Y=args[3]->toInt();
+
+ int anchorX=args[4]->toInt();
+ int anchorY=args[5]->toInt();
+
+ th->owner->tokens.emplace_back(GeomToken(CURVE_CUBIC,
+ Vector2(control1X, control1Y),
+ Vector2(control2X, control2Y),
+ Vector2(anchorX, anchorY)));
+ th->owner->owner->requestInvalidation(getSys());
+
+ return NULL;
+}
+
+/* KAPPA = 4 * (sqrt2 - 1) / 3
+ * This value was found in a Python prompt:
+ *
+ * >>> 4.0 * (2**0.5 - 1) / 3.0
+ *
+ * Source: http://whizkidtech.redprince.net/bezier/circle/
+ */
+const double KAPPA = 0.55228474983079356;
+
+ASFUNCTIONBODY(Graphics,drawRoundRect)
+{
+ Graphics* th=static_cast<Graphics*>(obj);
+ assert_and_throw(argslen==5 || argslen==6);
+ th->checkAndSetScaling();
+
+ double x=args[0]->toNumber();
+ double y=args[1]->toNumber();
+ double width=args[2]->toNumber();
+ double height=args[3]->toNumber();
+ double ellipseWidth=args[4]->toNumber();
+ double ellipseHeight;
+ if (argslen == 6)
+ ellipseHeight=args[5]->toNumber();
+
+ if (argslen == 5 || std::isnan(ellipseHeight))
+ ellipseHeight=ellipseWidth;
+
+ ellipseHeight /= 2;
+ ellipseWidth /= 2;
+
+ double kappaW = KAPPA * ellipseWidth;
+ double kappaH = KAPPA * ellipseHeight;
+
+ /*
+ * A-----B
+ * / \
+ * H C
+ * | |
+ * G D
+ * \ /
+ * F-----E
+ *
+ * Flash starts and stops the pen at 'D', so we will too.
+ */
+
+ // D
+ th->owner->tokens.emplace_back(GeomToken(MOVE, Vector2(x+width, y+height-ellipseHeight)));
+
+ // D -> E
+ th->owner->tokens.emplace_back(GeomToken(CURVE_CUBIC,
+ Vector2(x+width, y+height-ellipseHeight+kappaH),
+ Vector2(x+width-ellipseWidth+kappaW, y+height),
+ Vector2(x+width-ellipseWidth, y+height)));
+
+ // E -> F
+ th->owner->tokens.emplace_back(GeomToken(STRAIGHT, Vector2(x+ellipseWidth, y+height)));
+
+ // F -> G
+ th->owner->tokens.emplace_back(GeomToken(CURVE_CUBIC,
+ Vector2(x+ellipseWidth-kappaW, y+height),
+ Vector2(x, y+height-kappaH),
+ Vector2(x, y+height-ellipseHeight)));
+
+ // G -> H
+ th->owner->tokens.emplace_back(GeomToken(STRAIGHT, Vector2(x, y+ellipseHeight)));
+
+ // H -> A
+ th->owner->tokens.emplace_back(GeomToken(CURVE_CUBIC,
+ Vector2(x, y+ellipseHeight-kappaH),
+ Vector2(x+ellipseWidth-kappaW, y),
+ Vector2(x+ellipseWidth, y)));
+
+ // A -> B
+ th->owner->tokens.emplace_back(GeomToken(STRAIGHT, Vector2(x+width-ellipseWidth, y)));
+
+ // B -> C
+ th->owner->tokens.emplace_back(GeomToken(CURVE_CUBIC,
+ Vector2(x+width-ellipseWidth+kappaW, y),
+ Vector2(x+width, y+kappaH),
+ Vector2(x+width, y+ellipseHeight)));
+
+ // C -> D
+ th->owner->tokens.emplace_back(GeomToken(STRAIGHT, Vector2(x+width, y+height-ellipseHeight)));
+
+ th->owner->owner->requestInvalidation(getSys());
+
+ return NULL;
+}
+
+ASFUNCTIONBODY(Graphics,drawCircle)
+{
+ Graphics* th=static_cast<Graphics*>(obj);
+ assert_and_throw(argslen==3);
+ th->checkAndSetScaling();
+
+ double x=args[0]->toNumber();
+ double y=args[1]->toNumber();
+ double radius=args[2]->toNumber();
+
+ double kappa = KAPPA*radius;
+
+ // right
+ th->owner->tokens.emplace_back(GeomToken(MOVE, Vector2(x+radius, y)));
+
+ // bottom
+ th->owner->tokens.emplace_back(GeomToken(CURVE_CUBIC,
+ Vector2(x+radius, y+kappa ),
+ Vector2(x+kappa , y+radius),
+ Vector2(x , y+radius)));
+
+ // left
+ th->owner->tokens.emplace_back(GeomToken(CURVE_CUBIC,
+ Vector2(x-kappa , y+radius),
+ Vector2(x-radius, y+kappa ),
+ Vector2(x-radius, y )));
+
+ // top
+ th->owner->tokens.emplace_back(GeomToken(CURVE_CUBIC,
+ Vector2(x-radius, y-kappa ),
+ Vector2(x-kappa , y-radius),
+ Vector2(x , y-radius)));
+
+ // back to right
+ th->owner->tokens.emplace_back(GeomToken(CURVE_CUBIC,
+ Vector2(x+kappa , y-radius),
+ Vector2(x+radius, y-kappa ),
+ Vector2(x+radius, y )));
+
+ th->owner->owner->requestInvalidation(getSys());
+
+ return NULL;
+}
+
+ASFUNCTIONBODY(Graphics,drawEllipse)
+{
+ Graphics* th=static_cast<Graphics*>(obj);
+ assert_and_throw(argslen==4);
+ th->checkAndSetScaling();
+
+ double left=args[0]->toNumber();
+ double top=args[1]->toNumber();
+ double width=args[2]->toNumber();
+ double height=args[3]->toNumber();
+
+ double xkappa = KAPPA*width/2;
+ double ykappa = KAPPA*height/2;
+
+ // right
+ th->owner->tokens.emplace_back(GeomToken(MOVE, Vector2(left+width, top+height/2)));
+
+ // bottom
+ th->owner->tokens.emplace_back(GeomToken(CURVE_CUBIC,
+ Vector2(left+width , top+height/2+ykappa),
+ Vector2(left+width/2+xkappa, top+height),
+ Vector2(left+width/2, top+height)));
+
+ // left
+ th->owner->tokens.emplace_back(GeomToken(CURVE_CUBIC,
+ Vector2(left+width/2-xkappa, top+height),
+ Vector2(left, top+height/2+ykappa),
+ Vector2(left, top+height/2)));
+
+ // top
+ th->owner->tokens.emplace_back(GeomToken(CURVE_CUBIC,
+ Vector2(left, top+height/2-ykappa),
+ Vector2(left+width/2-xkappa, top),
+ Vector2(left+width/2, top)));
+
+ // back to right
+ th->owner->tokens.emplace_back(GeomToken(CURVE_CUBIC,
+ Vector2(left+width/2+xkappa, top),
+ Vector2(left+width, top+height/2-ykappa),
+ Vector2(left+width, top+height/2)));
+
+ th->owner->owner->requestInvalidation(getSys());
+
+ return NULL;
+}
+
+ASFUNCTIONBODY(Graphics,drawRect)
+{
+ Graphics* th=static_cast<Graphics*>(obj);
+ assert_and_throw(argslen==4);
+ th->checkAndSetScaling();
+
+ int x=args[0]->toInt();
+ int y=args[1]->toInt();
+ int width=args[2]->toInt();
+ int height=args[3]->toInt();
+
+ const Vector2 a(x,y);
+ const Vector2 b(x+width,y);
+ const Vector2 c(x+width,y+height);
+ const Vector2 d(x,y+height);
+
+ th->owner->tokens.emplace_back(GeomToken(MOVE, a));
+ th->owner->tokens.emplace_back(GeomToken(STRAIGHT, b));
+ th->owner->tokens.emplace_back(GeomToken(STRAIGHT, c));
+ th->owner->tokens.emplace_back(GeomToken(STRAIGHT, d));
+ th->owner->tokens.emplace_back(GeomToken(STRAIGHT, a));
+ th->owner->owner->requestInvalidation(getSys());
+
+ return NULL;
+}
+
+ASFUNCTIONBODY(Graphics,drawPath)
+{
+ Graphics* th=static_cast<Graphics*>(obj);
+ th->checkAndSetScaling();
+
+ _NR<Vector> commands;
+ _NR<Vector> data;
+ tiny_string winding;
+ ARG_UNPACK (commands) (data) (winding, "evenOdd");
+
+ if (commands.isNull() || data.isNull())
+ throwError<ArgumentError>(kInvalidParamError);
+
+ pathToTokens(commands, data, winding, th->owner->tokens);
+
+ th->owner->owner->requestInvalidation(getSys());
+
+ return NULL;
+}
+
+void Graphics::pathToTokens(_NR<Vector> commands, _NR<Vector> data,
+ tiny_string winding, std::vector<GeomToken>& tokens)
+{
+ if (commands.isNull() || data.isNull())
+ return;
+
+ if (winding != "evenOdd")
+ LOG(LOG_NOT_IMPLEMENTED, "Only event-odd winding implemented in Graphics.drawPath");
+
+ _R<Number> zeroRef = _MR(Class<Number>::getInstanceS(0));
+ Number *zero = zeroRef.getPtr();
+
+ int k = 0;
+ for (unsigned int i=0; i<commands->size(); i++)
+ {
+ switch (commands->at(i)->toInt())
+ {
+ case GraphicsPathCommand::MOVE_TO:
+ {
+ number_t x = data->at(k++, zero)->toNumber();
+ number_t y = data->at(k++, zero)->toNumber();
+ tokens.emplace_back(GeomToken(MOVE, Vector2(x, y)));
+ break;
+ }
+
+ case GraphicsPathCommand::LINE_TO:
+ {
+ number_t x = data->at(k++, zero)->toNumber();
+ number_t y = data->at(k++, zero)->toNumber();
+ tokens.emplace_back(GeomToken(STRAIGHT, Vector2(x, y)));
+ break;
+ }
+
+ case GraphicsPathCommand::CURVE_TO:
+ {
+ number_t cx = data->at(k++, zero)->toNumber();
+ number_t cy = data->at(k++, zero)->toNumber();
+ number_t x = data->at(k++, zero)->toNumber();
+ number_t y = data->at(k++, zero)->toNumber();
+ tokens.emplace_back(GeomToken(CURVE_QUADRATIC,
+ Vector2(cx, cy),
+ Vector2(x, y)));
+ break;
+ }
+
+ case GraphicsPathCommand::WIDE_MOVE_TO:
+ {
+ k+=2;
+ number_t x = data->at(k++, zero)->toNumber();
+ number_t y = data->at(k++, zero)->toNumber();
+ tokens.emplace_back(GeomToken(MOVE, Vector2(x, y)));
+ break;
+ }
+
+ case GraphicsPathCommand::WIDE_LINE_TO:
+ {
+ k+=2;
+ number_t x = data->at(k++, zero)->toNumber();
+ number_t y = data->at(k++, zero)->toNumber();
+ tokens.emplace_back(GeomToken(STRAIGHT, Vector2(x, y)));
+ break;
+ }
+
+ case GraphicsPathCommand::CUBIC_CURVE_TO:
+ {
+ number_t c1x = data->at(k++, zero)->toNumber();
+ number_t c1y = data->at(k++, zero)->toNumber();
+ number_t c2x = data->at(k++, zero)->toNumber();
+ number_t c2y = data->at(k++, zero)->toNumber();
+ number_t x = data->at(k++, zero)->toNumber();
+ number_t y = data->at(k++, zero)->toNumber();
+ tokens.emplace_back(GeomToken(CURVE_CUBIC,
+ Vector2(c1x, c1y),
+ Vector2(c2x, c2y),
+ Vector2(x, y)));
+ break;
+ }
+
+ case GraphicsPathCommand::NO_OP:
+ default:
+ break;
+ }
+ }
+}
+
+/* Solve for c in the matrix equation
+ *
+ * [ 1 x1 y1 ] [ c[0] ] [ u1 ]
+ * [ 1 x2 y2 ] [ c[1] ] = [ u2 ]
+ * [ 1 x3 y3 ] [ c[2] ] [ u3 ]
+ *
+ * The result will be put in the output parameter c.
+ */
+void Graphics::solveVertexMapping(double x1, double y1,
+ double x2, double y2,
+ double x3, double y3,
+ double u1, double u2, double u3,
+ double c[3])
+{
+ double eps = 1e-15;
+ double det = fabs(x2*y3 + x1*y2 + y1*x3 - y2*x3 - x1*y3 - y1*x2);
+
+ if (det < eps)
+ {
+ // Degenerate matrix
+ c[0] = c[1] = c[2] = 0;
+ return;
+ }
+
+ // Symbolic solution of the equation by Gaussian elimination
+ if (fabs(x1-x2) < eps)
+ {
+ c[2] = (u2-u1)/(y2-y1);
+ c[1] = (u3 - u1 - (y3-y1)*c[2])/(x3-x1);
+ c[0] = u1 - x1*c[1] - y1*c[2];
+ }
+ else
+ {
+ c[2] = ((x2-x1)*(u3-u1) - (x3-x1)*(u2-u1))/((y3-y1)*(x2-x1) - (x3-x1)*(y2-y1));
+ c[1] = (u2 - u1 - (y2-y1)*c[2])/(x2-x1);
+ c[0] = u1 - x1*c[1] - y1*c[2];
+ }
+}
+
+ASFUNCTIONBODY(Graphics,drawTriangles)
+{
+ Graphics* th=static_cast<Graphics*>(obj);
+ th->checkAndSetScaling();
+
+ _NR<Vector> vertices;
+ _NR<Vector> indices;
+ _NR<Vector> uvtData;
+ tiny_string culling;
+ ARG_UNPACK (vertices) (indices, NullRef) (uvtData, NullRef) (culling, "none");
+
+ drawTrianglesToTokens(vertices, indices, uvtData, culling, th->owner->tokens);
+ th->owner->owner->requestInvalidation(getSys());
+
+ return NULL;
+}
+
+void Graphics::drawTrianglesToTokens(_NR<Vector> vertices, _NR<Vector> indices, _NR<Vector> uvtData, tiny_string culling, std::vector<GeomToken>& tokens)
+{
+ if (culling != "none")
+ LOG(LOG_NOT_IMPLEMENTED, "Graphics.drawTriangles doesn't support culling");
+
+ // Validate the parameters
+ if (vertices.isNull())
+ return;
+
+ if ((indices.isNull() && (vertices->size() % 6 != 0)) ||
+ (!indices.isNull() && (indices->size() % 3 != 0)))
+ {
+ throwError<ArgumentError>(kInvalidParamError);
+ }
+
+ unsigned int numvertices=vertices->size()/2;
+ unsigned int numtriangles;
+ bool has_uvt=false;
+ int uvtElemSize=2;
+ int texturewidth=0;
+ int textureheight=0;
+
+ if (indices.isNull())
+ numtriangles=numvertices/3;
+ else
+ numtriangles=indices->size()/3;
+
+ if (!uvtData.isNull())
+ {
+ if (uvtData->size()==2*numvertices)
+ {
+ has_uvt=true;
+ uvtElemSize=2; /* (u, v) */
+ }
+ else if (uvtData->size()==3*numvertices)
+ {
+ has_uvt=true;
+ uvtElemSize=3; /* (u, v, t), t is ignored */
+ LOG(LOG_NOT_IMPLEMENTED, "Graphics.drawTriangles doesn't support t in uvtData parameter");
+ }
+ else
+ {
+ throwError<ArgumentError>(kInvalidParamError);
+ }
+
+ TokenContainer::getTextureSize(tokens, &texturewidth, &textureheight);
+ }
+
+ // According to testing, drawTriangles first fills the current
+ // path and creates a new path, but keeps the source.
+ tokens.emplace_back(FILL_KEEP_SOURCE);
+
+ if (has_uvt && (texturewidth==0 || textureheight==0))
+ return;
+
+ // Construct the triangles
+ for (unsigned int i=0; i<numtriangles; i++)
+ {
+ double x[3], y[3], u[3]={0}, v[3]={0};
+ for (unsigned int j=0; j<3; j++)
+ {
+ unsigned int vertex;
+ if (indices.isNull())
+ vertex=3*i+j;
+ else
+ vertex=indices->at(3*i+j)->toInt();
+
+ x[j]=vertices->at(2*vertex)->toNumber();
+ y[j]=vertices->at(2*vertex+1)->toNumber();
+
+ if (has_uvt)
+ {
+ u[j]=uvtData->at(vertex*uvtElemSize)->toNumber()*texturewidth;
+ v[j]=uvtData->at(vertex*uvtElemSize+1)->toNumber()*textureheight;
+ }
+ }
+
+ Vector2 a(x[0], y[0]);
+ Vector2 b(x[1], y[1]);
+ Vector2 c(x[2], y[2]);
+
+ tokens.emplace_back(GeomToken(MOVE, a));
+ tokens.emplace_back(GeomToken(STRAIGHT, b));
+ tokens.emplace_back(GeomToken(STRAIGHT, c));
+ tokens.emplace_back(GeomToken(STRAIGHT, a));
+
+ if (has_uvt)
+ {
+ double t[6];
+
+ // Use the known (x, y) and (u, v)
+ // correspondences to compute a transformation
+ // t from (x, y) space into (u, v) space
+ // (cairo needs the mapping in this
+ // direction).
+ //
+ // u = t[0] + t[1]*x + t[2]*y
+ // v = t[3] + t[4]*x + t[5]*y
+ //
+ // u and v parts can be solved separately.
+ solveVertexMapping(x[0], y[0], x[1], y[1], x[2], y[2],
+ u[0], u[1], u[2], t);
+ solveVertexMapping(x[0], y[0], x[1], y[1], x[2], y[2],
+ v[0], v[1], v[2], &t[3]);
+
+ MATRIX m(t[1], t[5], t[4], t[2], t[0], t[3]);
+ tokens.emplace_back(GeomToken(FILL_TRANSFORM_TEXTURE, m));
+ }
+ }
+}
+
+ASFUNCTIONBODY(Graphics,drawGraphicsData)
+{
+ Graphics* th=static_cast<Graphics*>(obj);
+ th->checkAndSetScaling();
+
+ _NR<Vector> graphicsData;
+ ARG_UNPACK(graphicsData);
+
+ for (unsigned int i=0; i<graphicsData->size(); i++)
+ {
+ IGraphicsData *graphElement = dynamic_cast<IGraphicsData *>(graphicsData->at(i));
+ if (!graphElement)
+ {
+ LOG(LOG_ERROR, "Invalid type in Graphics::drawGraphicsData()");
+ continue;
+ }
+
+ graphElement->appendToTokens(th->owner->tokens);
+ }
+
+ th->owner->owner->requestInvalidation(getSys());
+
+ return NULL;
+}
+
+ASFUNCTIONBODY(Graphics,lineStyle)
+{
+ Graphics* th=static_cast<Graphics*>(obj);
+ th->checkAndSetScaling();
+
+ if (argslen == 0)
+ {
+ th->owner->tokens.emplace_back(CLEAR_STROKE);
+ return NULL;
+ }
+ uint32_t color = 0;
+ uint8_t alpha = 255;
+ UI16_SWF thickness = UI16_SWF(imax(args[0]->toNumber() * 20, 0));
+ if (argslen >= 2)
+ color = args[1]->toUInt();
+ if (argslen >= 3)
+ alpha = uint8_t(args[1]->toNumber() * 255);
+
+ // TODO: pixel hinting, scaling, caps, miter, joints
+
+ LINESTYLE2 style(0xff);
+ style.Color = RGBA(color, alpha);
+ style.Width = thickness;
+ th->owner->tokens.emplace_back(GeomToken(SET_STROKE, style));
+ return NULL;
+}
+
+ASFUNCTIONBODY(Graphics,lineBitmapStyle)
+{
+ Graphics* th=static_cast<Graphics*>(obj);
+ th->checkAndSetScaling();
+
+ _NR<BitmapData> bitmap;
+ _NR<Matrix> matrix;
+ bool repeat, smooth;
+ ARG_UNPACK (bitmap) (matrix, NullRef) (repeat, true) (smooth, false);
+
+ if (bitmap.isNull())
+ return NULL;
+
+ LINESTYLE2 style(0xff);
+ style.Width = th->owner->getCurrentLineWidth();
+ style.HasFillFlag = true;
+ style.FillType = createBitmapFill(bitmap, matrix, repeat, smooth);
+
+ th->owner->tokens.emplace_back(GeomToken(SET_STROKE, style));
+
+ return NULL;
+}
+
+ASFUNCTIONBODY(Graphics,lineGradientStyle)
+{
+ Graphics* th=static_cast<Graphics*>(obj);
+ th->checkAndSetScaling();
+
+ tiny_string type;
+ _NR<Array> colors;
+ _NR<Array> alphas;
+ _NR<Array> ratios;
+ _NR<Matrix> matrix;
+ tiny_string spreadMethod;
+ tiny_string interpolationMethod;
+ number_t focalPointRatio;
+ ARG_UNPACK (type) (colors) (alphas) (ratios) (matrix, NullRef)
+ (spreadMethod, "pad") (interpolationMethod, "rgb") (focalPointRatio, 0);
+
+ LINESTYLE2 style(0xff);
+ style.Width = th->owner->getCurrentLineWidth();
+ style.HasFillFlag = true;
+ style.FillType = createGradientFill(type, colors, alphas, ratios, matrix,
+ spreadMethod, interpolationMethod,
+ focalPointRatio);
+
+ th->owner->tokens.emplace_back(GeomToken(SET_STROKE, style));
+
+ return NULL;
+}
+
+ASFUNCTIONBODY(Graphics,beginGradientFill)
+{
+ Graphics* th=static_cast<Graphics*>(obj);
+ th->checkAndSetScaling();
+
+ tiny_string type;
+ _NR<Array> colors;
+ _NR<Array> alphas;
+ _NR<ASObject> ratiosParam;
+ _NR<Matrix> matrix;
+ tiny_string spreadMethod;
+ tiny_string interpolationMethod;
+ number_t focalPointRatio;
+ ARG_UNPACK (type) (colors) (alphas) (ratiosParam) (matrix, NullRef)
+ (spreadMethod, "pad") (interpolationMethod, "rgb") (focalPointRatio, 0);
+
+ //Work around for bug in YouTube player of July 13 2011
+ if (!ratiosParam->is<Array>())
+ return NULL;
+ if (ratiosParam.isNull())
+ return NULL;
+
+ ratiosParam->incRef();
+ _NR<Array> ratios = _MNR(ratiosParam->as<Array>());
+
+ FILLSTYLE style = createGradientFill(type, colors, alphas, ratios, matrix,
+ spreadMethod, interpolationMethod,
+ focalPointRatio);
+ th->owner->tokens.emplace_back(GeomToken(SET_FILL, style));
+
+ return NULL;
+}
+
+FILLSTYLE Graphics::createGradientFill(const tiny_string& type,
+ _NR<Array> colors,
+ _NR<Array> alphas,
+ _NR<Array> ratios,
+ _NR<Matrix> matrix,
+ const tiny_string& spreadMethod,
+ const tiny_string& interpolationMethod,
+ number_t focalPointRatio)
+{
+ FILLSTYLE style(0xff);
+
+ if (colors.isNull() || alphas.isNull() || ratios.isNull())
+ return style;
+
+ int NumGradient = colors->size();
+ if (NumGradient != (int)alphas->size() || NumGradient != (int)ratios->size())
+ return style;
+
+ if (NumGradient < 1 || NumGradient > 15)
+ return style;
+
+ if(type == "linear")
+ style.FillStyleType=LINEAR_GRADIENT;
+ else if(type == "radial")
+ style.FillStyleType=RADIAL_GRADIENT;
+ else
+ return style;
+
+ // Don't support FOCALGRADIENT for now.
+ GRADIENT grad(0xff);
+ for(int i = 0; i < NumGradient; i ++)
+ {
+ GRADRECORD record(0xff);
+ record.Color = RGBA(colors->at(i)->toUInt(), (int)alphas->at(i)->toNumber()*255);
+ record.Ratio = UI8(ratios->at(i)->toUInt());
+ grad.GradientRecords.push_back(record);
+ }
+
+ if(matrix.isNull())
+ {
+ cairo_matrix_scale(&style.Matrix, 100.0/16384.0, 100.0/16384.0);
+ }
+ else
+ {
+ style.Matrix = matrix->getMATRIX();
+ //Conversion from twips to pixels
+ cairo_matrix_scale(&style.Matrix, 1.0f/20.0f, 1.0f/20.0f);
+ }
+
+ if (spreadMethod == "pad")
+ grad.SpreadMode = 0;
+ else if (spreadMethod == "reflect")
+ grad.SpreadMode = 1;
+ else if (spreadMethod == "repeat")
+ grad.SpreadMode = 2;
+ else
+ grad.SpreadMode = 0; // should not be reached
+
+ if (interpolationMethod == "rgb")
+ grad.InterpolationMode = 0;
+ else if (interpolationMethod == "linearRGB")
+ grad.InterpolationMode = 1;
+ else
+ grad.InterpolationMode = 0; // should not be reached
+
+ style.Gradient = grad;
+ return style;
+}
+
+FILLSTYLE Graphics::createBitmapFill(_R<BitmapData> bitmap, _NR<Matrix> matrix, bool repeat, bool smooth)
+{
+ FILLSTYLE style(0xff);
+ if(repeat && smooth)
+ style.FillStyleType = REPEATING_BITMAP;
+ else if(repeat && !smooth)
+ style.FillStyleType = NON_SMOOTHED_REPEATING_BITMAP;
+ else if(!repeat && smooth)
+ style.FillStyleType = CLIPPED_BITMAP;
+ else
+ style.FillStyleType = NON_SMOOTHED_CLIPPED_BITMAP;
+
+ if(!matrix.isNull())
+ style.Matrix = matrix->getMATRIX();
+
+ style.bitmap = bitmap->getBitmapContainer();
+
+ return style;
+}
+
+FILLSTYLE Graphics::createSolidFill(uint32_t color, uint8_t alpha)
+{
+ FILLSTYLE style(0xff);
+ style.FillStyleType = SOLID_FILL;
+ style.Color = RGBA(color, alpha);
+ return style;
+}
+
+ASFUNCTIONBODY(Graphics,beginBitmapFill)
+{
+ Graphics* th = obj->as<Graphics>();
+ _NR<BitmapData> bitmap;
+ _NR<Matrix> matrix;
+ bool repeat, smooth;
+ ARG_UNPACK (bitmap) (matrix, NullRef) (repeat, true) (smooth, false);
+
+ if(bitmap.isNull())
+ return NULL;
+
+ th->checkAndSetScaling();
+
+ FILLSTYLE style = createBitmapFill(bitmap, matrix, repeat, smooth);
+ th->owner->tokens.emplace_back(GeomToken(SET_FILL, style));
+ return NULL;
+}
+
+ASFUNCTIONBODY(Graphics,beginFill)
+{
+ Graphics* th=static_cast<Graphics*>(obj);
+ th->checkAndSetScaling();
+ uint32_t color=0;
+ uint8_t alpha=255;
+ if(argslen>=1)
+ color=args[0]->toUInt();
+ if(argslen>=2)
+ alpha=(uint8_t(args[1]->toNumber()*0xff));
+ FILLSTYLE style = Graphics::createSolidFill(color, alpha);
+ th->owner->tokens.emplace_back(GeomToken(SET_FILL, style));
+ return NULL;
+}
+
+ASFUNCTIONBODY(Graphics,endFill)
+{
+ Graphics* th=static_cast<Graphics*>(obj);
+ th->checkAndSetScaling();
+ th->owner->tokens.emplace_back(CLEAR_FILL);
+ return NULL;
+}
+
+ASFUNCTIONBODY(Graphics,copyFrom)
+{
+ Graphics* th=static_cast<Graphics*>(obj);
+ _NR<Graphics> source;
+ ARG_UNPACK(source);
+ if (source.isNull())
+ return NULL;
+
+ th->owner->tokens.assign(source->owner->tokens.begin(),
+ source->owner->tokens.end());
+ return NULL;
+}
diff --git a/src/scripting/flash/display/Graphics.h b/src/scripting/flash/display/Graphics.h
new file mode 100644
index 0000000..50b430a
--- /dev/null
+++ b/src/scripting/flash/display/Graphics.h
@@ -0,0 +1,103 @@
+/**************************************************************************
+ Lightspark, a free flash player implementation
+
+ Copyright (C) 2009-2013 Alessandro Pignotti (a.pignotti at sssup.it)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+**************************************************************************/
+
+#ifndef SCRIPTING_FLASH_DISPLAY_GRAPHICS_H
+#define SCRIPTING_FLASH_DISPLAY_GRAPHICS_H 1
+
+#include <vector>
+#include "asobject.h"
+#include "backends/geometry.h"
+
+namespace lightspark
+{
+
+class TokenContainer;
+class Array;
+class Matrix;
+class BitmapData;
+class Vector;
+
+/* This objects paints to its owners tokens */
+class Graphics: public ASObject
+{
+private:
+ TokenContainer *const owner;
+ void checkAndSetScaling();
+ static void solveVertexMapping(double x1, double y1,
+ double x2, double y2,
+ double x3, double y3,
+ double u1, double u2, double u3,
+ double c[3]);
+public:
+ Graphics(Class_base* c):ASObject(c),owner(NULL)
+ {
+// throw RunTimeException("Cannot instantiate a Graphics object");
+ }
+ Graphics(Class_base* c, TokenContainer* _o)
+ : ASObject(c),owner(_o) {}
+ static void sinit(Class_base* c);
+ static void buildTraits(ASObject* o);
+ static FILLSTYLE createGradientFill(const tiny_string& type,
+ _NR<Array> colors,
+ _NR<Array> alphas,
+ _NR<Array> ratios,
+ _NR<Matrix> matrix,
+ const tiny_string& spreadMethod,
+ const tiny_string& interpolationMethod,
+ number_t focalPointRatio);
+ static FILLSTYLE createBitmapFill(_R<BitmapData> bitmap,
+ _NR<Matrix> matrix,
+ bool repeat,
+ bool smooth);
+ static FILLSTYLE createSolidFill(uint32_t color, uint8_t alpha);
+ static void pathToTokens(_NR<Vector> commands,
+ _NR<Vector> data,
+ tiny_string windings,
+ std::vector<GeomToken>& tokens);
+ static void drawTrianglesToTokens(_NR<Vector> vertices,
+ _NR<Vector> indices,
+ _NR<Vector> uvtData,
+ tiny_string culling,
+ std::vector<GeomToken>& tokens);
+ ASFUNCTION(_constructor);
+ ASFUNCTION(lineBitmapStyle);
+ ASFUNCTION(lineGradientStyle);
+ ASFUNCTION(lineStyle);
+ ASFUNCTION(beginFill);
+ ASFUNCTION(beginGradientFill);
+ ASFUNCTION(beginBitmapFill);
+ ASFUNCTION(endFill);
+ ASFUNCTION(drawRect);
+ ASFUNCTION(drawRoundRect);
+ ASFUNCTION(drawCircle);
+ ASFUNCTION(drawEllipse);
+ ASFUNCTION(drawGraphicsData);
+ ASFUNCTION(drawPath);
+ ASFUNCTION(drawTriangles);
+ ASFUNCTION(moveTo);
+ ASFUNCTION(lineTo);
+ ASFUNCTION(curveTo);
+ ASFUNCTION(cubicCurveTo);
+ ASFUNCTION(clear);
+ ASFUNCTION(copyFrom);
+};
+
+};
+
+#endif /* SCRIPTING_FLASH_DISPLAY_GRAPHICS_H */
diff --git a/src/scripting/flash/display/GraphicsBitmapFill.cpp b/src/scripting/flash/display/GraphicsBitmapFill.cpp
new file mode 100644
index 0000000..1f59afa
--- /dev/null
+++ b/src/scripting/flash/display/GraphicsBitmapFill.cpp
@@ -0,0 +1,70 @@
+/**************************************************************************
+ Lightspark, a free flash player implementation
+
+ Copyright (C) 2013 Antti Ajanki (antti.ajanki at iki.fi)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+**************************************************************************/
+
+#include "scripting/flash/display/GraphicsBitmapFill.h"
+#include "scripting/flash/display/BitmapData.h"
+#include "scripting/flash/display/Graphics.h"
+#include "scripting/flash/geom/flashgeom.h"
+#include "scripting/class.h"
+#include "scripting/argconv.h"
+
+using namespace lightspark;
+
+GraphicsBitmapFill::GraphicsBitmapFill(Class_base* c):
+ ASObject(c), repeat(true), smooth(false)
+{
+}
+
+void GraphicsBitmapFill::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED | CLASS_FINAL);
+ REGISTER_GETTER_SETTER(c, bitmapData);
+ REGISTER_GETTER_SETTER(c, matrix);
+ REGISTER_GETTER_SETTER(c, repeat);
+ REGISTER_GETTER_SETTER(c, smooth);
+
+ c->addImplementedInterface(InterfaceClass<IGraphicsFill>::getClass());
+ IGraphicsFill::linkTraits(c);
+ c->addImplementedInterface(InterfaceClass<IGraphicsData>::getClass());
+ IGraphicsData::linkTraits(c);
+}
+
+ASFUNCTIONBODY(GraphicsBitmapFill, _constructor)
+{
+ GraphicsBitmapFill* th = obj->as<GraphicsBitmapFill>();
+ ASObject::_constructor(obj,NULL,0);
+ ARG_UNPACK (th->bitmapData, NullRef) (th->matrix, NullRef) (th->repeat, true) (th->smooth, false);
+ return NULL;
+}
+
+ASFUNCTIONBODY_GETTER_SETTER(GraphicsBitmapFill, bitmapData);
+ASFUNCTIONBODY_GETTER_SETTER(GraphicsBitmapFill, matrix);
+ASFUNCTIONBODY_GETTER_SETTER(GraphicsBitmapFill, repeat);
+ASFUNCTIONBODY_GETTER_SETTER(GraphicsBitmapFill, smooth);
+
+FILLSTYLE GraphicsBitmapFill::toFillStyle()
+{
+ return Graphics::createBitmapFill(bitmapData, matrix, repeat, smooth);
+}
+
+void GraphicsBitmapFill::appendToTokens(std::vector<GeomToken>& tokens)
+{
+
+ tokens.emplace_back(GeomToken(SET_FILL, toFillStyle()));
+}
diff --git a/src/scripting/toplevel/UInteger.h b/src/scripting/flash/display/GraphicsBitmapFill.h
similarity index 56%
copy from src/scripting/toplevel/UInteger.h
copy to src/scripting/flash/display/GraphicsBitmapFill.h
index fe0fbcc..effa7f2 100644
--- a/src/scripting/toplevel/UInteger.h
+++ b/src/scripting/flash/display/GraphicsBitmapFill.h
@@ -1,7 +1,7 @@
/**************************************************************************
Lightspark, a free flash player implementation
- Copyright (C) 2009-2013 Alessandro Pignotti (a.pignotti at sssup.it)
+ Copyright (C) 2013 Antti Ajanki (antti.ajanki at iki.fi)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
@@ -17,41 +17,33 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
-#ifndef SCRIPTING_TOPLEVEL_UINTEGER_H
-#define SCRIPTING_TOPLEVEL_UINTEGER_H 1
-#include "compat.h"
+#ifndef SCRIPTING_FLASH_DISPLAY_GRAPHICSBITMAPFILL_H
+#define SCRIPTING_FLASH_DISPLAY_GRAPHICSBITMAPFILL_H 1
+
#include "asobject.h"
+#include "scripting/flash/display/IGraphicsFill.h"
+#include "scripting/flash/display/IGraphicsData.h"
namespace lightspark
{
-class UInteger: public ASObject
+class BitmapData;
+class Matrix;
+
+class GraphicsBitmapFill: public ASObject, public IGraphicsFill, public IGraphicsData
{
-friend ASObject* abstract_ui(uint32_t i);
public:
- uint32_t val;
- UInteger(Class_base* c,uint32_t v=0):ASObject(c),val(v){type=T_UINTEGER;}
-
+ GraphicsBitmapFill(Class_base* c);
static void sinit(Class_base* c);
- tiny_string toString();
- static tiny_string toString(uint32_t val);
- int32_t toInt()
- {
- return val;
- }
- uint32_t toUInt()
- {
- return val;
- }
- TRISTATE isLess(ASObject* r);
- bool isEqual(ASObject* o);
ASFUNCTION(_constructor);
- ASFUNCTION(generator);
- ASFUNCTION(_toString);
- ASFUNCTION(_valueOf);
- std::string toDebugString() { return toString()+"ui"; }
- //CHECK: should this have a special serialization?
+ ASPROPERTY_GETTER_SETTER(_NR<BitmapData>, bitmapData);
+ ASPROPERTY_GETTER_SETTER(_NR<Matrix>, matrix);
+ ASPROPERTY_GETTER_SETTER(bool, repeat);
+ ASPROPERTY_GETTER_SETTER(bool, smooth);
+ FILLSTYLE toFillStyle();
+ void appendToTokens(std::vector<GeomToken>& tokens);
+};
+
};
-}
-#endif /* SCRIPTING_TOPLEVEL_UINTEGER_H */
+#endif /* SCRIPTING_FLASH_DISPLAY_GRAPHICSBITMAPFILL_H */
diff --git a/src/scripting/flash/sensors/flashsensors.cpp b/src/scripting/flash/display/GraphicsEndFill.cpp
similarity index 58%
copy from src/scripting/flash/sensors/flashsensors.cpp
copy to src/scripting/flash/display/GraphicsEndFill.cpp
index bee463b..4c24347 100644
--- a/src/scripting/flash/sensors/flashsensors.cpp
+++ b/src/scripting/flash/display/GraphicsEndFill.cpp
@@ -1,7 +1,7 @@
/**************************************************************************
Lightspark, a free flash player implementation
- Copyright (C) 2011-2013 Alessandro Pignotti (a.pignotti at sssup.it)
+ Copyright (C) 2013 Antti Ajanki (antti.ajanki at iki.fi)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
@@ -17,31 +17,31 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
-#include <map>
-#include "backends/security.h"
-#include "scripting/abc.h"
-#include "scripting/flash/sensors/flashsensors.h"
+#include "scripting/flash/display/GraphicsEndFill.h"
#include "scripting/class.h"
-#include "scripting/flash/system/flashsystem.h"
-#include "compat.h"
-#include "backends/audio.h"
-using namespace std;
using namespace lightspark;
-Accelerometer::Accelerometer(Class_base* c):ASObject(c) {}
+GraphicsEndFill::GraphicsEndFill(Class_base* c):
+ ASObject(c)
+{
+}
-void Accelerometer::sinit(Class_base* c)
+void GraphicsEndFill::sinit(Class_base* c)
{
- // properties
- c->setDeclaredMethodByQName("isSupported", "", Class<IFunction>::getFunction(_isSupported),GETTER_METHOD,false);
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED | CLASS_FINAL);
+ c->addImplementedInterface(InterfaceClass<IGraphicsFill>::getClass());
+ IGraphicsFill::linkTraits(c);
+ c->addImplementedInterface(InterfaceClass<IGraphicsData>::getClass());
+ IGraphicsData::linkTraits(c);
}
-void Accelerometer::buildTraits(ASObject *o)
+FILLSTYLE GraphicsEndFill::toFillStyle()
{
+ return FILLSTYLE(0xff);
}
-ASFUNCTIONBODY(Accelerometer,_isSupported)
+void GraphicsEndFill::appendToTokens(std::vector<GeomToken>& tokens)
{
- return abstract_b(false);
+ tokens.emplace_back(CLEAR_FILL);
}
diff --git a/src/backends/rtmputils.h b/src/scripting/flash/display/GraphicsEndFill.h
similarity index 61%
copy from src/backends/rtmputils.h
copy to src/scripting/flash/display/GraphicsEndFill.h
index 7e9de51..b65bf54 100644
--- a/src/backends/rtmputils.h
+++ b/src/scripting/flash/display/GraphicsEndFill.h
@@ -1,7 +1,7 @@
/**************************************************************************
Lightspark, a free flash player implementation
- Copyright (C) 2011-2013 Alessandro Pignotti (a.pignotti at sssup.it)
+ Copyright (C) 2013 Antti Ajanki (antti.ajanki at iki.fi)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
@@ -17,25 +17,25 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
-#ifndef BACKENDS_RTMPUTILS_H
-#define BACKENDS_RTMPUTILS_H 1
+#ifndef SCRIPTING_FLASH_DISPLAY_GRAPHICSENDFILL_H
+#define SCRIPTING_FLASH_DISPLAY_GRAPHICSENDFILL_H 1
-#include "backends/netutils.h"
+#include "asobject.h"
+#include "scripting/flash/display/IGraphicsFill.h"
+#include "scripting/flash/display/IGraphicsData.h"
namespace lightspark
{
-class ILoadable;
-
-class RTMPDownloader: public ThreadedDownloader
+class GraphicsEndFill: public ASObject, public IGraphicsFill, public IGraphicsData
{
-private:
- void execute();
- void threadAbort();
- tiny_string stream;
public:
- RTMPDownloader(const tiny_string& _url, const tiny_string& _stream, ILoadable* o);
+ GraphicsEndFill(Class_base* c);
+ static void sinit(Class_base* c);
+ FILLSTYLE toFillStyle();
+ void appendToTokens(std::vector<GeomToken>& tokens);
};
};
-#endif /* BACKENDS_RTMPUTILS_H */
+
+#endif /* SCRIPTING_FLASH_DISPLAY_GRAPHICSENDFILL_H */
diff --git a/src/scripting/flash/display/GraphicsGradientFill.cpp b/src/scripting/flash/display/GraphicsGradientFill.cpp
new file mode 100644
index 0000000..3133413
--- /dev/null
+++ b/src/scripting/flash/display/GraphicsGradientFill.cpp
@@ -0,0 +1,96 @@
+/**************************************************************************
+ Lightspark, a free flash player implementation
+
+ Copyright (C) 2013 Antti Ajanki (antti.ajanki at iki.fi)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+**************************************************************************/
+
+#include "scripting/flash/display/GraphicsGradientFill.h"
+#include "scripting/flash/display/Graphics.h"
+#include "scripting/flash/geom/flashgeom.h"
+#include "scripting/toplevel/toplevel.h"
+#include "scripting/toplevel/Array.h"
+#include "scripting/class.h"
+#include "scripting/argconv.h"
+
+using namespace lightspark;
+
+GraphicsGradientFill::GraphicsGradientFill(Class_base* c):
+ ASObject(c), focalPointRatio(0), interpolationMethod("rgb"),
+ spreadMethod("pad"), type("linear")
+{
+}
+
+void GraphicsGradientFill::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED | CLASS_FINAL);
+ REGISTER_GETTER_SETTER(c, alphas);
+ REGISTER_GETTER_SETTER(c, colors);
+ REGISTER_GETTER_SETTER(c, focalPointRatio);
+ REGISTER_GETTER_SETTER(c, interpolationMethod);
+ REGISTER_GETTER_SETTER(c, matrix);
+ REGISTER_GETTER_SETTER(c, ratios);
+ REGISTER_GETTER_SETTER(c, spreadMethod);
+ REGISTER_GETTER_SETTER(c, type);
+
+ c->addImplementedInterface(InterfaceClass<IGraphicsFill>::getClass());
+ IGraphicsFill::linkTraits(c);
+ c->addImplementedInterface(InterfaceClass<IGraphicsData>::getClass());
+ IGraphicsData::linkTraits(c);
+}
+
+void GraphicsGradientFill::finalize()
+{
+ ASObject::finalize();
+ alphas.reset();
+ colors.reset();
+ matrix.reset();
+ ratios.reset();
+}
+
+ASFUNCTIONBODY(GraphicsGradientFill, _constructor)
+{
+ GraphicsGradientFill* th = obj->as<GraphicsGradientFill>();
+ ASObject::_constructor(obj,NULL,0);
+ ARG_UNPACK (th->type, "linear")
+ (th->colors, NullRef)
+ (th->alphas, NullRef)
+ (th->ratios, NullRef)
+ (th->matrix, NullRef)
+ (th->spreadMethod, "pad")
+ (th->interpolationMethod, "rgb")
+ (th->focalPointRatio, 0);
+ return NULL;
+}
+
+ASFUNCTIONBODY_GETTER_SETTER(GraphicsGradientFill, alphas);
+ASFUNCTIONBODY_GETTER_SETTER(GraphicsGradientFill, colors);
+ASFUNCTIONBODY_GETTER_SETTER(GraphicsGradientFill, focalPointRatio);
+ASFUNCTIONBODY_GETTER_SETTER(GraphicsGradientFill, interpolationMethod);
+ASFUNCTIONBODY_GETTER_SETTER(GraphicsGradientFill, matrix);
+ASFUNCTIONBODY_GETTER_SETTER(GraphicsGradientFill, ratios);
+ASFUNCTIONBODY_GETTER_SETTER(GraphicsGradientFill, spreadMethod);
+ASFUNCTIONBODY_GETTER_SETTER(GraphicsGradientFill, type);
+
+FILLSTYLE GraphicsGradientFill::toFillStyle()
+{
+ return Graphics::createGradientFill(type, colors, alphas, ratios,
+ matrix, spreadMethod, interpolationMethod, focalPointRatio);
+}
+
+void GraphicsGradientFill::appendToTokens(std::vector<GeomToken>& tokens)
+{
+ tokens.emplace_back(GeomToken(SET_FILL, toFillStyle()));
+}
diff --git a/src/scripting/flash/display/GraphicsGradientFill.h b/src/scripting/flash/display/GraphicsGradientFill.h
new file mode 100644
index 0000000..3cf422c
--- /dev/null
+++ b/src/scripting/flash/display/GraphicsGradientFill.h
@@ -0,0 +1,55 @@
+/**************************************************************************
+ Lightspark, a free flash player implementation
+
+ Copyright (C) 2013 Antti Ajanki (antti.ajanki at iki.fi)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+**************************************************************************/
+
+#ifndef SCRIPTING_FLASH_DISPLAY_GRAPHICSGRADIENTFILL_H
+#define SCRIPTING_FLASH_DISPLAY_GRAPHICSGRADIENTFILL_H 1
+
+#include "asobject.h"
+#include "tiny_string.h"
+#include "scripting/flash/display/IGraphicsFill.h"
+#include "scripting/flash/display/IGraphicsData.h"
+
+namespace lightspark
+{
+
+class Array;
+class Matrix;
+
+class GraphicsGradientFill: public ASObject, public IGraphicsFill, public IGraphicsData
+{
+public:
+ GraphicsGradientFill(Class_base* c);
+ static void sinit(Class_base* c);
+ void finalize();
+ ASFUNCTION(_constructor);
+ ASPROPERTY_GETTER_SETTER(_NR<Array>, alphas);
+ ASPROPERTY_GETTER_SETTER(_NR<Array>, colors);
+ ASPROPERTY_GETTER_SETTER(number_t, focalPointRatio);
+ ASPROPERTY_GETTER_SETTER(tiny_string, interpolationMethod);
+ ASPROPERTY_GETTER_SETTER(_NR<Matrix>, matrix);
+ ASPROPERTY_GETTER_SETTER(_NR<Array>, ratios);
+ ASPROPERTY_GETTER_SETTER(tiny_string, spreadMethod);
+ ASPROPERTY_GETTER_SETTER(tiny_string, type);
+ FILLSTYLE toFillStyle();
+ void appendToTokens(std::vector<GeomToken>& tokens);
+};
+
+};
+
+#endif /* SCRIPTING_FLASH_DISPLAY_GRAPHICSGRADIENTFILL_H */
diff --git a/src/scripting/flash/display/GraphicsPath.cpp b/src/scripting/flash/display/GraphicsPath.cpp
new file mode 100644
index 0000000..a58482b
--- /dev/null
+++ b/src/scripting/flash/display/GraphicsPath.cpp
@@ -0,0 +1,173 @@
+/**************************************************************************
+ Lightspark, a free flash player implementation
+
+ Copyright (C) 2013 Antti Ajanki (antti.ajanki at iki.fi)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+**************************************************************************/
+
+#include "scripting/toplevel/Vector.h"
+#include "scripting/flash/display/GraphicsPath.h"
+#include "scripting/flash/display/Graphics.h"
+#include "scripting/argconv.h"
+#include "scripting/class.h"
+
+using namespace lightspark;
+
+GraphicsPath::GraphicsPath(Class_base* c):
+ ASObject(c), winding("evenOdd")
+{
+}
+
+void GraphicsPath::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED | CLASS_FINAL);
+ REGISTER_GETTER_SETTER(c, commands);
+ REGISTER_GETTER_SETTER(c, data);
+ REGISTER_GETTER_SETTER(c, winding);
+ c->setDeclaredMethodByQName("curveTo","",Class<IFunction>::getFunction(curveTo),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("lineTo","",Class<IFunction>::getFunction(lineTo),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("moveTo","",Class<IFunction>::getFunction(moveTo),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("wideLineTo","",Class<IFunction>::getFunction(wideLineTo),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("wideMoveTo","",Class<IFunction>::getFunction(wideMoveTo),NORMAL_METHOD,true);
+
+ c->addImplementedInterface(InterfaceClass<IGraphicsPath>::getClass());
+ IGraphicsPath::linkTraits(c);
+ c->addImplementedInterface(InterfaceClass<IGraphicsData>::getClass());
+ IGraphicsData::linkTraits(c);
+}
+
+ASFUNCTIONBODY_GETTER_SETTER(GraphicsPath, commands);
+ASFUNCTIONBODY_GETTER_SETTER(GraphicsPath, data);
+ASFUNCTIONBODY_GETTER_SETTER(GraphicsPath, winding);
+
+ASFUNCTIONBODY(GraphicsPath, _constructor)
+{
+ _NR<Vector> commands;
+ _NR<Vector> data;
+ GraphicsPath* th = obj->as<GraphicsPath>();
+ ARG_UNPACK(commands, NullRef)(data, NullRef)(th->winding, "evenOdd");
+
+ ASObject::_constructor(obj,NULL,0);
+
+ if (!commands.isNull())
+ th->commands = commands;
+ if (!data.isNull())
+ th->data = data;
+
+ return NULL;
+}
+
+void GraphicsPath::finalize()
+{
+ ASObject::finalize();
+ commands.reset();
+ data.reset();
+}
+
+void GraphicsPath::ensureValid()
+{
+ if (commands.isNull())
+ commands = _MNR(Template<Vector>::getInstanceS(Class<Integer>::getClass()));
+ if (data.isNull())
+ data = _MNR(Template<Vector>::getInstanceS(Class<Number>::getClass()));
+}
+
+ASFUNCTIONBODY(GraphicsPath, curveTo)
+{
+ GraphicsPath* th=obj->as<GraphicsPath>();
+ number_t cx;
+ number_t cy;
+ number_t ax;
+ number_t ay;
+ ARG_UNPACK (cx) (cy) (ax) (ay);
+
+ th->ensureValid();
+ th->commands->append(abstract_i(GraphicsPathCommand::CURVE_TO));
+ th->data->append(abstract_d(ax));
+ th->data->append(abstract_d(ay));
+ th->data->append(abstract_d(cx));
+ th->data->append(abstract_d(cy));
+
+ return NULL;
+}
+
+ASFUNCTIONBODY(GraphicsPath, lineTo)
+{
+ GraphicsPath* th=obj->as<GraphicsPath>();
+ number_t x;
+ number_t y;
+ ARG_UNPACK (x) (y);
+
+ th->ensureValid();
+ th->commands->append(abstract_i(GraphicsPathCommand::LINE_TO));
+ th->data->append(abstract_d(x));
+ th->data->append(abstract_d(y));
+
+ return NULL;
+}
+
+ASFUNCTIONBODY(GraphicsPath, moveTo)
+{
+ GraphicsPath* th=obj->as<GraphicsPath>();
+ number_t x;
+ number_t y;
+ ARG_UNPACK (x) (y);
+
+ th->ensureValid();
+ th->commands->append(abstract_i(GraphicsPathCommand::MOVE_TO));
+ th->data->append(abstract_d(x));
+ th->data->append(abstract_d(y));
+
+ return NULL;
+}
+
+ASFUNCTIONBODY(GraphicsPath, wideLineTo)
+{
+ GraphicsPath* th=obj->as<GraphicsPath>();
+ number_t x;
+ number_t y;
+ ARG_UNPACK (x) (y);
+
+ th->ensureValid();
+ th->commands->append(abstract_i(GraphicsPathCommand::LINE_TO));
+ th->data->append(abstract_d(0));
+ th->data->append(abstract_d(0));
+ th->data->append(abstract_d(x));
+ th->data->append(abstract_d(y));
+
+ return NULL;
+}
+
+ASFUNCTIONBODY(GraphicsPath, wideMoveTo)
+{
+ GraphicsPath* th=obj->as<GraphicsPath>();
+ number_t x;
+ number_t y;
+ ARG_UNPACK (x) (y);
+
+ th->ensureValid();
+ th->commands->append(abstract_i(GraphicsPathCommand::MOVE_TO));
+ th->data->append(abstract_d(0));
+ th->data->append(abstract_d(0));
+ th->data->append(abstract_d(x));
+ th->data->append(abstract_d(y));
+
+ return NULL;
+}
+
+void GraphicsPath::appendToTokens(std::vector<GeomToken>& tokens)
+{
+ Graphics::pathToTokens(commands, data, winding, tokens);
+}
diff --git a/src/scripting/toplevel/UInteger.h b/src/scripting/flash/display/GraphicsPath.h
similarity index 54%
copy from src/scripting/toplevel/UInteger.h
copy to src/scripting/flash/display/GraphicsPath.h
index fe0fbcc..74bf931 100644
--- a/src/scripting/toplevel/UInteger.h
+++ b/src/scripting/flash/display/GraphicsPath.h
@@ -1,7 +1,7 @@
/**************************************************************************
Lightspark, a free flash player implementation
- Copyright (C) 2009-2013 Alessandro Pignotti (a.pignotti at sssup.it)
+ Copyright (C) 2013 Antti Ajanki (antti.ajanki at iki.fi)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
@@ -17,41 +17,39 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
-#ifndef SCRIPTING_TOPLEVEL_UINTEGER_H
-#define SCRIPTING_TOPLEVEL_UINTEGER_H 1
-#include "compat.h"
+#ifndef SCRIPTING_FLASH_DISPLAY_GRAPHICSPATH_H
+#define SCRIPTING_FLASH_DISPLAY_GRAPHICSPATH_H 1
+
#include "asobject.h"
+#include "tiny_string.h"
+#include "scripting/flash/display/IGraphicsPath.h"
+#include "scripting/flash/display/IGraphicsData.h"
namespace lightspark
{
-class UInteger: public ASObject
+class Vector;
+
+class GraphicsPath: public ASObject, public IGraphicsPath, public IGraphicsData
{
-friend ASObject* abstract_ui(uint32_t i);
+private:
+ void ensureValid();
public:
- uint32_t val;
- UInteger(Class_base* c,uint32_t v=0):ASObject(c),val(v){type=T_UINTEGER;}
-
+ GraphicsPath(Class_base* c);
static void sinit(Class_base* c);
- tiny_string toString();
- static tiny_string toString(uint32_t val);
- int32_t toInt()
- {
- return val;
- }
- uint32_t toUInt()
- {
- return val;
- }
- TRISTATE isLess(ASObject* r);
- bool isEqual(ASObject* o);
+ void finalize();
ASFUNCTION(_constructor);
- ASFUNCTION(generator);
- ASFUNCTION(_toString);
- ASFUNCTION(_valueOf);
- std::string toDebugString() { return toString()+"ui"; }
- //CHECK: should this have a special serialization?
+ ASPROPERTY_GETTER_SETTER(_NR<Vector>, commands);
+ ASPROPERTY_GETTER_SETTER(_NR<Vector>, data);
+ ASPROPERTY_GETTER_SETTER(tiny_string, winding);
+ ASFUNCTION(curveTo);
+ ASFUNCTION(lineTo);
+ ASFUNCTION(moveTo);
+ ASFUNCTION(wideLineTo);
+ ASFUNCTION(wideMoveTo);
+ void appendToTokens(std::vector<GeomToken>& tokens);
+};
+
};
-}
-#endif /* SCRIPTING_TOPLEVEL_UINTEGER_H */
+#endif /* SCRIPTING_FLASH_DISPLAY_GRAPHICSPATH_H */
diff --git a/src/scripting/flash/display/GraphicsShaderFill.cpp b/src/scripting/flash/display/GraphicsShaderFill.cpp
new file mode 100644
index 0000000..4094e3d
--- /dev/null
+++ b/src/scripting/flash/display/GraphicsShaderFill.cpp
@@ -0,0 +1,73 @@
+/**************************************************************************
+ Lightspark, a free flash player implementation
+
+ Copyright (C) 2013 Antti Ajanki (antti.ajanki at iki.fi)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+**************************************************************************/
+
+#include "scripting/flash/display/GraphicsShaderFill.h"
+#include "scripting/flash/display/flashdisplay.h"
+#include "scripting/flash/geom/flashgeom.h"
+#include "scripting/class.h"
+#include "scripting/argconv.h"
+
+using namespace lightspark;
+
+GraphicsShaderFill::GraphicsShaderFill(Class_base* c):
+ ASObject(c)
+{
+}
+
+void GraphicsShaderFill::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED | CLASS_FINAL);
+ REGISTER_GETTER_SETTER(c, matrix);
+ REGISTER_GETTER_SETTER(c, shader);
+
+ c->addImplementedInterface(InterfaceClass<IGraphicsFill>::getClass());
+ IGraphicsFill::linkTraits(c);
+ c->addImplementedInterface(InterfaceClass<IGraphicsData>::getClass());
+ IGraphicsData::linkTraits(c);
+}
+
+void GraphicsShaderFill::finalize()
+{
+ ASObject::finalize();
+ matrix.reset();
+ shader.reset();
+}
+
+ASFUNCTIONBODY(GraphicsShaderFill, _constructor)
+{
+ GraphicsShaderFill* th = obj->as<GraphicsShaderFill>();
+ ASObject::_constructor(obj,NULL,0);
+ ARG_UNPACK (th->shader, NullRef) (th->matrix, NullRef);
+ return NULL;
+}
+
+ASFUNCTIONBODY_GETTER_SETTER(GraphicsShaderFill, matrix);
+ASFUNCTIONBODY_GETTER_SETTER(GraphicsShaderFill, shader);
+
+FILLSTYLE GraphicsShaderFill::toFillStyle()
+{
+ LOG(LOG_NOT_IMPLEMENTED, "GraphicsShaderFill::toFillStyle()");
+ return FILLSTYLE(0xff);
+}
+
+void GraphicsShaderFill::appendToTokens(std::vector<GeomToken>& tokens)
+{
+ LOG(LOG_NOT_IMPLEMENTED, "GraphicsShaderFill::appendToTokens()");
+ return;
+}
diff --git a/src/scripting/flash/accessibility/flashaccessibility.h b/src/scripting/flash/display/GraphicsShaderFill.h
similarity index 57%
copy from src/scripting/flash/accessibility/flashaccessibility.h
copy to src/scripting/flash/display/GraphicsShaderFill.h
index 19d00b8..28ed4a6 100644
--- a/src/scripting/flash/accessibility/flashaccessibility.h
+++ b/src/scripting/flash/display/GraphicsShaderFill.h
@@ -1,7 +1,7 @@
/**************************************************************************
Lightspark, a free flash player implementation
- Copyright (C) 2009-2013 Alessandro Pignotti (a.pignotti at sssup.it)
+ Copyright (C) 2013 Antti Ajanki (antti.ajanki at iki.fi)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
@@ -17,31 +17,32 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
-#ifndef SCRIPTING_FLASH_ACCESSIBILITY_FLASHACCESSIBILITY_H
-#define SCRIPTING_FLASH_ACCESSIBILITY_FLASHACCESSIBILITY_H 1
+#ifndef SCRIPTING_FLASH_DISPLAY_GRAPHICSSHADERFILL_H
+#define SCRIPTING_FLASH_DISPLAY_GRAPHICSSHADERFILL_H 1
#include "asobject.h"
+#include "scripting/flash/display/IGraphicsFill.h"
+#include "scripting/flash/display/IGraphicsData.h"
namespace lightspark
{
-class AccessibilityProperties : public ASObject
+class Matrix;
+class Shader;
+
+class GraphicsShaderFill: public ASObject, public IGraphicsFill, public IGraphicsData
{
-private:
- ASPROPERTY_GETTER_SETTER(tiny_string,name);
public:
- AccessibilityProperties(Class_base* c):ASObject(c){}
- static void sinit(Class_base*);
+ GraphicsShaderFill(Class_base* c);
+ static void sinit(Class_base* c);
+ void finalize();
ASFUNCTION(_constructor);
+ ASPROPERTY_GETTER_SETTER(_NR<Matrix>, matrix);
+ ASPROPERTY_GETTER_SETTER(_NR<Shader>, shader);
+ FILLSTYLE toFillStyle();
+ void appendToTokens(std::vector<GeomToken>& tokens);
};
-class AccessibilityImplementation : public ASObject
-{
-public:
- AccessibilityImplementation(Class_base* c):ASObject(c){}
- static void sinit(Class_base*);
- ASFUNCTION(_constructor);
};
-}
-#endif /* SCRIPTING_FLASH_ACCESSIBILITY_FLASHACCESSIBILITY_H */
+#endif /* SCRIPTING_FLASH_DISPLAY_GRAPHICSSHADERFILL_H */
diff --git a/src/scripting/flash/display/GraphicsSolidFill.cpp b/src/scripting/flash/display/GraphicsSolidFill.cpp
new file mode 100644
index 0000000..1dcbbc0
--- /dev/null
+++ b/src/scripting/flash/display/GraphicsSolidFill.cpp
@@ -0,0 +1,63 @@
+/**************************************************************************
+ Lightspark, a free flash player implementation
+
+ Copyright (C) 2013 Antti Ajanki (antti.ajanki at iki.fi)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+**************************************************************************/
+
+#include "scripting/flash/display/GraphicsSolidFill.h"
+#include "scripting/flash/display/Graphics.h"
+#include "scripting/class.h"
+#include "scripting/argconv.h"
+
+using namespace lightspark;
+
+GraphicsSolidFill::GraphicsSolidFill(Class_base* c):
+ ASObject(c), alpha(1.0), color(0)
+{
+}
+
+void GraphicsSolidFill::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED | CLASS_FINAL);
+ REGISTER_GETTER_SETTER(c, alpha);
+ REGISTER_GETTER_SETTER(c, color);
+
+ c->addImplementedInterface(InterfaceClass<IGraphicsFill>::getClass());
+ IGraphicsFill::linkTraits(c);
+ c->addImplementedInterface(InterfaceClass<IGraphicsData>::getClass());
+ IGraphicsData::linkTraits(c);
+}
+
+ASFUNCTIONBODY(GraphicsSolidFill, _constructor)
+{
+ GraphicsSolidFill* th = obj->as<GraphicsSolidFill>();
+ ASObject::_constructor(obj,NULL,0);
+ ARG_UNPACK (th->color, 0) (th->alpha, 1.0);
+ return NULL;
+}
+
+ASFUNCTIONBODY_GETTER_SETTER(GraphicsSolidFill, alpha);
+ASFUNCTIONBODY_GETTER_SETTER(GraphicsSolidFill, color);
+
+FILLSTYLE GraphicsSolidFill::toFillStyle()
+{
+ return Graphics::createSolidFill(color, static_cast<uint8_t>(255*alpha));
+}
+
+void GraphicsSolidFill::appendToTokens(std::vector<GeomToken>& tokens)
+{
+ tokens.emplace_back(GeomToken(SET_FILL, toFillStyle()));
+}
diff --git a/src/scripting/flash/accessibility/flashaccessibility.h b/src/scripting/flash/display/GraphicsSolidFill.h
similarity index 60%
copy from src/scripting/flash/accessibility/flashaccessibility.h
copy to src/scripting/flash/display/GraphicsSolidFill.h
index 19d00b8..a283dec 100644
--- a/src/scripting/flash/accessibility/flashaccessibility.h
+++ b/src/scripting/flash/display/GraphicsSolidFill.h
@@ -1,7 +1,7 @@
/**************************************************************************
Lightspark, a free flash player implementation
- Copyright (C) 2009-2013 Alessandro Pignotti (a.pignotti at sssup.it)
+ Copyright (C) 2013 Antti Ajanki (antti.ajanki at iki.fi)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
@@ -17,31 +17,28 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
-#ifndef SCRIPTING_FLASH_ACCESSIBILITY_FLASHACCESSIBILITY_H
-#define SCRIPTING_FLASH_ACCESSIBILITY_FLASHACCESSIBILITY_H 1
+#ifndef SCRIPTING_FLASH_DISPLAY_GRAPHICSSOLIDFILL_H
+#define SCRIPTING_FLASH_DISPLAY_GRAPHICSSOLIDFILL_H 1
#include "asobject.h"
+#include "scripting/flash/display/IGraphicsFill.h"
+#include "scripting/flash/display/IGraphicsData.h"
namespace lightspark
{
-class AccessibilityProperties : public ASObject
+class GraphicsSolidFill: public ASObject, public IGraphicsFill, public IGraphicsData
{
-private:
- ASPROPERTY_GETTER_SETTER(tiny_string,name);
public:
- AccessibilityProperties(Class_base* c):ASObject(c){}
- static void sinit(Class_base*);
+ GraphicsSolidFill(Class_base* c);
+ static void sinit(Class_base* c);
ASFUNCTION(_constructor);
+ ASPROPERTY_GETTER_SETTER(number_t, alpha);
+ ASPROPERTY_GETTER_SETTER(uint32_t, color);
+ FILLSTYLE toFillStyle();
+ void appendToTokens(std::vector<GeomToken>& tokens);
};
-class AccessibilityImplementation : public ASObject
-{
-public:
- AccessibilityImplementation(Class_base* c):ASObject(c){}
- static void sinit(Class_base*);
- ASFUNCTION(_constructor);
};
-}
-#endif /* SCRIPTING_FLASH_ACCESSIBILITY_FLASHACCESSIBILITY_H */
+#endif /* SCRIPTING_FLASH_DISPLAY_GRAPHICSSOLIDFILL_H */
diff --git a/src/scripting/flash/display/GraphicsStroke.cpp b/src/scripting/flash/display/GraphicsStroke.cpp
new file mode 100644
index 0000000..8858830
--- /dev/null
+++ b/src/scripting/flash/display/GraphicsStroke.cpp
@@ -0,0 +1,109 @@
+/**************************************************************************
+ Lightspark, a free flash player implementation
+
+ Copyright (C) 2013 Antti Ajanki (antti.ajanki at iki.fi)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+**************************************************************************/
+
+#include <limits>
+#include "scripting/flash/display/GraphicsStroke.h"
+#include "scripting/flash/display/IGraphicsFill.h"
+#include "scripting/class.h"
+#include "scripting/argconv.h"
+#include "swftypes.h"
+
+using namespace lightspark;
+
+GraphicsStroke::GraphicsStroke(Class_base* c):
+ ASObject(c), caps("none"), joints("round"), miterLimit(3.0),
+ pixelHinting(false), scaleMode("normal"),
+ thickness(std::numeric_limits<double>::quiet_NaN())
+{
+}
+
+void GraphicsStroke::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED | CLASS_FINAL);
+ REGISTER_GETTER_SETTER(c, caps);
+ REGISTER_GETTER_SETTER(c, fill);
+ REGISTER_GETTER_SETTER(c, joints);
+ REGISTER_GETTER_SETTER(c, miterLimit);
+ REGISTER_GETTER_SETTER(c, pixelHinting);
+ REGISTER_GETTER_SETTER(c, scaleMode);
+ REGISTER_GETTER_SETTER(c, thickness);
+
+ c->addImplementedInterface(InterfaceClass<IGraphicsStroke>::getClass());
+ IGraphicsStroke::linkTraits(c);
+ c->addImplementedInterface(InterfaceClass<IGraphicsData>::getClass());
+ IGraphicsData::linkTraits(c);
+}
+
+void GraphicsStroke::finalize()
+{
+ ASObject::finalize();
+ fill.reset();
+}
+
+ASFUNCTIONBODY(GraphicsStroke, _constructor)
+{
+ GraphicsStroke* th = obj->as<GraphicsStroke>();
+ _NR<ASObject> fill;
+ ASObject::_constructor(obj,NULL,0);
+ ARG_UNPACK (th->thickness, std::numeric_limits<double>::quiet_NaN())
+ (th->pixelHinting, false)
+ (th->scaleMode, "normal")
+ (th->caps, "none")
+ (th->joints, "rounds")
+ (th->miterLimit, 3.0)
+ (th->fill, NullRef);
+ th->validateFill(NullRef);
+ return NULL;
+}
+
+ASFUNCTIONBODY_GETTER_SETTER(GraphicsStroke, caps);
+ASFUNCTIONBODY_GETTER_SETTER_CB(GraphicsStroke, fill, validateFill);
+ASFUNCTIONBODY_GETTER_SETTER(GraphicsStroke, joints);
+ASFUNCTIONBODY_GETTER_SETTER(GraphicsStroke, miterLimit);
+ASFUNCTIONBODY_GETTER_SETTER(GraphicsStroke, pixelHinting);
+ASFUNCTIONBODY_GETTER_SETTER(GraphicsStroke, scaleMode);
+ASFUNCTIONBODY_GETTER_SETTER(GraphicsStroke, thickness);
+
+void GraphicsStroke::validateFill(_NR<ASObject> oldValue)
+{
+ if (!fill.isNull() && !fill->is<IGraphicsFill>())
+ {
+ tiny_string wrongClass = fill->getClassName();
+ fill = oldValue;
+ throwError<TypeError>(kCheckTypeFailedError, wrongClass, "IGraphicsFill");
+ }
+}
+
+void GraphicsStroke::appendToTokens(std::vector<GeomToken>& tokens)
+{
+ LINESTYLE2 style(0xff);
+ style.Width = thickness;
+
+ // TODO: pixel hinting, scaling, caps, miter, joints
+
+ if (!fill.isNull())
+ {
+ IGraphicsFill *gfill = dynamic_cast<IGraphicsFill*>(fill.getPtr());
+ assert(gfill);
+ style.HasFillFlag = true;
+ style.FillType = gfill->toFillStyle();
+ }
+
+ tokens.emplace_back(GeomToken(SET_STROKE, style));
+}
diff --git a/src/scripting/toplevel/UInteger.h b/src/scripting/flash/display/GraphicsStroke.h
similarity index 52%
copy from src/scripting/toplevel/UInteger.h
copy to src/scripting/flash/display/GraphicsStroke.h
index fe0fbcc..54eb6fc 100644
--- a/src/scripting/toplevel/UInteger.h
+++ b/src/scripting/flash/display/GraphicsStroke.h
@@ -1,7 +1,7 @@
/**************************************************************************
Lightspark, a free flash player implementation
- Copyright (C) 2009-2013 Alessandro Pignotti (a.pignotti at sssup.it)
+ Copyright (C) 2013 Antti Ajanki (antti.ajanki at iki.fi)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
@@ -17,41 +17,35 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
-#ifndef SCRIPTING_TOPLEVEL_UINTEGER_H
-#define SCRIPTING_TOPLEVEL_UINTEGER_H 1
-#include "compat.h"
+#ifndef SCRIPTING_FLASH_DISPLAY_GRAPHICSSTROKE_H
+#define SCRIPTING_FLASH_DISPLAY_GRAPHICSSTROKE_H 1
+
#include "asobject.h"
+#include "scripting/flash/display/IGraphicsStroke.h"
+#include "scripting/flash/display/IGraphicsData.h"
namespace lightspark
{
-class UInteger: public ASObject
+class GraphicsStroke: public ASObject, public IGraphicsStroke, public IGraphicsData
{
-friend ASObject* abstract_ui(uint32_t i);
+protected:
+ void validateFill(_NR<ASObject> oldValue);
public:
- uint32_t val;
- UInteger(Class_base* c,uint32_t v=0):ASObject(c),val(v){type=T_UINTEGER;}
-
+ GraphicsStroke(Class_base* c);
static void sinit(Class_base* c);
- tiny_string toString();
- static tiny_string toString(uint32_t val);
- int32_t toInt()
- {
- return val;
- }
- uint32_t toUInt()
- {
- return val;
- }
- TRISTATE isLess(ASObject* r);
- bool isEqual(ASObject* o);
+ void finalize();
ASFUNCTION(_constructor);
- ASFUNCTION(generator);
- ASFUNCTION(_toString);
- ASFUNCTION(_valueOf);
- std::string toDebugString() { return toString()+"ui"; }
- //CHECK: should this have a special serialization?
+ ASPROPERTY_GETTER_SETTER(tiny_string, caps);
+ ASPROPERTY_GETTER_SETTER(_NR<ASObject>, fill); // really IGraphicsFill
+ ASPROPERTY_GETTER_SETTER(tiny_string, joints);
+ ASPROPERTY_GETTER_SETTER(number_t, miterLimit);
+ ASPROPERTY_GETTER_SETTER(bool, pixelHinting);
+ ASPROPERTY_GETTER_SETTER(tiny_string, scaleMode);
+ ASPROPERTY_GETTER_SETTER(number_t, thickness);
+ void appendToTokens(std::vector<GeomToken>& tokens);
+};
+
};
-}
-#endif /* SCRIPTING_TOPLEVEL_UINTEGER_H */
+#endif /* SCRIPTING_FLASH_DISPLAY_GRAPHICSSTROKE_H */
diff --git a/src/scripting/flash/display/GraphicsTrianglePath.cpp b/src/scripting/flash/display/GraphicsTrianglePath.cpp
new file mode 100644
index 0000000..faa44cb
--- /dev/null
+++ b/src/scripting/flash/display/GraphicsTrianglePath.cpp
@@ -0,0 +1,74 @@
+/**************************************************************************
+ Lightspark, a free flash player implementation
+
+ Copyright (C) 2013 Antti Ajanki (antti.ajanki at iki.fi)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+**************************************************************************/
+
+#include "scripting/flash/display/GraphicsTrianglePath.h"
+#include "scripting/flash/display/Graphics.h"
+#include "scripting/toplevel/Vector.h"
+#include "scripting/class.h"
+#include "scripting/argconv.h"
+
+using namespace lightspark;
+
+GraphicsTrianglePath::GraphicsTrianglePath(Class_base* c):
+ ASObject(c), culling("none")
+{
+}
+
+void GraphicsTrianglePath::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED | CLASS_FINAL);
+ REGISTER_GETTER_SETTER(c, culling);
+ REGISTER_GETTER_SETTER(c, indices);
+ REGISTER_GETTER_SETTER(c, uvtData);
+ REGISTER_GETTER_SETTER(c, vertices);
+
+ c->addImplementedInterface(InterfaceClass<IGraphicsPath>::getClass());
+ IGraphicsPath::linkTraits(c);
+ c->addImplementedInterface(InterfaceClass<IGraphicsData>::getClass());
+ IGraphicsData::linkTraits(c);
+}
+
+void GraphicsTrianglePath::finalize()
+{
+ ASObject::finalize();
+ indices.reset();
+ uvtData.reset();
+ vertices.reset();
+}
+
+ASFUNCTIONBODY(GraphicsTrianglePath, _constructor)
+{
+ GraphicsTrianglePath* th = obj->as<GraphicsTrianglePath>();
+ ASObject::_constructor(obj,NULL,0);
+ ARG_UNPACK (th->vertices, NullRef)
+ (th->indices, NullRef)
+ (th->uvtData, NullRef)
+ (th->culling, "none");
+ return NULL;
+}
+
+ASFUNCTIONBODY_GETTER_SETTER(GraphicsTrianglePath, culling);
+ASFUNCTIONBODY_GETTER_SETTER(GraphicsTrianglePath, indices);
+ASFUNCTIONBODY_GETTER_SETTER(GraphicsTrianglePath, uvtData);
+ASFUNCTIONBODY_GETTER_SETTER(GraphicsTrianglePath, vertices);
+
+void GraphicsTrianglePath::appendToTokens(std::vector<GeomToken>& tokens)
+{
+ Graphics::drawTrianglesToTokens(vertices, indices, uvtData, culling, tokens);
+}
diff --git a/src/scripting/toplevel/UInteger.h b/src/scripting/flash/display/GraphicsTrianglePath.h
similarity index 56%
copy from src/scripting/toplevel/UInteger.h
copy to src/scripting/flash/display/GraphicsTrianglePath.h
index fe0fbcc..5e30e9e 100644
--- a/src/scripting/toplevel/UInteger.h
+++ b/src/scripting/flash/display/GraphicsTrianglePath.h
@@ -1,7 +1,7 @@
/**************************************************************************
Lightspark, a free flash player implementation
- Copyright (C) 2009-2013 Alessandro Pignotti (a.pignotti at sssup.it)
+ Copyright (C) 2013 Antti Ajanki (antti.ajanki at iki.fi)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
@@ -17,41 +17,32 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
-#ifndef SCRIPTING_TOPLEVEL_UINTEGER_H
-#define SCRIPTING_TOPLEVEL_UINTEGER_H 1
-#include "compat.h"
+#ifndef SCRIPTING_FLASH_DISPLAY_GRAPHICSTRIANGLEPATH_H
+#define SCRIPTING_FLASH_DISPLAY_GRAPHICSTRIANGLEPATH_H 1
+
#include "asobject.h"
+#include "scripting/flash/display/IGraphicsPath.h"
+#include "scripting/flash/display/IGraphicsData.h"
namespace lightspark
{
-class UInteger: public ASObject
+class Vector;
+
+class GraphicsTrianglePath: public ASObject, public IGraphicsPath, public IGraphicsData
{
-friend ASObject* abstract_ui(uint32_t i);
public:
- uint32_t val;
- UInteger(Class_base* c,uint32_t v=0):ASObject(c),val(v){type=T_UINTEGER;}
-
+ GraphicsTrianglePath(Class_base* c);
static void sinit(Class_base* c);
- tiny_string toString();
- static tiny_string toString(uint32_t val);
- int32_t toInt()
- {
- return val;
- }
- uint32_t toUInt()
- {
- return val;
- }
- TRISTATE isLess(ASObject* r);
- bool isEqual(ASObject* o);
+ void finalize();
ASFUNCTION(_constructor);
- ASFUNCTION(generator);
- ASFUNCTION(_toString);
- ASFUNCTION(_valueOf);
- std::string toDebugString() { return toString()+"ui"; }
- //CHECK: should this have a special serialization?
+ ASPROPERTY_GETTER_SETTER(tiny_string, culling);
+ ASPROPERTY_GETTER_SETTER(_NR<Vector>, indices);
+ ASPROPERTY_GETTER_SETTER(_NR<Vector>, uvtData);
+ ASPROPERTY_GETTER_SETTER(_NR<Vector>, vertices);
+ void appendToTokens(std::vector<GeomToken>& tokens);
+};
+
};
-}
-#endif /* SCRIPTING_TOPLEVEL_UINTEGER_H */
+#endif /* SCRIPTING_FLASH_DISPLAY_GRAPHICSTRIANGLEPATH_H */
diff --git a/src/backends/rtmputils.h b/src/scripting/flash/display/IGraphicsData.h
similarity index 64%
copy from src/backends/rtmputils.h
copy to src/scripting/flash/display/IGraphicsData.h
index 7e9de51..480527b 100644
--- a/src/backends/rtmputils.h
+++ b/src/scripting/flash/display/IGraphicsData.h
@@ -1,7 +1,7 @@
/**************************************************************************
Lightspark, a free flash player implementation
- Copyright (C) 2011-2013 Alessandro Pignotti (a.pignotti at sssup.it)
+ Copyright (C) 2013 Antti Ajanki (antti.ajanki at iki.fi)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
@@ -17,25 +17,26 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
-#ifndef BACKENDS_RTMPUTILS_H
-#define BACKENDS_RTMPUTILS_H 1
+#ifndef SCRIPTING_FLASH_DISPLAY_IGRAPHICSDATA_H
+#define SCRIPTING_FLASH_DISPLAY_IGRAPHICSDATA_H 1
-#include "backends/netutils.h"
+#include <vector>
+#include "backends/geometry.h"
namespace lightspark
{
-class ILoadable;
+class Class_base;
-class RTMPDownloader: public ThreadedDownloader
+class IGraphicsData
{
-private:
- void execute();
- void threadAbort();
- tiny_string stream;
+protected:
+ virtual ~IGraphicsData() {}
public:
- RTMPDownloader(const tiny_string& _url, const tiny_string& _stream, ILoadable* o);
+ static void linkTraits(Class_base* c) {};
+ // Appends GeomTokens for drawing this object into tokens
+ virtual void appendToTokens(std::vector<GeomToken>& tokens) = 0;
};
};
-#endif /* BACKENDS_RTMPUTILS_H */
+#endif /* SCRIPTING_FLASH_DISPLAY_IGRAPHICSDATA_H */
diff --git a/src/backends/rtmputils.h b/src/scripting/flash/display/IGraphicsFill.h
similarity index 69%
copy from src/backends/rtmputils.h
copy to src/scripting/flash/display/IGraphicsFill.h
index 7e9de51..b3d4d18 100644
--- a/src/backends/rtmputils.h
+++ b/src/scripting/flash/display/IGraphicsFill.h
@@ -1,7 +1,7 @@
/**************************************************************************
Lightspark, a free flash player implementation
- Copyright (C) 2011-2013 Alessandro Pignotti (a.pignotti at sssup.it)
+ Copyright (C) 2013 Antti Ajanki (antti.ajanki at iki.fi)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
@@ -17,25 +17,24 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
-#ifndef BACKENDS_RTMPUTILS_H
-#define BACKENDS_RTMPUTILS_H 1
+#ifndef SCRIPTING_FLASH_DISPLAY_IGRAPHICSFILL_H
+#define SCRIPTING_FLASH_DISPLAY_IGRAPHICSFILL_H 1
-#include "backends/netutils.h"
+#include "swftypes.h"
namespace lightspark
{
-class ILoadable;
+class Class_base;
-class RTMPDownloader: public ThreadedDownloader
+class IGraphicsFill
{
-private:
- void execute();
- void threadAbort();
- tiny_string stream;
+protected:
+ virtual ~IGraphicsFill() {}
public:
- RTMPDownloader(const tiny_string& _url, const tiny_string& _stream, ILoadable* o);
+ static void linkTraits(Class_base* c) {};
+ virtual FILLSTYLE toFillStyle() = 0;
};
};
-#endif /* BACKENDS_RTMPUTILS_H */
+#endif /* SCRIPTING_FLASH_DISPLAY_IGRAPHICSFILL_H */
diff --git a/src/backends/rtmputils.h b/src/scripting/flash/display/IGraphicsPath.h
similarity index 69%
copy from src/backends/rtmputils.h
copy to src/scripting/flash/display/IGraphicsPath.h
index 7e9de51..93da267 100644
--- a/src/backends/rtmputils.h
+++ b/src/scripting/flash/display/IGraphicsPath.h
@@ -1,7 +1,7 @@
/**************************************************************************
Lightspark, a free flash player implementation
- Copyright (C) 2011-2013 Alessandro Pignotti (a.pignotti at sssup.it)
+ Copyright (C) 2013 Antti Ajanki (antti.ajanki at iki.fi)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
@@ -17,25 +17,19 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
-#ifndef BACKENDS_RTMPUTILS_H
-#define BACKENDS_RTMPUTILS_H 1
-
-#include "backends/netutils.h"
+#ifndef SCRIPTING_FLASH_DISPLAY_IGRAPHICSPATH_H
+#define SCRIPTING_FLASH_DISPLAY_IGRAPHICSPATH_H 1
namespace lightspark
{
-class ILoadable;
+class Class_base;
-class RTMPDownloader: public ThreadedDownloader
+class IGraphicsPath
{
-private:
- void execute();
- void threadAbort();
- tiny_string stream;
public:
- RTMPDownloader(const tiny_string& _url, const tiny_string& _stream, ILoadable* o);
+ static void linkTraits(Class_base* c) {};
};
};
-#endif /* BACKENDS_RTMPUTILS_H */
+#endif /* SCRIPTING_FLASH_DISPLAY_IGRAPHICSPATH_H */
diff --git a/src/backends/rtmputils.h b/src/scripting/flash/display/IGraphicsStroke.h
similarity index 69%
copy from src/backends/rtmputils.h
copy to src/scripting/flash/display/IGraphicsStroke.h
index 7e9de51..f11c2ba 100644
--- a/src/backends/rtmputils.h
+++ b/src/scripting/flash/display/IGraphicsStroke.h
@@ -1,7 +1,7 @@
/**************************************************************************
Lightspark, a free flash player implementation
- Copyright (C) 2011-2013 Alessandro Pignotti (a.pignotti at sssup.it)
+ Copyright (C) 2013 Antti Ajanki (antti.ajanki at iki.fi)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
@@ -17,25 +17,19 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
-#ifndef BACKENDS_RTMPUTILS_H
-#define BACKENDS_RTMPUTILS_H 1
-
-#include "backends/netutils.h"
+#ifndef SCRIPTING_FLASH_DISPLAY_IGRAPHICSSTROKE_H
+#define SCRIPTING_FLASH_DISPLAY_IGRAPHICSSTROKE_H 1
namespace lightspark
{
-class ILoadable;
+class Class_base;
-class RTMPDownloader: public ThreadedDownloader
+class IGraphicsStroke
{
-private:
- void execute();
- void threadAbort();
- tiny_string stream;
public:
- RTMPDownloader(const tiny_string& _url, const tiny_string& _stream, ILoadable* o);
+ static void linkTraits(Class_base* c) {};
};
};
-#endif /* BACKENDS_RTMPUTILS_H */
+#endif /* SCRIPTING_FLASH_DISPLAY_IGRAPHICSSTROKE_H */
diff --git a/src/scripting/flash/display/TokenContainer.cpp b/src/scripting/flash/display/TokenContainer.cpp
index d1ad664..e20c286 100644
--- a/src/scripting/flash/display/TokenContainer.cpp
+++ b/src/scripting/flash/display/TokenContainer.cpp
@@ -230,17 +230,16 @@ bool TokenContainer::boundsRect(number_t& xmin, number_t& xmax, number_t& ymin,
}
/* Find the size of the active texture (bitmap set by the latest SET_FILL). */
-void TokenContainer::getTextureSize(int *width, int *height) const
+void TokenContainer::getTextureSize(std::vector<GeomToken>& tokens, int *width, int *height)
{
*width=0;
*height=0;
- unsigned int len=tokens.size();
- for(unsigned int i=0;i<len;i++)
+ for(int i=tokens.size()-1;i>=0;i--)
{
- const FILLSTYLE& style=tokens[len-i-1].fillStyle;
+ const FILLSTYLE& style=tokens[i].fillStyle;
const FILL_STYLE_TYPE& fstype=style.FillStyleType;
- if(tokens[len-i-1].type==SET_FILL &&
+ if(tokens[i].type==SET_FILL &&
(fstype==REPEATING_BITMAP ||
fstype==NON_SMOOTHED_REPEATING_BITMAP ||
fstype==CLIPPED_BITMAP ||
@@ -255,3 +254,17 @@ void TokenContainer::getTextureSize(int *width, int *height) const
}
}
}
+
+/* Return the width of the latest SET_STROKE */
+uint16_t TokenContainer::getCurrentLineWidth() const
+{
+ for(int i=tokens.size()-1;i>=0;i--)
+ {
+ if(tokens[i].type==SET_STROKE)
+ {
+ return tokens[i].lineStyle.Width;
+ }
+ }
+
+ return 0;
+}
diff --git a/src/scripting/flash/display/TokenContainer.h b/src/scripting/flash/display/TokenContainer.h
index 5fdb7b8..fbfe13d 100644
--- a/src/scripting/flash/display/TokenContainer.h
+++ b/src/scripting/flash/display/TokenContainer.h
@@ -24,6 +24,7 @@
#include "backends/geometry.h"
#include "backends/graphics.h"
#include "scripting/flash/display/DisplayObject.h"
+#include "scripting/flash/display/Graphics.h"
namespace lightspark
{
@@ -49,7 +50,8 @@ public:
static void FromShaperecordListToShapeVector(const std::vector<SHAPERECORD>& shapeRecords,
tokensVector& tokens, const std::list<FILLSTYLE>& fillStyles,
const MATRIX& matrix = MATRIX());
- void getTextureSize(int *width, int *height) const;
+ static void getTextureSize(std::vector<GeomToken>& tokens, int *width, int *height);
+ uint16_t getCurrentLineWidth() const;
float scaling;
protected:
TokenContainer(DisplayObject* _o);
diff --git a/src/scripting/flash/display/flashdisplay.cpp b/src/scripting/flash/display/flashdisplay.cpp
index 1fa9722..ac23bc4 100644
--- a/src/scripting/flash/display/flashdisplay.cpp
+++ b/src/scripting/flash/display/flashdisplay.cpp
@@ -22,6 +22,7 @@
#include "backends/security.h"
#include "scripting/abc.h"
#include "scripting/flash/display/flashdisplay.h"
+#include "scripting/flash/display/Graphics.h"
#include "swf.h"
#include "scripting/flash/geom/flashgeom.h"
#include "scripting/flash/system/flashsystem.h"
@@ -53,41 +54,45 @@ std::ostream& lightspark::operator<<(std::ostream& s, const DisplayObject& r)
LoaderInfo::LoaderInfo(Class_base* c):EventDispatcher(c),applicationDomain(NullRef),securityDomain(NullRef),
contentType("application/x-shockwave-flash"),
bytesLoaded(0),bytesTotal(0),sharedEvents(NullRef),
- loader(NullRef),loadStatus(STARTED),actionScriptVersion(3),childAllowsParent(true)
+ loader(NullRef),bytesData(NullRef),loadStatus(STARTED),actionScriptVersion(3),swfVersion(0),childAllowsParent(true),uncaughtErrorEvents(NullRef)
{
}
LoaderInfo::LoaderInfo(Class_base* c, _R<Loader> l):EventDispatcher(c),applicationDomain(NullRef),securityDomain(NullRef),
contentType("application/x-shockwave-flash"),
bytesLoaded(0),bytesTotal(0),sharedEvents(NullRef),
- loader(l),loadStatus(STARTED),actionScriptVersion(3),childAllowsParent(true)
+ loader(l),bytesData(NullRef),loadStatus(STARTED),actionScriptVersion(3),swfVersion(0),childAllowsParent(true),uncaughtErrorEvents(NullRef)
{
}
void LoaderInfo::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<EventDispatcher>::getRef());
+ CLASS_SETUP(c, EventDispatcher, _constructor, CLASS_SEALED);
c->setDeclaredMethodByQName("loaderURL","",Class<IFunction>::getFunction(_getLoaderURL),GETTER_METHOD,true);
c->setDeclaredMethodByQName("loader","",Class<IFunction>::getFunction(_getLoader),GETTER_METHOD,true);
c->setDeclaredMethodByQName("content","",Class<IFunction>::getFunction(_getContent),GETTER_METHOD,true);
c->setDeclaredMethodByQName("url","",Class<IFunction>::getFunction(_getURL),GETTER_METHOD,true);
c->setDeclaredMethodByQName("bytesLoaded","",Class<IFunction>::getFunction(_getBytesLoaded),GETTER_METHOD,true);
c->setDeclaredMethodByQName("bytesTotal","",Class<IFunction>::getFunction(_getBytesTotal),GETTER_METHOD,true);
+ c->setDeclaredMethodByQName("bytes","",Class<IFunction>::getFunction(_getBytes),GETTER_METHOD,true);
c->setDeclaredMethodByQName("applicationDomain","",Class<IFunction>::getFunction(_getApplicationDomain),GETTER_METHOD,true);
c->setDeclaredMethodByQName("sharedEvents","",Class<IFunction>::getFunction(_getSharedEvents),GETTER_METHOD,true);
c->setDeclaredMethodByQName("width","",Class<IFunction>::getFunction(_getWidth),GETTER_METHOD,true);
c->setDeclaredMethodByQName("height","",Class<IFunction>::getFunction(_getHeight),GETTER_METHOD,true);
REGISTER_GETTER(c,parameters);
REGISTER_GETTER(c,actionScriptVersion);
+ REGISTER_GETTER(c,swfVersion);
REGISTER_GETTER(c,childAllowsParent);
REGISTER_GETTER(c,contentType);
+ REGISTER_GETTER(c,uncaughtErrorEvents);
}
ASFUNCTIONBODY_GETTER(LoaderInfo,parameters);
ASFUNCTIONBODY_GETTER(LoaderInfo,actionScriptVersion);
ASFUNCTIONBODY_GETTER(LoaderInfo,childAllowsParent);
ASFUNCTIONBODY_GETTER(LoaderInfo,contentType);
+ASFUNCTIONBODY_GETTER(LoaderInfo,swfVersion);
+ASFUNCTIONBODY_GETTER(LoaderInfo,uncaughtErrorEvents);
void LoaderInfo::buildTraits(ASObject* o)
{
@@ -101,6 +106,7 @@ void LoaderInfo::finalize()
applicationDomain.reset();
securityDomain.reset();
waitedObject.reset();
+ bytesData.reset();
}
void LoaderInfo::resetState()
@@ -108,6 +114,8 @@ void LoaderInfo::resetState()
SpinlockLocker l(spinlock);
bytesLoaded=0;
bytesTotal=0;
+ if(!bytesData.isNull())
+ bytesData->setLength(0);
loadStatus=STARTED;
}
@@ -187,6 +195,7 @@ ASFUNCTIONBODY(LoaderInfo,_constructor)
EventDispatcher::_constructor(obj,NULL,0);
th->sharedEvents=_MR(Class<EventDispatcher>::getInstanceS());
th->parameters = _MR(Class<ASObject>::getInstanceS());
+ th->uncaughtErrorEvents = _MR(Class<UncaughtErrorEvents>::getInstanceS());
return NULL;
}
@@ -243,6 +252,17 @@ ASFUNCTIONBODY(LoaderInfo,_getBytesTotal)
return abstract_i(th->bytesTotal);
}
+ASFUNCTIONBODY(LoaderInfo,_getBytes)
+{
+ LoaderInfo* th=static_cast<LoaderInfo*>(obj);
+ if (th->bytesData.isNull())
+ th->bytesData = _NR<ByteArray>(Class<ByteArray>::getInstanceS());
+ if (!th->loader->getContent().isNull())
+ th->bytesData->writeObject(th->loader->getContent().getPtr());
+
+ return th->bytesData.getPtr();
+}
+
ASFUNCTIONBODY(LoaderInfo,_getApplicationDomain)
{
LoaderInfo* th=static_cast<LoaderInfo*>(obj);
@@ -296,19 +316,27 @@ void LoaderThread::execute()
streambuf *sbuf = 0;
if(source==URL)
{
- if(!createDownloader(false, loaderInfo, loaderInfo.getPtr(), false))
+ _R<MemoryStreamCache> cache(_MR(new MemoryStreamCache));
+ if(!createDownloader(cache, loaderInfo, loaderInfo.getPtr(), false))
return;
- downloader->waitForData(); //Wait for some data, making sure our check for failure is working
- if(downloader->hasFailed()) //Check to see if the download failed for some reason
+ sbuf = cache->createReader();
+
+ // Wait for some data, making sure our check for failure is working
+ sbuf->sgetc(); // peek one byte
+ if(downloader->getRequestStatus() == 204) // empty answer
+ return;
+
+ if(cache->hasFailed()) //Check to see if the download failed for some reason
{
LOG(LOG_ERROR, "Loader::execute(): Download of URL failed: " << url);
getVm()->addEvent(loaderInfo,_MR(Class<IOErrorEvent>::getInstanceS()));
+ getVm()->addEvent(loader,_MR(Class<IOErrorEvent>::getInstanceS()));
+ delete sbuf;
// downloader will be deleted in jobFence
return;
}
getVm()->addEvent(loaderInfo,_MR(Class<Event>::getInstanceS("open")));
- sbuf=downloader;
}
else if(source==BYTES)
{
@@ -324,19 +352,15 @@ void LoaderThread::execute()
ParseThread local_pt(s,loaderInfo->applicationDomain,loaderInfo->securityDomain,loader.getPtr(),url.getParsedURL());
local_pt.execute();
- // Delete the bytes container (downloader or bytes_buf)
+ // Delete the bytes container (cache reader or bytes_buf)
+ delete sbuf;
+ sbuf = NULL;
if (source==URL) {
//Acquire the lock to ensure consistency in threadAbort
SpinlockLocker l(downloaderLock);
if(downloader)
getSys()->downloadManager->destroy(downloader);
downloader=NULL;
- sbuf = NULL;
- }
- else if (source==BYTES)
- {
- delete sbuf;
- sbuf = NULL;
}
bytes.reset();
@@ -356,6 +380,7 @@ ASFUNCTIONBODY(Loader,_constructor)
Loader* th=static_cast<Loader*>(obj);
DisplayObjectContainer::_constructor(obj,NULL,0);
th->contentLoaderInfo->setLoaderURL(getSys()->mainClip->getOrigin().getParsedURL());
+ th->uncaughtErrorEvents = _MR(Class<UncaughtErrorEvents>::getInstanceS());
return NULL;
}
@@ -402,12 +427,21 @@ ASFUNCTIONBODY(Loader,load)
//Check if a security domain has been manually set
_NR<SecurityDomain> secDomain;
_NR<SecurityDomain> curSecDomain=ABCVm::getCurrentSecurityDomain(getVm()->currentCallContext);
- if(!context.isNull() && !context->securityDomain.isNull())
+ if(!context.isNull())
{
- //The passed domain must be the current one. See Loader::load specs.
- if(context->securityDomain!=curSecDomain)
- throw Class<SecurityError>::getInstanceS("SecurityError: securityDomain must be current one");
- secDomain=curSecDomain;
+ if (!context->securityDomain.isNull())
+ {
+ //The passed domain must be the current one. See Loader::load specs.
+ if(context->securityDomain!=curSecDomain)
+ throw Class<SecurityError>::getInstanceS("SecurityError: securityDomain must be current one");
+ secDomain=curSecDomain;
+ }
+
+ bool sameDomain = (secDomain == curSecDomain);
+ th->allowCodeImport = !sameDomain || context->getAllowCodeImport();
+
+ if (!context->parameters.isNull())
+ th->contentLoaderInfo->setParameters(context->parameters);
}
//Default is to create a child ApplicationDomain if the file is in the same security context
//otherwise create a child of the system domain. If the security domain is different
@@ -443,6 +477,19 @@ ASFUNCTIONBODY(Loader,load)
SecurityManager::checkURLStaticAndThrow(th->url, ~(SecurityManager::LOCAL_WITH_FILE),
SecurityManager::LOCAL_WITH_FILE | SecurityManager::LOCAL_TRUSTED, true);
+ if (!context.isNull() && context->getCheckPolicyFile())
+ {
+ //TODO: this should be async as it could block if invoked from ExternalInterface
+ SecurityManager::EVALUATIONRESULT evaluationResult;
+ evaluationResult = getSys()->securityManager->evaluatePoliciesURL(th->url, true);
+ if(evaluationResult == SecurityManager::NA_CROSSDOMAIN_POLICY)
+ {
+ // should this dispatch SecurityErrorEvent instead of throwing?
+ throw Class<SecurityError>::getInstanceS(
+ "SecurityError: connection to domain not allowed by securityManager");
+ }
+ }
+
th->incRef();
r->incRef();
LoaderThread *thread=new LoaderThread(_MR(r), _MR(th));
@@ -473,6 +520,11 @@ ASFUNCTIONBODY(Loader,loadBytes)
_NR<SecurityDomain> curSecDomain=ABCVm::getCurrentSecurityDomain(getVm()->currentCallContext);
th->contentLoaderInfo->securityDomain = curSecDomain;
+ th->allowCodeImport = context.isNull() || context->getAllowCodeImport();
+
+ if (!context.isNull() && !context->parameters.isNull())
+ th->contentLoaderInfo->setParameters(context->parameters);
+
if(bytes->getLength()!=0)
{
th->incRef();
@@ -492,6 +544,22 @@ ASFUNCTIONBODY(Loader,_unload)
th->unload();
return NULL;
}
+ASFUNCTIONBODY(Loader,_unloadAndStop)
+{
+ Loader* th=static_cast<Loader*>(obj);
+ th->unload();
+ LOG(LOG_NOT_IMPLEMENTED,"unloadAndStop does not execute any stopping actions");
+ /* TODO: (taken from specs)
+ Sounds are stopped.
+ Stage event listeners are removed.
+ Event listeners for enterFrame, frameConstructed, exitFrame, activate and deactivate are removed.
+ Timers are stopped.
+ Camera and Microphone instances are detached
+ Movie clips are stopped.
+ */
+
+ return NULL;
+}
void Loader::unload()
{
@@ -526,7 +594,7 @@ void Loader::finalize()
contentLoaderInfo.reset();
}
-Loader::Loader(Class_base* c):DisplayObjectContainer(c),content(NullRef),contentLoaderInfo(NullRef),loaded(false)
+Loader::Loader(Class_base* c):DisplayObjectContainer(c),content(NullRef),contentLoaderInfo(NullRef),loaded(false), allowCodeImport(true),uncaughtErrorEvents(NullRef)
{
incRef();
contentLoaderInfo=_MR(Class<LoaderInfo>::getInstanceS(_MR(this)));
@@ -538,16 +606,19 @@ Loader::~Loader()
void Loader::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<DisplayObjectContainer>::getRef());
+ CLASS_SETUP(c, DisplayObjectContainer, _constructor, CLASS_SEALED);
c->setDeclaredMethodByQName("contentLoaderInfo","",Class<IFunction>::getFunction(_getContentLoaderInfo),GETTER_METHOD,true);
c->setDeclaredMethodByQName("content","",Class<IFunction>::getFunction(_getContent),GETTER_METHOD,true);
c->setDeclaredMethodByQName("close","",Class<IFunction>::getFunction(close),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("loadBytes","",Class<IFunction>::getFunction(loadBytes),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("load","",Class<IFunction>::getFunction(load),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("unload","",Class<IFunction>::getFunction(_unload),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("unloadAndStop","",Class<IFunction>::getFunction(_unloadAndStop),NORMAL_METHOD,true);
+ REGISTER_GETTER(c,uncaughtErrorEvents);
}
+ASFUNCTIONBODY_GETTER(Loader,uncaughtErrorEvents);
+
void Loader::threadFinished(IThreadJob* finishedJob)
{
SpinlockLocker l(spinlock);
@@ -590,8 +661,7 @@ void Sprite::finalize()
void Sprite::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<DisplayObjectContainer>::getRef());
+ CLASS_SETUP(c, DisplayObjectContainer, _constructor, CLASS_SEALED);
c->setDeclaredMethodByQName("graphics","",Class<IFunction>::getFunction(_getGraphics),GETTER_METHOD,true);
c->setDeclaredMethodByQName("startDrag","",Class<IFunction>::getFunction(_startDrag),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("stopDrag","",Class<IFunction>::getFunction(_stopDrag),NORMAL_METHOD,true);
@@ -849,8 +919,7 @@ FrameLabel::FrameLabel(Class_base* c, const FrameLabel_data& data):ASObject(c),F
void FrameLabel::sinit(Class_base* c)
{
- c->setConstructor(NULL);
- c->setSuper(Class<ASObject>::getRef());
+ CLASS_SETUP_NO_CONSTRUCTOR(c, ASObject, CLASS_SEALED | CLASS_FINAL);
c->setDeclaredMethodByQName("frame","",Class<IFunction>::getFunction(_getFrame),GETTER_METHOD,true);
c->setDeclaredMethodByQName("name","",Class<IFunction>::getFunction(_getName),GETTER_METHOD,true);
}
@@ -906,8 +975,7 @@ Scene::Scene(Class_base* c, const Scene_data& data, uint32_t _numFrames):ASObjec
void Scene::sinit(Class_base* c)
{
- c->setConstructor(NULL);
- c->setSuper(Class<ASObject>::getRef());
+ CLASS_SETUP_NO_CONSTRUCTOR(c, ASObject, CLASS_SEALED | CLASS_FINAL);
c->setDeclaredMethodByQName("labels","",Class<IFunction>::getFunction(_getLabels),GETTER_METHOD,true);
c->setDeclaredMethodByQName("name","",Class<IFunction>::getFunction(_getName),GETTER_METHOD,true);
c->setDeclaredMethodByQName("numFrames","",Class<IFunction>::getFunction(_getNumFrames),GETTER_METHOD,true);
@@ -999,8 +1067,7 @@ void FrameContainer::addFrameLabel(uint32_t frame, const tiny_string& label)
void MovieClip::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<Sprite>::getRef());
+ CLASS_SETUP(c, Sprite, _constructor, CLASS_DYNAMIC_NOT_FINAL);
c->setDeclaredMethodByQName("currentFrame","",Class<IFunction>::getFunction(_getCurrentFrame),GETTER_METHOD,true);
c->setDeclaredMethodByQName("totalFrames","",Class<IFunction>::getFunction(_getTotalFrames),GETTER_METHOD,true);
c->setDeclaredMethodByQName("framesLoaded","",Class<IFunction>::getFunction(_getFramesLoaded),GETTER_METHOD,true);
@@ -1013,6 +1080,7 @@ void MovieClip::sinit(Class_base* c)
c->setDeclaredMethodByQName("play","",Class<IFunction>::getFunction(play),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("gotoAndStop","",Class<IFunction>::getFunction(gotoAndStop),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("gotoAndPlay","",Class<IFunction>::getFunction(gotoAndPlay),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("prevFrame","",Class<IFunction>::getFunction(prevFrame),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("nextFrame","",Class<IFunction>::getFunction(nextFrame),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("addFrameScript","",Class<IFunction>::getFunction(addFrameScript),NORMAL_METHOD,true);
REGISTER_GETTER_SETTER(c, enabled);
@@ -1164,7 +1232,7 @@ ASObject* MovieClip::gotoAnd(ASObject* const* args, const unsigned int argslen,
{
uint32_t dest=getFrameIdByLabel(args[0]->toString(), sceneName);
if(dest==FRAME_NOT_FOUND)
- throw Class<ArgumentError>::getInstanceS("gotoAndPlay/Stop: label not found");
+ throwError<ArgumentError>(kInvalidArgumentError,stop ? "gotoAndStop: label not found" : "gotoAndPlay: label not found");
next_FP = dest;
}
@@ -1179,7 +1247,7 @@ ASObject* MovieClip::gotoAnd(ASObject* const* args, const unsigned int argslen,
{
LOG(LOG_ERROR, next_FP << "= next_FP >= state.max_FP = " << getFramesLoaded());
/* spec says we should throw an error, but then YT breaks */
- //throw Class<ArgumentError>::getInstanceS("gotoAndPlay/Stop: frame not found");
+ //throwError<ArgumentError>(kInvalidArgumentError,stop ? "gotoAndStop: frame not found" : "gotoAndPlay: frame not found");
next_FP = getFramesLoaded()-1;
}
}
@@ -1211,6 +1279,15 @@ ASFUNCTIONBODY(MovieClip,nextFrame)
return NULL;
}
+ASFUNCTIONBODY(MovieClip,prevFrame)
+{
+ MovieClip* th=static_cast<MovieClip*>(obj);
+ assert_and_throw(th->state.FP<th->getFramesLoaded());
+ th->state.next_FP = th->state.FP-1;
+ th->state.explicit_FP=true;
+ return NULL;
+}
+
ASFUNCTIONBODY(MovieClip,_getFramesLoaded)
{
MovieClip* th=static_cast<MovieClip*>(obj);
@@ -1345,8 +1422,7 @@ void MovieClip::addScene(uint32_t sceneNo, uint32_t startframe, const tiny_strin
void DisplayObjectContainer::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<InteractiveObject>::getRef());
+ CLASS_SETUP(c, InteractiveObject, _constructor, CLASS_SEALED);
c->setDeclaredMethodByQName("numChildren","",Class<IFunction>::getFunction(_getNumChildren),GETTER_METHOD,true);
c->setDeclaredMethodByQName("getChildIndex","",Class<IFunction>::getFunction(_getChildIndex),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("setChildIndex","",Class<IFunction>::getFunction(_setChildIndex),NORMAL_METHOD,true);
@@ -1513,8 +1589,7 @@ void InteractiveObject::buildTraits(ASObject* o)
void InteractiveObject::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<DisplayObject>::getRef());
+ CLASS_SETUP(c, DisplayObject, _constructor, CLASS_SEALED);
c->setDeclaredMethodByQName("mouseEnabled","",Class<IFunction>::getFunction(_setMouseEnabled),SETTER_METHOD,true);
c->setDeclaredMethodByQName("mouseEnabled","",Class<IFunction>::getFunction(_getMouseEnabled),GETTER_METHOD,true);
c->setDeclaredMethodByQName("doubleClickEnabled","",Class<IFunction>::getFunction(_setDoubleClickEnabled),SETTER_METHOD,true);
@@ -1522,11 +1597,13 @@ void InteractiveObject::sinit(Class_base* c)
REGISTER_GETTER_SETTER(c, contextMenu);
REGISTER_GETTER_SETTER(c, tabEnabled);
REGISTER_GETTER_SETTER(c, tabIndex);
+ REGISTER_GETTER_SETTER(c, focusRect);
}
ASFUNCTIONBODY_GETTER_SETTER(InteractiveObject, contextMenu);
ASFUNCTIONBODY_GETTER_SETTER(InteractiveObject, tabEnabled);
ASFUNCTIONBODY_GETTER_SETTER(InteractiveObject, tabIndex);
+ASFUNCTIONBODY_GETTER_SETTER(InteractiveObject, focusRect); // stub
void DisplayObjectContainer::dumpDisplayList(unsigned int level)
{
@@ -1677,12 +1754,11 @@ ASFUNCTIONBODY(DisplayObjectContainer,contains)
DisplayObjectContainer* th=static_cast<DisplayObjectContainer*>(obj);
assert_and_throw(argslen==1);
if(args[0]->getObjectType() == T_CLASS)
- {
return abstract_b(false);
- }
- //Validate object type
- assert_and_throw(args[0] && args[0]->getClass() &&
- args[0]->getClass()->isSubClass(Class<DisplayObject>::getClass()));
+ if (!args[0]->getClass())
+ return abstract_b(false);
+ if (!args[0]->getClass()->isSubClass(Class<DisplayObject>::getClass()))
+ return abstract_b(false);
//Cast to object
DisplayObject* d=static_cast<DisplayObject*>(args[0]);
@@ -1958,8 +2034,7 @@ void Shape::finalize()
void Shape::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<DisplayObject>::getRef());
+ CLASS_SETUP(c, DisplayObject, _constructor, CLASS_SEALED);
c->setDeclaredMethodByQName("graphics","",Class<IFunction>::getFunction(_getGraphics),GETTER_METHOD,true);
}
@@ -1984,8 +2059,9 @@ ASFUNCTIONBODY(Shape,_getGraphics)
void MorphShape::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<DisplayObject>::getRef());
+ // FIXME: should use _constructorNotInstantiatable but then
+ // DefineMorphShapeTag::instance breaks
+ CLASS_SETUP_NO_CONSTRUCTOR(c, DisplayObject, CLASS_SEALED | CLASS_FINAL);
}
void MorphShape::buildTraits(ASObject* o)
@@ -1993,12 +2069,6 @@ void MorphShape::buildTraits(ASObject* o)
//No traits
}
-ASFUNCTIONBODY(MorphShape,_constructor)
-{
- DisplayObject::_constructor(obj,NULL,0);
- return NULL;
-}
-
bool MorphShape::boundsRect(number_t& xmin, number_t& xmax, number_t& ymin, number_t& ymax) const
{
LOG(LOG_NOT_IMPLEMENTED, "MorphShape::boundsRect is a stub");
@@ -2012,8 +2082,12 @@ _NR<DisplayObject> MorphShape::hitTestImpl(_NR<DisplayObject> last, number_t x,
void Stage::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<DisplayObjectContainer>::getRef());
+ CLASS_SETUP(c, DisplayObjectContainer, _constructor, CLASS_SEALED);
+ c->setDeclaredMethodByQName("allowFullScreen","",Class<IFunction>::getFunction(_getAllowFullScreen),GETTER_METHOD,true);
+ c->setDeclaredMethodByQName("allowFullScreenInteractive","",Class<IFunction>::getFunction(_getAllowFullScreenInteractive),GETTER_METHOD,true);
+ c->setDeclaredMethodByQName("colorCorrectionSupport","",Class<IFunction>::getFunction(_getColorCorrectionSupport),GETTER_METHOD,true);
+ c->setDeclaredMethodByQName("fullScreenHeight","",Class<IFunction>::getFunction(_getStageHeight),GETTER_METHOD,true);
+ c->setDeclaredMethodByQName("fullScreenWidth","",Class<IFunction>::getFunction(_getStageWidth),GETTER_METHOD,true);
c->setDeclaredMethodByQName("stageWidth","",Class<IFunction>::getFunction(_getStageWidth),GETTER_METHOD,true);
c->setDeclaredMethodByQName("stageWidth","",Class<IFunction>::getFunction(undefinedFunction),SETTER_METHOD,true);
c->setDeclaredMethodByQName("stageHeight","",Class<IFunction>::getFunction(_getStageHeight),GETTER_METHOD,true);
@@ -2026,23 +2100,65 @@ void Stage::sinit(Class_base* c)
c->setDeclaredMethodByQName("stageVideos","",Class<IFunction>::getFunction(_getStageVideos),GETTER_METHOD,true);
c->setDeclaredMethodByQName("focus","",Class<IFunction>::getFunction(_getFocus),GETTER_METHOD,true);
c->setDeclaredMethodByQName("focus","",Class<IFunction>::getFunction(_setFocus),SETTER_METHOD,true);
+ c->setDeclaredMethodByQName("frameRate","",Class<IFunction>::getFunction(_getFrameRate),GETTER_METHOD,true);
+ c->setDeclaredMethodByQName("frameRate","",Class<IFunction>::getFunction(_setFrameRate),SETTER_METHOD,true);
// override the setter from DisplayObjectContainer
c->setDeclaredMethodByQName("tabChildren","",Class<IFunction>::getFunction(_setTabChildren),SETTER_METHOD,true);
+ c->setDeclaredMethodByQName("wmodeGPU","",Class<IFunction>::getFunction(_getWmodeGPU),GETTER_METHOD,true);
+ c->setDeclaredMethodByQName("invalidate","",Class<IFunction>::getFunction(_invalidate),NORMAL_METHOD,true);
+ REGISTER_GETTER_SETTER(c,align);
+ REGISTER_GETTER_SETTER(c,colorCorrection);
REGISTER_GETTER_SETTER(c,displayState);
+ REGISTER_GETTER_SETTER(c,fullScreenSourceRect);
+ REGISTER_GETTER_SETTER(c,showDefaultContextMenu);
+ REGISTER_GETTER_SETTER(c,quality);
+ REGISTER_GETTER_SETTER(c,stageFocusRect);
}
+ASFUNCTIONBODY_GETTER_SETTER_CB(Stage,align,onAlign);
+ASFUNCTIONBODY_GETTER_SETTER_CB(Stage,colorCorrection,onColorCorrection);
+ASFUNCTIONBODY_GETTER_SETTER_CB(Stage,displayState,onDisplayState);
+ASFUNCTIONBODY_GETTER_SETTER(Stage,showDefaultContextMenu); // stub
+ASFUNCTIONBODY_GETTER_SETTER_CB(Stage,fullScreenSourceRect,onFullScreenSourceRect);
+ASFUNCTIONBODY_GETTER_SETTER(Stage,quality);
+ASFUNCTIONBODY_GETTER_SETTER(Stage,stageFocusRect); // stub
+
void Stage::onDisplayState(const tiny_string&)
{
- LOG(LOG_NOT_IMPLEMENTED,"Stage.displayState = " << displayState);
+ if (displayState != "normal")
+ LOG(LOG_NOT_IMPLEMENTED,"Stage.displayState = " << displayState);
+ displayState = "normal"; // until fullscreen support is implemented
}
-ASFUNCTIONBODY_GETTER_SETTER_CB(Stage,displayState,onDisplayState);
+void Stage::onAlign(const tiny_string& /*oldValue*/)
+{
+ LOG(LOG_NOT_IMPLEMENTED, "Stage.align = " << align);
+}
+
+void Stage::onColorCorrection(const tiny_string& oldValue)
+{
+ if (colorCorrection != "default" &&
+ colorCorrection != "on" &&
+ colorCorrection != "off")
+ {
+ colorCorrection = oldValue;
+ throwError<ArgumentError>(kInvalidEnumError, "colorCorrection");
+ }
+}
+
+void Stage::onFullScreenSourceRect(_NR<Rectangle> /*oldValue*/)
+{
+ LOG(LOG_NOT_IMPLEMENTED, "Stage.fullScreenSourceRect");
+ fullScreenSourceRect.reset();
+}
void Stage::buildTraits(ASObject* o)
{
}
-Stage::Stage(Class_base* c):DisplayObjectContainer(c)
+Stage::Stage(Class_base* c):
+ DisplayObjectContainer(c), colorCorrection("default"),
+ showDefaultContextMenu(true), quality("high")
{
onStage = true;
}
@@ -2152,7 +2268,7 @@ ASFUNCTIONBODY(Stage,_setScaleMode)
ASFUNCTIONBODY(Stage,_getStageVideos)
{
LOG(LOG_NOT_IMPLEMENTED, "Accelerated rendering through StageVideo not implemented, SWF should fall back to Video");
- return Class<Vector>::getInstanceS(Class<StageVideo>::getClass());
+ return Template<Vector>::getInstanceS(Class<StageVideo>::getClass());
}
_NR<InteractiveObject> Stage::getFocusTarget()
@@ -2207,665 +2323,94 @@ ASFUNCTIONBODY(Stage,_setTabChildren)
return NULL;
}
-void Graphics::sinit(Class_base* c)
-{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setDeclaredMethodByQName("clear","",Class<IFunction>::getFunction(clear),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("copyFrom","",Class<IFunction>::getFunction(copyFrom),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("drawRect","",Class<IFunction>::getFunction(drawRect),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("drawRoundRect","",Class<IFunction>::getFunction(drawRoundRect),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("drawCircle","",Class<IFunction>::getFunction(drawCircle),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("drawTriangles","",Class<IFunction>::getFunction(drawTriangles),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("moveTo","",Class<IFunction>::getFunction(moveTo),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("curveTo","",Class<IFunction>::getFunction(curveTo),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("cubicCurveTo","",Class<IFunction>::getFunction(cubicCurveTo),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("lineTo","",Class<IFunction>::getFunction(lineTo),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("lineStyle","",Class<IFunction>::getFunction(lineStyle),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("beginFill","",Class<IFunction>::getFunction(beginFill),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("beginGradientFill","",Class<IFunction>::getFunction(beginGradientFill),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("beginBitmapFill","",Class<IFunction>::getFunction(beginBitmapFill),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("endFill","",Class<IFunction>::getFunction(endFill),NORMAL_METHOD,true);
-}
-
-void Graphics::buildTraits(ASObject* o)
-{
-}
-
-ASFUNCTIONBODY(Graphics,_constructor)
-{
- return NULL;
-}
-
-ASFUNCTIONBODY(Graphics,clear)
-{
- Graphics* th=static_cast<Graphics*>(obj);
- th->checkAndSetScaling();
- th->owner->tokens.clear();
- th->owner->owner->requestInvalidation(getSys());
- return NULL;
-}
-
-ASFUNCTIONBODY(Graphics,moveTo)
-{
- Graphics* th=static_cast<Graphics*>(obj);
- th->checkAndSetScaling();
- assert_and_throw(argslen==2);
-
- th->curX=args[0]->toInt();
- th->curY=args[1]->toInt();
-
- th->owner->tokens.emplace_back(GeomToken(MOVE, Vector2(th->curX, th->curY)));
- return NULL;
-}
-
-ASFUNCTIONBODY(Graphics,lineTo)
-{
- Graphics* th=static_cast<Graphics*>(obj);
- assert_and_throw(argslen==2);
- th->checkAndSetScaling();
-
- int x=args[0]->toInt();
- int y=args[1]->toInt();
-
- th->owner->tokens.emplace_back(GeomToken(STRAIGHT, Vector2(x, y)));
- th->owner->owner->requestInvalidation(getSys());
-
- th->curX=x;
- th->curY=y;
- return NULL;
-}
-
-ASFUNCTIONBODY(Graphics,curveTo)
-{
- Graphics* th=static_cast<Graphics*>(obj);
- assert_and_throw(argslen==4);
- th->checkAndSetScaling();
-
- int controlX=args[0]->toInt();
- int controlY=args[1]->toInt();
-
- int anchorX=args[2]->toInt();
- int anchorY=args[3]->toInt();
-
- th->owner->tokens.emplace_back(GeomToken(CURVE_QUADRATIC,
- Vector2(controlX, controlY),
- Vector2(anchorX, anchorY)));
- th->owner->owner->requestInvalidation(getSys());
-
- th->curX=anchorX;
- th->curY=anchorY;
- return NULL;
-}
-
-ASFUNCTIONBODY(Graphics,cubicCurveTo)
-{
- Graphics* th=static_cast<Graphics*>(obj);
- assert_and_throw(argslen==6);
- th->checkAndSetScaling();
-
- int control1X=args[0]->toInt();
- int control1Y=args[1]->toInt();
-
- int control2X=args[2]->toInt();
- int control2Y=args[3]->toInt();
-
- int anchorX=args[4]->toInt();
- int anchorY=args[5]->toInt();
-
- th->owner->tokens.emplace_back(GeomToken(CURVE_CUBIC,
- Vector2(control1X, control1Y),
- Vector2(control2X, control2Y),
- Vector2(anchorX, anchorY)));
- th->owner->owner->requestInvalidation(getSys());
-
- th->curX=anchorX;
- th->curY=anchorY;
- return NULL;
-}
-
-/* KAPPA = 4 * (sqrt2 - 1) / 3
- * This value was found in a Python prompt:
- *
- * >>> 4.0 * (2**0.5 - 1) / 3.0
- *
- * Source: http://whizkidtech.redprince.net/bezier/circle/
- */
-const double KAPPA = 0.55228474983079356;
-
-ASFUNCTIONBODY(Graphics,drawRoundRect)
-{
- Graphics* th=static_cast<Graphics*>(obj);
- assert_and_throw(argslen==5 || argslen==6);
- th->checkAndSetScaling();
-
- double x=args[0]->toNumber();
- double y=args[1]->toNumber();
- double width=args[2]->toNumber();
- double height=args[3]->toNumber();
- double ellipseWidth=args[4]->toNumber();
- double ellipseHeight;
- if (argslen == 6)
- ellipseHeight=args[5]->toNumber();
-
- if (argslen == 5 || std::isnan(ellipseHeight))
- ellipseHeight=ellipseWidth;
-
- ellipseHeight /= 2;
- ellipseWidth /= 2;
-
- double kappaW = KAPPA * ellipseWidth;
- double kappaH = KAPPA * ellipseHeight;
-
- /*
- * A-----B
- * / \
- * H C
- * | |
- * G D
- * \ /
- * F-----E
- *
- * Flash starts and stops the pen at 'D', so we will too.
- */
-
- // D
- th->owner->tokens.emplace_back(GeomToken(MOVE, Vector2(x+width, y+height-ellipseHeight)));
-
- // D -> E
- th->owner->tokens.emplace_back(GeomToken(CURVE_CUBIC,
- Vector2(x+width, y+height-ellipseHeight+kappaH),
- Vector2(x+width-ellipseWidth+kappaW, y+height),
- Vector2(x+width-ellipseWidth, y+height)));
-
- // E -> F
- th->owner->tokens.emplace_back(GeomToken(STRAIGHT, Vector2(x+ellipseWidth, y+height)));
-
- // F -> G
- th->owner->tokens.emplace_back(GeomToken(CURVE_CUBIC,
- Vector2(x+ellipseWidth-kappaW, y+height),
- Vector2(x, y+height-kappaH),
- Vector2(x, y+height-ellipseHeight)));
-
- // G -> H
- th->owner->tokens.emplace_back(GeomToken(STRAIGHT, Vector2(x, y+ellipseHeight)));
-
- // H -> A
- th->owner->tokens.emplace_back(GeomToken(CURVE_CUBIC,
- Vector2(x, y+ellipseHeight-kappaH),
- Vector2(x+ellipseWidth-kappaW, y),
- Vector2(x+ellipseWidth, y)));
-
- // A -> B
- th->owner->tokens.emplace_back(GeomToken(STRAIGHT, Vector2(x+width-ellipseWidth, y)));
-
- // B -> C
- th->owner->tokens.emplace_back(GeomToken(CURVE_CUBIC,
- Vector2(x+width-ellipseWidth+kappaW, y),
- Vector2(x+width, y+kappaH),
- Vector2(x+width, y+ellipseHeight)));
-
- // C -> D
- th->owner->tokens.emplace_back(GeomToken(STRAIGHT, Vector2(x+width, y+height-ellipseHeight)));
-
- th->owner->owner->requestInvalidation(getSys());
-
- return NULL;
-}
-
-ASFUNCTIONBODY(Graphics,drawCircle)
-{
- Graphics* th=static_cast<Graphics*>(obj);
- assert_and_throw(argslen==3);
- th->checkAndSetScaling();
-
- double x=args[0]->toNumber();
- double y=args[1]->toNumber();
- double radius=args[2]->toNumber();
-
- double kappa = KAPPA*radius;
-
- // right
- th->owner->tokens.emplace_back(GeomToken(MOVE, Vector2(x+radius, y)));
-
- // bottom
- th->owner->tokens.emplace_back(GeomToken(CURVE_CUBIC,
- Vector2(x+radius, y+kappa ),
- Vector2(x+kappa , y+radius),
- Vector2(x , y+radius)));
-
- // left
- th->owner->tokens.emplace_back(GeomToken(CURVE_CUBIC,
- Vector2(x-kappa , y+radius),
- Vector2(x-radius, y+kappa ),
- Vector2(x-radius, y )));
-
- // top
- th->owner->tokens.emplace_back(GeomToken(CURVE_CUBIC,
- Vector2(x-radius, y-kappa ),
- Vector2(x-kappa , y-radius),
- Vector2(x , y-radius)));
-
- // back to right
- th->owner->tokens.emplace_back(GeomToken(CURVE_CUBIC,
- Vector2(x+kappa , y-radius),
- Vector2(x+radius, y-kappa ),
- Vector2(x+radius, y )));
-
- th->owner->owner->requestInvalidation(getSys());
-
- return NULL;
-}
-
-ASFUNCTIONBODY(Graphics,drawRect)
+ASFUNCTIONBODY(Stage,_getFrameRate)
{
- Graphics* th=static_cast<Graphics*>(obj);
- assert_and_throw(argslen==4);
- th->checkAndSetScaling();
-
- int x=args[0]->toInt();
- int y=args[1]->toInt();
- int width=args[2]->toInt();
- int height=args[3]->toInt();
-
- const Vector2 a(x,y);
- const Vector2 b(x+width,y);
- const Vector2 c(x+width,y+height);
- const Vector2 d(x,y+height);
-
- th->owner->tokens.emplace_back(GeomToken(MOVE, a));
- th->owner->tokens.emplace_back(GeomToken(STRAIGHT, b));
- th->owner->tokens.emplace_back(GeomToken(STRAIGHT, c));
- th->owner->tokens.emplace_back(GeomToken(STRAIGHT, d));
- th->owner->tokens.emplace_back(GeomToken(STRAIGHT, a));
- th->owner->owner->requestInvalidation(getSys());
-
- return NULL;
-}
-
-/* Solve for c in the matrix equation
- *
- * [ 1 x1 y1 ] [ c[0] ] [ u1 ]
- * [ 1 x2 y2 ] [ c[1] ] = [ u2 ]
- * [ 1 x3 y3 ] [ c[2] ] [ u3 ]
- *
- * The result will be put in the output parameter c.
- */
-void Graphics::solveVertexMapping(double x1, double y1,
- double x2, double y2,
- double x3, double y3,
- double u1, double u2, double u3,
- double c[3])
-{
- double eps = 1e-15;
- double det = fabs(x2*y3 + x1*y2 + y1*x3 - y2*x3 - x1*y3 - y1*x2);
-
- if (det < eps)
- {
- // Degenerate matrix
- c[0] = c[1] = c[2] = 0;
- return;
- }
-
- // Symbolic solution of the equation by Gaussian elimination
- if (fabs(x1-x2) < eps)
- {
- c[2] = (u2-u1)/(y2-y1);
- c[1] = (u3 - u1 - (y3-y1)*c[2])/(x3-x1);
- c[0] = u1 - x1*c[1] - y1*c[2];
- }
+ Stage* th=obj->as<Stage>();
+ _NR<RootMovieClip> root = th->getRoot();
+ if (root.isNull())
+ return abstract_d(getSys()->mainClip->getFrameRate());
else
- {
- c[2] = ((x2-x1)*(u3-u1) - (x3-x1)*(u2-u1))/((y3-y1)*(x2-x1) - (x3-x1)*(y2-y1));
- c[1] = (u2 - u1 - (y2-y1)*c[2])/(x2-x1);
- c[0] = u1 - x1*c[1] - y1*c[2];
- }
+ return abstract_d(root->getFrameRate());
}
-ASFUNCTIONBODY(Graphics,drawTriangles)
+ASFUNCTIONBODY(Stage,_setFrameRate)
{
- Graphics* th=static_cast<Graphics*>(obj);
- _NR<Vector> vertices;
- _NR<Vector> indices;
- _NR<Vector> uvtData;
- tiny_string culling;
- ARG_UNPACK (vertices) (indices, NullRef) (uvtData, NullRef) (culling, "none");
-
- if (culling != "none")
- LOG(LOG_NOT_IMPLEMENTED, "Graphics.drawTriangles doesn't support culling");
-
- // Validate the parameters
- if ((indices.isNull() && (vertices->size() % 6 != 0)) ||
- (!indices.isNull() && (indices->size() % 3 != 0)))
- {
- throwError<ArgumentError>(kInvalidParamError);
- }
-
- unsigned int numvertices=vertices->size()/2;
- unsigned int numtriangles;
- bool has_uvt=false;
- int uvtElemSize=2;
- int texturewidth=0;
- int textureheight=0;
-
- if (indices.isNull())
- numtriangles=numvertices/3;
- else
- numtriangles=indices->size()/3;
-
- if (!uvtData.isNull())
- {
- if (uvtData->size()==2*numvertices)
- {
- has_uvt=true;
- uvtElemSize=2; /* (u, v) */
- }
- else if (uvtData->size()==3*numvertices)
- {
- has_uvt=true;
- uvtElemSize=3; /* (u, v, t), t is ignored */
- LOG(LOG_NOT_IMPLEMENTED, "Graphics.drawTriangles doesn't support t in uvtData parameter");
- }
- else
- {
- throwError<ArgumentError>(kInvalidParamError);
- }
-
- th->owner->getTextureSize(&texturewidth, &textureheight);
- }
-
- // According to testing, drawTriangles first fills the current
- // path and creates a new path, but keeps the source.
- th->owner->tokens.emplace_back(FILL_KEEP_SOURCE);
-
- if (has_uvt && (texturewidth==0 || textureheight==0))
- return NULL;
-
- // Construct the triangles
- for (unsigned int i=0; i<numtriangles; i++)
- {
- double x[3], y[3], u[3]={0}, v[3]={0};
- for (unsigned int j=0; j<3; j++)
- {
- unsigned int vertex;
- if (indices.isNull())
- vertex=3*i+j;
- else
- vertex=indices->at(3*i+j)->toInt();
-
- x[j]=vertices->at(2*vertex)->toNumber();
- y[j]=vertices->at(2*vertex+1)->toNumber();
-
- if (has_uvt)
- {
- u[j]=uvtData->at(vertex*uvtElemSize)->toNumber()*texturewidth;
- v[j]=uvtData->at(vertex*uvtElemSize+1)->toNumber()*textureheight;
- }
- }
-
- Vector2 a(x[0], y[0]);
- Vector2 b(x[1], y[1]);
- Vector2 c(x[2], y[2]);
-
- th->owner->tokens.emplace_back(GeomToken(MOVE, a));
- th->owner->tokens.emplace_back(GeomToken(STRAIGHT, b));
- th->owner->tokens.emplace_back(GeomToken(STRAIGHT, c));
- th->owner->tokens.emplace_back(GeomToken(STRAIGHT, a));
-
- if (has_uvt)
- {
- double t[6];
-
- // Use the known (x, y) and (u, v)
- // correspondences to compute a transformation
- // t from (x, y) space into (u, v) space
- // (cairo needs the mapping in this
- // direction).
- //
- // u = t[0] + t[1]*x + t[2]*y
- // v = t[3] + t[4]*x + t[5]*y
- //
- // u and v parts can be solved separately.
- th->solveVertexMapping(x[0], y[0], x[1], y[1], x[2], y[2],
- u[0], u[1], u[2], t);
- th->solveVertexMapping(x[0], y[0], x[1], y[1], x[2], y[2],
- v[0], v[1], v[2], &t[3]);
-
- MATRIX m(t[1], t[5], t[4], t[2], t[0], t[3]);
- th->owner->tokens.emplace_back(GeomToken(FILL_TRANSFORM_TEXTURE, m));
- }
- }
-
- th->owner->owner->requestInvalidation(getSys());
-
+ Stage* th=obj->as<Stage>();
+ number_t frameRate;
+ ARG_UNPACK(frameRate);
+ _NR<RootMovieClip> root = th->getRoot();
+ if (!root.isNull())
+ root->setFrameRate(frameRate);
return NULL;
}
-ASFUNCTIONBODY(Graphics,lineStyle)
+ASFUNCTIONBODY(Stage,_getAllowFullScreen)
{
- Graphics* th=static_cast<Graphics*>(obj);
- th->checkAndSetScaling();
-
- if (argslen == 0)
- {
- th->owner->tokens.emplace_back(CLEAR_STROKE);
- return NULL;
- }
- uint32_t color = 0;
- uint8_t alpha = 255;
- UI16_SWF thickness = UI16_SWF(imax(args[0]->toNumber() * 20, 0));
- if (argslen >= 2)
- color = args[1]->toUInt();
- if (argslen >= 3)
- alpha = uint8_t(args[1]->toNumber() * 255);
-
- // TODO: pixel hinting, scaling, caps, miter, joints
-
- LINESTYLE2 style(0xff);
- style.Color = RGBA(color, alpha);
- style.Width = thickness;
- th->owner->tokens.emplace_back(GeomToken(SET_STROKE, style));
- return NULL;
+ return abstract_b(false); // until fullscreen support is implemented
}
-ASFUNCTIONBODY(Graphics,beginGradientFill)
+ASFUNCTIONBODY(Stage,_getAllowFullScreenInteractive)
{
- Graphics* th=static_cast<Graphics*>(obj);
- assert_and_throw(argslen>=4);
- th->checkAndSetScaling();
-
- FILLSTYLE style(0xff);
-
- assert_and_throw(args[1]->getObjectType()==T_ARRAY);
- Array* colors=Class<Array>::cast(args[1]);
-
- assert_and_throw(args[2]->getObjectType()==T_ARRAY);
- Array* alphas=Class<Array>::cast(args[2]);
-
- //assert_and_throw(args[3]->getObjectType()==T_ARRAY);
- //Work around for bug in YouTube player of July 13 2011
- if(args[3]->getObjectType()==T_UNDEFINED)
- return NULL;
- Array* ratios=Class<Array>::cast(args[3]);
-
- int NumGradient = colors->size();
- if (NumGradient != (int)alphas->size() || NumGradient != (int)ratios->size())
- return NULL;
-
- if (NumGradient < 1 || NumGradient > 15)
- return NULL;
-
- const tiny_string& type=args[0]->toString();
-
- if(type == "linear")
- style.FillStyleType=LINEAR_GRADIENT;
- else if(type == "radial")
- style.FillStyleType=RADIAL_GRADIENT;
- else
- return NULL;
-
- // Don't support FOCALGRADIENT for now.
- GRADIENT grad(0xff);
- for(int i = 0; i < NumGradient; i ++)
- {
- GRADRECORD record(0xff);
- record.Color = RGBA(colors->at(i)->toUInt(), (int)alphas->at(i)->toNumber()*255);
- record.Ratio = UI8(ratios->at(i)->toUInt());
- grad.GradientRecords.push_back(record);
- }
-
- if(argslen > 4 && args[4]->getClass()==Class<Matrix>::getClass())
- {
- style.Matrix = static_cast<Matrix*>(args[4])->getMATRIX();
- //Conversion from twips to pixels
- cairo_matrix_scale(&style.Matrix, 1.0f/20.0f, 1.0f/20.0f);
- }
- else
- {
- cairo_matrix_scale(&style.Matrix, 100.0/16384.0, 100.0/16384.0);
- }
-
- if(argslen > 5)
- {
- const tiny_string& spread=args[5]->toString();
- if (spread == "pad")
- grad.SpreadMode = 0;
- else if (spread == "reflect")
- grad.SpreadMode = 1;
- else if (spread == "repeat")
- grad.SpreadMode = 2;
- }
- else
- {
- //default is pad
- grad.SpreadMode = 0;
- }
-
-
- if(argslen > 6)
- {
- const tiny_string& interp=args[6]->toString();
- if (interp == "rgb")
- grad.InterpolationMode = 0;
- else if (interp == "linearRGB")
- grad.InterpolationMode = 1;
- }
- else
- {
- //default is rgb
- grad.InterpolationMode = 0;
- }
-
- style.Gradient = grad;
- th->owner->tokens.emplace_back(GeomToken(SET_FILL, style));
- return NULL;
+ return abstract_b(false);
}
-ASFUNCTIONBODY(Graphics,beginBitmapFill)
+ASFUNCTIONBODY(Stage,_getColorCorrectionSupport)
{
- Graphics* th = obj->as<Graphics>();
- _NR<BitmapData> bitmap;
- _NR<Matrix> matrix;
- bool repeat, smooth;
- ARG_UNPACK (bitmap) (matrix, NullRef) (repeat, true) (smooth, false);
-
- if(bitmap.isNull())
- return NULL;
-
- th->checkAndSetScaling();
- FILLSTYLE style(0xff);
- if(repeat && smooth)
- style.FillStyleType = REPEATING_BITMAP;
- else if(repeat && !smooth)
- style.FillStyleType = NON_SMOOTHED_REPEATING_BITMAP;
- else if(!repeat && smooth)
- style.FillStyleType = CLIPPED_BITMAP;
- else
- style.FillStyleType = NON_SMOOTHED_CLIPPED_BITMAP;
-
- if(!matrix.isNull())
- style.Matrix = matrix->getMATRIX();
-
- style.bitmap = bitmap->getBitmapContainer();
- th->owner->tokens.emplace_back(GeomToken(SET_FILL, style));
- return NULL;
+ return abstract_b(false); // until color correction is implemented
}
-ASFUNCTIONBODY(Graphics,beginFill)
+ASFUNCTIONBODY(Stage,_getWmodeGPU)
{
- Graphics* th=static_cast<Graphics*>(obj);
- th->checkAndSetScaling();
- uint32_t color=0;
- uint8_t alpha=255;
- if(argslen>=1)
- color=args[0]->toUInt();
- if(argslen>=2)
- alpha=(uint8_t(args[1]->toNumber()*0xff));
- FILLSTYLE style(0xff);
- style.FillStyleType = SOLID_FILL;
- style.Color = RGBA(color, alpha);
- th->owner->tokens.emplace_back(GeomToken(SET_FILL, style));
- return NULL;
+ return abstract_b(false);
}
-
-ASFUNCTIONBODY(Graphics,endFill)
+ASFUNCTIONBODY(Stage,_invalidate)
{
- Graphics* th=static_cast<Graphics*>(obj);
- th->checkAndSetScaling();
- th->owner->tokens.emplace_back(CLEAR_FILL);
+ LOG(LOG_NOT_IMPLEMENTED,"invalidate not implemented yet");
+ // TODO this crashes lightspark
+ //Stage* th=obj->as<Stage>();
+ //_R<FlushInvalidationQueueEvent> event=_MR(new (getSys()->unaccountedMemory) FlushInvalidationQueueEvent());
+ //getVm()->addEvent(_MR(th),event);
return NULL;
}
-ASFUNCTIONBODY(Graphics,copyFrom)
-{
- Graphics* th=static_cast<Graphics*>(obj);
- _NR<Graphics> source;
- ARG_UNPACK(source);
- if (source.isNull())
- return NULL;
-
- th->owner->tokens.assign(source->owner->tokens.begin(),
- source->owner->tokens.end());
- return NULL;
-}
-
-void LineScaleMode::sinit(Class_base* c)
-{
- c->setConstructor(NULL);
- c->setVariableByQName("HORIZONTAL","",Class<ASString>::getInstanceS("horizontal"),DECLARED_TRAIT);
- c->setVariableByQName("NONE","",Class<ASString>::getInstanceS("none"),DECLARED_TRAIT);
- c->setVariableByQName("NORMAL","",Class<ASString>::getInstanceS("normal"),DECLARED_TRAIT);
- c->setVariableByQName("VERTICAL","",Class<ASString>::getInstanceS("vertical"),DECLARED_TRAIT);
-}
void StageScaleMode::sinit(Class_base* c)
{
- c->setConstructor(NULL);
- c->setVariableByQName("EXACT_FIT","",Class<ASString>::getInstanceS("exactFit"),DECLARED_TRAIT);
- c->setVariableByQName("NO_BORDER","",Class<ASString>::getInstanceS("noBorder"),DECLARED_TRAIT);
- c->setVariableByQName("NO_SCALE","",Class<ASString>::getInstanceS("noScale"),DECLARED_TRAIT);
- c->setVariableByQName("SHOW_ALL","",Class<ASString>::getInstanceS("showAll"),DECLARED_TRAIT);
+ CLASS_SETUP_NO_CONSTRUCTOR(c, ASObject, CLASS_SEALED | CLASS_FINAL);
+ c->setVariableByQName("EXACT_FIT","",Class<ASString>::getInstanceS("exactFit"),CONSTANT_TRAIT);
+ c->setVariableByQName("NO_BORDER","",Class<ASString>::getInstanceS("noBorder"),CONSTANT_TRAIT);
+ c->setVariableByQName("NO_SCALE","",Class<ASString>::getInstanceS("noScale"),CONSTANT_TRAIT);
+ c->setVariableByQName("SHOW_ALL","",Class<ASString>::getInstanceS("showAll"),CONSTANT_TRAIT);
}
void StageAlign::sinit(Class_base* c)
{
- c->setConstructor(NULL);
- c->setVariableByQName("TOP_LEFT","",Class<ASString>::getInstanceS("TL"),DECLARED_TRAIT);
+ CLASS_SETUP_NO_CONSTRUCTOR(c, ASObject, CLASS_SEALED | CLASS_FINAL);
+ c->setVariableByQName("BOTTOM","",Class<ASString>::getInstanceS("B"),CONSTANT_TRAIT);
+ c->setVariableByQName("BOTTOM_LEFT","",Class<ASString>::getInstanceS("BL"),CONSTANT_TRAIT);
+ c->setVariableByQName("BOTTOM_RIGHT","",Class<ASString>::getInstanceS("BR"),CONSTANT_TRAIT);
+ c->setVariableByQName("LEFT","",Class<ASString>::getInstanceS("L"),CONSTANT_TRAIT);
+ c->setVariableByQName("RIGHT","",Class<ASString>::getInstanceS("R"),CONSTANT_TRAIT);
+ c->setVariableByQName("TOP","",Class<ASString>::getInstanceS("T"),CONSTANT_TRAIT);
+ c->setVariableByQName("TOP_LEFT","",Class<ASString>::getInstanceS("TL"),CONSTANT_TRAIT);
+ c->setVariableByQName("TOP_RIGHT","",Class<ASString>::getInstanceS("TR"),CONSTANT_TRAIT);
}
void StageQuality::sinit(Class_base* c)
{
- c->setConstructor(NULL);
- c->setVariableByQName("BEST","",Class<ASString>::getInstanceS("best"),DECLARED_TRAIT);
- c->setVariableByQName("HIGH","",Class<ASString>::getInstanceS("high"),DECLARED_TRAIT);
- c->setVariableByQName("LOW","",Class<ASString>::getInstanceS("low"),DECLARED_TRAIT);
- c->setVariableByQName("MEDIUM","",Class<ASString>::getInstanceS("medium"),DECLARED_TRAIT);
+ CLASS_SETUP_NO_CONSTRUCTOR(c, ASObject, CLASS_SEALED | CLASS_FINAL);
+ c->setVariableByQName("BEST","",Class<ASString>::getInstanceS("best"),CONSTANT_TRAIT);
+ c->setVariableByQName("HIGH","",Class<ASString>::getInstanceS("high"),CONSTANT_TRAIT);
+ c->setVariableByQName("LOW","",Class<ASString>::getInstanceS("low"),CONSTANT_TRAIT);
+ c->setVariableByQName("MEDIUM","",Class<ASString>::getInstanceS("medium"),CONSTANT_TRAIT);
}
void StageDisplayState::sinit(Class_base* c)
{
- c->setConstructor(NULL);
- c->setVariableByQName("FULL_SCREEN","",Class<ASString>::getInstanceS("fullScreen"),DECLARED_TRAIT);
- c->setVariableByQName("NORMAL","",Class<ASString>::getInstanceS("normal"),DECLARED_TRAIT);
+ CLASS_SETUP_NO_CONSTRUCTOR(c, ASObject, CLASS_SEALED | CLASS_FINAL);
+ c->setVariableByQName("FULL_SCREEN","",Class<ASString>::getInstanceS("fullScreen"),CONSTANT_TRAIT);
+ c->setVariableByQName("FULL_SCREEN_INTERACTIVE","",Class<ASString>::getInstanceS("fullScreenInteractive"),CONSTANT_TRAIT);
+ c->setVariableByQName("NORMAL","",Class<ASString>::getInstanceS("normal"),CONSTANT_TRAIT);
}
Bitmap::Bitmap(Class_base* c, _NR<LoaderInfo> li, std::istream *s, FILE_TYPE type):
@@ -2934,8 +2479,7 @@ void Bitmap::finalize()
void Bitmap::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<DisplayObject>::getRef());
+ CLASS_SETUP(c, DisplayObject, _constructor, CLASS_SEALED);
REGISTER_GETTER_SETTER(c,bitmapData);
REGISTER_GETTER_SETTER(c,smoothing);
}
@@ -3027,8 +2571,7 @@ IntSize Bitmap::getBitmapSize() const
void SimpleButton::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<InteractiveObject>::getRef());
+ CLASS_SETUP(c, InteractiveObject, _constructor, CLASS_SEALED);
c->setDeclaredMethodByQName("upState","",Class<IFunction>::getFunction(_getUpState),GETTER_METHOD,true);
c->setDeclaredMethodByQName("upState","",Class<IFunction>::getFunction(_setUpState),SETTER_METHOD,true);
c->setDeclaredMethodByQName("downState","",Class<IFunction>::getFunction(_getDownState),GETTER_METHOD,true);
@@ -3039,6 +2582,8 @@ void SimpleButton::sinit(Class_base* c)
c->setDeclaredMethodByQName("hitTestState","",Class<IFunction>::getFunction(_setHitTestState),SETTER_METHOD,true);
c->setDeclaredMethodByQName("enabled","",Class<IFunction>::getFunction(_getEnabled),GETTER_METHOD,true);
c->setDeclaredMethodByQName("enabled","",Class<IFunction>::getFunction(_setEnabled),SETTER_METHOD,true);
+ c->setDeclaredMethodByQName("useHandCursor","",Class<IFunction>::getFunction(_getUseHandCursor),GETTER_METHOD,true);
+ c->setDeclaredMethodByQName("useHandCursor","",Class<IFunction>::getFunction(_setUseHandCursor),SETTER_METHOD,true);
}
void SimpleButton::buildTraits(ASObject* o)
@@ -3273,43 +2818,62 @@ ASFUNCTIONBODY(SimpleButton,_getUseHandCursor)
void GradientType::sinit(Class_base* c)
{
- c->setConstructor(NULL);
- c->setVariableByQName("LINEAR","",Class<ASString>::getInstanceS("linear"),DECLARED_TRAIT);
- c->setVariableByQName("RADIAL","",Class<ASString>::getInstanceS("radial"),DECLARED_TRAIT);
+ CLASS_SETUP_NO_CONSTRUCTOR(c, ASObject, CLASS_SEALED | CLASS_FINAL);
+ c->setVariableByQName("LINEAR","",Class<ASString>::getInstanceS("linear"),CONSTANT_TRAIT);
+ c->setVariableByQName("RADIAL","",Class<ASString>::getInstanceS("radial"),CONSTANT_TRAIT);
}
void BlendMode::sinit(Class_base* c)
{
- c->setConstructor(NULL);
- c->setVariableByQName("ADD","",Class<ASString>::getInstanceS("add"),DECLARED_TRAIT);
- c->setVariableByQName("ALPHA","",Class<ASString>::getInstanceS("alpha"),DECLARED_TRAIT);
- c->setVariableByQName("DARKEN","",Class<ASString>::getInstanceS("darken"),DECLARED_TRAIT);
- c->setVariableByQName("DIFFERENCE","",Class<ASString>::getInstanceS("difference"),DECLARED_TRAIT);
- c->setVariableByQName("ERASE","",Class<ASString>::getInstanceS("erase"),DECLARED_TRAIT);
- c->setVariableByQName("HARDLIGHT","",Class<ASString>::getInstanceS("hardlight"),DECLARED_TRAIT);
- c->setVariableByQName("INVERT","",Class<ASString>::getInstanceS("invert"),DECLARED_TRAIT);
- c->setVariableByQName("LAYER","",Class<ASString>::getInstanceS("layer"),DECLARED_TRAIT);
- c->setVariableByQName("LIGHTEN","",Class<ASString>::getInstanceS("lighten"),DECLARED_TRAIT);
- c->setVariableByQName("MULTIPLY","",Class<ASString>::getInstanceS("multiply"),DECLARED_TRAIT);
- c->setVariableByQName("NORMAL","",Class<ASString>::getInstanceS("normal"),DECLARED_TRAIT);
- c->setVariableByQName("OVERLAY","",Class<ASString>::getInstanceS("overlay"),DECLARED_TRAIT);
- c->setVariableByQName("SCREEN","",Class<ASString>::getInstanceS("screen"),DECLARED_TRAIT);
- c->setVariableByQName("SUBSTRACT","",Class<ASString>::getInstanceS("substract"),DECLARED_TRAIT);
+ CLASS_SETUP_NO_CONSTRUCTOR(c, ASObject, CLASS_SEALED | CLASS_FINAL);
+ c->setVariableByQName("ADD","",Class<ASString>::getInstanceS("add"),CONSTANT_TRAIT);
+ c->setVariableByQName("ALPHA","",Class<ASString>::getInstanceS("alpha"),CONSTANT_TRAIT);
+ c->setVariableByQName("DARKEN","",Class<ASString>::getInstanceS("darken"),CONSTANT_TRAIT);
+ c->setVariableByQName("DIFFERENCE","",Class<ASString>::getInstanceS("difference"),CONSTANT_TRAIT);
+ c->setVariableByQName("ERASE","",Class<ASString>::getInstanceS("erase"),CONSTANT_TRAIT);
+ c->setVariableByQName("HARDLIGHT","",Class<ASString>::getInstanceS("hardlight"),CONSTANT_TRAIT);
+ c->setVariableByQName("INVERT","",Class<ASString>::getInstanceS("invert"),CONSTANT_TRAIT);
+ c->setVariableByQName("LAYER","",Class<ASString>::getInstanceS("layer"),CONSTANT_TRAIT);
+ c->setVariableByQName("LIGHTEN","",Class<ASString>::getInstanceS("lighten"),CONSTANT_TRAIT);
+ c->setVariableByQName("MULTIPLY","",Class<ASString>::getInstanceS("multiply"),CONSTANT_TRAIT);
+ c->setVariableByQName("NORMAL","",Class<ASString>::getInstanceS("normal"),CONSTANT_TRAIT);
+ c->setVariableByQName("OVERLAY","",Class<ASString>::getInstanceS("overlay"),CONSTANT_TRAIT);
+ c->setVariableByQName("SCREEN","",Class<ASString>::getInstanceS("screen"),CONSTANT_TRAIT);
+ c->setVariableByQName("SUBTRACT","",Class<ASString>::getInstanceS("subtract"),CONSTANT_TRAIT);
}
void SpreadMethod::sinit(Class_base* c)
{
- c->setConstructor(NULL);
- c->setVariableByQName("PAD","",Class<ASString>::getInstanceS("pad"),DECLARED_TRAIT);
- c->setVariableByQName("REFLECT","",Class<ASString>::getInstanceS("reflect"),DECLARED_TRAIT);
- c->setVariableByQName("REPEAT","",Class<ASString>::getInstanceS("repeat"),DECLARED_TRAIT);
+ CLASS_SETUP_NO_CONSTRUCTOR(c, ASObject, CLASS_SEALED | CLASS_FINAL);
+ c->setVariableByQName("PAD","",Class<ASString>::getInstanceS("pad"),CONSTANT_TRAIT);
+ c->setVariableByQName("REFLECT","",Class<ASString>::getInstanceS("reflect"),CONSTANT_TRAIT);
+ c->setVariableByQName("REPEAT","",Class<ASString>::getInstanceS("repeat"),CONSTANT_TRAIT);
}
void InterpolationMethod::sinit(Class_base* c)
{
- c->setConstructor(NULL);
- c->setVariableByQName("RGB","",Class<ASString>::getInstanceS("rgb"),DECLARED_TRAIT);
- c->setVariableByQName("LINEAR_RGB","",Class<ASString>::getInstanceS("linearRGB"),DECLARED_TRAIT);
+ CLASS_SETUP_NO_CONSTRUCTOR(c, ASObject, CLASS_SEALED | CLASS_FINAL);
+ c->setVariableByQName("RGB","",Class<ASString>::getInstanceS("rgb"),CONSTANT_TRAIT);
+ c->setVariableByQName("LINEAR_RGB","",Class<ASString>::getInstanceS("linearRGB"),CONSTANT_TRAIT);
+}
+
+void GraphicsPathCommand::sinit(Class_base* c)
+{
+ CLASS_SETUP_NO_CONSTRUCTOR(c, ASObject, CLASS_SEALED | CLASS_FINAL);
+ c->setVariableByQName("CUBIC_CURVE_TO","",abstract_i(6),CONSTANT_TRAIT);
+ c->setVariableByQName("CURVE_TO","",abstract_i(3),CONSTANT_TRAIT);
+ c->setVariableByQName("LINE_TO","",abstract_i(2),CONSTANT_TRAIT);
+ c->setVariableByQName("MOVE_TO","",abstract_i(1),CONSTANT_TRAIT);
+ c->setVariableByQName("NO_OP","",abstract_i(0),CONSTANT_TRAIT);
+ c->setVariableByQName("WIDE_LINE_TO","",abstract_i(5),CONSTANT_TRAIT);
+ c->setVariableByQName("WIDE_MOVE_TO","",abstract_i(4),CONSTANT_TRAIT);
+}
+
+void GraphicsPathWinding::sinit(Class_base* c)
+{
+ CLASS_SETUP_NO_CONSTRUCTOR(c, ASObject, CLASS_SEALED | CLASS_FINAL);
+ c->setVariableByQName("EVEN_ODD","",Class<ASString>::getInstanceS("evenOdd"),CONSTANT_TRAIT);
+ c->setVariableByQName("NON_ZERO","",Class<ASString>::getInstanceS("nonZero"),CONSTANT_TRAIT);
}
/* Go through the hierarchy and add all
@@ -3456,8 +3020,7 @@ void MovieClip::constructionComplete()
void AVM1Movie::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<DisplayObject>::getRef());
+ CLASS_SETUP(c, DisplayObject, _constructor, CLASS_SEALED);
}
void AVM1Movie::buildTraits(ASObject* o)
@@ -3473,8 +3036,7 @@ ASFUNCTIONBODY(AVM1Movie,_constructor)
void Shader::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASObject>::getRef());
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED);
}
ASFUNCTIONBODY(Shader,_constructor)
@@ -3485,12 +3047,11 @@ ASFUNCTIONBODY(Shader,_constructor)
void BitmapDataChannel::sinit(Class_base* c)
{
- c->setConstructor(NULL);
- c->setSuper(Class<ASObject>::getRef());
- c->setVariableByQName("ALPHA","",abstract_ui(8),DECLARED_TRAIT);
- c->setVariableByQName("BLUE","",abstract_ui(4),DECLARED_TRAIT);
- c->setVariableByQName("GREEN","",abstract_ui(2),DECLARED_TRAIT);
- c->setVariableByQName("RED","",abstract_ui(1),DECLARED_TRAIT);
+ CLASS_SETUP_NO_CONSTRUCTOR(c, ASObject, CLASS_SEALED | CLASS_FINAL);
+ c->setVariableByQName("ALPHA","",abstract_ui(8),CONSTANT_TRAIT);
+ c->setVariableByQName("BLUE","",abstract_ui(4),CONSTANT_TRAIT);
+ c->setVariableByQName("GREEN","",abstract_ui(2),CONSTANT_TRAIT);
+ c->setVariableByQName("RED","",abstract_ui(1),CONSTANT_TRAIT);
}
unsigned int BitmapDataChannel::channelShift(uint32_t channelConstant)
@@ -3515,3 +3076,12 @@ unsigned int BitmapDataChannel::channelShift(uint32_t channelConstant)
return shift;
}
+
+void LineScaleMode::sinit(Class_base* c)
+{
+ CLASS_SETUP_NO_CONSTRUCTOR(c, ASObject, CLASS_SEALED | CLASS_FINAL);
+ c->setVariableByQName("HORIZONTAL","",Class<ASString>::getInstanceS("horizontal"),CONSTANT_TRAIT);
+ c->setVariableByQName("NONE","",Class<ASString>::getInstanceS("none"),CONSTANT_TRAIT);
+ c->setVariableByQName("NORMAL","",Class<ASString>::getInstanceS("normal"),CONSTANT_TRAIT);
+ c->setVariableByQName("VERTICAL","",Class<ASString>::getInstanceS("vertical"),CONSTANT_TRAIT);
+}
diff --git a/src/scripting/flash/display/flashdisplay.h b/src/scripting/flash/display/flashdisplay.h
index 451821e..8a9f24f 100644
--- a/src/scripting/flash/display/flashdisplay.h
+++ b/src/scripting/flash/display/flashdisplay.h
@@ -31,6 +31,7 @@
#include "backends/netutils.h"
#include "scripting/flash/display/DisplayObject.h"
#include "scripting/flash/display/TokenContainer.h"
+#include "scripting/flash/ui/ContextMenu.h"
namespace lightspark
{
@@ -43,6 +44,10 @@ class RenderContext;
class ApplicationDomain;
class SecurityDomain;
class BitmapData;
+class Matrix;
+class Vector;
+class Graphics;
+class Rectangle;
class InteractiveObject: public DisplayObject
{
@@ -61,9 +66,10 @@ protected:
~InteractiveObject();
public:
InteractiveObject(Class_base* c);
- ASPROPERTY_GETTER_SETTER(_NR<ASObject>,contextMenu); // TOOD: should be NativeMenu
+ ASPROPERTY_GETTER_SETTER(_NR<ContextMenu>,contextMenu); // TOOD: should be NativeMenu
ASPROPERTY_GETTER_SETTER(bool,tabEnabled);
ASPROPERTY_GETTER_SETTER(int32_t,tabIndex);
+ ASPROPERTY_GETTER_SETTER(_NR<ASObject>,focusRect);
ASFUNCTION(_constructor);
ASFUNCTION(_setMouseEnabled);
ASFUNCTION(_getMouseEnabled);
@@ -171,55 +177,6 @@ public:
ASFUNCTION(_setUseHandCursor);
};
-/* This objects paints to its owners tokens */
-class Graphics: public ASObject
-{
-private:
- int curX, curY;
- TokenContainer *const owner;
- //TODO: Add spinlock
- void checkAndSetScaling()
- {
- if(owner->scaling != 1.0f)
- {
- owner->scaling = 1.0f;
- owner->tokens.clear();
- assert(curX == 0 && curY == 0);
- }
- }
- static void solveVertexMapping(double x1, double y1,
- double x2, double y2,
- double x3, double y3,
- double u1, double u2, double u3,
- double c[3]);
-public:
- Graphics(Class_base* c):ASObject(c),curX(0),curY(0),owner(NULL)
- {
- throw RunTimeException("Cannot instantiate a Graphics object");
- }
- Graphics(Class_base* c, TokenContainer* _o)
- : ASObject(c),curX(0),curY(0),owner(_o) {}
- static void sinit(Class_base* c);
- static void buildTraits(ASObject* o);
- ASFUNCTION(_constructor);
- ASFUNCTION(lineStyle);
- ASFUNCTION(beginFill);
- ASFUNCTION(beginGradientFill);
- ASFUNCTION(beginBitmapFill);
- ASFUNCTION(endFill);
- ASFUNCTION(drawRect);
- ASFUNCTION(drawRoundRect);
- ASFUNCTION(drawCircle);
- ASFUNCTION(drawTriangles);
- ASFUNCTION(moveTo);
- ASFUNCTION(lineTo);
- ASFUNCTION(curveTo);
- ASFUNCTION(cubicCurveTo);
- ASFUNCTION(clear);
- ASFUNCTION(copyFrom);
-};
-
-
class Shape: public DisplayObject, public TokenContainer
{
protected:
@@ -253,7 +210,6 @@ public:
MorphShape(Class_base* c):DisplayObject(c){}
static void sinit(Class_base* c);
static void buildTraits(ASObject* o);
- ASFUNCTION(_constructor);
};
class Loader;
@@ -272,6 +228,7 @@ private:
tiny_string loaderURL;
_NR<EventDispatcher> sharedEvents;
_NR<Loader> loader;
+ _NR<ByteArray> bytesData;
/*
* waitedObject is the object we are supposed to wait,
* it's necessary when multiple loads are invoked on
@@ -290,18 +247,20 @@ private:
void sendInit();
public:
ASPROPERTY_GETTER(uint32_t,actionScriptVersion);
+ ASPROPERTY_GETTER(uint32_t,swfVersion);
ASPROPERTY_GETTER(bool, childAllowsParent);
+ ASPROPERTY_GETTER(_NR<UncaughtErrorEvents>,uncaughtErrorEvents);
LoaderInfo(Class_base* c);
LoaderInfo(Class_base* c, _R<Loader> l);
void finalize();
static void sinit(Class_base* c);
static void buildTraits(ASObject* o);
ASFUNCTION(_constructor);
- ASFUNCTION(addEventListener);
ASFUNCTION(_getLoaderURL);
ASFUNCTION(_getURL);
ASFUNCTION(_getBytesLoaded);
ASFUNCTION(_getBytesTotal);
+ ASFUNCTION(_getBytes);
ASFUNCTION(_getApplicationDomain);
ASFUNCTION(_getLoader);
ASFUNCTION(_getContent);
@@ -318,6 +277,7 @@ public:
void setBytesLoaded(uint32_t b);
void setURL(const tiny_string& _url, bool setParameters=true);
void setLoaderURL(const tiny_string& _url) { loaderURL=_url; }
+ void setParameters(_NR<ASObject> p) { parameters = p; }
void resetState();
};
@@ -349,6 +309,7 @@ private:
_NR<LoaderInfo> contentLoaderInfo;
void unload();
bool loaded;
+ bool allowCodeImport;
public:
Loader(Class_base* c);
~Loader();
@@ -361,8 +322,10 @@ public:
ASFUNCTION(load);
ASFUNCTION(loadBytes);
ASFUNCTION(_unload);
+ ASFUNCTION(_unloadAndStop);
ASFUNCTION(_getContentLoaderInfo);
ASFUNCTION(_getContent);
+ ASPROPERTY_GETTER(_NR<UncaughtErrorEvents>,uncaughtErrorEvents);
int getDepth() const
{
return 0;
@@ -370,6 +333,7 @@ public:
void setContent(_R<DisplayObject> o);
_NR<DisplayObject> getContent() { return content; }
_R<LoaderInfo> getContentLoaderInfo() { return contentLoaderInfo; }
+ bool allowLoadingSWF() { return allowCodeImport; };
};
class Sprite: public DisplayObjectContainer, public TokenContainer
@@ -528,6 +492,7 @@ public:
ASFUNCTION(play);
ASFUNCTION(gotoAndStop);
ASFUNCTION(gotoAndPlay);
+ ASFUNCTION(prevFrame);
ASFUNCTION(nextFrame);
ASFUNCTION(_getCurrentFrame);
ASFUNCTION(_getCurrentFrameLabel);
@@ -550,6 +515,9 @@ private:
uint32_t internalGetHeight() const;
uint32_t internalGetWidth() const;
void onDisplayState(const tiny_string&);
+ void onAlign(const tiny_string&);
+ void onColorCorrection(const tiny_string&);
+ void onFullScreenSourceRect(_NR<Rectangle>);
// Keyboard focus object is accessed from the VM thread (AS
// code) and the input thread and is protected focusSpinlock
Spinlock focusSpinlock;
@@ -564,6 +532,9 @@ public:
_NR<InteractiveObject> getFocusTarget();
void setFocusTarget(_NR<InteractiveObject> focus);
ASFUNCTION(_constructor);
+ ASFUNCTION(_getAllowFullScreen);
+ ASFUNCTION(_getAllowFullScreenInteractive);
+ ASFUNCTION(_getColorCorrectionSupport);
ASFUNCTION(_getStageWidth);
ASFUNCTION(_getStageHeight);
ASFUNCTION(_getScaleMode);
@@ -573,7 +544,17 @@ public:
ASFUNCTION(_getFocus);
ASFUNCTION(_setFocus);
ASFUNCTION(_setTabChildren);
+ ASFUNCTION(_getFrameRate);
+ ASFUNCTION(_setFrameRate);
+ ASFUNCTION(_getWmodeGPU);
+ ASFUNCTION(_invalidate);
+ ASPROPERTY_GETTER_SETTER(tiny_string,align);
+ ASPROPERTY_GETTER_SETTER(tiny_string,colorCorrection);
ASPROPERTY_GETTER_SETTER(tiny_string,displayState);
+ ASPROPERTY_GETTER_SETTER(_NR<Rectangle>,fullScreenSourceRect);
+ ASPROPERTY_GETTER_SETTER(bool,showDefaultContextMenu);
+ ASPROPERTY_GETTER_SETTER(tiny_string,quality);
+ ASPROPERTY_GETTER_SETTER(bool,stageFocusRect);
};
class StageScaleMode: public ASObject
@@ -645,6 +626,22 @@ public:
static void sinit(Class_base* c);
};
+class GraphicsPathCommand: public ASObject
+{
+public:
+ enum {NO_OP=0, MOVE_TO, LINE_TO, CURVE_TO, WIDE_MOVE_TO, WIDE_LINE_TO, CUBIC_CURVE_TO};
+ GraphicsPathCommand(Class_base* c):ASObject(c){}
+ static void sinit(Class_base* c);
+};
+
+class GraphicsPathWinding: public ASObject
+{
+public:
+ GraphicsPathWinding(Class_base* c):ASObject(c){}
+ static void sinit(Class_base* c);
+
+};
+
class IntSize
{
public:
diff --git a/src/scripting/flash/errors/flasherrors.cpp b/src/scripting/flash/errors/flasherrors.cpp
index 81c0a83..087f5a1 100644
--- a/src/scripting/flash/errors/flasherrors.cpp
+++ b/src/scripting/flash/errors/flasherrors.cpp
@@ -32,8 +32,7 @@ ASFUNCTIONBODY(IOError,_constructor)
void IOError::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASError>::getRef());
+ CLASS_SETUP(c, ASError, _constructor, CLASS_DYNAMIC_NOT_FINAL);
}
void IOError::buildTraits(ASObject* o)
@@ -49,8 +48,7 @@ ASFUNCTIONBODY(EOFError,_constructor)
void EOFError::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<IOError>::getRef());
+ CLASS_SETUP(c, IOError, _constructor, CLASS_DYNAMIC_NOT_FINAL);
}
void EOFError::buildTraits(ASObject* o)
@@ -66,8 +64,7 @@ ASFUNCTIONBODY(IllegalOperationError,_constructor)
void IllegalOperationError::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASError>::getRef());
+ CLASS_SETUP(c, ASError, _constructor, CLASS_DYNAMIC_NOT_FINAL);
}
void IllegalOperationError::buildTraits(ASObject* o)
@@ -85,8 +82,7 @@ ASFUNCTIONBODY(InvalidSWFError,_constructor)
void InvalidSWFError::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASError>::getRef());
+ CLASS_SETUP(c, ASError, _constructor, CLASS_DYNAMIC_NOT_FINAL);
}
void InvalidSWFError::buildTraits(ASObject* o)
@@ -102,8 +98,7 @@ ASFUNCTIONBODY(MemoryError,_constructor)
void MemoryError::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASError>::getRef());
+ CLASS_SETUP(c, ASError, _constructor, CLASS_DYNAMIC_NOT_FINAL);
}
void MemoryError::buildTraits(ASObject* o)
@@ -119,8 +114,7 @@ ASFUNCTIONBODY(ScriptTimeoutError,_constructor)
void ScriptTimeoutError::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASError>::getRef());
+ CLASS_SETUP(c, ASError, _constructor, CLASS_DYNAMIC_NOT_FINAL);
}
void ScriptTimeoutError::buildTraits(ASObject* o)
@@ -136,8 +130,7 @@ ASFUNCTIONBODY(StackOverflowError,_constructor)
void StackOverflowError::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASError>::getRef());
+ CLASS_SETUP(c, ASError, _constructor, CLASS_DYNAMIC_NOT_FINAL);
}
void StackOverflowError::buildTraits(ASObject* o)
diff --git a/src/scripting/flash/events/flashevents.cpp b/src/scripting/flash/events/flashevents.cpp
index 6f99dfd..5495dd7 100644
--- a/src/scripting/flash/events/flashevents.cpp
+++ b/src/scripting/flash/events/flashevents.cpp
@@ -49,9 +49,7 @@ void Event::finalize()
void Event::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASObject>::getRef());
-
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED);
c->setVariableByQName("ACTIVATE","",Class<ASString>::getInstanceS("activate"),DECLARED_TRAIT);
c->setVariableByQName("ADDED","",Class<ASString>::getInstanceS("added"),DECLARED_TRAIT);
c->setVariableByQName("ADDED_TO_STAGE","",Class<ASString>::getInstanceS("addedToStage"),DECLARED_TRAIT);
@@ -189,8 +187,7 @@ ASFUNCTIONBODY(Event,clone)
void EventPhase::sinit(Class_base* c)
{
- c->setConstructor(NULL);
- c->setSuper(Class<ASObject>::getRef());
+ CLASS_SETUP_NO_CONSTRUCTOR(c, ASObject, CLASS_SEALED | CLASS_FINAL);
c->setVariableByQName("CAPTURING_PHASE","",abstract_i(CAPTURING_PHASE),DECLARED_TRAIT);
c->setVariableByQName("BUBBLING_PHASE","",abstract_i(BUBBLING_PHASE),DECLARED_TRAIT);
c->setVariableByQName("AT_TARGET","",abstract_i(AT_TARGET),DECLARED_TRAIT);
@@ -201,10 +198,8 @@ FocusEvent::FocusEvent(Class_base* c):Event(c, "focusEvent")
}
void FocusEvent::sinit(Class_base* c)
-{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<Event>::getRef());
-
+{
+ CLASS_SETUP(c, Event, _constructor, CLASS_SEALED);
c->setVariableByQName("FOCUS_IN","",Class<ASString>::getInstanceS("focusIn"),DECLARED_TRAIT);
c->setVariableByQName("FOCUS_OUT","",Class<ASString>::getInstanceS("focusOut"),DECLARED_TRAIT);
c->setVariableByQName("MOUSE_FOCUS_CHANGE","",Class<ASString>::getInstanceS("mouseFocusChange"),DECLARED_TRAIT);
@@ -249,9 +244,7 @@ Event* ProgressEvent::cloneImpl() const
void ProgressEvent::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<Event>::getRef());
-
+ CLASS_SETUP(c, Event, _constructor, CLASS_SEALED);
c->setVariableByQName("PROGRESS","",Class<ASString>::getInstanceS("progress"),DECLARED_TRAIT);
REGISTER_GETTER_SETTER(c,bytesLoaded);
REGISTER_GETTER_SETTER(c,bytesTotal);
@@ -279,18 +272,14 @@ ASFUNCTIONBODY(ProgressEvent,_constructor)
void TimerEvent::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<Event>::getRef());
-
+ CLASS_SETUP(c, Event, _constructor, CLASS_SEALED);
c->setVariableByQName("TIMER","",Class<ASString>::getInstanceS("timer"),DECLARED_TRAIT);
c->setVariableByQName("TIMER_COMPLETE","",Class<ASString>::getInstanceS("timerComplete"),DECLARED_TRAIT);
}
void MouseEvent::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<Event>::getRef());
-
+ CLASS_SETUP(c, Event, _constructor, CLASS_SEALED);
c->setVariableByQName("CLICK","",Class<ASString>::getInstanceS("click"),DECLARED_TRAIT);
c->setVariableByQName("DOUBLE_CLICK","",Class<ASString>::getInstanceS("doubleClick"),DECLARED_TRAIT);
c->setVariableByQName("MOUSE_DOWN","",Class<ASString>::getInstanceS("mouseDown"),DECLARED_TRAIT);
@@ -302,6 +291,7 @@ void MouseEvent::sinit(Class_base* c)
c->setVariableByQName("RIGHT_CLICK","",Class<ASString>::getInstanceS("rightClick"),DECLARED_TRAIT);
c->setVariableByQName("ROLL_OVER","",Class<ASString>::getInstanceS("rollOver"),DECLARED_TRAIT);
c->setVariableByQName("ROLL_OUT","",Class<ASString>::getInstanceS("rollOut"),DECLARED_TRAIT);
+ c->setDeclaredMethodByQName("updateAfterEvent","",Class<IFunction>::getFunction(updateAfterEvent),NORMAL_METHOD,true);
REGISTER_GETTER(c,relatedObject);
REGISTER_GETTER(c,stageX);
@@ -454,6 +444,11 @@ ASFUNCTIONBODY(MouseEvent,_setter_shiftKey)
th->modifiers |= GDK_SHIFT_MASK;
return NULL;
}
+ASFUNCTIONBODY(MouseEvent,updateAfterEvent)
+{
+ LOG(LOG_NOT_IMPLEMENTED,"MouseEvent::updateAfterEvent not implemented");
+ return NULL;
+}
void MouseEvent::buildTraits(ASObject* o)
{
@@ -488,9 +483,7 @@ IOErrorEvent::IOErrorEvent(Class_base* c) : ErrorEvent(c, "ioError")
void IOErrorEvent::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ErrorEvent>::getRef());
-
+ CLASS_SETUP(c, ErrorEvent, _constructor, CLASS_SEALED);
c->setVariableByQName("DISK_ERROR","",Class<ASString>::getInstanceS("diskError"),DECLARED_TRAIT);
c->setVariableByQName("IO_ERROR","",Class<ASString>::getInstanceS("ioError"),DECLARED_TRAIT);
c->setVariableByQName("NETWORK_ERROR","",Class<ASString>::getInstanceS("networkError"),DECLARED_TRAIT);
@@ -510,9 +503,8 @@ void EventDispatcher::finalize()
void EventDispatcher::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED);
c->addImplementedInterface(InterfaceClass<IEventDispatcher>::getClass());
- c->setSuper(Class<ASObject>::getRef());
c->setDeclaredMethodByQName("addEventListener","",Class<IFunction>::getFunction(addEventListener),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("hasEventListener","",Class<IFunction>::getFunction(_hasEventListener),NORMAL_METHOD,true);
@@ -564,18 +556,12 @@ ASFUNCTIONBODY(EventDispatcher,addEventListener)
Locker l(th->handlersMutex);
//Search if any listener is already registered for the event
list<listener>& listeners=th->handlers[eventName];
- if(find(listeners.begin(),listeners.end(),make_pair(f,useCapture))!=listeners.end())
- {
- LOG(LOG_CALLS,_("Weird event reregistration"));
- return NULL;
- }
f->incRef();
const listener newListener(_MR(f), priority, useCapture);
//Ordered insertion
list<listener>::iterator insertionPoint=upper_bound(listeners.begin(),listeners.end(),newListener);
listeners.insert(insertionPoint,newListener);
}
-
return NULL;
}
@@ -642,7 +628,6 @@ ASFUNCTIONBODY(EventDispatcher,dispatchEvent)
args[0]->incRef();
_R<Event> e=_MR(Class<Event>::cast(args[0]));
- assert_and_throw(e->type!="");
// Must call the AS getter, because the getter may have been
// overridden
@@ -731,7 +716,6 @@ bool EventDispatcher::hasEventListener(const tiny_string& eventName)
NetStatusEvent::NetStatusEvent(Class_base* cb, const tiny_string& level, const tiny_string& code):Event(cb, "netStatus")
{
- //The object has been initialized internally
ASObject* info=Class<ASObject>::getInstanceS();
info->setVariableByQName("level","",Class<ASString>::getInstanceS(level),DECLARED_TRAIT);
info->setVariableByQName("code","",Class<ASString>::getInstanceS(code),DECLARED_TRAIT);
@@ -740,9 +724,7 @@ NetStatusEvent::NetStatusEvent(Class_base* cb, const tiny_string& level, const t
void NetStatusEvent::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<Event>::getRef());
-
+ CLASS_SETUP(c, Event, _constructor, CLASS_SEALED);
c->setVariableByQName("NET_STATUS","",Class<ASString>::getInstanceS("netStatus"),DECLARED_TRAIT);
}
@@ -769,7 +751,12 @@ ASFUNCTIONBODY(NetStatusEvent,_constructor)
//Uninitialized info
info=getSys()->getNullRef();
}
- obj->setVariableByQName("info","",info,DECLARED_TRAIT);
+ multiname infoName(NULL);
+ infoName.name_type=multiname::NAME_STRING;
+ infoName.name_s_id=getSys()->getUniqueStringId("info");
+ infoName.ns.push_back(nsNameAndKind("",NAMESPACE));
+ infoName.isAttribute = false;
+ obj->setVariableByMultiname(infoName, info, CONST_NOT_ALLOWED);
return NULL;
}
@@ -800,9 +787,7 @@ FullScreenEvent::FullScreenEvent(Class_base* c):Event(c, "fullScreenEvent")
void FullScreenEvent::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<Event>::getRef());
-
+ CLASS_SETUP(c, Event, _constructor, CLASS_SEALED);
c->setVariableByQName("FULL_SCREEN","",Class<ASString>::getInstanceS("fullScreen"),DECLARED_TRAIT);
}
@@ -820,9 +805,7 @@ KeyboardEvent::KeyboardEvent(Class_base* c, tiny_string _type, uint32_t _charcod
void KeyboardEvent::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<Event>::getRef());
-
+ CLASS_SETUP(c, Event, _constructor, CLASS_SEALED);
REGISTER_GETTER_SETTER(c, altKey);
REGISTER_GETTER_SETTER(c, charCode);
REGISTER_GETTER_SETTER(c, commandKey);
@@ -959,11 +942,8 @@ TextEvent::TextEvent(Class_base* c,const tiny_string& t):Event(c,t)
void TextEvent::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<Event>::getRef());
-
+ CLASS_SETUP(c, Event, _constructor, CLASS_SEALED);
c->setVariableByQName("TEXT_INPUT","",Class<ASString>::getInstanceS("textInput"),DECLARED_TRAIT);
-
REGISTER_GETTER_SETTER(c,text);
}
@@ -985,9 +965,7 @@ ErrorEvent::ErrorEvent(Class_base* c, const tiny_string& t, const std::string& e
void ErrorEvent::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<TextEvent>::getRef());
-
+ CLASS_SETUP(c, TextEvent, _constructor, CLASS_SEALED);
c->setVariableByQName("ERROR","",Class<ASString>::getInstanceS("error"),DECLARED_TRAIT);
}
@@ -1008,9 +986,7 @@ SecurityErrorEvent::SecurityErrorEvent(Class_base* c, const std::string& e):Erro
void SecurityErrorEvent::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ErrorEvent>::getRef());
-
+ CLASS_SETUP(c, ErrorEvent, _constructor, CLASS_SEALED);
c->setVariableByQName("SECURITY_ERROR","",Class<ASString>::getInstanceS("securityError"),DECLARED_TRAIT);
}
@@ -1020,9 +996,7 @@ AsyncErrorEvent::AsyncErrorEvent(Class_base* c):ErrorEvent(c, "asyncError")
void AsyncErrorEvent::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ErrorEvent>::getRef());
-
+ CLASS_SETUP(c, ErrorEvent, _constructor, CLASS_SEALED);
c->setVariableByQName("ASYNC_ERROR","",Class<ASString>::getInstanceS("asyncError"),DECLARED_TRAIT);
}
@@ -1033,6 +1007,24 @@ ASFUNCTIONBODY(AsyncErrorEvent,_constructor)
return NULL;
}
+
+UncaughtErrorEvent::UncaughtErrorEvent(Class_base* c):ErrorEvent(c, "uncaughtError")
+{
+}
+
+void UncaughtErrorEvent::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, ErrorEvent, _constructor, CLASS_SEALED);
+ c->setVariableByQName("UNCAUGHT_ERROR","",Class<ASString>::getInstanceS("uncaughtError"),DECLARED_TRAIT);
+}
+
+ASFUNCTIONBODY(UncaughtErrorEvent,_constructor)
+{
+ uint32_t baseClassArgs=imin(argslen,4);
+ ErrorEvent::_constructor(obj,args,baseClassArgs);
+ return NULL;
+}
+
ABCContextInitEvent::ABCContextInitEvent(ABCContext* c, bool l):Event(NULL, "ABCContextInitEvent"),context(c),lazy(l)
{
}
@@ -1043,9 +1035,7 @@ ShutdownEvent::ShutdownEvent():Event(NULL, "shutdownEvent")
void HTTPStatusEvent::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<Event>::getRef());
-
+ CLASS_SETUP(c, Event, _constructor, CLASS_SEALED);
c->setVariableByQName("HTTP_STATUS","",Class<ASString>::getInstanceS("httpStatus"),DECLARED_TRAIT);
}
@@ -1109,18 +1099,14 @@ void ParseRPCMessageEvent::finalize()
void StatusEvent::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<Event>::getRef());
-
+ CLASS_SETUP(c, Event, _constructor, CLASS_SEALED);
/* TODO: dispatch this event */
c->setVariableByQName("STATUS","",Class<ASString>::getInstanceS("status"),DECLARED_TRAIT);
}
void DataEvent::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<TextEvent>::getRef());
-
+ CLASS_SETUP(c, TextEvent, _constructor, CLASS_SEALED);
/* TODO: dispatch this event */
c->setVariableByQName("DATA","",Class<ASString>::getInstanceS("data"),DECLARED_TRAIT);
/* TODO: dispatch this event */
@@ -1160,9 +1146,7 @@ Event* DataEvent::cloneImpl() const
void InvokeEvent::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<Event>::getRef());
-
+ CLASS_SETUP(c, Event, _constructor, CLASS_SEALED);
c->setVariableByQName("INVOKE","",Class<ASString>::getInstanceS("invoke"),DECLARED_TRAIT);
}
@@ -1179,9 +1163,7 @@ DRMErrorEvent::DRMErrorEvent(Class_base* c) : ErrorEvent(c, "drmAuthenticate")
void DRMErrorEvent::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ErrorEvent>::getRef());
-
+ CLASS_SETUP(c, ErrorEvent, _constructor, CLASS_SEALED);
c->setVariableByQName("DRM_ERROR","",Class<ASString>::getInstanceS("drmError"),DECLARED_TRAIT);
c->setVariableByQName("DRM_LOAD_DEVICEID_ERROR","",Class<ASString>::getInstanceS("drmLoadDeviceIdError"),DECLARED_TRAIT);
}
@@ -1201,9 +1183,7 @@ DRMStatusEvent::DRMStatusEvent(Class_base* c) : Event(c, "drmAuthenticate")
void DRMStatusEvent::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<Event>::getRef());
-
+ CLASS_SETUP(c, Event, _constructor, CLASS_SEALED);
c->setVariableByQName("DRM_STATUS","",Class<ASString>::getInstanceS("drmStatus"),DECLARED_TRAIT);
}
@@ -1216,18 +1196,59 @@ ASFUNCTIONBODY(DRMStatusEvent,_constructor)
return NULL;
}
+VideoEvent::VideoEvent(Class_base* c)
+ : Event(c, "renderState"),status("unavailable")
+{
+}
+
+void VideoEvent::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, Event, _constructor, CLASS_SEALED);
+ c->setVariableByQName("RENDER_STATE","",Class<ASString>::getInstanceS("renderState"),CONSTANT_TRAIT);
+ c->setVariableByQName("RENDER_STATUS_ACCELERATED","",Class<ASString>::getInstanceS("accelerated"),CONSTANT_TRAIT);
+ c->setVariableByQName("RENDER_STATUS_SOFTWARE","",Class<ASString>::getInstanceS("software"),CONSTANT_TRAIT);
+ c->setVariableByQName("RENDER_STATUS_UNAVAILABLE","",Class<ASString>::getInstanceS("unavailable"),CONSTANT_TRAIT);
+ REGISTER_GETTER(c,status);
+}
+
+ASFUNCTIONBODY(VideoEvent,_constructor)
+{
+ uint32_t baseClassArgs=imin(argslen,3);
+ Event::_constructor(obj,args,baseClassArgs);
+
+ VideoEvent* th=static_cast<VideoEvent*>(obj);
+ if(argslen>=4)
+ {
+ th->status=args[3]->toString();
+ }
+
+ return NULL;
+}
+
+Event* VideoEvent::cloneImpl() const
+{
+ VideoEvent *clone;
+ clone = Class<VideoEvent>::getInstanceS();
+ clone->status = status;
+ // Event
+ clone->type = type;
+ clone->bubbles = bubbles;
+ clone->cancelable = cancelable;
+ return clone;
+}
+
+ASFUNCTIONBODY_GETTER(VideoEvent,status);
+
+
StageVideoEvent::StageVideoEvent(Class_base* c)
- : Event(c, "renderState")
+ : Event(c, "renderState"),status("unavailable")
{
}
void StageVideoEvent::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<Event>::getRef());
-
- c->setVariableByQName("RENDER_STATE","",Class<ASString>::getInstanceS("renderState"),DECLARED_TRAIT);
-
+ CLASS_SETUP(c, Event, _constructor, CLASS_SEALED);
+ c->setVariableByQName("RENDER_STATE","",Class<ASString>::getInstanceS("renderState"),CONSTANT_TRAIT);
REGISTER_GETTER(c,colorSpace);
REGISTER_GETTER(c,status);
}
@@ -1273,6 +1294,7 @@ StageVideoAvailabilityEvent::StageVideoAvailabilityEvent(Class_base* c)
void StageVideoAvailabilityEvent::sinit(Class_base* c)
{
+ CLASS_SETUP_NO_CONSTRUCTOR(c, Event, CLASS_SEALED);
c->setVariableByQName("STAGE_VIDEO_AVAILABILITY","",Class<ASString>::getInstanceS("stageVideoAvailability"),DECLARED_TRAIT);
REGISTER_GETTER(c, availability);
}
@@ -1304,3 +1326,63 @@ Event* StageVideoAvailabilityEvent::cloneImpl() const
}
ASFUNCTIONBODY_GETTER(StageVideoAvailabilityEvent,availability);
+
+void ContextMenuEvent::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, Event, _constructor, CLASS_SEALED);
+ c->setVariableByQName("MENU_ITEM_SELECT","",Class<ASString>::getInstanceS("menuItemSelect"),DECLARED_TRAIT);
+ c->setVariableByQName("MENU_SELECT","",Class<ASString>::getInstanceS("menuSelect"),DECLARED_TRAIT);
+}
+
+
+void TouchEvent::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, Event, _constructor, CLASS_SEALED);
+ c->setVariableByQName("TOUCH_BEGIN","",Class<ASString>::getInstanceS("touchBegin"),DECLARED_TRAIT);
+ c->setVariableByQName("TOUCH_END","",Class<ASString>::getInstanceS("touchEnd"),DECLARED_TRAIT);
+ c->setVariableByQName("TOUCH_MOVE","",Class<ASString>::getInstanceS("touchMove"),DECLARED_TRAIT);
+ c->setVariableByQName("TOUCH_OUT","",Class<ASString>::getInstanceS("touchOut"),DECLARED_TRAIT);
+ c->setVariableByQName("TOUCH_OVER","",Class<ASString>::getInstanceS("touchOver"),DECLARED_TRAIT);
+ c->setVariableByQName("TOUCH_ROLL_OUT","",Class<ASString>::getInstanceS("touchRollOut"),DECLARED_TRAIT);
+ c->setVariableByQName("TOUCH_ROLL_OVER","",Class<ASString>::getInstanceS("touchRollOver"),DECLARED_TRAIT);
+ c->setVariableByQName("TOUCH_TAP","",Class<ASString>::getInstanceS("touchTap"),DECLARED_TRAIT);
+}
+
+void GestureEvent::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, Event, _constructor, CLASS_SEALED);
+ c->setVariableByQName("GESTURE_TWO_FINGER_TAP","",Class<ASString>::getInstanceS("gestureTwoFingerTap"),DECLARED_TRAIT);
+}
+
+void PressAndTapGestureEvent::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, GestureEvent, _constructor, CLASS_SEALED);
+ c->setVariableByQName("GESTURE_PRESS_AND_TAP","",Class<ASString>::getInstanceS("gesturePressAndTap"),DECLARED_TRAIT);
+}
+
+void TransformGestureEvent::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, GestureEvent, _constructor, CLASS_SEALED);
+ c->setVariableByQName("GESTURE_PAN","",Class<ASString>::getInstanceS("gesturePan"),DECLARED_TRAIT);
+ c->setVariableByQName("GESTURE_ROTATE","",Class<ASString>::getInstanceS("gestureRotate"),DECLARED_TRAIT);
+ c->setVariableByQName("GESTURE_SWIPE","",Class<ASString>::getInstanceS("gestureSwipe"),DECLARED_TRAIT);
+ c->setVariableByQName("GESTURE_ZOOM","",Class<ASString>::getInstanceS("gestureZoom"),DECLARED_TRAIT);
+}
+
+UncaughtErrorEvents::UncaughtErrorEvents(Class_base* c):
+ EventDispatcher(c)
+{
+}
+
+void UncaughtErrorEvents::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, EventDispatcher, _constructor, CLASS_SEALED);
+}
+
+ASFUNCTIONBODY(UncaughtErrorEvents, _constructor)
+{
+ EventDispatcher::_constructor(obj, NULL, 0);
+ UncaughtErrorEvents* th=Class<UncaughtErrorEvents>::cast(obj);
+ LOG(LOG_NOT_IMPLEMENTED,"UncaughtErrorEvents is not implemented");
+ return NULL;
+}
diff --git a/src/scripting/flash/events/flashevents.h b/src/scripting/flash/events/flashevents.h
index 2c3cdfc..fd71e15 100644
--- a/src/scripting/flash/events/flashevents.h
+++ b/src/scripting/flash/events/flashevents.h
@@ -145,8 +145,7 @@ class NetStatusEvent: public Event
private:
virtual Event* cloneImpl() const;
public:
- NetStatusEvent(Class_base* c):Event(c, "netStatus"){}
- NetStatusEvent(Class_base* cb, const tiny_string& l, const tiny_string& c);
+ NetStatusEvent(Class_base* cb, const tiny_string& l="", const tiny_string& c="");
static void sinit(Class_base*);
static void buildTraits(ASObject* o)
{
@@ -223,6 +222,18 @@ public:
ASFUNCTION(_constructor);
};
+class UncaughtErrorEvent: public ErrorEvent
+{
+public:
+ UncaughtErrorEvent(Class_base* c);
+ static void sinit(Class_base*);
+ static void buildTraits(ASObject* o)
+ {
+ }
+ ASFUNCTION(_constructor);
+};
+
+
class ProgressEvent: public Event
{
private:
@@ -273,7 +284,8 @@ public:
ASFUNCTION_GETTER_SETTER(shiftKey);
ASPROPERTY_GETTER(number_t,stageX);
ASPROPERTY_GETTER(number_t,stageY);
- ASPROPERTY_GETTER(_NR<InteractiveObject>,relatedObject);
+ ASPROPERTY_GETTER(_NR<InteractiveObject>,relatedObject);
+ ASFUNCTION(updateAfterEvent);
};
class InvokeEvent: public Event
@@ -494,6 +506,17 @@ public:
ASFUNCTION(_constructor);
};
+class VideoEvent: public Event
+{
+private:
+ Event* cloneImpl() const;
+public:
+ VideoEvent(Class_base* c);
+ static void sinit(Class_base*);
+ ASFUNCTION(_constructor);
+ ASPROPERTY_GETTER(tiny_string,status);
+};
+
class StageVideoEvent: public Event
{
private:
@@ -517,5 +540,52 @@ public:
ASPROPERTY_GETTER(tiny_string,availability);
};
+class ContextMenuEvent: public Event
+{
+public:
+ ContextMenuEvent(Class_base* c) : Event(c, "ContextMenuEvent") {}
+ static void sinit(Class_base*);
+ static void buildTraits(ASObject* o) {}
};
+
+class TouchEvent: public Event
+{
+public:
+ TouchEvent(Class_base* c) : Event(c, "TouchEvent") {}
+ static void sinit(Class_base*);
+ static void buildTraits(ASObject* o) {}
+};
+
+class GestureEvent: public Event
+{
+public:
+ GestureEvent(Class_base* c, const tiny_string& t = "GestureEvent") : Event(c, t) {}
+ static void sinit(Class_base*);
+ static void buildTraits(ASObject* o) {}
+};
+
+class PressAndTapGestureEvent: public GestureEvent
+{
+public:
+ PressAndTapGestureEvent(Class_base* c) : GestureEvent(c, "PressAndTapGestureEvent") {}
+ static void sinit(Class_base*);
+ static void buildTraits(ASObject* o) {}
+};
+class TransformGestureEvent: public GestureEvent
+{
+public:
+ TransformGestureEvent(Class_base* c) : GestureEvent(c, "TransformGestureEvent") {}
+ static void sinit(Class_base*);
+ static void buildTraits(ASObject* o) {}
+};
+
+class UncaughtErrorEvents: public EventDispatcher
+{
+public:
+ UncaughtErrorEvents(Class_base* c);
+ static void sinit(Class_base*);
+ ASFUNCTION(_constructor);
+};
+
+}
#endif /* SCRIPTING_FLASH_EVENTS_FLASHEVENTS_H */
diff --git a/src/scripting/flash/external/ExternalInterface.cpp b/src/scripting/flash/external/ExternalInterface.cpp
index 7cc2130..bb7b3c0 100644
--- a/src/scripting/flash/external/ExternalInterface.cpp
+++ b/src/scripting/flash/external/ExternalInterface.cpp
@@ -26,7 +26,7 @@ using namespace lightspark;
void ExternalInterface::sinit(Class_base* c)
{
- c->setConstructor(NULL);
+ CLASS_SETUP_NO_CONSTRUCTOR(c, ASObject, CLASS_SEALED | CLASS_FINAL);
c->setDeclaredMethodByQName("available","",Class<IFunction>::getFunction(_getAvailable),GETTER_METHOD,false);
c->setDeclaredMethodByQName("objectID","",Class<IFunction>::getFunction(_getObjectID),GETTER_METHOD,false);
c->setDeclaredMethodByQName("marshallExceptions","",Class<IFunction>::getFunction(_getMarshallExceptions),GETTER_METHOD,false);
@@ -73,7 +73,8 @@ ASFUNCTIONBODY(ExternalInterface, _setMarshallExceptions)
ASFUNCTIONBODY(ExternalInterface,addCallback)
{
if(getSys()->extScriptObject == NULL)
- throw Class<ASError>::getInstanceS("Container doesn't support callbacks");
+ return abstract_b(false);
+// throw Class<ASError>::getInstanceS("Container doesn't support callbacks");
assert_and_throw(argslen == 2);
@@ -90,7 +91,8 @@ ASFUNCTIONBODY(ExternalInterface,addCallback)
ASFUNCTIONBODY(ExternalInterface,call)
{
if(getSys()->extScriptObject == NULL)
- throw Class<ASError>::getInstanceS("Container doesn't support callbacks");
+ return getSys()->getNullRef();
+// throw Class<ASError>::getInstanceS("Container doesn't support callbacks");
assert_and_throw(argslen >= 1);
const tiny_string& arg0=args[0]->toString();
diff --git a/src/scripting/flash/sensors/flashsensors.cpp b/src/scripting/flash/filesystem/flashfilesystem.cpp
similarity index 60%
copy from src/scripting/flash/sensors/flashsensors.cpp
copy to src/scripting/flash/filesystem/flashfilesystem.cpp
index bee463b..1106815 100644
--- a/src/scripting/flash/sensors/flashsensors.cpp
+++ b/src/scripting/flash/filesystem/flashfilesystem.cpp
@@ -1,7 +1,7 @@
/**************************************************************************
Lightspark, a free flash player implementation
- Copyright (C) 2011-2013 Alessandro Pignotti (a.pignotti at sssup.it)
+ Copyright (C) 2009-2013 Alessandro Pignotti (a.pignotti at sssup.it)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
@@ -17,31 +17,26 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
-#include <map>
-#include "backends/security.h"
+#include "scripting/flash/filesystem/flashfilesystem.h"
#include "scripting/abc.h"
-#include "scripting/flash/sensors/flashsensors.h"
-#include "scripting/class.h"
-#include "scripting/flash/system/flashsystem.h"
+#include "scripting/argconv.h"
#include "compat.h"
-#include "backends/audio.h"
-using namespace std;
using namespace lightspark;
-Accelerometer::Accelerometer(Class_base* c):ASObject(c) {}
-
-void Accelerometer::sinit(Class_base* c)
+FileStream::FileStream(Class_base* c):
+ EventDispatcher(c)
{
- // properties
- c->setDeclaredMethodByQName("isSupported", "", Class<IFunction>::getFunction(_isSupported),GETTER_METHOD,false);
}
-void Accelerometer::buildTraits(ASObject *o)
+void FileStream::sinit(Class_base* c)
{
+ CLASS_SETUP(c, EventDispatcher, _constructor, CLASS_SEALED);
}
-
-ASFUNCTIONBODY(Accelerometer,_isSupported)
+ASFUNCTIONBODY(FileStream, _constructor)
{
- return abstract_b(false);
+ EventDispatcher::_constructor(obj, NULL, 0);
+ FileStream* th=Class<FileStream>::cast(obj);
+ LOG(LOG_NOT_IMPLEMENTED,"FileStream is not implemented");
+ return NULL;
}
diff --git a/src/scripting/flash/accessibility/flashaccessibility.h b/src/scripting/flash/filesystem/flashfilesystem.h
similarity index 67%
copy from src/scripting/flash/accessibility/flashaccessibility.h
copy to src/scripting/flash/filesystem/flashfilesystem.h
index 19d00b8..41df839 100644
--- a/src/scripting/flash/accessibility/flashaccessibility.h
+++ b/src/scripting/flash/filesystem/flashfilesystem.h
@@ -17,31 +17,25 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
-#ifndef SCRIPTING_FLASH_ACCESSIBILITY_FLASHACCESSIBILITY_H
-#define SCRIPTING_FLASH_ACCESSIBILITY_FLASHACCESSIBILITY_H 1
+#ifndef SCRIPTING_FLASH_FILESYSTEM_FLASHFILESYSTEM_H
+#define SCRIPTING_FLASH_PRINTING_FLASHFILESYSTEM_H 1
+#include "compat.h"
#include "asobject.h"
+#include "scripting/flash/events/flashevents.h"
namespace lightspark
{
-class AccessibilityProperties : public ASObject
+class FileStream: public EventDispatcher
{
-private:
- ASPROPERTY_GETTER_SETTER(tiny_string,name);
public:
- AccessibilityProperties(Class_base* c):ASObject(c){}
+ FileStream(Class_base* c);
static void sinit(Class_base*);
ASFUNCTION(_constructor);
+ ASPROPERTY_GETTER(bool,isSupported);
};
-class AccessibilityImplementation : public ASObject
-{
-public:
- AccessibilityImplementation(Class_base* c):ASObject(c){}
- static void sinit(Class_base*);
- ASFUNCTION(_constructor);
-};
}
-#endif /* SCRIPTING_FLASH_ACCESSIBILITY_FLASHACCESSIBILITY_H */
+#endif /* SCRIPTING_FLASH_FILESYSTEM_FLASHFILESYSTEM_H */
diff --git a/src/scripting/flash/filters/flashfilters.cpp b/src/scripting/flash/filters/flashfilters.cpp
index 9d70fc1..d230db4 100644
--- a/src/scripting/flash/filters/flashfilters.cpp
+++ b/src/scripting/flash/filters/flashfilters.cpp
@@ -19,14 +19,14 @@
#include "scripting/flash/filters/flashfilters.h"
#include "scripting/class.h"
+#include "scripting/argconv.h"
using namespace std;
using namespace lightspark;
void BitmapFilter::sinit(Class_base* c)
{
- c->setConstructor(NULL);
- c->setSuper(Class<ASObject>::getRef());
+ CLASS_SETUP(c, ASObject, _constructorNotInstantiatable, CLASS_SEALED);
c->setDeclaredMethodByQName("clone","",Class<IFunction>::getFunction(clone),NORMAL_METHOD,true);
}
@@ -41,24 +41,325 @@ ASFUNCTIONBODY(BitmapFilter,clone)
return th->cloneImpl();
}
+GlowFilter::GlowFilter(Class_base* c):
+ BitmapFilter(c), alpha(1.0), blurX(6.0), blurY(6.0), color(0xFF0000),
+ inner(false), knockout(false), quality(1), strength(2.0)
+{
+}
+
void GlowFilter::sinit(Class_base* c)
{
- c->setConstructor(NULL);
- c->setSuper(Class<BitmapFilter>::getRef());
+ CLASS_SETUP(c, BitmapFilter, _constructor, CLASS_SEALED | CLASS_FINAL);
+ REGISTER_GETTER_SETTER(c, alpha);
+ REGISTER_GETTER_SETTER(c, blurX);
+ REGISTER_GETTER_SETTER(c, blurY);
+ REGISTER_GETTER_SETTER(c, color);
+ REGISTER_GETTER_SETTER(c, inner);
+ REGISTER_GETTER_SETTER(c, knockout);
+ REGISTER_GETTER_SETTER(c, quality);
+ REGISTER_GETTER_SETTER(c, strength);
+}
+
+ASFUNCTIONBODY_GETTER_SETTER(GlowFilter, alpha);
+ASFUNCTIONBODY_GETTER_SETTER(GlowFilter, blurX);
+ASFUNCTIONBODY_GETTER_SETTER(GlowFilter, blurY);
+ASFUNCTIONBODY_GETTER_SETTER(GlowFilter, color);
+ASFUNCTIONBODY_GETTER_SETTER(GlowFilter, inner);
+ASFUNCTIONBODY_GETTER_SETTER(GlowFilter, knockout);
+ASFUNCTIONBODY_GETTER_SETTER(GlowFilter, quality);
+ASFUNCTIONBODY_GETTER_SETTER(GlowFilter, strength);
+
+ASFUNCTIONBODY(GlowFilter, _constructor)
+{
+ GlowFilter *th = obj->as<GlowFilter>();
+ ARG_UNPACK (th->color, 0xFF0000)
+ (th->alpha, 1.0)
+ (th->blurX, 6.0)
+ (th->blurY, 6.0)
+ (th->strength, 2.0)
+ (th->quality, 1)
+ (th->inner, false)
+ (th->knockout, false);
+ return NULL;
}
-GlowFilter* GlowFilter::cloneImpl() const
+BitmapFilter* GlowFilter::cloneImpl() const
+{
+ GlowFilter *cloned = Class<GlowFilter>::getInstanceS();
+ cloned->alpha = alpha;
+ cloned->blurX = blurX;
+ cloned->blurY = blurY;
+ cloned->color = color;
+ cloned->inner = inner;
+ cloned->knockout = knockout;
+ cloned->quality = quality;
+ cloned->strength = strength;
+ return cloned;
+}
+
+DropShadowFilter::DropShadowFilter(Class_base* c):
+ BitmapFilter(c), alpha(1.0), angle(45), blurX(4.0), blurY(4.0),
+ color(0), distance(4.0), hideObject(false), inner(false),
+ knockout(false), quality(1), strength(1.0)
{
- return Class<GlowFilter>::getInstanceS();
}
void DropShadowFilter::sinit(Class_base* c)
{
- c->setConstructor(NULL);
- c->setSuper(Class<BitmapFilter>::getRef());
+ CLASS_SETUP(c, BitmapFilter, _constructor, CLASS_SEALED | CLASS_FINAL);
+ REGISTER_GETTER_SETTER(c, alpha);
+ REGISTER_GETTER_SETTER(c, angle);
+ REGISTER_GETTER_SETTER(c, blurX);
+ REGISTER_GETTER_SETTER(c, blurY);
+ REGISTER_GETTER_SETTER(c, color);
+ REGISTER_GETTER_SETTER(c, distance);
+ REGISTER_GETTER_SETTER(c, hideObject);
+ REGISTER_GETTER_SETTER(c, inner);
+ REGISTER_GETTER_SETTER(c, knockout);
+ REGISTER_GETTER_SETTER(c, quality);
+ REGISTER_GETTER_SETTER(c, strength);
+}
+
+ASFUNCTIONBODY_GETTER_SETTER(DropShadowFilter, alpha);
+ASFUNCTIONBODY_GETTER_SETTER(DropShadowFilter, angle);
+ASFUNCTIONBODY_GETTER_SETTER(DropShadowFilter, blurX);
+ASFUNCTIONBODY_GETTER_SETTER(DropShadowFilter, blurY);
+ASFUNCTIONBODY_GETTER_SETTER(DropShadowFilter, color);
+ASFUNCTIONBODY_GETTER_SETTER(DropShadowFilter, distance);
+ASFUNCTIONBODY_GETTER_SETTER(DropShadowFilter, hideObject);
+ASFUNCTIONBODY_GETTER_SETTER(DropShadowFilter, inner);
+ASFUNCTIONBODY_GETTER_SETTER(DropShadowFilter, knockout);
+ASFUNCTIONBODY_GETTER_SETTER(DropShadowFilter, quality);
+ASFUNCTIONBODY_GETTER_SETTER(DropShadowFilter, strength);
+
+ASFUNCTIONBODY(DropShadowFilter, _constructor)
+{
+ DropShadowFilter *th = obj->as<DropShadowFilter>();
+ ARG_UNPACK (th->distance, 4.0)
+ (th->angle, 45)
+ (th->color, 0)
+ (th->alpha, 1.0)
+ (th->blurX, 4.0)
+ (th->blurY, 4.0)
+ (th->strength, 1.0)
+ (th->quality, 1)
+ (th->inner, false)
+ (th->knockout, false)
+ (th->hideObject, false);
+ return NULL;
+}
+
+BitmapFilter* DropShadowFilter::cloneImpl() const
+{
+ DropShadowFilter *cloned = Class<DropShadowFilter>::getInstanceS();
+ cloned->alpha = alpha;
+ cloned->angle = angle;
+ cloned->blurX = blurX;
+ cloned->blurY = blurY;
+ cloned->color = color;
+ cloned->distance = distance;
+ cloned->hideObject = hideObject;
+ cloned->inner = inner;
+ cloned->knockout = knockout;
+ cloned->quality = quality;
+ cloned->strength = strength;
+ return cloned;
+}
+
+GradientGlowFilter::GradientGlowFilter(Class_base* c):
+ BitmapFilter(c)
+{
+}
+
+void GradientGlowFilter::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, BitmapFilter, _constructor, CLASS_SEALED | CLASS_FINAL);
+}
+
+ASFUNCTIONBODY(GradientGlowFilter, _constructor)
+{
+ GradientGlowFilter *th = obj->as<GradientGlowFilter>();
+ LOG(LOG_NOT_IMPLEMENTED,"GradientGlowFilter is not implemented");
+ return NULL;
+}
+
+BitmapFilter* GradientGlowFilter::cloneImpl() const
+{
+ GradientGlowFilter *cloned = Class<GradientGlowFilter>::getInstanceS();
+ return cloned;
+}
+
+BevelFilter::BevelFilter(Class_base* c):
+ BitmapFilter(c)
+{
+}
+
+void BevelFilter::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, BitmapFilter, _constructor, CLASS_SEALED | CLASS_FINAL);
+}
+
+ASFUNCTIONBODY(BevelFilter, _constructor)
+{
+ BevelFilter *th = obj->as<BevelFilter>();
+ LOG(LOG_NOT_IMPLEMENTED,"GradientGlowFilter is not implemented");
+ return NULL;
+}
+
+BitmapFilter* BevelFilter::cloneImpl() const
+{
+ BevelFilter *cloned = Class<BevelFilter>::getInstanceS();
+ return cloned;
+}
+ColorMatrixFilter::ColorMatrixFilter(Class_base* c):
+ BitmapFilter(c),matrix(NULL)
+{
+}
+
+void ColorMatrixFilter::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, BitmapFilter, _constructor, CLASS_SEALED | CLASS_FINAL);
+ REGISTER_GETTER_SETTER(c, matrix);
+}
+
+ASFUNCTIONBODY_GETTER_SETTER(ColorMatrixFilter, matrix);
+
+ASFUNCTIONBODY(ColorMatrixFilter, _constructor)
+{
+ ColorMatrixFilter *th = obj->as<ColorMatrixFilter>();
+ ARG_UNPACK(th->matrix,NullRef);
+ return NULL;
+}
+
+BitmapFilter* ColorMatrixFilter::cloneImpl() const
+{
+ ColorMatrixFilter *cloned = Class<ColorMatrixFilter>::getInstanceS();
+ if (!matrix.isNull())
+ {
+ matrix->incRef();
+ cloned->matrix = matrix;
+ }
+ return cloned;
+}
+BlurFilter::BlurFilter(Class_base* c):
+ BitmapFilter(c)
+{
+}
+
+void BlurFilter::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, BitmapFilter, _constructor, CLASS_SEALED | CLASS_FINAL);
+}
+
+ASFUNCTIONBODY(BlurFilter, _constructor)
+{
+ BlurFilter *th = obj->as<BlurFilter>();
+ LOG(LOG_NOT_IMPLEMENTED,"BlurFilter is not implemented");
+ return NULL;
+}
+
+BitmapFilter* BlurFilter::cloneImpl() const
+{
+ BlurFilter *cloned = Class<BlurFilter>::getInstanceS();
+ return cloned;
+}
+
+ConvolutionFilter::ConvolutionFilter(Class_base* c):
+ BitmapFilter(c)
+{
+}
+
+void ConvolutionFilter::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, BitmapFilter, _constructor, CLASS_SEALED | CLASS_FINAL);
+}
+
+ASFUNCTIONBODY(ConvolutionFilter, _constructor)
+{
+ ConvolutionFilter *th = obj->as<ConvolutionFilter>();
+ LOG(LOG_NOT_IMPLEMENTED,"ConvolutionFilter is not implemented");
+ return NULL;
+}
+
+BitmapFilter* ConvolutionFilter::cloneImpl() const
+{
+ ConvolutionFilter *cloned = Class<ConvolutionFilter>::getInstanceS();
+ return cloned;
+}
+
+DisplacementMapFilter::DisplacementMapFilter(Class_base* c):
+ BitmapFilter(c)
+{
+}
+
+void DisplacementMapFilter::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, BitmapFilter, _constructor, CLASS_SEALED | CLASS_FINAL);
+}
+
+ASFUNCTIONBODY(DisplacementMapFilter, _constructor)
+{
+ DisplacementMapFilter *th = obj->as<DisplacementMapFilter>();
+ LOG(LOG_NOT_IMPLEMENTED,"DisplacementMapFilter is not implemented");
+ return NULL;
+}
+
+BitmapFilter* DisplacementMapFilter::cloneImpl() const
+{
+ DisplacementMapFilter *cloned = Class<DisplacementMapFilter>::getInstanceS();
+ return cloned;
+}
+
+GradientBevelFilter::GradientBevelFilter(Class_base* c):
+ BitmapFilter(c)
+{
+}
+
+void GradientBevelFilter::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, BitmapFilter, _constructor, CLASS_SEALED | CLASS_FINAL);
+}
+
+ASFUNCTIONBODY(GradientBevelFilter, _constructor)
+{
+ GradientBevelFilter *th = obj->as<GradientBevelFilter>();
+ LOG(LOG_NOT_IMPLEMENTED,"GradientBevelFilter is not implemented");
+ return NULL;
+}
+
+BitmapFilter* GradientBevelFilter::cloneImpl() const
+{
+ GradientBevelFilter *cloned = Class<GradientBevelFilter>::getInstanceS();
+ return cloned;
+}
+
+ShaderFilter::ShaderFilter(Class_base* c):
+ BitmapFilter(c)
+{
+}
+
+void ShaderFilter::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, BitmapFilter, _constructor, CLASS_SEALED | CLASS_FINAL);
+}
+
+ASFUNCTIONBODY(ShaderFilter, _constructor)
+{
+ ShaderFilter *th = obj->as<ShaderFilter>();
+ LOG(LOG_NOT_IMPLEMENTED,"ShaderFilter is not implemented");
+ return NULL;
+}
+
+BitmapFilter* ShaderFilter::cloneImpl() const
+{
+ ShaderFilter *cloned = Class<ShaderFilter>::getInstanceS();
+ return cloned;
}
-DropShadowFilter* DropShadowFilter::cloneImpl() const
+void BitmapFilterQuality::sinit(Class_base* c)
{
- return Class<DropShadowFilter>::getInstanceS();
+ CLASS_SETUP(c, ASObject, _constructorNotInstantiatable, CLASS_SEALED | CLASS_FINAL);
+ c->setVariableByQName("HIGH","",abstract_i(3),DECLARED_TRAIT);
+ c->setVariableByQName("LOW","",abstract_i(1),DECLARED_TRAIT);
+ c->setVariableByQName("MEDIUM","",abstract_i(3),DECLARED_TRAIT);
}
diff --git a/src/scripting/flash/filters/flashfilters.h b/src/scripting/flash/filters/flashfilters.h
index 2004b94..f81e73d 100644
--- a/src/scripting/flash/filters/flashfilters.h
+++ b/src/scripting/flash/filters/flashfilters.h
@@ -40,21 +40,124 @@ public:
class GlowFilter: public BitmapFilter
{
private:
- virtual GlowFilter* cloneImpl() const;
+ ASPROPERTY_GETTER_SETTER(number_t, alpha);
+ ASPROPERTY_GETTER_SETTER(number_t, blurX);
+ ASPROPERTY_GETTER_SETTER(number_t, blurY);
+ ASPROPERTY_GETTER_SETTER(uint32_t, color);
+ ASPROPERTY_GETTER_SETTER(bool, inner);
+ ASPROPERTY_GETTER_SETTER(bool, knockout);
+ ASPROPERTY_GETTER_SETTER(int32_t, quality);
+ ASPROPERTY_GETTER_SETTER(number_t, strength);
+ virtual BitmapFilter* cloneImpl() const;
public:
- GlowFilter(Class_base* c):BitmapFilter(c){}
+ GlowFilter(Class_base* c);
static void sinit(Class_base* c);
// static void buildTraits(ASObject* o);
+ ASFUNCTION(_constructor);
};
class DropShadowFilter: public BitmapFilter
{
private:
- virtual DropShadowFilter* cloneImpl() const;
+ ASPROPERTY_GETTER_SETTER(number_t, alpha);
+ ASPROPERTY_GETTER_SETTER(number_t, angle);
+ ASPROPERTY_GETTER_SETTER(number_t, blurX);
+ ASPROPERTY_GETTER_SETTER(number_t, blurY);
+ ASPROPERTY_GETTER_SETTER(uint32_t, color);
+ ASPROPERTY_GETTER_SETTER(number_t, distance);
+ ASPROPERTY_GETTER_SETTER(bool, hideObject);
+ ASPROPERTY_GETTER_SETTER(bool, inner);
+ ASPROPERTY_GETTER_SETTER(bool, knockout);
+ ASPROPERTY_GETTER_SETTER(int32_t, quality);
+ ASPROPERTY_GETTER_SETTER(number_t, strength);
+ virtual BitmapFilter* cloneImpl() const;
public:
- DropShadowFilter(Class_base* c):BitmapFilter(c){}
+ DropShadowFilter(Class_base* c);
static void sinit(Class_base* c);
// static void buildTraits(ASObject* o);
+ ASFUNCTION(_constructor);
+};
+
+class GradientGlowFilter: public BitmapFilter
+{
+private:
+ virtual BitmapFilter* cloneImpl() const;
+public:
+ GradientGlowFilter(Class_base* c);
+ static void sinit(Class_base* c);
+ ASFUNCTION(_constructor);
+};
+
+class BevelFilter: public BitmapFilter
+{
+private:
+ virtual BitmapFilter* cloneImpl() const;
+public:
+ BevelFilter(Class_base* c);
+ static void sinit(Class_base* c);
+ ASFUNCTION(_constructor);
+};
+class ColorMatrixFilter: public BitmapFilter
+{
+private:
+ virtual BitmapFilter* cloneImpl() const;
+public:
+ ColorMatrixFilter(Class_base* c);
+ static void sinit(Class_base* c);
+ ASFUNCTION(_constructor);
+ ASPROPERTY_GETTER_SETTER(_NR<Array>, matrix);
+};
+class BlurFilter: public BitmapFilter
+{
+private:
+ virtual BitmapFilter* cloneImpl() const;
+public:
+ BlurFilter(Class_base* c);
+ static void sinit(Class_base* c);
+ ASFUNCTION(_constructor);
+};
+class ConvolutionFilter: public BitmapFilter
+{
+private:
+ virtual BitmapFilter* cloneImpl() const;
+public:
+ ConvolutionFilter(Class_base* c);
+ static void sinit(Class_base* c);
+ ASFUNCTION(_constructor);
+};
+class DisplacementMapFilter: public BitmapFilter
+{
+private:
+ virtual BitmapFilter* cloneImpl() const;
+public:
+ DisplacementMapFilter(Class_base* c);
+ static void sinit(Class_base* c);
+ ASFUNCTION(_constructor);
+};
+class GradientBevelFilter: public BitmapFilter
+{
+private:
+ virtual BitmapFilter* cloneImpl() const;
+public:
+ GradientBevelFilter(Class_base* c);
+ static void sinit(Class_base* c);
+ ASFUNCTION(_constructor);
+};
+class ShaderFilter: public BitmapFilter
+{
+private:
+ virtual BitmapFilter* cloneImpl() const;
+public:
+ ShaderFilter(Class_base* c);
+ static void sinit(Class_base* c);
+ ASFUNCTION(_constructor);
+};
+
+class BitmapFilterQuality: public ASObject
+{
+public:
+ BitmapFilterQuality(Class_base* c):ASObject(c) {}
+ static void sinit(Class_base* c);
};
};
diff --git a/src/scripting/flash/geom/flashgeom.cpp b/src/scripting/flash/geom/flashgeom.cpp
index 4d7f12b..8d93cd9 100644
--- a/src/scripting/flash/geom/flashgeom.cpp
+++ b/src/scripting/flash/geom/flashgeom.cpp
@@ -26,7 +26,7 @@ using namespace std;
void Rectangle::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED);
IFunction* gleft=Class<IFunction>::getFunction(_getLeft);
c->setDeclaredMethodByQName("left","",gleft,GETTER_METHOD,true);
gleft->incRef();
@@ -490,7 +490,7 @@ ColorTransform::ColorTransform(Class_base* c, const CXFORMWITHALPHA& cx)
void ColorTransform::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED);
// properties
c->setDeclaredMethodByQName("color","",Class<IFunction>::getFunction(getColor),GETTER_METHOD,true);
@@ -582,7 +582,6 @@ ASFUNCTIONBODY(ColorTransform,setColor)
ASFUNCTIONBODY(ColorTransform,getColor)
{
- assert_and_throw(argslen==1);
ColorTransform* th=static_cast<ColorTransform*>(obj);
int ao, ro, go, bo;
@@ -738,7 +737,7 @@ ASFUNCTIONBODY(ColorTransform,_toString)
void Point::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED);
c->setDeclaredMethodByQName("x","",Class<IFunction>::getFunction(_getX),GETTER_METHOD,true);
c->setDeclaredMethodByQName("y","",Class<IFunction>::getFunction(_getY),GETTER_METHOD,true);
c->setDeclaredMethodByQName("length","",Class<IFunction>::getFunction(_getlength),GETTER_METHOD,true);
@@ -930,12 +929,13 @@ void Transform::finalize()
void Transform::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED);
c->setDeclaredMethodByQName("colorTransform","",Class<IFunction>::getFunction(_getColorTransform),GETTER_METHOD,true);
c->setDeclaredMethodByQName("colorTransform","",Class<IFunction>::getFunction(_setColorTransform),SETTER_METHOD,true);
c->setDeclaredMethodByQName("matrix","",Class<IFunction>::getFunction(_setMatrix),SETTER_METHOD,true);
c->setDeclaredMethodByQName("matrix","",Class<IFunction>::getFunction(_getMatrix),GETTER_METHOD,true);
c->setDeclaredMethodByQName("matrix","",Class<IFunction>::getFunction(_setMatrix),SETTER_METHOD,true);
+ c->setDeclaredMethodByQName("concatenatedMatrix","",Class<IFunction>::getFunction(_getConcatenatedMatrix),GETTER_METHOD,true);
}
ASFUNCTIONBODY(Transform,_constructor)
@@ -985,6 +985,13 @@ ASFUNCTIONBODY(Transform,_setColorTransform)
return NULL;
}
+ASFUNCTIONBODY(Transform,_getConcatenatedMatrix)
+{
+ Transform* th=Class<Transform>::cast(obj);
+ LOG(LOG_NOT_IMPLEMENTED,"contcatenatedMAtrix not implemented");
+ return Class<Matrix>::getInstanceS();
+}
+
void Transform::buildTraits(ASObject* o)
{
}
@@ -999,7 +1006,7 @@ Matrix::Matrix(Class_base* c, const MATRIX& m):ASObject(c),matrix(m)
void Matrix::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED);
//Properties
c->setDeclaredMethodByQName("a","",Class<IFunction>::getFunction(_get_a),GETTER_METHOD,true);
@@ -1318,7 +1325,7 @@ ASFUNCTIONBODY(Matrix,deltaTransformPoint)
void Vector3D::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED);
// constants
Vector3D* tx = new (c->memoryAccount) Vector3D(c);
@@ -1705,3 +1712,28 @@ ASFUNCTIONBODY(Vector3D,subtract)
return ret;
}
+
+
+void Matrix3D::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED);
+}
+
+ASFUNCTIONBODY(Matrix3D,_constructor)
+{
+ Matrix3D * th=static_cast<Matrix3D*>(obj);
+ LOG(LOG_NOT_IMPLEMENTED,"Matrix3D is not implemented");
+ return NULL;
+}
+
+void PerspectiveProjection::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED);
+}
+
+ASFUNCTIONBODY(PerspectiveProjection,_constructor)
+{
+ PerspectiveProjection * th=static_cast<PerspectiveProjection*>(obj);
+ LOG(LOG_NOT_IMPLEMENTED,"PerspectiveProjection is not implemented");
+ return NULL;
+}
diff --git a/src/scripting/flash/geom/flashgeom.h b/src/scripting/flash/geom/flashgeom.h
index 1ca359a..31dd8e8 100644
--- a/src/scripting/flash/geom/flashgeom.h
+++ b/src/scripting/flash/geom/flashgeom.h
@@ -107,7 +107,8 @@ public:
class ColorTransform: public ASObject
{
-private:
+friend class BitmapData;
+protected:
number_t redMultiplier,greenMultiplier,blueMultiplier,alphaMultiplier;
number_t redOffset,greenOffset,blueOffset,alphaOffset;
public:
@@ -184,6 +185,7 @@ public:
ASFUNCTION(_set_ty);
};
+class DisplayObject;
class Transform: public ASObject
{
private:
@@ -199,6 +201,8 @@ public:
ASFUNCTION(_setColorTransform);
ASFUNCTION(_getMatrix);
ASFUNCTION(_setMatrix);
+ ASFUNCTION(_getConcatenatedMatrix);
+
};
class Vector3D: public ASObject
@@ -243,5 +247,22 @@ public:
ASFUNCTION(_toString);
};
+class Matrix3D: public ASObject
+{
+public:
+ Matrix3D(Class_base* c):ASObject(c){}
+ static void sinit(Class_base* c);
+
+ ASFUNCTION(_constructor);
};
+class PerspectiveProjection: public ASObject
+{
+public:
+ PerspectiveProjection(Class_base* c):ASObject(c){}
+ static void sinit(Class_base* c);
+
+ ASFUNCTION(_constructor);
+};
+
+}
#endif /* SCRIPTING_FLASH_FLASHGEOM_H */
diff --git a/src/scripting/flash/media/flashmedia.cpp b/src/scripting/flash/media/flashmedia.cpp
index 3caaa55..f78cb52 100644
--- a/src/scripting/flash/media/flashmedia.cpp
+++ b/src/scripting/flash/media/flashmedia.cpp
@@ -24,6 +24,7 @@
#include <iostream>
#include "backends/audio.h"
#include "backends/rendering.h"
+#include "backends/streamcache.h"
#include "scripting/argconv.h"
using namespace lightspark;
@@ -31,8 +32,7 @@ using namespace std;
void SoundTransform::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASObject>::getRef());
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED | CLASS_FINAL);
REGISTER_GETTER_SETTER(c,volume);
REGISTER_GETTER_SETTER(c,pan);
}
@@ -55,8 +55,7 @@ ASFUNCTIONBODY(SoundTransform,_constructor)
void Video::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<DisplayObject>::getRef());
+ CLASS_SETUP(c, DisplayObject, _constructor, CLASS_SEALED);
c->setDeclaredMethodByQName("videoWidth","",Class<IFunction>::getFunction(_getVideoWidth),GETTER_METHOD,true);
c->setDeclaredMethodByQName("videoHeight","",Class<IFunction>::getFunction(_getVideoHeight),GETTER_METHOD,true);
c->setDeclaredMethodByQName("width","",Class<IFunction>::getFunction(Video::_getWidth),GETTER_METHOD,true);
@@ -64,8 +63,14 @@ void Video::sinit(Class_base* c)
c->setDeclaredMethodByQName("height","",Class<IFunction>::getFunction(Video::_getHeight),GETTER_METHOD,true);
c->setDeclaredMethodByQName("height","",Class<IFunction>::getFunction(Video::_setHeight),SETTER_METHOD,true);
c->setDeclaredMethodByQName("attachNetStream","",Class<IFunction>::getFunction(attachNetStream),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("clear","",Class<IFunction>::getFunction(clear),NORMAL_METHOD,true);
+ REGISTER_GETTER_SETTER(c, deblocking);
+ REGISTER_GETTER_SETTER(c, smoothing);
}
+ASFUNCTIONBODY_GETTER_SETTER(Video, deblocking);
+ASFUNCTIONBODY_GETTER_SETTER(Video, smoothing);
+
void Video::buildTraits(ASObject* o)
{
}
@@ -77,7 +82,8 @@ void Video::finalize()
}
Video::Video(Class_base* c, uint32_t w, uint32_t h)
- : DisplayObject(c),width(w),height(h),videoWidth(0),videoHeight(0),initialized(false),netStream(NullRef)
+ : DisplayObject(c),width(w),height(h),videoWidth(0),videoHeight(0),
+ initialized(false),netStream(NullRef),deblocking(0),smoothing(false)
{
}
@@ -204,6 +210,11 @@ ASFUNCTIONBODY(Video,attachNetStream)
th->netStream=_MR(Class<NetStream>::cast(args[0]));
return NULL;
}
+ASFUNCTIONBODY(Video,clear)
+{
+ LOG(LOG_NOT_IMPLEMENTED,"clear is not implemented");
+ return NULL;
+}
_NR<DisplayObject> Video::hitTestImpl(_NR<DisplayObject> last, number_t x, number_t y, DisplayObject::HIT_TYPE type)
{
@@ -215,7 +226,16 @@ _NR<DisplayObject> Video::hitTestImpl(_NR<DisplayObject> last, number_t x, numbe
}
Sound::Sound(Class_base* c)
- :EventDispatcher(c),downloader(NULL),soundChannelCreated(false),bytesLoaded(0),bytesTotal(0),length(60*1000)
+ :EventDispatcher(c),downloader(NULL),soundData(new MemoryStreamCache),
+ container(true),format(CODEC_NONE, 0, 0),bytesLoaded(0),bytesTotal(0),length(60*1000)
+{
+}
+
+Sound::Sound(Class_base* c, _R<StreamCache> data, AudioFormat _format)
+ :EventDispatcher(c),downloader(NULL),soundData(data),
+ container(false),format(_format),
+ bytesLoaded(soundData->getReceivedLength()),
+ bytesTotal(soundData->getReceivedLength()),length(60*1000)
{
}
@@ -227,8 +247,7 @@ Sound::~Sound()
void Sound::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<EventDispatcher>::getRef());
+ CLASS_SETUP(c, EventDispatcher, _constructor, CLASS_SEALED);
c->setDeclaredMethodByQName("load","",Class<IFunction>::getFunction(load),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("play","",Class<IFunction>::getFunction(play),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("close","",Class<IFunction>::getFunction(close),NORMAL_METHOD,true);
@@ -261,6 +280,9 @@ ASFUNCTIONBODY(Sound,load)
th->url = urlRequest->getRequestURL();
urlRequest->getPostData(th->postData);
+ _R<StreamCache> c(_MR(new MemoryStreamCache()));
+ th->soundData = c;
+
if(!th->url.isValid())
{
//Notify an error during loading
@@ -275,13 +297,13 @@ ASFUNCTIONBODY(Sound,load)
{
//This is a GET request
//Use disk cache our downloaded files
- th->downloader=getSys()->downloadManager->download(th->url, true, th);
+ th->downloader=getSys()->downloadManager->download(th->url, th->soundData, th);
}
else
{
list<tiny_string> headers=urlRequest->getHeaders();
- th->downloader=getSys()->downloadManager->downloadWithData(th->url, th->postData,
- headers, th);
+ th->downloader=getSys()->downloadManager->downloadWithData(th->url,
+ th->soundData, th->postData, headers, th);
//Clean up the postData for the next load
th->postData.clear();
}
@@ -302,19 +324,11 @@ ASFUNCTIONBODY(Sound,play)
if(startTime!=0)
LOG(LOG_NOT_IMPLEMENTED,"startTime not supported in Sound::play");
- if (!th->soundChannelCreated)
- {
- th->soundChannelCreated = true;
- th->incRef();
- return Class<SoundChannel>::getInstanceS(th->downloader, _MNR(th));
- }
+ th->incRef();
+ if (th->container)
+ return Class<SoundChannel>::getInstanceS(th->soundData);
else
- {
- LOG(LOG_NOT_IMPLEMENTED,"Sound::play called more than once");
- // should return a new independent SoundChannel for
- // the same downloaded data
- return getSys()->getUndefinedRef();
- }
+ return Class<SoundChannel>::getInstanceS(th->soundData, th->format);
}
ASFUNCTIONBODY(Sound,close)
@@ -352,8 +366,7 @@ ASFUNCTIONBODY_GETTER(Sound,length);
void SoundLoaderContext::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASObject>::getRef());
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED);
REGISTER_GETTER_SETTER(c,bufferTime);
REGISTER_GETTER_SETTER(c,checkPolicyFile);
}
@@ -374,10 +387,11 @@ ASFUNCTIONBODY(SoundLoaderContext,_constructor)
ASFUNCTIONBODY_GETTER_SETTER(SoundLoaderContext,bufferTime);
ASFUNCTIONBODY_GETTER_SETTER(SoundLoaderContext,checkPolicyFile);
-SoundChannel::SoundChannel(Class_base* c, std::streambuf *s, _NR<Sound> _owner)
- : EventDispatcher(c),stream(s),owner(_owner),stopped(false),audioDecoder(NULL),audioStream(NULL),position(0)
+SoundChannel::SoundChannel(Class_base* c, _NR<StreamCache> _stream, AudioFormat _format)
+: EventDispatcher(c),stream(_stream),stopped(false),audioDecoder(NULL),audioStream(NULL),
+ format(_format),position(0),soundTransform(_MR(Class<SoundTransform>::getInstanceS()))
{
- if(s)
+ if (!stream.isNull())
{
// Start playback
incRef();
@@ -392,19 +406,35 @@ SoundChannel::~SoundChannel()
void SoundChannel::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<EventDispatcher>::getRef());
+ CLASS_SETUP(c, EventDispatcher, _constructor, CLASS_SEALED | CLASS_FINAL);
c->setDeclaredMethodByQName("stop","",Class<IFunction>::getFunction(stop),NORMAL_METHOD,true);
REGISTER_GETTER(c,position);
+ REGISTER_GETTER_SETTER(c,soundTransform);
}
ASFUNCTIONBODY_GETTER(SoundChannel,position);
+ASFUNCTIONBODY_GETTER_SETTER_CB(SoundChannel,soundTransform,validateSoundTransform);
void SoundChannel::buildTraits(ASObject* o)
{
}
+void SoundChannel::finalize()
+{
+ EventDispatcher::finalize();
+ soundTransform.reset();
+}
+
+void SoundChannel::validateSoundTransform(_NR<SoundTransform> oldValue)
+{
+ if (soundTransform.isNull())
+ {
+ soundTransform = oldValue;
+ throwError<TypeError>(kNullPointerError, "soundTransform");
+ }
+}
+
ASFUNCTIONBODY(SoundChannel, _constructor)
{
EventDispatcher::_constructor(obj, NULL, 0);
@@ -421,7 +451,18 @@ ASFUNCTIONBODY(SoundChannel, stop)
void SoundChannel::execute()
{
- stream.exceptions ( istream::eofbit | istream::failbit | istream::badbit );
+ if (format.codec == CODEC_NONE)
+ playStream();
+ else
+ playRaw();
+}
+
+void SoundChannel::playStream()
+{
+ assert(!stream.isNull());
+ std::streambuf *sbuf = stream->createReader();
+ istream s(sbuf);
+ s.exceptions ( istream::eofbit | istream::failbit | istream::badbit );
bool waitForFlush=true;
StreamDecoder* streamDecoder=NULL;
@@ -429,7 +470,7 @@ void SoundChannel::execute()
try
{
#ifdef ENABLE_LIBAVCODEC
- streamDecoder=new FFMpegStreamDecoder(stream);
+ streamDecoder=new FFMpegStreamDecoder(s);
if(!streamDecoder->isValid())
threadAbort();
@@ -486,6 +527,45 @@ void SoundChannel::execute()
audioStream=NULL;
}
delete streamDecoder;
+ delete sbuf;
+
+ if (!ACQUIRE_READ(stopped))
+ {
+ incRef();
+ getVm()->addEvent(_MR(this),_MR(Class<Event>::getInstanceS("soundComplete")));
+ }
+}
+
+void SoundChannel::playRaw()
+{
+ assert(!stream.isNull());
+ FFMpegAudioDecoder *decoder = new FFMpegAudioDecoder(format.codec,
+ format.sampleRate,
+ format.channels,
+ true);
+ if (!decoder)
+ return;
+ if(!getSys()->audioManager->pluginLoaded())
+ return;
+
+ AudioStream *audioStream = NULL;
+ std::streambuf *sbuf = stream->createReader();
+ istream stream(sbuf);
+ do
+ {
+ decoder->decodeStreamSomePackets(stream, 0);
+ if (decoder->isValid())
+ audioStream=getSys()->audioManager->createStreamPlugin(decoder);
+ }
+ while (!ACQUIRE_READ(stopped) && !stream.eof() && !stream.fail() && !stream.bad());
+
+ decoder->setFlushing();
+ decoder->waitFlushed();
+ sleep(1);
+
+ delete audioStream;
+ delete decoder;
+ delete sbuf;
if (!ACQUIRE_READ(stopped))
{
@@ -513,8 +593,7 @@ void SoundChannel::threadAbort()
void StageVideo::sinit(Class_base *c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<EventDispatcher>::getRef());
+ CLASS_SETUP(c, EventDispatcher, _constructor, CLASS_SEALED);
}
ASFUNCTIONBODY(StageVideo,_constructor)
@@ -525,14 +604,14 @@ ASFUNCTIONBODY(StageVideo,_constructor)
void StageVideoAvailability::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED | CLASS_FINAL);
c->setVariableByQName("AVAILABLE","",Class<ASString>::getInstanceS("available"),DECLARED_TRAIT);
c->setVariableByQName("UNAVAILABLE","",Class<ASString>::getInstanceS("unavailable"),DECLARED_TRAIT);
}
void VideoStatus::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED | CLASS_FINAL);
c->setVariableByQName("ACCELERATED","",Class<ASString>::getInstanceS("accelerated"),DECLARED_TRAIT);
c->setVariableByQName("SOFTWARE","",Class<ASString>::getInstanceS("software"),DECLARED_TRAIT);
c->setVariableByQName("UNAVAILABLE","",Class<ASString>::getInstanceS("unavailable"),DECLARED_TRAIT);
diff --git a/src/scripting/flash/media/flashmedia.h b/src/scripting/flash/media/flashmedia.h
index b7a2841..5397764 100644
--- a/src/scripting/flash/media/flashmedia.h
+++ b/src/scripting/flash/media/flashmedia.h
@@ -34,6 +34,16 @@ namespace lightspark
class AudioDecoder;
class NetStream;
+class StreamCache;
+
+class AudioFormat
+{
+public:
+ AudioFormat(LS_AUDIO_CODEC co, int sr, int ch):codec(co),sampleRate(sr),channels(ch) {}
+ LS_AUDIO_CODEC codec;
+ int sampleRate;
+ int channels;
+};
class Sound: public EventDispatcher, public ILoadable
{
@@ -41,7 +51,12 @@ private:
URLInfo url;
std::vector<uint8_t> postData;
Downloader* downloader;
- bool soundChannelCreated;
+ _R<StreamCache> soundData;
+ // If container is true, audio format is parsed from
+ // soundData. If container is false, soundData is raw samples
+ // and format is defined by format member.
+ bool container;
+ AudioFormat format;
ASPROPERTY_GETTER(uint32_t,bytesLoaded);
ASPROPERTY_GETTER(uint32_t,bytesTotal);
ASPROPERTY_GETTER(number_t,length);
@@ -50,6 +65,7 @@ private:
void setBytesLoaded(uint32_t b);
public:
Sound(Class_base* c);
+ Sound(Class_base* c, _R<StreamCache> soundData, AudioFormat format);
~Sound();
static void sinit(Class_base*);
static void buildTraits(ASObject* o);
@@ -72,20 +88,23 @@ public:
class SoundChannel : public EventDispatcher, public IThreadJob
{
private:
- std::istream stream;
- // owner keeps reference to the Sound object that owns the
- // streambuf. TODO: ugly, get rid of this
- _NR<Sound> owner;
+ _NR<StreamCache> stream;
Mutex mutex;
ACQUIRE_RELEASE_FLAG(stopped);
AudioDecoder* audioDecoder;
AudioStream* audioStream;
+ AudioFormat format;
ASPROPERTY_GETTER_SETTER(uint32_t,position);
+ ASPROPERTY_GETTER_SETTER(_NR<SoundTransform>,soundTransform);
+ void validateSoundTransform(_NR<SoundTransform>);
+ void playStream();
+ void playRaw();
public:
- SoundChannel(Class_base* c, std::streambuf *s=NULL, _NR<Sound> owner=NullRef);
+ SoundChannel(Class_base* c, _NR<StreamCache> stream=NullRef, AudioFormat format=AudioFormat(CODEC_NONE,0,0));
~SoundChannel();
static void sinit(Class_base* c);
static void buildTraits(ASObject* o);
+ void finalize();
ASFUNCTION(_constructor);
ASFUNCTION(stop);
@@ -103,6 +122,8 @@ private:
mutable uint32_t videoWidth, videoHeight;
bool initialized;
_NR<NetStream> netStream;
+ ASPROPERTY_GETTER_SETTER(int32_t, deblocking);
+ ASPROPERTY_GETTER_SETTER(bool, smoothing);
public:
Video(Class_base* c, uint32_t w=320, uint32_t h=240);
void finalize();
@@ -117,6 +138,7 @@ public:
ASFUNCTION(_getHeight);
ASFUNCTION(_setHeight);
ASFUNCTION(attachNetStream);
+ ASFUNCTION(clear);
void renderImpl(RenderContext& ctxt) const;
bool boundsRect(number_t& xmin, number_t& xmax, number_t& ymin, number_t& ymax) const;
_NR<DisplayObject> hitTestImpl(_NR<DisplayObject> last, number_t x, number_t y, DisplayObject::HIT_TYPE type);
diff --git a/src/scripting/flash/accessibility/flashaccessibility.cpp b/src/scripting/flash/net/NetStreamPlayOptions.cpp
similarity index 50%
copy from src/scripting/flash/accessibility/flashaccessibility.cpp
copy to src/scripting/flash/net/NetStreamPlayOptions.cpp
index ebc460d..86ba82c 100644
--- a/src/scripting/flash/accessibility/flashaccessibility.cpp
+++ b/src/scripting/flash/net/NetStreamPlayOptions.cpp
@@ -1,8 +1,6 @@
/**************************************************************************
Lightspark, a free flash player implementation
- Copyright (C) 2009-2013 Alessandro Pignotti (a.pignotti at sssup.it)
-
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
@@ -17,35 +15,38 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
-#include "scripting/flash/accessibility/flashaccessibility.h"
+#include "scripting/flash/net/NetStreamPlayOptions.h"
#include "scripting/class.h"
#include "scripting/argconv.h"
+using namespace std;
using namespace lightspark;
-void AccessibilityProperties::sinit(Class_base* c)
+NetStreamPlayOptions::NetStreamPlayOptions(Class_base* c):EventDispatcher(c),len(-1),offset(-1),start(-2)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASObject>::getRef());
- REGISTER_GETTER_SETTER(c,name);
+
}
-
-ASFUNCTIONBODY(AccessibilityProperties,_constructor)
+void NetStreamPlayOptions::sinit(Class_base* c)
{
- LOG(LOG_NOT_IMPLEMENTED, _("AccessibilityProperties class is unimplemented."));
- return NULL;
+ CLASS_SETUP(c, EventDispatcher, _constructor, CLASS_DYNAMIC_NOT_FINAL);
+ REGISTER_GETTER_SETTER(c,len);
+ REGISTER_GETTER_SETTER(c,offset);
+ REGISTER_GETTER_SETTER(c,oldStreamName);
+ REGISTER_GETTER_SETTER(c,start);
+ REGISTER_GETTER_SETTER(c,streamName);
+ REGISTER_GETTER_SETTER(c,transition);
}
-ASFUNCTIONBODY_GETTER_SETTER(AccessibilityProperties,name);
+ASFUNCTIONBODY_GETTER_SETTER(NetStreamPlayOptions,len);
+ASFUNCTIONBODY_GETTER_SETTER(NetStreamPlayOptions,offset);
+ASFUNCTIONBODY_GETTER_SETTER(NetStreamPlayOptions,oldStreamName);
+ASFUNCTIONBODY_GETTER_SETTER(NetStreamPlayOptions,start);
+ASFUNCTIONBODY_GETTER_SETTER(NetStreamPlayOptions,streamName);
+ASFUNCTIONBODY_GETTER_SETTER(NetStreamPlayOptions,transition);
-void AccessibilityImplementation::sinit(Class_base* c)
+ASFUNCTIONBODY(NetStreamPlayOptions,_constructor)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASObject>::getRef());
-}
-
-ASFUNCTIONBODY(AccessibilityImplementation,_constructor)
-{
- LOG(LOG_NOT_IMPLEMENTED, _("AccessibilityImplementation class is unimplemented."));
+ EventDispatcher::_constructor(obj, NULL, 0);
return NULL;
}
+
diff --git a/src/scripting/flash/sensors/flashsensors.h b/src/scripting/flash/net/NetStreamPlayOptions.h
similarity index 64%
copy from src/scripting/flash/sensors/flashsensors.h
copy to src/scripting/flash/net/NetStreamPlayOptions.h
index 9f9ef19..8330d2a 100644
--- a/src/scripting/flash/sensors/flashsensors.h
+++ b/src/scripting/flash/net/NetStreamPlayOptions.h
@@ -1,8 +1,6 @@
/**************************************************************************
Lightspark, a free flash player implementation
- Copyright (C) 2011-2013 Alessandro Pignotti (a.pignotti at sssup.it)
-
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
@@ -17,25 +15,29 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
-#ifndef SCRIPTING_FLASH_SENSORS_FLASHSENSORS_H
-#define SCRIPTING_FLASH_SENSORS_FLASHSENSORS_H 1
+#ifndef NETSTREAMPLAYOPTIONS_H
+#define NETSTREAMPLAYOPTIONS_H
-#include "compat.h"
#include "asobject.h"
#include "scripting/flash/events/flashevents.h"
-#include "thread_pool.h"
-#include "backends/netutils.h"
-#include "timer.h"
-#include "backends/interfaces/audio/IAudioPlugin.h"
namespace lightspark
{
-class Accelerometer: public ASObject {
- public:
- Accelerometer(Class_base* c);
- static void sinit(Class_base* c);
- static void buildTraits(ASObject* o);
- ASFUNCTION(_isSupported);
+
+class NetStreamPlayOptions: public EventDispatcher
+{
+private:
+ ASPROPERTY_GETTER_SETTER(number_t,len);
+ ASPROPERTY_GETTER_SETTER(number_t,offset);
+ ASPROPERTY_GETTER_SETTER(tiny_string,oldStreamName);
+ ASPROPERTY_GETTER_SETTER(number_t,start);
+ ASPROPERTY_GETTER_SETTER(tiny_string,streamName);
+ ASPROPERTY_GETTER_SETTER(tiny_string,transition);
+public:
+ NetStreamPlayOptions(Class_base* c);
+ static void sinit(Class_base*);
+ ASFUNCTION(_constructor);
};
+
}
-#endif /* SCRIPTING_FLASH_SENSORS_FLASHSENSORS_H */
+#endif // NETSTREAMPLAYOPTIONS_H
diff --git a/src/scripting/flash/accessibility/flashaccessibility.cpp b/src/scripting/flash/net/NetStreamPlayTransitions.cpp
similarity index 51%
copy from src/scripting/flash/accessibility/flashaccessibility.cpp
copy to src/scripting/flash/net/NetStreamPlayTransitions.cpp
index ebc460d..7b23154 100644
--- a/src/scripting/flash/accessibility/flashaccessibility.cpp
+++ b/src/scripting/flash/net/NetStreamPlayTransitions.cpp
@@ -1,8 +1,6 @@
/**************************************************************************
Lightspark, a free flash player implementation
- Copyright (C) 2009-2013 Alessandro Pignotti (a.pignotti at sssup.it)
-
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
@@ -16,36 +14,27 @@
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
-
-#include "scripting/flash/accessibility/flashaccessibility.h"
+#include "scripting/flash/net/NetStreamPlayTransitions.h"
#include "scripting/class.h"
#include "scripting/argconv.h"
+using namespace std;
using namespace lightspark;
-void AccessibilityProperties::sinit(Class_base* c)
-{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASObject>::getRef());
- REGISTER_GETTER_SETTER(c,name);
-}
-
-ASFUNCTIONBODY(AccessibilityProperties,_constructor)
+NetStreamPlayTransitions::NetStreamPlayTransitions(Class_base* c):ASObject(c)
{
- LOG(LOG_NOT_IMPLEMENTED, _("AccessibilityProperties class is unimplemented."));
- return NULL;
+
}
-ASFUNCTIONBODY_GETTER_SETTER(AccessibilityProperties,name);
-
-void AccessibilityImplementation::sinit(Class_base* c)
+void NetStreamPlayTransitions::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASObject>::getRef());
+ CLASS_SETUP(c, ASObject, NULL, CLASS_FINAL);
+ c->setVariableByQName("APPEND","",Class<ASString>::getInstanceS("append"),CONSTANT_TRAIT);
+ c->setVariableByQName("APPEND_AND_WAIT","",Class<ASString>::getInstanceS("appendAndWait"),CONSTANT_TRAIT);
+ c->setVariableByQName("RESET","",Class<ASString>::getInstanceS("reset"),CONSTANT_TRAIT);
+ c->setVariableByQName("RESUME","",Class<ASString>::getInstanceS("resume"),CONSTANT_TRAIT);
+ c->setVariableByQName("STOP","",Class<ASString>::getInstanceS("stop"),CONSTANT_TRAIT);
+ c->setVariableByQName("SWAP","",Class<ASString>::getInstanceS("swap"),CONSTANT_TRAIT);
+ c->setVariableByQName("SWITCH","",Class<ASString>::getInstanceS("switch"),CONSTANT_TRAIT);
}
-ASFUNCTIONBODY(AccessibilityImplementation,_constructor)
-{
- LOG(LOG_NOT_IMPLEMENTED, _("AccessibilityImplementation class is unimplemented."));
- return NULL;
-}
diff --git a/src/backends/rtmputils.h b/src/scripting/flash/net/NetStreamPlayTransitions.h
similarity index 68%
copy from src/backends/rtmputils.h
copy to src/scripting/flash/net/NetStreamPlayTransitions.h
index 7e9de51..428d87b 100644
--- a/src/backends/rtmputils.h
+++ b/src/scripting/flash/net/NetStreamPlayTransitions.h
@@ -1,8 +1,6 @@
/**************************************************************************
Lightspark, a free flash player implementation
- Copyright (C) 2011-2013 Alessandro Pignotti (a.pignotti at sssup.it)
-
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
@@ -16,26 +14,20 @@
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
+#ifndef NETSTREAMPLAYTRANSITIONS_H
+#define NETSTREAMPLAYTRANSITIONS_H
-#ifndef BACKENDS_RTMPUTILS_H
-#define BACKENDS_RTMPUTILS_H 1
-
-#include "backends/netutils.h"
+#include "asobject.h"
namespace lightspark
{
-class ILoadable;
-
-class RTMPDownloader: public ThreadedDownloader
+class NetStreamPlayTransitions: public ASObject
{
-private:
- void execute();
- void threadAbort();
- tiny_string stream;
public:
- RTMPDownloader(const tiny_string& _url, const tiny_string& _stream, ILoadable* o);
+ NetStreamPlayTransitions(Class_base* c);
+ static void sinit(Class_base*);
};
-};
-#endif /* BACKENDS_RTMPUTILS_H */
+}
+#endif // NETSTREAMPLAYTRANSITIONS_H
diff --git a/src/scripting/flash/net/URLRequestHeader.cpp b/src/scripting/flash/net/URLRequestHeader.cpp
index cee832c..4bd97d6 100644
--- a/src/scripting/flash/net/URLRequestHeader.cpp
+++ b/src/scripting/flash/net/URLRequestHeader.cpp
@@ -10,8 +10,7 @@ URLRequestHeader::URLRequestHeader(Class_base* c) : ASObject(c)
void URLRequestHeader::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASObject>::getRef());
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_FINAL | CLASS_SEALED);
REGISTER_GETTER_SETTER(c,name);
REGISTER_GETTER_SETTER(c,value);
}
diff --git a/src/scripting/flash/net/URLStream.cpp b/src/scripting/flash/net/URLStream.cpp
index 1d3594a..3702865 100644
--- a/src/scripting/flash/net/URLStream.cpp
+++ b/src/scripting/flash/net/URLStream.cpp
@@ -43,17 +43,19 @@ void URLStreamThread::execute()
//TODO: support httpStatus, progress events
- if(!createDownloader(false, loader))
+ _R<MemoryStreamCache> cache(_MR(new MemoryStreamCache));
+ if(!createDownloader(cache, loader))
return;
bool success=false;
if(!downloader->hasFailed())
{
getVm()->addEvent(loader,_MR(Class<Event>::getInstanceS("open")));
- downloader->waitForTermination();
+ cache->waitForTermination();
if(!downloader->hasFailed() && !threadAborting)
{
- istream s(downloader);
+ std::streambuf *sbuf = cache->createReader();
+ istream s(sbuf);
uint8_t* buf=new uint8_t[downloader->getLength()];
//TODO: avoid this useless copy
s.read((char*)buf,downloader->getLength());
@@ -61,6 +63,7 @@ void URLStreamThread::execute()
data->acquireBuffer(buf,downloader->getLength());
//The buffers must not be deleted, it's now handled by the ByteArray instance
success=true;
+ delete sbuf;
}
}
@@ -86,8 +89,7 @@ void URLStreamThread::execute()
void URLStream::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<EventDispatcher>::getRef());
+ CLASS_SETUP(c, EventDispatcher, _constructor, CLASS_SEALED);
c->setDeclaredMethodByQName("load","",Class<IFunction>::getFunction(load),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("close","",Class<IFunction>::getFunction(close),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("load","",Class<IFunction>::getFunction(load),NORMAL_METHOD,true);
diff --git a/src/scripting/flash/net/URLStream.h b/src/scripting/flash/net/URLStream.h
index 3497f6f..1e7af44 100644
--- a/src/scripting/flash/net/URLStream.h
+++ b/src/scripting/flash/net/URLStream.h
@@ -23,6 +23,7 @@
#include "compat.h"
#include "asobject.h"
#include "scripting/flash/events/flashevents.h"
+#include "scripting/flash/utils/ByteArray.h"
#include "thread_pool.h"
#include "backends/netutils.h"
diff --git a/src/scripting/flash/net/XMLSocket.cpp b/src/scripting/flash/net/XMLSocket.cpp
index 273ce00..8fe5abd 100644
--- a/src/scripting/flash/net/XMLSocket.cpp
+++ b/src/scripting/flash/net/XMLSocket.cpp
@@ -172,8 +172,7 @@ XMLSocket::~XMLSocket()
void XMLSocket::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<EventDispatcher>::getRef());
+ CLASS_SETUP(c, EventDispatcher, _constructor, CLASS_SEALED);
c->setDeclaredMethodByQName("close","",Class<IFunction>::getFunction(_close),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("connect","",Class<IFunction>::getFunction(_connect),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("send","",Class<IFunction>::getFunction(_send),NORMAL_METHOD,true);
diff --git a/src/scripting/flash/net/flashnet.cpp b/src/scripting/flash/net/flashnet.cpp
index 7b268bc..695db78 100644
--- a/src/scripting/flash/net/flashnet.cpp
+++ b/src/scripting/flash/net/flashnet.cpp
@@ -29,6 +29,7 @@
#include "backends/audio.h"
#include "backends/builtindecoder.h"
#include "backends/rendering.h"
+#include "backends/streamcache.h"
#include "scripting/argconv.h"
using namespace std;
@@ -41,14 +42,15 @@ URLRequest::URLRequest(Class_base* c):ASObject(c),method(GET),contentType("appli
void URLRequest::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASObject>::getRef());
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_FINAL | CLASS_SEALED);
c->setDeclaredMethodByQName("url","",Class<IFunction>::getFunction(_setURL),SETTER_METHOD,true);
c->setDeclaredMethodByQName("url","",Class<IFunction>::getFunction(_getURL),GETTER_METHOD,true);
c->setDeclaredMethodByQName("method","",Class<IFunction>::getFunction(_setMethod),SETTER_METHOD,true);
c->setDeclaredMethodByQName("method","",Class<IFunction>::getFunction(_getMethod),GETTER_METHOD,true);
c->setDeclaredMethodByQName("data","",Class<IFunction>::getFunction(_setData),SETTER_METHOD,true);
c->setDeclaredMethodByQName("data","",Class<IFunction>::getFunction(_getData),GETTER_METHOD,true);
+ c->setDeclaredMethodByQName("digest","",Class<IFunction>::getFunction(_setDigest),SETTER_METHOD,true);
+ c->setDeclaredMethodByQName("digest","",Class<IFunction>::getFunction(_getDigest),GETTER_METHOD,true);
REGISTER_GETTER_SETTER(c,contentType);
REGISTER_GETTER_SETTER(c,requestHeaders);
}
@@ -283,12 +285,51 @@ ASFUNCTIONBODY(URLRequest,_setData)
return NULL;
}
+ASFUNCTIONBODY(URLRequest,_getDigest)
+{
+ URLRequest* th=obj->as<URLRequest>();
+ if (th->digest.empty())
+ return getSys()->getNullRef();
+ else
+ return Class<ASString>::getInstanceS(th->digest);
+}
+
+ASFUNCTIONBODY(URLRequest,_setDigest)
+{
+ URLRequest* th=obj->as<URLRequest>();
+ tiny_string value;
+ ARG_UNPACK(value);
+
+ int numHexChars = 0;
+ bool validChars = true;
+ for (CharIterator it=value.begin(); it!=value.end(); ++it)
+ {
+ if (((*it >= 'A') && (*it <= 'F')) ||
+ ((*it >= 'a') && (*it <= 'f')) ||
+ ((*it >= '0') && (*it <= '9')))
+ {
+ numHexChars++;
+ }
+ else
+ {
+ validChars = false;
+ break;
+ }
+ }
+
+ if (!validChars || numHexChars != 64)
+ throw Class<ArgumentError>::getInstanceS("An invalid digest was supplied", 2034);
+
+ th->digest = value;
+ return NULL;
+}
+
ASFUNCTIONBODY_GETTER_SETTER(URLRequest,contentType);
ASFUNCTIONBODY_GETTER_SETTER(URLRequest,requestHeaders);
void URLRequestMethod::sinit(Class_base* c)
{
- c->setSuper(Class<ASObject>::getRef());
+ CLASS_SETUP_NO_CONSTRUCTOR(c, ASObject, CLASS_FINAL | CLASS_SEALED);
c->setVariableByQName("GET","",Class<ASString>::getInstanceS("GET"),DECLARED_TRAIT);
c->setVariableByQName("POST","",Class<ASString>::getInstanceS("POST"),DECLARED_TRAIT);
}
@@ -304,7 +345,8 @@ void URLLoaderThread::execute()
//TODO: support httpStatus, progress events
- if(!createDownloader(false, loader, loader.getPtr()))
+ _R<MemoryStreamCache> cache(_MR(new MemoryStreamCache));
+ if(!createDownloader(cache, loader, loader.getPtr()))
return;
_NR<ASObject> data;
@@ -312,10 +354,12 @@ void URLLoaderThread::execute()
if(!downloader->hasFailed())
{
getVm()->addEvent(loader,_MR(Class<Event>::getInstanceS("open")));
- downloader->waitForTermination();
+
+ cache->waitForTermination();
if(!downloader->hasFailed() && !threadAborting)
{
- istream s(downloader);
+ std::streambuf *sbuf = cache->createReader();
+ istream s(sbuf);
uint8_t* buf=new uint8_t[downloader->getLength()+1];
//TODO: avoid this useless copy
s.read((char*)buf,downloader->getLength());
@@ -344,6 +388,7 @@ void URLLoaderThread::execute()
assert(false && "invalid dataFormat");
}
+ delete sbuf;
success=true;
}
}
@@ -381,8 +426,7 @@ void URLLoader::finalize()
void URLLoader::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<EventDispatcher>::getRef());
+ CLASS_SETUP(c, EventDispatcher, _constructor, CLASS_SEALED);
c->setDeclaredMethodByQName("dataFormat","",Class<IFunction>::getFunction(_getDataFormat),GETTER_METHOD,true);
c->setDeclaredMethodByQName("data","",Class<IFunction>::getFunction(_getData),GETTER_METHOD,true);
c->setDeclaredMethodByQName("data","",Class<IFunction>::getFunction(_setData),SETTER_METHOD,true);
@@ -539,12 +583,19 @@ ASFUNCTIONBODY(URLLoader,_setDataFormat)
void URLLoaderDataFormat::sinit(Class_base* c)
{
- c->setSuper(Class<ASObject>::getRef());
+ CLASS_SETUP(c, ASObject, _constructorNotInstantiatable, CLASS_FINAL | CLASS_SEALED);
c->setVariableByQName("VARIABLES","",Class<ASString>::getInstanceS("variables"),DECLARED_TRAIT);
c->setVariableByQName("TEXT","",Class<ASString>::getInstanceS("text"),DECLARED_TRAIT);
c->setVariableByQName("BINARY","",Class<ASString>::getInstanceS("binary"),DECLARED_TRAIT);
}
+void SharedObjectFlushStatus::sinit(Class_base* c)
+{
+ CLASS_SETUP_NO_CONSTRUCTOR(c, ASObject, CLASS_FINAL);
+ c->setVariableByQName("FLUSHED","",Class<ASString>::getInstanceS("flushed"),DECLARED_TRAIT);
+ c->setVariableByQName("PENDING","",Class<ASString>::getInstanceS("pending"),DECLARED_TRAIT);
+}
+
SharedObject::SharedObject(Class_base* c):EventDispatcher(c)
{
data=_MR(new_asobject());
@@ -552,10 +603,12 @@ SharedObject::SharedObject(Class_base* c):EventDispatcher(c)
void SharedObject::sinit(Class_base* c)
{
- c->setSuper(Class<EventDispatcher>::getRef());
+ // TODO: Use _constructorNotInstantiatable after getLocal is
+ // implemented
+ CLASS_SETUP_NO_CONSTRUCTOR(c, EventDispatcher, CLASS_SEALED);
c->setDeclaredMethodByQName("getLocal","",Class<IFunction>::getFunction(getLocal),NORMAL_METHOD,false);
REGISTER_GETTER(c,data);
-};
+}
ASFUNCTIONBODY_GETTER(SharedObject,data);
@@ -567,20 +620,21 @@ ASFUNCTIONBODY(SharedObject,getLocal)
void ObjectEncoding::sinit(Class_base* c)
{
- c->setSuper(Class<ASObject>::getRef());
+ CLASS_SETUP(c, ASObject, _constructorNotInstantiatable, CLASS_FINAL | CLASS_SEALED);
c->setVariableByQName("AMF0","",abstract_i(AMF0),DECLARED_TRAIT);
c->setVariableByQName("AMF3","",abstract_i(AMF3),DECLARED_TRAIT);
c->setVariableByQName("DEFAULT","",abstract_i(DEFAULT),DECLARED_TRAIT);
};
-NetConnection::NetConnection(Class_base* c):EventDispatcher(c),_connected(false),downloader(NULL),messageCount(0)
+NetConnection::NetConnection(Class_base* c):
+ EventDispatcher(c),_connected(false),downloader(NULL),messageCount(0),
+ proxyType(PT_NONE)
{
}
void NetConnection::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<EventDispatcher>::getRef());
+ CLASS_SETUP(c, EventDispatcher, _constructor, CLASS_SEALED);
c->setDeclaredMethodByQName("connect","",Class<IFunction>::getFunction(connect),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("call","",Class<IFunction>::getFunction(call),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("connected","",Class<IFunction>::getFunction(_getConnected),GETTER_METHOD,true);
@@ -590,7 +644,10 @@ void NetConnection::sinit(Class_base* c)
c->setDeclaredMethodByQName("objectEncoding","",Class<IFunction>::getFunction(_getObjectEncoding),GETTER_METHOD,true);
c->setDeclaredMethodByQName("objectEncoding","",Class<IFunction>::getFunction(_setObjectEncoding),SETTER_METHOD,true);
c->setDeclaredMethodByQName("protocol","",Class<IFunction>::getFunction(_getProtocol),GETTER_METHOD,true);
+ c->setDeclaredMethodByQName("proxyType","",Class<IFunction>::getFunction(_getProxyType),GETTER_METHOD,true);
+ c->setDeclaredMethodByQName("proxyType","",Class<IFunction>::getFunction(_setProxyType),SETTER_METHOD,true);
c->setDeclaredMethodByQName("uri","",Class<IFunction>::getFunction(_getURI),GETTER_METHOD,true);
+ c->setDeclaredMethodByQName("close","",Class<IFunction>::getFunction(close),GETTER_METHOD,true);
REGISTER_GETTER_SETTER(c,client);
}
@@ -607,6 +664,7 @@ void NetConnection::finalize()
ASFUNCTIONBODY(NetConnection, _constructor)
{
+ EventDispatcher::_constructor(obj, NULL, 0);
NetConnection* th=Class<NetConnection>::cast(obj);
th->objectEncoding = getSys()->staticNetConnectionDefaultObjectEncoding;
return NULL;
@@ -683,22 +741,25 @@ void NetConnection::execute()
assert(!messageData.empty());
std::list<tiny_string> headers;
headers.push_back("Content-Type: application/x-amf");
- downloader=getSys()->downloadManager->downloadWithData(uri, messageData,
- headers, NULL);
+ _R<MemoryStreamCache> cache(_MR(new MemoryStreamCache));
+ downloader=getSys()->downloadManager->downloadWithData(uri, cache,
+ messageData, headers, NULL);
//Get the whole answer
- downloader->waitForTermination();
- if(downloader->hasFailed()) //Check to see if the download failed for some reason
+ cache->waitForTermination();
+ if(cache->hasFailed()) //Check to see if the download failed for some reason
{
LOG(LOG_ERROR, "NetConnection::execute(): Download of URL failed: " << uri);
// getVm()->addEvent(contentLoaderInfo,_MR(Class<IOErrorEvent>::getInstanceS()));
getSys()->downloadManager->destroy(downloader);
return;
}
- istream s(downloader);
+ std::streambuf *sbuf = cache->createReader();
+ istream s(sbuf);
_R<ByteArray> message=_MR(Class<ByteArray>::getInstanceS());
uint8_t* buf=message->getBuffer(downloader->getLength(), true);
s.read((char*)buf,downloader->getLength());
//Download is done, destroy it
+ delete sbuf;
{
//Acquire the lock to ensure consistency in threadAbort
SpinlockLocker l(downloaderLock);
@@ -743,7 +804,9 @@ ASFUNCTIONBODY(NetConnection,connect)
//bool isRPC = false;
//Null argument means local file or web server, the spec only mentions NULL, but youtube uses UNDEFINED, so supporting that too.
- if(args[0]->getObjectType()==T_NULL || args[0]->getObjectType()==T_UNDEFINED)
+ if(args[0]->getObjectType()==T_NULL ||
+ args[0]->getObjectType()==T_UNDEFINED ||
+ !args[0]->isConstructed())
{
th->_connected = false;
isNull = true;
@@ -798,6 +861,14 @@ ASFUNCTIONBODY(NetConnection,_getConnected)
return abstract_b(th->_connected);
}
+ASFUNCTIONBODY(NetConnection,_getConnectedProxyType)
+{
+ NetConnection* th=Class<NetConnection>::cast(obj);
+ if (!th->_connected)
+ throw Class<ArgumentError>::getInstanceS("NetConnection object must be connected.", 2126);
+ return Class<ASString>::getInstanceS("none");
+}
+
ASFUNCTIONBODY(NetConnection,_getDefaultObjectEncoding)
{
return abstract_i(getSys()->staticNetConnectionDefaultObjectEncoding);
@@ -847,6 +918,59 @@ ASFUNCTIONBODY(NetConnection,_getProtocol)
throw Class<ArgumentError>::getInstanceS("get NetConnection.protocol before connect");
}
+ASFUNCTIONBODY(NetConnection,_getProxyType)
+{
+ NetConnection* th=Class<NetConnection>::cast(obj);
+ tiny_string name;
+ switch(th->proxyType)
+ {
+ case PT_NONE:
+ name = "NONE";
+ break;
+ case PT_HTTP:
+ name = "HTTP";
+ break;
+ case PT_CONNECT_ONLY:
+ name = "CONNECTOnly";
+ break;
+ case PT_CONNECT:
+ name = "CONNECT";
+ break;
+ case PT_BEST:
+ name = "best";
+ break;
+ default:
+ assert(false && "Invalid proxy type");
+ name = "";
+ break;
+ }
+ return Class<ASString>::getInstanceS(name);
+}
+
+ASFUNCTIONBODY(NetConnection,_setProxyType)
+{
+ NetConnection* th=Class<NetConnection>::cast(obj);
+ tiny_string value;
+ ARG_UNPACK(value);
+ if (value == "NONE")
+ th->proxyType = PT_NONE;
+ else if (value == "HTTP")
+ th->proxyType = PT_HTTP;
+ else if (value == "CONNECTOnly")
+ th->proxyType = PT_CONNECT_ONLY;
+ else if (value == "CONNECT")
+ th->proxyType = PT_CONNECT;
+ else if (value == "best")
+ th->proxyType = PT_BEST;
+ else
+ throwError<ArgumentError>(kInvalidEnumError, "proxyType");
+
+ if (th->proxyType != PT_NONE)
+ LOG(LOG_NOT_IMPLEMENTED, "Unimplemented proxy type " << value);
+
+ return NULL;
+}
+
ASFUNCTIONBODY(NetConnection,_getURI)
{
NetConnection* th=Class<NetConnection>::cast(obj);
@@ -859,8 +983,28 @@ ASFUNCTIONBODY(NetConnection,_getURI)
}
}
+ASFUNCTIONBODY(NetConnection,close)
+{
+ NetConnection* th=Class<NetConnection>::cast(obj);
+ if(th->_connected)
+ {
+ th->threadAbort();
+ th->_connected = false;
+ }
+ return NULL;
+}
+
ASFUNCTIONBODY_GETTER_SETTER(NetConnection, client);
+void NetStreamAppendBytesAction::sinit(Class_base* c)
+{
+ CLASS_SETUP_NO_CONSTRUCTOR(c, ASObject, CLASS_FINAL);
+ c->setVariableByQName("END_SEQUENCE","",Class<ASString>::getInstanceS("endSequence"),CONSTANT_TRAIT);
+ c->setVariableByQName("RESET_BEGIN","",Class<ASString>::getInstanceS("resetBegin"),CONSTANT_TRAIT);
+ c->setVariableByQName("RESET_SEEK","",Class<ASString>::getInstanceS("resetSeek"),CONSTANT_TRAIT);
+}
+
+
NetStream::NetStream(Class_base* c):EventDispatcher(c),tickStarted(false),paused(false),closed(true),
streamTime(0),frameRate(0),connection(),downloader(NULL),videoDecoder(NULL),
audioDecoder(NULL),audioStream(NULL),
@@ -888,8 +1032,7 @@ NetStream::~NetStream()
void NetStream::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<EventDispatcher>::getRef());
+ CLASS_SETUP(c, EventDispatcher, _constructor, CLASS_SEALED);
c->setVariableByQName("CONNECT_TO_FMS","",Class<ASString>::getInstanceS("connectToFMS"),DECLARED_TRAIT);
c->setVariableByQName("DIRECT_CONNECTIONS","",Class<ASString>::getInstanceS("directConnections"),DECLARED_TRAIT);
c->setDeclaredMethodByQName("play","",Class<IFunction>::getFunction(play),NORMAL_METHOD,true);
@@ -906,6 +1049,9 @@ void NetStream::sinit(Class_base* c)
c->setDeclaredMethodByQName("client","",Class<IFunction>::getFunction(_setClient),SETTER_METHOD,true);
c->setDeclaredMethodByQName("checkPolicyFile","",Class<IFunction>::getFunction(_getCheckPolicyFile),GETTER_METHOD,true);
c->setDeclaredMethodByQName("checkPolicyFile","",Class<IFunction>::getFunction(_setCheckPolicyFile),SETTER_METHOD,true);
+ c->setDeclaredMethodByQName("attach","",Class<IFunction>::getFunction(attach),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("appendBytes","",Class<IFunction>::getFunction(appendBytes),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("appendBytesAction","",Class<IFunction>::getFunction(appendBytesAction),NORMAL_METHOD,true);
REGISTER_GETTER(c, backBufferLength);
REGISTER_GETTER_SETTER(c, backBufferTime);
REGISTER_GETTER(c, bufferLength);
@@ -969,40 +1115,31 @@ ASFUNCTIONBODY(NetStream,_setCheckPolicyFile)
ASFUNCTIONBODY(NetStream,_constructor)
{
- obj->incRef();
- _R<NetStream> th=_MR(Class<NetStream>::cast(obj));
+ EventDispatcher::_constructor(obj, NULL, 0);
+ NetStream* th=obj->as<NetStream>();
LOG(LOG_CALLS,_("NetStream constructor"));
- assert_and_throw(argslen>=1 && argslen <=2);
- assert_and_throw(args[0]->getClass()==Class<NetConnection>::getClass());
+ tiny_string value;
+ _NR<NetConnection> netConnection;
- args[0]->incRef();
- _R<NetConnection> netConnection = _MR(Class<NetConnection>::cast(args[0]));
- if(argslen == 2)
- {
- if(args[1]->getObjectType() == T_STRING)
- {
- tiny_string value = Class<ASString>::cast(args[1])->toString();
- if(value == "directConnections")
- th->peerID = DIRECT_CONNECTIONS;
- else
- th->peerID = CONNECT_TO_FMS;
- }
- else if(args[1]->getObjectType() == T_NULL)
- th->peerID = CONNECT_TO_FMS;
- else
- throw Class<ArgumentError>::getInstanceS("NetStream constructor: peerID");
- }
+ ARG_UNPACK(netConnection)(value, "connectToFMS");
+
+ if(value == "directConnections")
+ th->peerID = DIRECT_CONNECTIONS;
+ else
+ th->peerID = CONNECT_TO_FMS;
- th->client = th;
+ th->incRef();
+ netConnection->incRef();
th->connection=netConnection;
+ th->client = _NR<ASObject>(th);
return NULL;
}
ASFUNCTIONBODY(NetStream,play)
{
- NetStream* th=Class<NetStream>::cast(obj);
+ NetStream* th=obj->as<NetStream>();
//Make sure the stream is restarted properly
if(th->closed)
@@ -1013,8 +1150,10 @@ ASFUNCTIONBODY(NetStream,play)
//Reset the paused states
th->paused = false;
// th->audioPaused = false;
- assert(!th->connection.isNull());
+ if (th->connection.isNull())
+ throwError<ASError>(0,"not connected");
+
if(th->connection->uri.getProtocol()=="http")
{
//Remoting connection used, this should not happen
@@ -1070,9 +1209,8 @@ ASFUNCTIONBODY(NetStream,play)
}
else //The URL is valid so we can start the download and add ourself as a job
{
- //Cahe the download only if it is not RTMP based
- bool cached=!th->url.isRTMP();
- th->downloader=getSys()->downloadManager->download(th->url, cached, NULL);
+ StreamCache *cache = new FileStreamCache;
+ th->downloader=getSys()->downloadManager->download(th->url, _MR(cache), NULL);
th->streamTime=0;
//To be decreffed in jobFence
th->incRef();
@@ -1149,6 +1287,35 @@ ASFUNCTIONBODY(NetStream,close)
ASFUNCTIONBODY(NetStream,seek)
{
//NetStream* th=Class<NetStream>::cast(obj);
+ LOG(LOG_NOT_IMPLEMENTED,"NetStream.seek is not implemented yet");
+ assert_and_throw(argslen == 1);
+ return NULL;
+}
+
+ASFUNCTIONBODY(NetStream,attach)
+{
+ NetStream* th=obj->as<NetStream>();
+ _NR<NetConnection> netConnection;
+ ARG_UNPACK(netConnection);
+
+ netConnection->incRef();
+ th->connection=netConnection;
+ return NULL;
+}
+ASFUNCTIONBODY(NetStream,appendBytes)
+{
+ NetStream* th=Class<NetStream>::cast(obj);
+ _NR<ByteArray> bytearray;
+ ARG_UNPACK(bytearray);
+
+ if(!bytearray.isNull())
+ th->downloader->append(bytearray->getBuffer(bytearray->getLength(),false),bytearray->getLength());
+ return NULL;
+}
+ASFUNCTIONBODY(NetStream,appendBytesAction)
+{
+ //NetStream* th=Class<NetStream>::cast(obj);
+ LOG(LOG_NOT_IMPLEMENTED,"NetStream.appendBytesAction is not implemented yet");
assert_and_throw(argslen == 1);
return NULL;
}
@@ -1232,7 +1399,8 @@ void NetStream::execute()
//The downloader hasn't failed yet at this point
- istream s(downloader);
+ std::streambuf *sbuf = downloader->getCache()->createReader();
+ istream s(sbuf);
s.exceptions(istream::goodbit);
ThreadProfile* profile=getSys()->allocateProfiler(RGB(0,0,200));
@@ -1307,6 +1475,7 @@ void NetStream::execute()
}
catch(JobTerminationException& e)
{
+ LOG(LOG_ERROR, "JobTerminationException in NetStream ");
waitForFlush=false;
}
catch(exception& e)
@@ -1349,6 +1518,7 @@ void NetStream::execute()
audioStream=NULL;
}
delete streamDecoder;
+ delete sbuf;
}
void NetStream::threadAbort()
@@ -1605,8 +1775,7 @@ void URLVariables::decode(const tiny_string& s)
void URLVariables::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASObject>::getRef());
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_DYNAMIC_NOT_FINAL);
c->setDeclaredMethodByQName("decode","",Class<IFunction>::getFunction(decode),NORMAL_METHOD,true);
c->prototype->setVariableByQName("toString","",Class<IFunction>::getFunction(_toString),DYNAMIC_TRAIT);
}
@@ -1734,12 +1903,7 @@ ASFUNCTIONBODY(lightspark,sendToURL)
//TODO: should we disallow accessing local files in a directory above
//the current one like we do with NetStream.play?
- vector<uint8_t> postData;
- urlRequest->getPostData(postData);
- assert_and_throw(postData.empty());
-
- //Don't cache our downloaded files
- Downloader* downloader=getSys()->downloadManager->download(url, false, NULL);
+ Downloader* downloader=getSys()->downloadManager->download(url, _MR(new MemoryStreamCache), NULL);
//TODO: make the download asynchronous instead of waiting for an unused response
downloader->waitForTermination();
getSys()->downloadManager->destroy(downloader);
@@ -1783,8 +1947,7 @@ ASFUNCTIONBODY(lightspark,navigateToURL)
void Responder::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASObject>::getRef());
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED);
c->setDeclaredMethodByQName("onResult","",Class<IFunction>::getFunction(onResult),NORMAL_METHOD,true);
}
@@ -1820,6 +1983,90 @@ ASFUNCTIONBODY(Responder, onResult)
return NULL;
}
+LocalConnection::LocalConnection(Class_base* c):
+ EventDispatcher(c),isSupported(false)
+{
+}
+
+void LocalConnection::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, EventDispatcher, _constructor, CLASS_SEALED);
+ c->setDeclaredMethodByQName("allowDomain","",Class<IFunction>::getFunction(allowDomain),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("allowInsecureDomain","",Class<IFunction>::getFunction(allowInsecureDomain),NORMAL_METHOD,true);
+ REGISTER_GETTER(c,isSupported);
+}
+ASFUNCTIONBODY_GETTER(LocalConnection, isSupported);
+
+ASFUNCTIONBODY(LocalConnection, _constructor)
+{
+ EventDispatcher::_constructor(obj, NULL, 0);
+ LocalConnection* th=Class<LocalConnection>::cast(obj);
+ LOG(LOG_NOT_IMPLEMENTED,"LocalConnection is not implemented");
+ return NULL;
+}
+ASFUNCTIONBODY(LocalConnection, allowDomain)
+{
+ LocalConnection* th=Class<LocalConnection>::cast(obj);
+ LOG(LOG_NOT_IMPLEMENTED,"LocalConnection::allowDomain is not implemented");
+ return NULL;
+}
+ASFUNCTIONBODY(LocalConnection, allowInsecureDomain)
+{
+ EventDispatcher::_constructor(obj, NULL, 0);
+ LocalConnection* th=Class<LocalConnection>::cast(obj);
+ LOG(LOG_NOT_IMPLEMENTED,"LocalConnection::allowInsecureDomain is not implemented");
+ return NULL;
+}
+
+NetGroup::NetGroup(Class_base* c):
+ EventDispatcher(c)
+{
+}
+
+void NetGroup::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, EventDispatcher, _constructor, CLASS_SEALED);
+}
+
+ASFUNCTIONBODY(NetGroup, _constructor)
+{
+ EventDispatcher::_constructor(obj, NULL, 0);
+ NetGroup* th=Class<NetGroup>::cast(obj);
+ LOG(LOG_NOT_IMPLEMENTED,"NetGroup is not implemented");
+ return NULL;
+}
+
+
+ASSocket::ASSocket(Class_base* c):
+ EventDispatcher(c)
+{
+}
+
+void ASSocket::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, EventDispatcher, _constructor, CLASS_SEALED);
+}
+
+ASFUNCTIONBODY(ASSocket, _constructor)
+{
+ EventDispatcher::_constructor(obj, NULL, 0);
+ ASSocket* th=Class<ASSocket>::cast(obj);
+ LOG(LOG_NOT_IMPLEMENTED,"ASSocket is not implemented");
+ return NULL;
+}
+
+DRMManager::DRMManager(Class_base* c):
+ EventDispatcher(c),isSupported(false)
+{
+}
+
+void DRMManager::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, EventDispatcher, _constructorNotInstantiatable, CLASS_SEALED);
+ REGISTER_GETTER(c,isSupported);
+}
+ASFUNCTIONBODY_GETTER(DRMManager, isSupported);
+
ASFUNCTIONBODY(lightspark,registerClassAlias)
{
assert_and_throw(argslen==2 && args[0]->getObjectType()==T_STRING && args[1]->getObjectType()==T_CLASS);
diff --git a/src/scripting/flash/net/flashnet.h b/src/scripting/flash/net/flashnet.h
index 0ab5b27..9274c15 100644
--- a/src/scripting/flash/net/flashnet.h
+++ b/src/scripting/flash/net/flashnet.h
@@ -39,6 +39,7 @@ private:
METHOD method;
tiny_string url;
_NR<ASObject> data;
+ tiny_string digest;
tiny_string validatedContentType() const;
tiny_string getContentTypeHeader() const;
void validateHeaderName(const tiny_string& headerName) const;
@@ -56,6 +57,8 @@ public:
ASFUNCTION(_setMethod);
ASFUNCTION(_setData);
ASFUNCTION(_getData);
+ ASFUNCTION(_getDigest);
+ ASFUNCTION(_setDigest);
URLInfo getRequestURL() const;
std::list<tiny_string> getHeaders() const;
void getPostData(std::vector<uint8_t>& data) const;
@@ -91,6 +94,14 @@ public:
static void sinit(Class_base*);
};
+
+class SharedObjectFlushStatus: public ASObject
+{
+public:
+ SharedObjectFlushStatus(Class_base* c):ASObject(c){}
+ static void sinit(Class_base*);
+};
+
class SharedObject: public EventDispatcher
{
public:
@@ -165,6 +176,7 @@ class NetConnection: public EventDispatcher, public IThreadJob
{
friend class NetStream;
private:
+ enum PROXY_TYPE { PT_NONE, PT_HTTP, PT_CONNECT_ONLY, PT_CONNECT, PT_BEST };
//Indicates whether the application is connected to a server through a persistent RMTP connection/HTTP server with Flash Remoting
bool _connected;
tiny_string protocol;
@@ -178,6 +190,7 @@ private:
uint32_t messageCount;
//The connection is to a flash media server
ObjectEncoding::ENCODING objectEncoding;
+ PROXY_TYPE proxyType;
//IThreadJob interface
void execute();
void threadAbort();
@@ -191,15 +204,27 @@ public:
ASFUNCTION(connect);
ASFUNCTION(call);
ASFUNCTION(_getConnected);
+ ASFUNCTION(_getConnectedProxyType);
ASFUNCTION(_getDefaultObjectEncoding);
ASFUNCTION(_setDefaultObjectEncoding);
ASFUNCTION(_getObjectEncoding);
ASFUNCTION(_setObjectEncoding);
ASFUNCTION(_getProtocol);
+ ASFUNCTION(_getProxyType);
+ ASFUNCTION(_setProxyType);
ASFUNCTION(_getURI);
+ ASFUNCTION(close);
ASPROPERTY_GETTER_SETTER(NullableRef<ASObject>,client);
};
+class NetStreamAppendBytesAction: public ASObject
+{
+public:
+ NetStreamAppendBytesAction(Class_base* c):ASObject(c){}
+ static void sinit(Class_base*);
+};
+
+
class SoundTransform;
class NetStream: public EventDispatcher, public IThreadJob, public ITickJob
{
@@ -264,6 +289,9 @@ public:
ASFUNCTION(_setClient);
ASFUNCTION(_getCheckPolicyFile);
ASFUNCTION(_setCheckPolicyFile);
+ ASFUNCTION(attach);
+ ASFUNCTION(appendBytes);
+ ASFUNCTION(appendBytesAction);
ASPROPERTY_GETTER(number_t, backBufferLength);
ASPROPERTY_GETTER_SETTER(number_t, backBufferTime);
ASPROPERTY_GETTER(number_t, bufferLength);
@@ -334,11 +362,46 @@ public:
void unlock();
};
+class LocalConnection: public EventDispatcher
+{
+public:
+ LocalConnection(Class_base* c);
+ static void sinit(Class_base*);
+ ASFUNCTION(_constructor);
+ ASPROPERTY_GETTER(bool,isSupported);
+ ASFUNCTION(allowDomain);
+ ASFUNCTION(allowInsecureDomain);
+};
+
+class NetGroup: public EventDispatcher
+{
+public:
+ NetGroup(Class_base* c);
+ static void sinit(Class_base*);
+ ASFUNCTION(_constructor);
+};
+
+class ASSocket: public EventDispatcher, IDataInput, IDataOutput
+{
+public:
+ ASSocket(Class_base* c);
+ static void sinit(Class_base*);
+ ASFUNCTION(_constructor);
+};
+
+class DRMManager: public EventDispatcher
+{
+public:
+ DRMManager(Class_base* c);
+ static void sinit(Class_base*);
+ ASPROPERTY_GETTER(bool,isSupported);
+};
+
ASObject* navigateToURL(ASObject* obj,ASObject* const* args, const unsigned int argslen);
ASObject* sendToURL(ASObject* obj,ASObject* const* args, const unsigned int argslen);
ASObject* registerClassAlias(ASObject* obj,ASObject* const* args, const unsigned int argslen);
ASObject* getClassByAlias(ASObject* obj,ASObject* const* args, const unsigned int argslen);
-};
+}
#endif /* SCRIPTING_FLASH_NET_FLASHNET_H */
diff --git a/src/scripting/flash/printing/flashprinting.cpp b/src/scripting/flash/printing/flashprinting.cpp
new file mode 100644
index 0000000..2d46b4b
--- /dev/null
+++ b/src/scripting/flash/printing/flashprinting.cpp
@@ -0,0 +1,69 @@
+/**************************************************************************
+ Lightspark, a free flash player implementation
+
+ Copyright (C) 2009-2013 Alessandro Pignotti (a.pignotti at sssup.it)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+**************************************************************************/
+
+#include "scripting/flash/printing/flashprinting.h"
+#include "scripting/abc.h"
+#include "scripting/argconv.h"
+#include "compat.h"
+
+using namespace lightspark;
+
+PrintJob::PrintJob(Class_base* c):
+ EventDispatcher(c),isSupported(false)
+{
+}
+
+void PrintJob::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, EventDispatcher, _constructor, CLASS_SEALED);
+ REGISTER_GETTER(c,isSupported);
+}
+ASFUNCTIONBODY_GETTER(PrintJob, isSupported);
+
+ASFUNCTIONBODY(PrintJob, _constructor)
+{
+ EventDispatcher::_constructor(obj, NULL, 0);
+ PrintJob* th=Class<PrintJob>::cast(obj);
+ LOG(LOG_NOT_IMPLEMENTED,"PrintJob is not implemented");
+ return NULL;
+}
+
+PrintJobOptions::PrintJobOptions(Class_base* c):
+ ASObject(c)
+{
+}
+
+void PrintJobOptions::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED);
+}
+
+ASFUNCTIONBODY(PrintJobOptions, _constructor)
+{
+ PrintJobOptions* th=Class<PrintJobOptions>::cast(obj);
+ LOG(LOG_NOT_IMPLEMENTED,"PrintJobOptions is not implemented");
+ return NULL;
+}
+
+void PrintJobOrientation::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED| CLASS_FINAL);
+ c->setVariableByQName("LANDSCAPE","",Class<ASString>::getInstanceS("landscape"),CONSTANT_TRAIT);
+ c->setVariableByQName("PORTRAIT","",Class<ASString>::getInstanceS("portrait"),CONSTANT_TRAIT);
+}
diff --git a/src/scripting/flash/accessibility/flashaccessibility.h b/src/scripting/flash/printing/flashprinting.h
similarity index 67%
copy from src/scripting/flash/accessibility/flashaccessibility.h
copy to src/scripting/flash/printing/flashprinting.h
index 19d00b8..9932183 100644
--- a/src/scripting/flash/accessibility/flashaccessibility.h
+++ b/src/scripting/flash/printing/flashprinting.h
@@ -17,31 +17,40 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
-#ifndef SCRIPTING_FLASH_ACCESSIBILITY_FLASHACCESSIBILITY_H
-#define SCRIPTING_FLASH_ACCESSIBILITY_FLASHACCESSIBILITY_H 1
+#ifndef SCRIPTING_FLASH_PRINTING_FLASHPRINTING_H
+#define SCRIPTING_FLASH_PRINTING_FLASHPRINTING_H 1
+#include "compat.h"
#include "asobject.h"
+#include "scripting/flash/events/flashevents.h"
namespace lightspark
{
-class AccessibilityProperties : public ASObject
+class PrintJob: public EventDispatcher
{
-private:
- ASPROPERTY_GETTER_SETTER(tiny_string,name);
public:
- AccessibilityProperties(Class_base* c):ASObject(c){}
+ PrintJob(Class_base* c);
static void sinit(Class_base*);
ASFUNCTION(_constructor);
+ ASPROPERTY_GETTER(bool,isSupported);
};
-class AccessibilityImplementation : public ASObject
+class PrintJobOptions: public ASObject
{
public:
- AccessibilityImplementation(Class_base* c):ASObject(c){}
+ PrintJobOptions(Class_base* c);
static void sinit(Class_base*);
ASFUNCTION(_constructor);
};
+class PrintJobOrientation: public ASObject
+{
+public:
+ PrintJobOrientation(Class_base* c) : ASObject(c) {}
+ static void sinit(Class_base*);
+};
+
+
}
-#endif /* SCRIPTING_FLASH_ACCESSIBILITY_FLASHACCESSIBILITY_H */
+#endif /* SCRIPTING_FLASH_PRINTING_FLASHPRINTING_H */
diff --git a/src/scripting/flash/sensors/flashsensors.cpp b/src/scripting/flash/sensors/flashsensors.cpp
index bee463b..3d4587f 100644
--- a/src/scripting/flash/sensors/flashsensors.cpp
+++ b/src/scripting/flash/sensors/flashsensors.cpp
@@ -29,10 +29,11 @@
using namespace std;
using namespace lightspark;
-Accelerometer::Accelerometer(Class_base* c):ASObject(c) {}
+Accelerometer::Accelerometer(Class_base* c):EventDispatcher(c) {}
void Accelerometer::sinit(Class_base* c)
{
+ CLASS_SETUP_NO_CONSTRUCTOR(c, EventDispatcher, CLASS_SEALED);
// properties
c->setDeclaredMethodByQName("isSupported", "", Class<IFunction>::getFunction(_isSupported),GETTER_METHOD,false);
}
diff --git a/src/scripting/flash/sensors/flashsensors.h b/src/scripting/flash/sensors/flashsensors.h
index 9f9ef19..760c476 100644
--- a/src/scripting/flash/sensors/flashsensors.h
+++ b/src/scripting/flash/sensors/flashsensors.h
@@ -30,7 +30,7 @@
namespace lightspark
{
-class Accelerometer: public ASObject {
+class Accelerometer: public EventDispatcher {
public:
Accelerometer(Class_base* c);
static void sinit(Class_base* c);
diff --git a/src/scripting/flash/system/flashsystem.cpp b/src/scripting/flash/system/flashsystem.cpp
index 26701f6..6c5224b 100644
--- a/src/scripting/flash/system/flashsystem.cpp
+++ b/src/scripting/flash/system/flashsystem.cpp
@@ -43,6 +43,7 @@ const char* Capabilities::MANUFACTURER = "Adobe Linux";
void Capabilities::sinit(Class_base* c)
{
+ CLASS_SETUP(c, ASObject, _constructorNotInstantiatable, CLASS_SEALED | CLASS_FINAL);
c->setDeclaredMethodByQName("language","",Class<IFunction>::getFunction(_getLanguage),GETTER_METHOD,false);
c->setDeclaredMethodByQName("playerType","",Class<IFunction>::getFunction(_getPlayerType),GETTER_METHOD,false);
c->setDeclaredMethodByQName("version","",Class<IFunction>::getFunction(_getVersion),GETTER_METHOD,false);
@@ -55,6 +56,8 @@ void Capabilities::sinit(Class_base* c)
c->setDeclaredMethodByQName("serverString","",Class<IFunction>::getFunction(_getServerString),GETTER_METHOD,false);
c->setDeclaredMethodByQName("screenResolutionX","",Class<IFunction>::getFunction(_getScreenResolutionX),GETTER_METHOD,false);
c->setDeclaredMethodByQName("screenResolutionY","",Class<IFunction>::getFunction(_getScreenResolutionY),GETTER_METHOD,false);
+ c->setDeclaredMethodByQName("hasAccessibility","",Class<IFunction>::getFunction(_getHasAccessibility),GETTER_METHOD,false);
+
}
ASFUNCTIONBODY(Capabilities,_getPlayerType)
@@ -105,8 +108,56 @@ ASFUNCTIONBODY(Capabilities,_getVersion)
ASFUNCTIONBODY(Capabilities,_getServerString)
{
- LOG(LOG_NOT_IMPLEMENTED, "Capabilities.serverString is not implemented");
- return Class<ASString>::getInstanceS("");
+ LOG(LOG_NOT_IMPLEMENTED,"Capabilities: not all capabilities are reported in ServerString");
+ tiny_string res = "A=t&SA=t&SV=t&MP3=t&OS=Linux&PT=PlugIn&L=en&TLS=t";
+ res +="&V=";
+ res += EMULATED_VERSION;
+ res +="&M=";
+ res += MANUFACTURER;
+
+ GdkScreen* screen = gdk_screen_get_default();
+ gint width = gdk_screen_get_width (screen);
+ gint height = gdk_screen_get_height (screen);
+ char buf[40];
+ snprintf(buf,40,"&R=%ix%i",width,height);
+ res += buf;
+
+ /*
+ avHardwareDisable AVD
+ hasAccessibility ACC
+ hasAudio A
+ hasAudioEncoder AE
+ hasEmbeddedVideo EV
+ hasIME IME
+ hasMP3 MP3
+ hasPrinting PR
+ hasScreenBroadcast SB
+ hasScreenPlayback SP
+ hasStreamingAudio SA
+ hasStreamingVideo SV
+ hasTLS TLS
+ hasVideoEncoder VE
+ isDebugger DEB
+ language L
+ localFileReadDisable LFD
+ manufacturer M
+ maxLevelIDC ML
+ os OS
+ pixelAspectRatio AR
+ playerType PT
+ screenColor COL
+ screenDPI DP
+ screenResolutionX R
+ screenResolutionY R
+ version V
+ supports Dolby Digital audio DD
+ supports Dolby Digital Plus audio DDP
+ supports DTS audio DTS
+ supports DTS Express audio DTE
+ supports DTS-HD High Resolution Audio DTH
+ supports DTS-HD Master Audio DTM
+ */
+ return Class<ASString>::getInstanceS(res);
}
ASFUNCTIONBODY(Capabilities,_getScreenResolutionX)
{
@@ -120,14 +171,21 @@ ASFUNCTIONBODY(Capabilities,_getScreenResolutionY)
gint height = gdk_screen_get_height (screen);
return abstract_d(height);
}
+ASFUNCTIONBODY(Capabilities,_getHasAccessibility)
+{
+ LOG(LOG_NOT_IMPLEMENTED,"hasAccessibility always returns false");
+ return abstract_b(false);
+}
-ApplicationDomain::ApplicationDomain(Class_base* c, _NR<ApplicationDomain> p):ASObject(c),parentDomain(p)
+#define MIN_DOMAIN_MEMORY_LIMIT 1024
+ApplicationDomain::ApplicationDomain(Class_base* c, _NR<ApplicationDomain> p):ASObject(c),domainMemory(Class<ByteArray>::getInstanceS()),parentDomain(p)
{
+ domainMemory->setLength(MIN_DOMAIN_MEMORY_LIMIT);
}
void ApplicationDomain::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED | CLASS_FINAL);
//Static
c->setDeclaredMethodByQName("currentDomain","",Class<IFunction>::getFunction(_getCurrentDomain),GETTER_METHOD,false);
c->setDeclaredMethodByQName("MIN_DOMAIN_MEMORY_LENGTH","",Class<IFunction>::getFunction(_getMinDomainMemoryLength),GETTER_METHOD,false);
@@ -171,7 +229,7 @@ ASFUNCTIONBODY(ApplicationDomain,_constructor)
ASFUNCTIONBODY(ApplicationDomain,_getMinDomainMemoryLength)
{
- return abstract_ui(1024);
+ return abstract_ui(MIN_DOMAIN_MEMORY_LIMIT);
}
ASFUNCTIONBODY(ApplicationDomain,_getCurrentDomain)
@@ -229,7 +287,8 @@ ASFUNCTIONBODY(ApplicationDomain,getDefinition)
LOG(LOG_CALLS,_("Looking for definition of ") << name);
ASObject* target;
ASObject* o=th->getVariableAndTargetByMultiname(name,target);
- assert_and_throw(o);
+ if(o == NULL)
+ throwError<ReferenceError>(kClassNotFoundError,name.normalizedName());
//TODO: specs says that also namespaces and function may be returned
assert_and_throw(o->getObjectType()==T_CLASS);
@@ -329,10 +388,20 @@ ASObject* ApplicationDomain::getVariableByMultinameOpportunistic(const multiname
return NULL;
}
+LoaderContext::LoaderContext(Class_base* c):
+ ASObject(c),allowCodeImport(true),checkPolicyFile(false)
+{
+}
+
void LoaderContext::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED);
+ c->setDeclaredMethodByQName("allowLoadBytesCodeExecution","",Class<IFunction>::getFunction(_getter_allowCodeImport),GETTER_METHOD,false);
+ c->setDeclaredMethodByQName("allowLoadBytesCodeExecution","",Class<IFunction>::getFunction(_setter_allowCodeImport),SETTER_METHOD,false);
+ REGISTER_GETTER_SETTER(c, allowCodeImport);
REGISTER_GETTER_SETTER(c, applicationDomain);
+ REGISTER_GETTER_SETTER(c, checkPolicyFile);
+ REGISTER_GETTER_SETTER(c, parameters);
REGISTER_GETTER_SETTER(c, securityDomain);
}
@@ -346,22 +415,31 @@ void LoaderContext::finalize()
ASFUNCTIONBODY(LoaderContext,_constructor)
{
LoaderContext* th=Class<LoaderContext>::cast(obj);
- bool checkPolicy;
- _NR<ApplicationDomain> appDomain;
- _NR<SecurityDomain> secDomain;
- ARG_UNPACK (checkPolicy, false) (appDomain, NullRef) (secDomain, NullRef);
- //TODO: Support checkPolicyFile
- th->applicationDomain=appDomain;
- th->securityDomain=secDomain;
+ ARG_UNPACK (th->checkPolicyFile, false)
+ (th->applicationDomain, NullRef)
+ (th->securityDomain, NullRef);
return NULL;
}
+ASFUNCTIONBODY_GETTER_SETTER(LoaderContext, allowCodeImport);
ASFUNCTIONBODY_GETTER_SETTER(LoaderContext, applicationDomain);
+ASFUNCTIONBODY_GETTER_SETTER(LoaderContext, checkPolicyFile);
+ASFUNCTIONBODY_GETTER_SETTER(LoaderContext, parameters);
ASFUNCTIONBODY_GETTER_SETTER(LoaderContext, securityDomain);
+bool LoaderContext::getCheckPolicyFile()
+{
+ return checkPolicyFile;
+}
+
+bool LoaderContext::getAllowCodeImport()
+{
+ return allowCodeImport;
+}
+
void SecurityDomain::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED);
//Static
c->setDeclaredMethodByQName("currentDomain","",Class<IFunction>::getFunction(_getCurrentDomain),GETTER_METHOD,false);
}
@@ -384,8 +462,8 @@ ASFUNCTIONBODY(SecurityDomain,_getCurrentDomain)
void Security::sinit(Class_base* c)
{
+ CLASS_SETUP(c, ASObject, _constructorNotInstantiatable, CLASS_SEALED | CLASS_FINAL);
//Fully static class
- c->setConstructor(NULL);
c->setDeclaredMethodByQName("exactSettings","",Class<IFunction>::getFunction(_getExactSettings),GETTER_METHOD,false);
c->setDeclaredMethodByQName("exactSettings","",Class<IFunction>::getFunction(_setExactSettings),SETTER_METHOD,false);
c->setDeclaredMethodByQName("sandboxType","",Class<IFunction>::getFunction(_getSandboxType),GETTER_METHOD,false);
@@ -401,6 +479,7 @@ void Security::sinit(Class_base* c)
c->setDeclaredMethodByQName("allowInsecureDomain","",Class<IFunction>::getFunction(allowInsecureDomain),NORMAL_METHOD,false);
c->setDeclaredMethodByQName("loadPolicyFile","",Class<IFunction>::getFunction(loadPolicyFile),NORMAL_METHOD,false);
c->setDeclaredMethodByQName("showSettings","",Class<IFunction>::getFunction(showSettings),NORMAL_METHOD,false);
+ c->setDeclaredMethodByQName("pageDomain","",Class<IFunction>::getFunction(pageDomain),GETTER_METHOD,false);
getSys()->securityManager->setExactSettings(true, false);
}
@@ -461,6 +540,12 @@ ASFUNCTIONBODY(Security, showSettings)
return NULL;
}
+ASFUNCTIONBODY(Security, pageDomain)
+{
+ tiny_string s = getSys()->mainClip->getBaseURL().getProtocol()+"://"+getSys()->mainClip->getBaseURL().getHostname();
+ return Class<ASString>::getInstanceS(s);
+}
+
ASFUNCTIONBODY(lightspark, fscommand)
{
assert_and_throw(argslen >= 1 && argslen <= 2);
@@ -476,6 +561,7 @@ ASFUNCTIONBODY(lightspark, fscommand)
void System::sinit(Class_base* c)
{
+ CLASS_SETUP(c, ASObject, _constructorNotInstantiatable, CLASS_SEALED | CLASS_FINAL);
c->setDeclaredMethodByQName("totalMemory","",Class<IFunction>::getFunction(totalMemory),GETTER_METHOD,false);
}
@@ -483,5 +569,24 @@ void System::sinit(Class_base* c)
ASFUNCTIONBODY(System,totalMemory)
{
LOG(LOG_NOT_IMPLEMENTED, "System.totalMemory not implemented");
- return abstract_d(0);
+ return abstract_d(1024);
+}
+
+ASWorker::ASWorker(Class_base* c):
+ EventDispatcher(c)
+{
+ LOG(LOG_NOT_IMPLEMENTED, "Worker not implemented");
}
+
+void ASWorker::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, EventDispatcher, _constructorNotInstantiatable, CLASS_SEALED | CLASS_FINAL);
+ c->setDeclaredMethodByQName("current","",Class<IFunction>::getFunction(_getCurrent),GETTER_METHOD,false);
+}
+ASFUNCTIONBODY(ASWorker,_getCurrent)
+{
+ LOG(LOG_NOT_IMPLEMENTED, "Worker not implemented");
+ return getSys()->getUndefinedRef();
+}
+
+
diff --git a/src/scripting/flash/system/flashsystem.h b/src/scripting/flash/system/flashsystem.h
index cf86063..5c6a948 100644
--- a/src/scripting/flash/system/flashsystem.h
+++ b/src/scripting/flash/system/flashsystem.h
@@ -22,7 +22,9 @@
#include "compat.h"
#include "asobject.h"
-#include "scripting/flash/utils/flashutils.h"
+#include "scripting/flash/utils/ByteArray.h"
+#include "scripting/toplevel/toplevel.h"
+#include "scripting/flash/events/flashevents.h"
namespace lightspark
{
@@ -48,6 +50,7 @@ public:
ASFUNCTION(_getServerString);
ASFUNCTION(_getScreenResolutionX);
ASFUNCTION(_getScreenResolutionY);
+ ASFUNCTION(_getHasAccessibility);
};
class ApplicationDomain: public ASObject
@@ -57,6 +60,8 @@ private:
public:
ApplicationDomain(Class_base* c, _NR<ApplicationDomain> p=NullRef);
void finalize();
+ std::map<const multiname*, Class_base*> classesBeingDefined;
+
static void sinit(Class_base* c);
static void buildTraits(ASObject* o);
void registerGlobalScope(Global* scope);
@@ -102,12 +107,17 @@ public:
class LoaderContext: public ASObject
{
public:
- LoaderContext(Class_base* c):ASObject(c){};
+ LoaderContext(Class_base* c);
static void sinit(Class_base* c);
ASFUNCTION(_constructor);
+ ASPROPERTY_GETTER_SETTER(bool, allowCodeImport);
ASPROPERTY_GETTER_SETTER(_NR<ApplicationDomain>, applicationDomain);
+ ASPROPERTY_GETTER_SETTER(bool, checkPolicyFile);
+ ASPROPERTY_GETTER_SETTER(_NR<ASObject>, parameters);
ASPROPERTY_GETTER_SETTER(_NR<SecurityDomain>, securityDomain);
void finalize();
+ bool getAllowCodeImport();
+ bool getCheckPolicyFile();
};
class SecurityDomain: public ASObject
@@ -132,6 +142,7 @@ public:
ASFUNCTION(allowInsecureDomain);
ASFUNCTION(loadPolicyFile);
ASFUNCTION(showSettings);
+ ASFUNCTION(pageDomain);
};
ASObject* fscommand(ASObject* obj,ASObject* const* args, const unsigned int argslen);
@@ -143,6 +154,13 @@ public:
static void sinit(Class_base* c);
ASFUNCTION(totalMemory);
};
-
+class ASWorker: public EventDispatcher
+{
+public:
+ ASWorker(Class_base* c);
+ static void sinit(Class_base*);
+ ASFUNCTION(_getCurrent);
};
+
+}
#endif /* SCRIPTING_FLASH_SYSTEM_FLASHSYSTEM_H */
diff --git a/src/scripting/flash/text/flashtext.cpp b/src/scripting/flash/text/flashtext.cpp
index e9420ba..829447e 100644
--- a/src/scripting/flash/text/flashtext.cpp
+++ b/src/scripting/flash/text/flashtext.cpp
@@ -33,16 +33,14 @@ using namespace lightspark;
void lightspark::AntiAliasType::sinit(Class_base* c)
{
- c->setConstructor(NULL);
+ CLASS_SETUP_NO_CONSTRUCTOR(c, ASObject, CLASS_FINAL | CLASS_SEALED);
c->setVariableByQName("ADVANCED","",Class<ASString>::getInstanceS("advanced"),DECLARED_TRAIT);
c->setVariableByQName("NORMAL","",Class<ASString>::getInstanceS("normal"),DECLARED_TRAIT);
}
void ASFont::sinit(Class_base* c)
{
-// c->constructor=Class<IFunction>::getFunction(_constructor);
- //c->setConstructor(NULL);
- c->setSuper(Class<ASObject>::getRef());
+ CLASS_SETUP_NO_CONSTRUCTOR(c, ASObject, CLASS_SEALED);
c->setDeclaredMethodByQName("enumerateFonts","",Class<IFunction>::getFunction(enumerateFonts),NORMAL_METHOD,false);
c->setDeclaredMethodByQName("registerFont","",Class<IFunction>::getFunction(registerFont),NORMAL_METHOD,false);
@@ -93,60 +91,123 @@ ASFUNCTIONBODY(ASFont,registerFont)
}
TextField::TextField(Class_base* c, const TextData& textData, bool _selectable, bool readOnly)
- : InteractiveObject(c), TextData(textData), type(READ_ONLY),
- mouseWheelEnabled(true), selectable(_selectable)
+ : InteractiveObject(c), TextData(textData), type(ET_READ_ONLY),
+ antiAliasType(AA_NORMAL), gridFitType(GF_PIXEL),
+ textInteractionMode(TI_NORMAL), alwaysShowSelection(false),
+ caretIndex(0), condenseWhite(false), displayAsPassword(false),
+ embedFonts(false), maxChars(0), mouseWheelEnabled(true),
+ selectable(_selectable), selectionBeginIndex(0), selectionEndIndex(0),
+ sharpness(0), thickness(0), useRichTextClipboard(false)
{
if (!readOnly)
{
- type = EDITABLE;
+ type = ET_EDITABLE;
tabEnabled = true;
}
}
void TextField::sinit(Class_base* c)
{
- c->setConstructor(NULL);
- c->setSuper(Class<InteractiveObject>::getRef());
- c->setDeclaredMethodByQName("width","",Class<IFunction>::getFunction(TextField::_getWidth),GETTER_METHOD,true);
- c->setDeclaredMethodByQName("width","",Class<IFunction>::getFunction(TextField::_setWidth),SETTER_METHOD,true);
+ CLASS_SETUP_NO_CONSTRUCTOR(c, InteractiveObject, CLASS_SEALED);
+
+ // methods
+ c->setDeclaredMethodByQName("appendText","",Class<IFunction>::getFunction(TextField:: appendText),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("getTextFormat","",Class<IFunction>::getFunction(_getTextFormat),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("setTextFormat","",Class<IFunction>::getFunction(_setTextFormat),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("getLineIndexAtPoint","",Class<IFunction>::getFunction(_getLineIndexAtPoint),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("getLineIndexOfChar","",Class<IFunction>::getFunction(_getLineIndexOfChar),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("getLineLength","",Class<IFunction>::getFunction(_getLineLength),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("getLineMetrics","",Class<IFunction>::getFunction(_getLineMetrics),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("getLineOffset","",Class<IFunction>::getFunction(_getLineOffset),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("getLineText","",Class<IFunction>::getFunction(_getLineText),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("replaceSelectedText","",Class<IFunction>::getFunction(_replaceSelectedText),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("replaceText","",Class<IFunction>::getFunction(_replaceText),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("setSelection","",Class<IFunction>::getFunction(_setSelection),NORMAL_METHOD,true);
+
+ // properties
+ c->setDeclaredMethodByQName("antiAliasType","",Class<IFunction>::getFunction(TextField::_getAntiAliasType),GETTER_METHOD,true);
+ c->setDeclaredMethodByQName("antiAliasType","",Class<IFunction>::getFunction(TextField::_setAntiAliasType),SETTER_METHOD,true);
+ c->setDeclaredMethodByQName("autoSize","",Class<IFunction>::getFunction(TextField::_setAutoSize),SETTER_METHOD,true);
+ c->setDeclaredMethodByQName("autoSize","",Class<IFunction>::getFunction(TextField::_getAutoSize),GETTER_METHOD,true);
+ c->setDeclaredMethodByQName("defaultTextFormat","",Class<IFunction>::getFunction(TextField::_getDefaultTextFormat),GETTER_METHOD,true);
+ c->setDeclaredMethodByQName("defaultTextFormat","",Class<IFunction>::getFunction(TextField::_setDefaultTextFormat),SETTER_METHOD,true);
+ c->setDeclaredMethodByQName("gridFitType","",Class<IFunction>::getFunction(TextField::_getGridFitType),GETTER_METHOD,true);
+ c->setDeclaredMethodByQName("gridFitType","",Class<IFunction>::getFunction(TextField::_setGridFitType),SETTER_METHOD,true);
c->setDeclaredMethodByQName("height","",Class<IFunction>::getFunction(TextField::_getHeight),GETTER_METHOD,true);
c->setDeclaredMethodByQName("height","",Class<IFunction>::getFunction(TextField::_setHeight),SETTER_METHOD,true);
c->setDeclaredMethodByQName("htmlText","",Class<IFunction>::getFunction(TextField::_getHtmlText),GETTER_METHOD,true);
c->setDeclaredMethodByQName("htmlText","",Class<IFunction>::getFunction(TextField::_setHtmlText),SETTER_METHOD,true);
- c->setDeclaredMethodByQName("textHeight","",Class<IFunction>::getFunction(TextField::_getTextHeight),GETTER_METHOD,true);
- c->setDeclaredMethodByQName("textWidth","",Class<IFunction>::getFunction(TextField::_getTextWidth),GETTER_METHOD,true);
+ c->setDeclaredMethodByQName("length","",Class<IFunction>::getFunction(TextField::_getLength),GETTER_METHOD,true);
c->setDeclaredMethodByQName("text","",Class<IFunction>::getFunction(TextField::_getText),GETTER_METHOD,true);
c->setDeclaredMethodByQName("text","",Class<IFunction>::getFunction(TextField::_setText),SETTER_METHOD,true);
+ c->setDeclaredMethodByQName("textHeight","",Class<IFunction>::getFunction(TextField::_getTextHeight),GETTER_METHOD,true);
+ c->setDeclaredMethodByQName("textWidth","",Class<IFunction>::getFunction(TextField::_getTextWidth),GETTER_METHOD,true);
+ c->setDeclaredMethodByQName("width","",Class<IFunction>::getFunction(TextField::_getWidth),GETTER_METHOD,true);
+ c->setDeclaredMethodByQName("width","",Class<IFunction>::getFunction(TextField::_setWidth),SETTER_METHOD,true);
c->setDeclaredMethodByQName("wordWrap","",Class<IFunction>::getFunction(TextField::_setWordWrap),SETTER_METHOD,true);
c->setDeclaredMethodByQName("wordWrap","",Class<IFunction>::getFunction(TextField::_getWordWrap),GETTER_METHOD,true);
- c->setDeclaredMethodByQName("autoSize","",Class<IFunction>::getFunction(TextField::_setAutoSize),SETTER_METHOD,true);
- c->setDeclaredMethodByQName("autoSize","",Class<IFunction>::getFunction(TextField::_getAutoSize),GETTER_METHOD,true);
- c->setDeclaredMethodByQName("appendText","",Class<IFunction>::getFunction(TextField:: appendText),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("getTextFormat","",Class<IFunction>::getFunction(_getTextFormat),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("setTextFormat","",Class<IFunction>::getFunction(_setTextFormat),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("getLineMetrics","",Class<IFunction>::getFunction(_getLineMetrics),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("defaultTextFormat","",Class<IFunction>::getFunction(TextField::_getDefaultTextFormat),GETTER_METHOD,true);
- c->setDeclaredMethodByQName("defaultTextFormat","",Class<IFunction>::getFunction(TextField::_setDefaultTextFormat),SETTER_METHOD,true);
-
+ c->setDeclaredMethodByQName("numLines","",Class<IFunction>::getFunction(TextField::_getNumLines),GETTER_METHOD,true);
+ c->setDeclaredMethodByQName("maxScrollH","",Class<IFunction>::getFunction(TextField::_getMaxScrollH),GETTER_METHOD,true);
+ c->setDeclaredMethodByQName("maxScrollV","",Class<IFunction>::getFunction(TextField::_getMaxScrollV),GETTER_METHOD,true);
+ c->setDeclaredMethodByQName("bottomScrollV","",Class<IFunction>::getFunction(TextField::_getBottomScrollV),GETTER_METHOD,true);
+ c->setDeclaredMethodByQName("restrict","",Class<IFunction>::getFunction(TextField::_getRestrict),GETTER_METHOD,true);
+ c->setDeclaredMethodByQName("restrict","",Class<IFunction>::getFunction(TextField::_setRestrict),SETTER_METHOD,true);
+ c->setDeclaredMethodByQName("textInteractionMode","",Class<IFunction>::getFunction(TextField::_getTextInteractionMode),GETTER_METHOD,true);
+
+ REGISTER_GETTER_SETTER(c, alwaysShowSelection);
REGISTER_GETTER_SETTER(c, background);
REGISTER_GETTER_SETTER(c, backgroundColor);
REGISTER_GETTER_SETTER(c, border);
REGISTER_GETTER_SETTER(c, borderColor);
+ REGISTER_GETTER(c, caretIndex);
+ REGISTER_GETTER_SETTER(c, condenseWhite);
+ REGISTER_GETTER_SETTER(c, displayAsPassword);
+ REGISTER_GETTER_SETTER(c, embedFonts);
+ REGISTER_GETTER_SETTER(c, maxChars);
REGISTER_GETTER_SETTER(c, multiline);
REGISTER_GETTER_SETTER(c, mouseWheelEnabled);
+ REGISTER_GETTER_SETTER(c, scrollH);
+ REGISTER_GETTER_SETTER(c, scrollV);
REGISTER_GETTER_SETTER(c, selectable);
+ REGISTER_GETTER(c, selectionBeginIndex);
+ REGISTER_GETTER(c, selectionEndIndex);
+ REGISTER_GETTER_SETTER(c, sharpness);
+ REGISTER_GETTER_SETTER(c, styleSheet);
REGISTER_GETTER_SETTER(c, textColor);
+ REGISTER_GETTER_SETTER(c, thickness);
REGISTER_GETTER_SETTER(c, type);
+ REGISTER_GETTER_SETTER(c, useRichTextClipboard);
}
+ASFUNCTIONBODY_GETTER_SETTER(TextField, alwaysShowSelection); // stub
ASFUNCTIONBODY_GETTER_SETTER(TextField, background);
ASFUNCTIONBODY_GETTER_SETTER(TextField, backgroundColor);
ASFUNCTIONBODY_GETTER_SETTER(TextField, border);
ASFUNCTIONBODY_GETTER_SETTER(TextField, borderColor);
+ASFUNCTIONBODY_GETTER(TextField, caretIndex);
+ASFUNCTIONBODY_GETTER_SETTER(TextField, condenseWhite);
+ASFUNCTIONBODY_GETTER_SETTER(TextField, displayAsPassword); // stub
+ASFUNCTIONBODY_GETTER_SETTER(TextField, embedFonts); // stub
+ASFUNCTIONBODY_GETTER_SETTER(TextField, maxChars); // stub
ASFUNCTIONBODY_GETTER_SETTER(TextField, multiline);
-ASFUNCTIONBODY_GETTER_SETTER(TextField, mouseWheelEnabled);
-ASFUNCTIONBODY_GETTER_SETTER(TextField, selectable);
+ASFUNCTIONBODY_GETTER_SETTER(TextField, mouseWheelEnabled); // stub
+ASFUNCTIONBODY_GETTER_SETTER_CB(TextField, scrollH, validateScrollH);
+ASFUNCTIONBODY_GETTER_SETTER_CB(TextField, scrollV, validateScrollV);
+ASFUNCTIONBODY_GETTER_SETTER(TextField, selectable); // stub
+ASFUNCTIONBODY_GETTER(TextField, selectionBeginIndex);
+ASFUNCTIONBODY_GETTER(TextField, selectionEndIndex);
+ASFUNCTIONBODY_GETTER_SETTER_CB(TextField, sharpness, validateSharpness); // stub
+ASFUNCTIONBODY_GETTER_SETTER(TextField, styleSheet); // stub
ASFUNCTIONBODY_GETTER_SETTER(TextField, textColor);
+ASFUNCTIONBODY_GETTER_SETTER_CB(TextField, thickness, validateThickness); // stub
+ASFUNCTIONBODY_GETTER_SETTER(TextField, useRichTextClipboard); // stub
+
+void TextField::finalize()
+{
+ ASObject::finalize();
+ restrictChars.reset();
+ styleSheet.reset();
+}
void TextField::buildTraits(ASObject* o)
{
@@ -167,7 +228,10 @@ _NR<DisplayObject> TextField::hitTestImpl(_NR<DisplayObject> last, number_t x, n
number_t xmin,xmax,ymin,ymax;
boundsRect(xmin,xmax,ymin,ymax);
if( xmin <= x && x <= xmax && ymin <= y && y <= ymax && isHittable(type))
- return last;
+ {
+ incRef();
+ return _MNR(this);
+ }
else
return NullRef;
}
@@ -181,8 +245,8 @@ ASFUNCTIONBODY(TextField,_getWordWrap)
ASFUNCTIONBODY(TextField,_setWordWrap)
{
TextField* th=Class<TextField>::cast(obj);
- assert_and_throw(argslen==1);
- th->wordWrap=Boolean_concrete(args[0]);
+ ARG_UNPACK(th->wordWrap);
+ th->setSizeAndPositionFromAutoSize();
if(th->onStage)
th->requestInvalidation(getSys());
return NULL;
@@ -208,23 +272,59 @@ ASFUNCTIONBODY(TextField,_getAutoSize)
ASFUNCTIONBODY(TextField,_setAutoSize)
{
TextField* th=Class<TextField>::cast(obj);
- assert_and_throw(argslen==1);
- tiny_string temp = args[0]->toString();
- if(temp == "none")
- th->autoSize = AS_NONE;//TODO: take care of corner cases : what to do with sizes when changing the autoSize
- else if (temp == "left")
- th->autoSize = AS_LEFT;
- else if (temp == "right")
- th->autoSize = AS_RIGHT;
- else if (temp == "center")
- th->autoSize = AS_CENTER;
+ tiny_string autoSizeString;
+ ARG_UNPACK(autoSizeString);
+
+ AUTO_SIZE newAutoSize = AS_NONE;
+ if(autoSizeString == "none")
+ newAutoSize = AS_NONE;
+ else if (autoSizeString == "left")
+ newAutoSize = AS_LEFT;
+ else if (autoSizeString == "right")
+ newAutoSize = AS_RIGHT;
+ else if (autoSizeString == "center")
+ newAutoSize = AS_CENTER;
else
- throw Class<ArgumentError>::getInstanceS("Wrong argument in TextField.autoSize");
- if(th->onStage)
- th->requestInvalidation(getSys());//TODO:check if there was any change
+ throwError<ArgumentError>(kInvalidEnumError, "autoSize");
+
+ if (th->autoSize != newAutoSize)
+ {
+ th->autoSize = newAutoSize;
+ th->setSizeAndPositionFromAutoSize();
+ if(th->onStage)
+ th->requestInvalidation(getSys());
+ }
+
return NULL;
}
+void TextField::setSizeAndPositionFromAutoSize()
+{
+ if (autoSize == AS_NONE)
+ return;
+
+ height = textHeight;
+ if (!wordWrap && width < textWidth)
+ {
+ if (autoSize == AS_RIGHT)
+ {
+ number_t oldX = getXY().x;
+ setX(oldX+width-textWidth);
+ width = textWidth;
+ }
+ else if (autoSize == AS_CENTER)
+ {
+ number_t oldX = getXY().x;
+ setX(oldX + width/2 - textWidth/2);
+ width = textWidth;
+ }
+ else // AS_LEFT, because AS_NONE was handled before
+ {
+ width = textWidth;
+ }
+ }
+}
+
ASFUNCTIONBODY(TextField,_getWidth)
{
TextField* th=Class<TextField>::cast(obj);
@@ -383,7 +483,7 @@ ASFUNCTIONBODY(TextField,_setDefaultTextFormat)
ASFUNCTIONBODY(TextField, _getter_type)
{
TextField* th=Class<TextField>::cast(obj);
- if (th->type == READ_ONLY)
+ if (th->type == ET_READ_ONLY)
return Class<ASString>::getInstanceS("dynamic");
else
return Class<ASString>::getInstanceS("input");
@@ -397,19 +497,370 @@ ASFUNCTIONBODY(TextField, _setter_type)
ARG_UNPACK(value);
if (value == "dynamic")
- th->type = READ_ONLY;
+ th->type = ET_READ_ONLY;
else if (value == "input")
- th->type = EDITABLE;
+ th->type = ET_EDITABLE;
else
throwError<ArgumentError>(kInvalidEnumError, "type");
return NULL;
}
+ASFUNCTIONBODY(TextField,_getLineIndexAtPoint)
+{
+ TextField* th=Class<TextField>::cast(obj);
+ number_t x;
+ number_t y;
+ ARG_UNPACK(x) (y);
+
+ std::vector<LineData> lines = CairoPangoRenderer::getLineData(*th);
+ std::vector<LineData>::const_iterator it;
+ int i;
+ for (i=0, it=lines.begin(); it!=lines.end(); ++i, ++it)
+ {
+ if (x > it->extents.Xmin && x <= it->extents.Xmax &&
+ y > it->extents.Ymin && y <= it->extents.Ymax)
+ return abstract_i(i);
+ }
+
+ return abstract_i(-1);
+}
+
+ASFUNCTIONBODY(TextField,_getLineIndexOfChar)
+{
+ TextField* th=Class<TextField>::cast(obj);
+ int32_t charIndex;
+ ARG_UNPACK(charIndex);
+
+ if (charIndex < 0)
+ return abstract_i(-1);
+
+ std::vector<LineData> lines = CairoPangoRenderer::getLineData(*th);
+ std::vector<LineData>::const_iterator it;
+ int i;
+ for (i=0, it=lines.begin(); it!=lines.end(); ++i, ++it)
+ {
+ if (charIndex >= it->firstCharOffset &&
+ charIndex < it->firstCharOffset + it->length)
+ return abstract_i(i);
+ }
+
+ // testing shows that returns -1 on invalid index instead of
+ // throwing RangeError
+ return abstract_i(-1);
+}
+
+ASFUNCTIONBODY(TextField,_getLineLength)
+{
+ TextField* th=Class<TextField>::cast(obj);
+ int32_t lineIndex;
+ ARG_UNPACK(lineIndex);
+
+ std::vector<LineData> lines = CairoPangoRenderer::getLineData(*th);
+ if (lineIndex < 0 || lineIndex >= (int32_t)lines.size())
+ throwError<RangeError>(kParamRangeError);
+
+ return abstract_i(lines[lineIndex].length);
+}
+
ASFUNCTIONBODY(TextField,_getLineMetrics)
{
- LOG(LOG_NOT_IMPLEMENTED, "TextField.getLineMetrics() returns bogus values");
- return Class<TextLineMetrics>::getInstanceS(19, 280, 14, 11, 3.5, 0);
+ TextField* th=Class<TextField>::cast(obj);
+ int32_t lineIndex;
+ ARG_UNPACK(lineIndex);
+
+ std::vector<LineData> lines = CairoPangoRenderer::getLineData(*th);
+ if (lineIndex < 0 || lineIndex >= (int32_t)lines.size())
+ throwError<RangeError>(kParamRangeError);
+
+ return Class<TextLineMetrics>::getInstanceS(
+ lines[lineIndex].indent,
+ lines[lineIndex].extents.Xmax - lines[lineIndex].extents.Xmin,
+ lines[lineIndex].extents.Ymax - lines[lineIndex].extents.Ymin,
+ lines[lineIndex].ascent,
+ lines[lineIndex].descent,
+ lines[lineIndex].leading);
+}
+
+ASFUNCTIONBODY(TextField,_getLineOffset)
+{
+ TextField* th=Class<TextField>::cast(obj);
+ int32_t lineIndex;
+ ARG_UNPACK(lineIndex);
+
+ std::vector<LineData> lines = CairoPangoRenderer::getLineData(*th);
+ if (lineIndex < 0 || lineIndex >= (int32_t)lines.size())
+ throwError<RangeError>(kParamRangeError);
+
+ return abstract_i(lines[lineIndex].firstCharOffset);
+}
+
+ASFUNCTIONBODY(TextField,_getLineText)
+{
+ TextField* th=Class<TextField>::cast(obj);
+ int32_t lineIndex;
+ ARG_UNPACK(lineIndex);
+
+ std::vector<LineData> lines = CairoPangoRenderer::getLineData(*th);
+ if (lineIndex < 0 || lineIndex >= (int32_t)lines.size())
+ throwError<RangeError>(kParamRangeError);
+
+ tiny_string substr = th->text.substr(lines[lineIndex].firstCharOffset,
+ lines[lineIndex].length);
+ return Class<ASString>::getInstanceS(substr);
+}
+
+ASFUNCTIONBODY(TextField,_getAntiAliasType)
+{
+ TextField* th=Class<TextField>::cast(obj);
+ if (th->antiAliasType == AA_NORMAL)
+ return Class<ASString>::getInstanceS("normal");
+ else
+ return Class<ASString>::getInstanceS("advanced");
+}
+
+ASFUNCTIONBODY(TextField,_setAntiAliasType)
+{
+ TextField* th=Class<TextField>::cast(obj);
+ tiny_string value;
+ ARG_UNPACK(value);
+
+ if (value == "advanced")
+ {
+ th->antiAliasType = AA_ADVANCED;
+ LOG(LOG_NOT_IMPLEMENTED, "TextField advanced antiAliasType not implemented");
+ }
+ else
+ th->antiAliasType = AA_NORMAL;
+
+
+ return NULL;
+}
+
+ASFUNCTIONBODY(TextField,_getGridFitType)
+{
+ TextField* th=Class<TextField>::cast(obj);
+ if (th->gridFitType == GF_NONE)
+ return Class<ASString>::getInstanceS("none");
+ else if (th->gridFitType == GF_PIXEL)
+ return Class<ASString>::getInstanceS("pixel");
+ else
+ return Class<ASString>::getInstanceS("subpixel");
+}
+
+ASFUNCTIONBODY(TextField,_setGridFitType)
+{
+ TextField* th=Class<TextField>::cast(obj);
+ tiny_string value;
+ ARG_UNPACK(value);
+
+ if (value == "none")
+ th->gridFitType = GF_NONE;
+ else if (value == "pixel")
+ th->gridFitType = GF_PIXEL;
+ else
+ th->gridFitType = GF_SUBPIXEL;
+
+ LOG(LOG_NOT_IMPLEMENTED, "TextField gridFitType not implemented");
+
+ return NULL;
+}
+
+ASFUNCTIONBODY(TextField,_getLength)
+{
+ TextField* th=Class<TextField>::cast(obj);
+ return abstract_i(th->text.numChars());
+}
+
+ASFUNCTIONBODY(TextField,_getNumLines)
+{
+ TextField* th=Class<TextField>::cast(obj);
+ return abstract_i(CairoPangoRenderer::getLineData(*th).size());
+}
+
+ASFUNCTIONBODY(TextField,_getMaxScrollH)
+{
+ TextField* th=Class<TextField>::cast(obj);
+ return abstract_i(th->getMaxScrollH());
+}
+
+ASFUNCTIONBODY(TextField,_getMaxScrollV)
+{
+ TextField* th=Class<TextField>::cast(obj);
+ return abstract_i(th->getMaxScrollV());
+}
+
+ASFUNCTIONBODY(TextField,_getBottomScrollV)
+{
+ TextField* th=Class<TextField>::cast(obj);
+ std::vector<LineData> lines = CairoPangoRenderer::getLineData(*th);
+ for (unsigned int k=0; k<lines.size()-1; k++)
+ {
+ if (lines[k+1].extents.Ymin >= (int)th->height)
+ return abstract_i(k + 1);
+ }
+
+ return abstract_i(lines.size() + 1);
+}
+
+ASFUNCTIONBODY(TextField,_getRestrict)
+{
+ TextField* th=Class<TextField>::cast(obj);
+ if (th->restrictChars.isNull())
+ return NULL;
+ else
+ {
+ th->restrictChars->incRef();
+ return th->restrictChars.getPtr();
+ }
+}
+
+ASFUNCTIONBODY(TextField,_setRestrict)
+{
+ TextField* th=Class<TextField>::cast(obj);
+ ARG_UNPACK(th->restrictChars);
+ if (!th->restrictChars.isNull())
+ LOG(LOG_NOT_IMPLEMENTED, "TextField restrict property");
+ return NULL;
+}
+
+ASFUNCTIONBODY(TextField,_getTextInteractionMode)
+{
+ TextField* th=Class<TextField>::cast(obj);
+ if (th->textInteractionMode == TI_NORMAL)
+ return Class<ASString>::getInstanceS("normal");
+ else
+ return Class<ASString>::getInstanceS("selection");
+}
+
+ASFUNCTIONBODY(TextField,_setSelection)
+{
+ TextField* th=Class<TextField>::cast(obj);
+ ARG_UNPACK(th->selectionBeginIndex) (th->selectionEndIndex);
+
+ if (th->selectionBeginIndex < 0)
+ th->selectionBeginIndex = 0;
+
+ if (th->selectionEndIndex >= (int32_t)th->text.numChars())
+ th->selectionEndIndex = th->text.numChars()-1;
+
+ if (th->selectionBeginIndex > th->selectionEndIndex)
+ th->selectionBeginIndex = th->selectionEndIndex;
+
+ if (th->selectionBeginIndex == th->selectionEndIndex)
+ th->caretIndex = th->selectionBeginIndex;
+
+ LOG(LOG_NOT_IMPLEMENTED, "TextField selection will not be rendered");
+
+ return NULL;
+}
+
+ASFUNCTIONBODY(TextField,_replaceSelectedText)
+{
+ TextField* th=Class<TextField>::cast(obj);
+ tiny_string newText;
+ ARG_UNPACK(newText);
+ th->replaceText(th->selectionBeginIndex, th->selectionEndIndex, newText);
+ return NULL;
+}
+
+ASFUNCTIONBODY(TextField,_replaceText)
+{
+ TextField* th=Class<TextField>::cast(obj);
+ int32_t begin;
+ int32_t end;
+ tiny_string newText;
+ ARG_UNPACK(begin) (end) (newText);
+ th->replaceText(begin, end, newText);
+ return NULL;
+}
+
+void TextField::replaceText(unsigned int begin, unsigned int end, const tiny_string& newText)
+{
+ if (!styleSheet.isNull())
+ throw Class<ASError>::getInstanceS("Can not replace text on text field with a style sheet");
+
+ if (begin >= text.numChars())
+ {
+ text = text + newText;
+ }
+ else if (begin > end)
+ {
+ return;
+ }
+ else if (end >= text.numChars())
+ {
+ text = text.substr(0, begin) + newText;
+ }
+ else
+ {
+ text = text.substr(0, begin) + newText + text.substr(end, text.end());
+ }
+
+ textUpdated();
+}
+
+void TextField::validateThickness(number_t /*oldValue*/)
+{
+ thickness = dmin(dmax(thickness, -200.), 200.);
+}
+
+void TextField::validateSharpness(number_t /*oldValue*/)
+{
+ sharpness = dmin(dmax(sharpness, -400.), 400.);
+}
+
+void TextField::validateScrollH(int32_t oldValue)
+{
+ int32_t maxScrollH = getMaxScrollH();
+ if (scrollH > maxScrollH)
+ scrollH = maxScrollH;
+
+ if (onStage && (scrollH != oldValue))
+ requestInvalidation(getSys());
+}
+
+void TextField::validateScrollV(int32_t oldValue)
+{
+ int32_t maxScrollV = getMaxScrollV();
+ if (scrollV < 1)
+ scrollV = 1;
+ else if (scrollV > maxScrollV)
+ scrollV = maxScrollV;
+
+ if (onStage && (scrollV != oldValue))
+ requestInvalidation(getSys());
+}
+
+int32_t TextField::getMaxScrollH()
+{
+ if (wordWrap || (textWidth <= width))
+ return 0;
+ else
+ return textWidth;
+}
+
+int32_t TextField::getMaxScrollV()
+{
+ std::vector<LineData> lines = CairoPangoRenderer::getLineData(*this);
+ if (lines.size() <= 1)
+ return 1;
+
+ int32_t Ymax = lines[lines.size()-1].extents.Ymax;
+ int32_t measuredTextHeight = Ymax - lines[0].extents.Ymin;
+ if (measuredTextHeight <= (int32_t)height)
+ return 1;
+
+ // one full page from the bottom
+ for (int k=(int)lines.size()-1; k>=0; k--)
+ {
+ if (Ymax - lines[k].extents.Ymin > (int32_t)height)
+ {
+ return imin(k+1+1, lines.size());
+ }
+ }
+
+ return 1;
}
void TextField::updateSizes()
@@ -461,12 +912,53 @@ tiny_string TextField::toHtmlText()
void TextField::setHtmlText(const tiny_string& html)
{
HtmlTextParser parser;
- parser.parseTextAndFormating(html, this);
+ if (condenseWhite)
+ {
+ tiny_string processedHtml = compactHTMLWhiteSpace(html);
+ parser.parseTextAndFormating(processedHtml, this);
+ }
+ else
+ {
+ parser.parseTextAndFormating(html, this);
+ }
+ textUpdated();
+}
+
+tiny_string TextField::compactHTMLWhiteSpace(const tiny_string& html)
+{
+ tiny_string compacted;
+ bool previousWasSpace = false;
+ for (CharIterator ch=html.begin(); ch!=html.end(); ++ch)
+ {
+ if (g_unichar_isspace(*ch))
+ {
+ if (!previousWasSpace)
+ compacted += ' ';
+ previousWasSpace = true;
+ }
+ else
+ {
+ compacted += *ch;
+ previousWasSpace = false;
+ }
+ }
+
+ return compacted;
}
void TextField::updateText(const tiny_string& new_text)
{
text = new_text;
+ textUpdated();
+}
+
+void TextField::textUpdated()
+{
+ scrollH = 0;
+ scrollV = 1;
+ selectionBeginIndex = 0;
+ selectionEndIndex = 0;
+
if(onStage)
requestInvalidation(getSys());
else
@@ -647,8 +1139,9 @@ uint32_t TextField::HtmlTextParser::parseFontSize(const Glib::ustring& sizestr,
return (uint32_t)size;
}
-void TextFieldAutoSize ::sinit(Class_base* c)
+void TextFieldAutoSize::sinit(Class_base* c)
{
+ CLASS_SETUP_NO_CONSTRUCTOR(c, ASObject, CLASS_FINAL | CLASS_SEALED);
c->setVariableByQName("CENTER","",Class<ASString>::getInstanceS("center"),DECLARED_TRAIT);
c->setVariableByQName("LEFT","",Class<ASString>::getInstanceS("left"),DECLARED_TRAIT);
c->setVariableByQName("NONE","",Class<ASString>::getInstanceS("none"),DECLARED_TRAIT);
@@ -657,12 +1150,14 @@ void TextFieldAutoSize ::sinit(Class_base* c)
void TextFieldType::sinit(Class_base* c)
{
+ CLASS_SETUP_NO_CONSTRUCTOR(c, ASObject, CLASS_FINAL | CLASS_SEALED);
c->setVariableByQName("DYNAMIC","",Class<ASString>::getInstanceS("dynamic"),DECLARED_TRAIT);
c->setVariableByQName("INPUT","",Class<ASString>::getInstanceS("input"),DECLARED_TRAIT);
}
-void TextFormatAlign ::sinit(Class_base* c)
+void TextFormatAlign::sinit(Class_base* c)
{
+ CLASS_SETUP_NO_CONSTRUCTOR(c, ASObject, CLASS_FINAL | CLASS_SEALED);
c->setVariableByQName("CENTER","",Class<ASString>::getInstanceS("center"),DECLARED_TRAIT);
c->setVariableByQName("END","",Class<ASString>::getInstanceS("end"),DECLARED_TRAIT);
c->setVariableByQName("JUSTIFY","",Class<ASString>::getInstanceS("justify"),DECLARED_TRAIT);
@@ -673,8 +1168,7 @@ void TextFormatAlign ::sinit(Class_base* c)
void TextFormat::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASObject>::getRef());
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED);
REGISTER_GETTER_SETTER(c,align);
REGISTER_GETTER_SETTER(c,blockIndent);
REGISTER_GETTER_SETTER(c,bold);
@@ -773,8 +1267,7 @@ void StyleSheet::finalize()
void StyleSheet::sinit(Class_base* c)
{
- c->setConstructor(NULL);
- c->setSuper(Class<EventDispatcher>::getRef());
+ CLASS_SETUP_NO_CONSTRUCTOR(c, EventDispatcher, CLASS_DYNAMIC_NOT_FINAL);
c->setDeclaredMethodByQName("styleNames","",Class<IFunction>::getFunction(_getStyleNames),GETTER_METHOD,true);
c->setDeclaredMethodByQName("setStyle","",Class<IFunction>::getFunction(setStyle),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("getStyle","",Class<IFunction>::getFunction(getStyle),NORMAL_METHOD,true);
@@ -833,9 +1326,10 @@ ASFUNCTIONBODY(StyleSheet,_getStyleNames)
void StaticText::sinit(Class_base* c)
{
- //TODO: spec says that constructor should throw ArgumentError
- c->setConstructor(NULL);
- c->setSuper(Class<DisplayObject>::getRef());
+ // FIXME: the constructor should be
+ // _constructorNotInstantiatable but that breaks when
+ // DisplayObjectContainer::initFrame calls the constructor
+ CLASS_SETUP_NO_CONSTRUCTOR(c, DisplayObject, CLASS_FINAL | CLASS_SEALED);
c->setDeclaredMethodByQName("text","",Class<IFunction>::getFunction(_getText),GETTER_METHOD,true);
}
@@ -847,8 +1341,7 @@ ASFUNCTIONBODY(StaticText,_getText)
void FontStyle::sinit(Class_base* c)
{
- c->setConstructor(NULL);
- c->setSuper(Class<ASObject>::getRef());
+ CLASS_SETUP_NO_CONSTRUCTOR(c, ASObject, CLASS_FINAL | CLASS_SEALED);
c->setVariableByQName("BOLD","",Class<ASString>::getInstanceS("bold"),DECLARED_TRAIT);
c->setVariableByQName("BOLD_ITALIC","",Class<ASString>::getInstanceS("boldItalic"),DECLARED_TRAIT);
c->setVariableByQName("ITALIC","",Class<ASString>::getInstanceS("italic"),DECLARED_TRAIT);
@@ -857,8 +1350,7 @@ void FontStyle::sinit(Class_base* c)
void FontType::sinit(Class_base* c)
{
- c->setConstructor(NULL);
- c->setSuper(Class<ASObject>::getRef());
+ CLASS_SETUP_NO_CONSTRUCTOR(c, ASObject, CLASS_FINAL | CLASS_SEALED);
c->setVariableByQName("DEVICE","",Class<ASString>::getInstanceS("device"),DECLARED_TRAIT);
c->setVariableByQName("EMBEDDED","",Class<ASString>::getInstanceS("embedded"),DECLARED_TRAIT);
c->setVariableByQName("EMBEDDED_CFF","",Class<ASString>::getInstanceS("embeddedCFF"),DECLARED_TRAIT);
@@ -866,8 +1358,7 @@ void FontType::sinit(Class_base* c)
void TextDisplayMode::sinit(Class_base* c)
{
- c->setConstructor(NULL);
- c->setSuper(Class<ASObject>::getRef());
+ CLASS_SETUP_NO_CONSTRUCTOR(c, ASObject, CLASS_FINAL | CLASS_SEALED);
c->setVariableByQName("CRT","",Class<ASString>::getInstanceS("crt"),DECLARED_TRAIT);
c->setVariableByQName("DEFAULT","",Class<ASString>::getInstanceS("default"),DECLARED_TRAIT);
c->setVariableByQName("LCD","",Class<ASString>::getInstanceS("lcd"),DECLARED_TRAIT);
@@ -875,25 +1366,29 @@ void TextDisplayMode::sinit(Class_base* c)
void TextColorType::sinit(Class_base* c)
{
- c->setConstructor(NULL);
- c->setSuper(Class<ASObject>::getRef());
+ CLASS_SETUP_NO_CONSTRUCTOR(c, ASObject, CLASS_FINAL | CLASS_SEALED);
c->setVariableByQName("DARK_COLOR","",Class<ASString>::getInstanceS("dark"),DECLARED_TRAIT);
c->setVariableByQName("LIGHT_COLOR","",Class<ASString>::getInstanceS("light"),DECLARED_TRAIT);
}
void GridFitType::sinit(Class_base* c)
{
- c->setConstructor(NULL);
- c->setSuper(Class<ASObject>::getRef());
+ CLASS_SETUP_NO_CONSTRUCTOR(c, ASObject, CLASS_FINAL | CLASS_SEALED);
c->setVariableByQName("NONE","",Class<ASString>::getInstanceS("none"),DECLARED_TRAIT);
c->setVariableByQName("PIXEL","",Class<ASString>::getInstanceS("pixel"),DECLARED_TRAIT);
c->setVariableByQName("SUBPIXEL","",Class<ASString>::getInstanceS("subpixel"),DECLARED_TRAIT);
}
+void TextInteractionMode::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_FINAL | CLASS_SEALED);
+ c->setVariableByQName("NORMAL","",Class<ASString>::getInstanceS("normal"),DECLARED_TRAIT);
+ c->setVariableByQName("SELECTION","",Class<ASString>::getInstanceS("selection"),DECLARED_TRAIT);
+}
+
void TextLineMetrics::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASObject>::getRef());
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED);
REGISTER_GETTER_SETTER(c, ascent);
REGISTER_GETTER_SETTER(c, descent);
REGISTER_GETTER_SETTER(c, height);
diff --git a/src/scripting/flash/text/flashtext.h b/src/scripting/flash/text/flashtext.h
index 7999be0..601b368 100644
--- a/src/scripting/flash/text/flashtext.h
+++ b/src/scripting/flash/text/flashtext.h
@@ -52,6 +52,20 @@ public:
ASPROPERTY_GETTER(tiny_string, fontType);
};
+class StyleSheet: public EventDispatcher
+{
+private:
+ std::map<tiny_string, _R<ASObject> > styles;
+public:
+ StyleSheet(Class_base* c):EventDispatcher(c){}
+ void finalize();
+ ASFUNCTION(getStyle);
+ ASFUNCTION(setStyle);
+ ASFUNCTION(_getStyleNames);
+ static void sinit(Class_base* c);
+ static void buildTraits(ASObject* o);
+};
+
class TextField: public InteractiveObject, public TextData
{
private:
@@ -73,7 +87,10 @@ private:
};
public:
- enum EDIT_TYPE {READ_ONLY, EDITABLE};
+ enum EDIT_TYPE { ET_READ_ONLY, ET_EDITABLE };
+ enum ANTI_ALIAS_TYPE { AA_NORMAL, AA_ADVANCED };
+ enum GRID_FIT_TYPE { GF_NONE, GF_PIXEL, GF_SUBPIXEL };
+ enum TEXT_INTERACTION_MODE { TI_NORMAL, TI_SELECTION };
private:
_NR<DisplayObject> hitTestImpl(_NR<DisplayObject> last, number_t x, number_t y, HIT_TYPE type);
void renderImpl(RenderContext& ctxt) const;
@@ -84,13 +101,33 @@ private:
//Computes and changes (text)width and (text)height using Pango
void updateSizes();
tiny_string toHtmlText();
+ tiny_string compactHTMLWhiteSpace(const tiny_string&);
+ void validateThickness(number_t oldValue);
+ void validateSharpness(number_t oldValue);
+ void validateScrollH(int32_t oldValue);
+ void validateScrollV(int32_t oldValue);
+ int32_t getMaxScrollH();
+ int32_t getMaxScrollV();
+ void textUpdated();
+ void setSizeAndPositionFromAutoSize();
+ void replaceText(unsigned int begin, unsigned int end, const tiny_string& newText);
EDIT_TYPE type;
+ ANTI_ALIAS_TYPE antiAliasType;
+ GRID_FIT_TYPE gridFitType;
+ TEXT_INTERACTION_MODE textInteractionMode;
+ _NR<ASString> restrictChars;
public:
TextField(Class_base* c, const TextData& textData=TextData(), bool _selectable=true, bool readOnly=true);
+ void finalize();
static void sinit(Class_base* c);
static void buildTraits(ASObject* o);
void setHtmlText(const tiny_string& html);
ASFUNCTION(appendText);
+ ASFUNCTION(_getAntiAliasType);
+ ASFUNCTION(_setAntiAliasType);
+ ASFUNCTION(_getGridFitType);
+ ASFUNCTION(_setGridFitType);
+ ASFUNCTION(_getLength);
ASFUNCTION(_getWidth);
ASFUNCTION(_setWidth);
ASFUNCTION(_getHeight);
@@ -109,16 +146,45 @@ public:
ASFUNCTION(_setTextFormat);
ASFUNCTION(_getDefaultTextFormat);
ASFUNCTION(_setDefaultTextFormat);
+ ASFUNCTION(_getLineIndexAtPoint);
+ ASFUNCTION(_getLineIndexOfChar);
+ ASFUNCTION(_getLineLength);
ASFUNCTION(_getLineMetrics);
+ ASFUNCTION(_getLineOffset);
+ ASFUNCTION(_getLineText);
+ ASFUNCTION(_getNumLines);
+ ASFUNCTION(_getMaxScrollH);
+ ASFUNCTION(_getMaxScrollV);
+ ASFUNCTION(_getBottomScrollV);
+ ASFUNCTION(_getRestrict);
+ ASFUNCTION(_setRestrict);
+ ASFUNCTION(_getTextInteractionMode);
+ ASFUNCTION(_setSelection);
+ ASFUNCTION(_replaceText);
+ ASFUNCTION(_replaceSelectedText);
+ ASPROPERTY_GETTER_SETTER(bool, alwaysShowSelection);
ASFUNCTION_GETTER_SETTER(background);
ASFUNCTION_GETTER_SETTER(backgroundColor);
ASFUNCTION_GETTER_SETTER(border);
ASFUNCTION_GETTER_SETTER(borderColor);
+ ASPROPERTY_GETTER(int32_t, caretIndex);
+ ASPROPERTY_GETTER_SETTER(bool, condenseWhite);
+ ASPROPERTY_GETTER_SETTER(bool, displayAsPassword);
+ ASPROPERTY_GETTER_SETTER(bool, embedFonts);
+ ASPROPERTY_GETTER_SETTER(int32_t, maxChars);
ASFUNCTION_GETTER_SETTER(multiline);
ASPROPERTY_GETTER_SETTER(bool, mouseWheelEnabled);
+ ASFUNCTION_GETTER_SETTER(scrollH);
+ ASFUNCTION_GETTER_SETTER(scrollV);
ASPROPERTY_GETTER_SETTER(bool, selectable);
+ ASPROPERTY_GETTER(int32_t, selectionBeginIndex);
+ ASPROPERTY_GETTER(int32_t, selectionEndIndex);
+ ASPROPERTY_GETTER_SETTER(number_t, sharpness);
+ ASPROPERTY_GETTER_SETTER(_NR<StyleSheet>, styleSheet);
ASFUNCTION_GETTER_SETTER(textColor);
+ ASPROPERTY_GETTER_SETTER(number_t, thickness);
ASFUNCTION_GETTER_SETTER(type);
+ ASPROPERTY_GETTER_SETTER(bool, useRichTextClipboard);
};
class TextFormat: public ASObject
@@ -172,20 +238,6 @@ public:
static void sinit(Class_base* c);
};
-class StyleSheet: public EventDispatcher
-{
-private:
- std::map<tiny_string, _R<ASObject> > styles;
-public:
- StyleSheet(Class_base* c):EventDispatcher(c){}
- void finalize();
- ASFUNCTION(getStyle);
- ASFUNCTION(setStyle);
- ASFUNCTION(_getStyleNames);
- static void sinit(Class_base* c);
- static void buildTraits(ASObject* o);
-};
-
class StaticText: public DisplayObject, public TokenContainer
{
private:
@@ -242,6 +294,13 @@ public:
static void sinit(Class_base* c);
};
+class TextInteractionMode: public ASObject
+{
+public:
+ TextInteractionMode(Class_base* c):ASObject(c){}
+ static void sinit(Class_base* c);
+};
+
class TextLineMetrics : public ASObject
{
protected:
diff --git a/src/scripting/flash/text/flashtextengine.cpp b/src/scripting/flash/text/flashtextengine.cpp
index c9c4900..69cd51c 100644
--- a/src/scripting/flash/text/flashtextengine.cpp
+++ b/src/scripting/flash/text/flashtextengine.cpp
@@ -29,33 +29,103 @@ using namespace lightspark;
void ContentElement::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASObject>::getRef());
+ CLASS_SETUP(c, ASObject, _constructorNotInstantiatable, CLASS_SEALED);
+ REGISTER_GETTER_SETTER(c,elementFormat);
}
-
-ASFUNCTIONBODY(ContentElement, _constructor)
+ASFUNCTIONBODY_GETTER_SETTER(ContentElement,elementFormat)
+
+ElementFormat::ElementFormat(Class_base *c): ASObject(c),
+ alignmentBaseline("useDominantBaseline"),
+ alpha(1.0),
+ baselineShift(0.0),
+ breakOpportunity("auto"),
+ color(0x000000),
+ digitCase("default"),
+ digitWidth("default"),
+ dominantBaseline("roman"),
+ fontDescription(NULL),
+ fontSize(12.0),
+ kerning("on"),
+ ligatureLevel("common"),
+ locale("en"),
+ locked(false),
+ textRotation("auto"),
+ trackingLeft(0.0),
+ trackingRight(0.0),
+ typographicCase("default")
{
- throwError<ArgumentError>(kCantInstantiateError, "ContentElement");
- return NULL;
+
}
void ElementFormat::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASObject>::getRef());
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_FINAL | CLASS_SEALED);
c->setVariableByQName("GRAPHIC_ELEMENT","",abstract_ui(0xFDEF),CONSTANT_TRAIT);
+ REGISTER_GETTER_SETTER(c,alignmentBaseline);
+ REGISTER_GETTER_SETTER(c,alpha);
+ REGISTER_GETTER_SETTER(c,baselineShift);
+ REGISTER_GETTER_SETTER(c,breakOpportunity);
+ REGISTER_GETTER_SETTER(c,color);
+ REGISTER_GETTER_SETTER(c,digitCase);
+ REGISTER_GETTER_SETTER(c,digitWidth);
+ REGISTER_GETTER_SETTER(c,dominantBaseline);
+ REGISTER_GETTER_SETTER(c,fontDescription);
+ REGISTER_GETTER_SETTER(c,fontSize);
+ REGISTER_GETTER_SETTER(c,kerning);
+ REGISTER_GETTER_SETTER(c,ligatureLevel);
+ REGISTER_GETTER_SETTER(c,locale);
+ REGISTER_GETTER_SETTER(c,locked);
+ REGISTER_GETTER_SETTER(c,textRotation);
+ REGISTER_GETTER_SETTER(c,trackingLeft);
+ REGISTER_GETTER_SETTER(c,trackingRight);
+ REGISTER_GETTER_SETTER(c,typographicCase);
}
+ASFUNCTIONBODY_GETTER_SETTER(ElementFormat,alignmentBaseline)
+ASFUNCTIONBODY_GETTER_SETTER(ElementFormat,alpha)
+ASFUNCTIONBODY_GETTER_SETTER(ElementFormat,baselineShift)
+ASFUNCTIONBODY_GETTER_SETTER(ElementFormat,breakOpportunity)
+ASFUNCTIONBODY_GETTER_SETTER(ElementFormat,color)
+ASFUNCTIONBODY_GETTER_SETTER(ElementFormat,digitCase)
+ASFUNCTIONBODY_GETTER_SETTER(ElementFormat,digitWidth)
+ASFUNCTIONBODY_GETTER_SETTER(ElementFormat,dominantBaseline)
+ASFUNCTIONBODY_GETTER_SETTER(ElementFormat,fontDescription)
+ASFUNCTIONBODY_GETTER_SETTER(ElementFormat,fontSize)
+ASFUNCTIONBODY_GETTER_SETTER(ElementFormat,kerning)
+ASFUNCTIONBODY_GETTER_SETTER(ElementFormat,ligatureLevel)
+ASFUNCTIONBODY_GETTER_SETTER(ElementFormat,locale)
+ASFUNCTIONBODY_GETTER_SETTER(ElementFormat,locked)
+ASFUNCTIONBODY_GETTER_SETTER(ElementFormat,textRotation)
+ASFUNCTIONBODY_GETTER_SETTER(ElementFormat,trackingLeft)
+ASFUNCTIONBODY_GETTER_SETTER(ElementFormat,trackingRight)
+ASFUNCTIONBODY_GETTER_SETTER(ElementFormat,typographicCase)
ASFUNCTIONBODY(ElementFormat, _constructor)
{
- LOG(LOG_NOT_IMPLEMENTED, "ElementFormat class not implemented");
+ ElementFormat* th=static_cast<ElementFormat*>(obj);
+ ARG_UNPACK(th->fontDescription, NullRef)(th->fontSize, 12.0)(th->color, 0x000000) (th->alpha, 1.0)(th->textRotation, "auto")
+ (th->dominantBaseline, "roman") (th->alignmentBaseline, "useDominantBaseline") (th->baselineShift, 0.0)(th->kerning, "on")
+ (th->trackingRight, 0.0)(th->trackingLeft, 0.0)(th->locale, "en")(th->breakOpportunity, "auto")(th->digitCase, "default")
+ (th->digitWidth, "default")(th->ligatureLevel, "common")(th->typographicCase, "default");
return NULL;
}
+void FontLookup::sinit(Class_base* c)
+{
+ CLASS_SETUP_NO_CONSTRUCTOR(c, ASObject, CLASS_FINAL | CLASS_SEALED);
+ c->setVariableByQName("DEVICE","",Class<ASString>::getInstanceS("device"),CONSTANT_TRAIT);
+ c->setVariableByQName("EMBEDDED_CFF","",Class<ASString>::getInstanceS("embeddedCFF"),CONSTANT_TRAIT);
+}
+
void FontDescription::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASObject>::getRef());
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_FINAL | CLASS_SEALED);
+ REGISTER_GETTER_SETTER(c,cffHinting);
+ REGISTER_GETTER_SETTER(c,fontLookup);
+ REGISTER_GETTER_SETTER(c,fontName);
+ REGISTER_GETTER_SETTER(c,fontPosture);
+ REGISTER_GETTER_SETTER(c,fontWeight);
+ REGISTER_GETTER_SETTER(c,locked);
+ REGISTER_GETTER_SETTER(c,renderingMode);
}
ASFUNCTIONBODY(FontDescription, _constructor)
@@ -63,24 +133,103 @@ ASFUNCTIONBODY(FontDescription, _constructor)
LOG(LOG_NOT_IMPLEMENTED, "FontDescription class not implemented");
return NULL;
}
+ASFUNCTIONBODY_GETTER_SETTER(FontDescription,cffHinting)
+ASFUNCTIONBODY_GETTER_SETTER(FontDescription,fontLookup)
+ASFUNCTIONBODY_GETTER_SETTER(FontDescription,fontName)
+ASFUNCTIONBODY_GETTER_SETTER(FontDescription,fontPosture)
+ASFUNCTIONBODY_GETTER_SETTER(FontDescription,fontWeight)
+ASFUNCTIONBODY_GETTER_SETTER(FontDescription,locked)
+ASFUNCTIONBODY_GETTER_SETTER(FontDescription,renderingMode)
void FontWeight::sinit(Class_base* c)
{
- c->setConstructor(NULL);
- c->setSuper(Class<ASObject>::getRef());
+ CLASS_SETUP_NO_CONSTRUCTOR(c, ASObject, CLASS_FINAL | CLASS_SEALED);
c->setVariableByQName("BOLD","",Class<ASString>::getInstanceS("bold"),CONSTANT_TRAIT);
c->setVariableByQName("NORMAL","",Class<ASString>::getInstanceS("normal"),CONSTANT_TRAIT);
}
+void FontMetrics::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, ASObject,_constructor, CLASS_FINAL);
+}
+ASFUNCTIONBODY(FontMetrics, _constructor)
+{
+ //FontMetrics* th=static_cast<FontMetrics*>(obj);
+ LOG(LOG_NOT_IMPLEMENTED, "FontMetrics is a stub");
+ return NULL;
+}
+
+void Kerning::sinit(Class_base* c)
+{
+ CLASS_SETUP_NO_CONSTRUCTOR(c, ASObject, CLASS_FINAL | CLASS_SEALED);
+ c->setVariableByQName("AUTO","",Class<ASString>::getInstanceS("auto"),CONSTANT_TRAIT);
+ c->setVariableByQName("OFF","",Class<ASString>::getInstanceS("off"),CONSTANT_TRAIT);
+ c->setVariableByQName("ON","",Class<ASString>::getInstanceS("on"),CONSTANT_TRAIT);
+}
+
+void LineJustification::sinit(Class_base* c)
+{
+ CLASS_SETUP_NO_CONSTRUCTOR(c, ASObject, CLASS_FINAL | CLASS_SEALED);
+ c->setVariableByQName("ALL_BUT_LAST","",Class<ASString>::getInstanceS("allButLast"),CONSTANT_TRAIT);
+ c->setVariableByQName("ALL_BUT_MANDATORY_BREAK","",Class<ASString>::getInstanceS("allButMandatoryBreak"),CONSTANT_TRAIT);
+ c->setVariableByQName("ALL_INCLUDING_LAST","",Class<ASString>::getInstanceS("allIncludingLast"),CONSTANT_TRAIT);
+ c->setVariableByQName("UNJUSTIFIED","",Class<ASString>::getInstanceS("unjustified"),CONSTANT_TRAIT);
+}
+void TextBaseline::sinit(Class_base* c)
+{
+ CLASS_SETUP_NO_CONSTRUCTOR(c, ASObject, CLASS_FINAL | CLASS_SEALED);
+ c->setVariableByQName("ASCENT","",Class<ASString>::getInstanceS("ascent"),CONSTANT_TRAIT);
+ c->setVariableByQName("DESCENT","",Class<ASString>::getInstanceS("descent"),CONSTANT_TRAIT);
+ c->setVariableByQName("IDEOGRAPHIC_BOTTOM","",Class<ASString>::getInstanceS("ideographicBottom"),CONSTANT_TRAIT);
+ c->setVariableByQName("IDEOGRAPHIC_CENTER","",Class<ASString>::getInstanceS("ideographicCenter"),CONSTANT_TRAIT);
+ c->setVariableByQName("IDEOGRAPHIC_TOP","",Class<ASString>::getInstanceS("ideographicTop"),CONSTANT_TRAIT);
+ c->setVariableByQName("ROMAN","",Class<ASString>::getInstanceS("roman"),CONSTANT_TRAIT);
+ c->setVariableByQName("USE_DOMINANT_BASELINE","",Class<ASString>::getInstanceS("useDominantBaseline"),CONSTANT_TRAIT);
+}
+
+void TextJustifier::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, ASObject, _constructor, 0);
+}
+ASFUNCTIONBODY(TextJustifier, _constructor)
+{
+ throwError<ArgumentError>(kCantInstantiateError, "TextJustifier cannot be instantiated");
+ return NULL;
+}
+void SpaceJustifier::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, TextJustifier, _constructor, CLASS_FINAL);
+}
+ASFUNCTIONBODY(SpaceJustifier, _constructor)
+{
+ //SpaceJustifier* th=static_cast<SpaceJustifier*>(obj);
+ LOG(LOG_NOT_IMPLEMENTED, "SpaceJustifier is a stub");
+ return NULL;
+}
+void EastAsianJustifier::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, TextJustifier, _constructor, CLASS_FINAL);
+}
+ASFUNCTIONBODY(EastAsianJustifier, _constructor)
+{
+ //EastAsianJustifier* th=static_cast<EastAsianJustifier*>(obj);
+ LOG(LOG_NOT_IMPLEMENTED, "EastAsianJustifier is a stub");
+ return NULL;
+}
+
void TextBlock::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASObject>::getRef());
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_FINAL | CLASS_SEALED);
c->setDeclaredMethodByQName("createTextLine","",Class<IFunction>::getFunction(createTextLine),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("recreateTextLine","",Class<IFunction>::getFunction(recreateTextLine),NORMAL_METHOD,true);
REGISTER_GETTER_SETTER(c, content);
+ REGISTER_GETTER_SETTER(c, textJustifier);
+ REGISTER_GETTER_SETTER(c, bidiLevel);
}
-ASFUNCTIONBODY_GETTER_SETTER(TextBlock, content);
+ASFUNCTIONBODY_GETTER_SETTER(TextBlock, content)
+ASFUNCTIONBODY_GETTER_SETTER(TextBlock, textJustifier)
+ASFUNCTIONBODY_GETTER_SETTER(TextBlock, bidiLevel)
ASFUNCTIONBODY(TextBlock, _constructor)
{
@@ -97,31 +246,92 @@ ASFUNCTIONBODY(TextBlock, createTextLine)
TextBlock* th=static_cast<TextBlock*>(obj);
_NR<TextLine> previousLine;
int32_t width;
- ARG_UNPACK (previousLine, NullRef) (width, MAX_LINE_WIDTH);
+ number_t lineOffset;
+ bool fitSomething;
+ ARG_UNPACK (previousLine, NullRef) (width, MAX_LINE_WIDTH) (lineOffset, 0.0) (fitSomething, false);
if (argslen > 2)
LOG(LOG_NOT_IMPLEMENTED, "TextBlock::createTextLine ignored some parameters");
- if (width <= 0 || width > MAX_LINE_WIDTH)
- throw Class<ArgumentError>::getInstanceS("Invalid width");
-
- if (!previousLine.isNull())
+ if (!fitSomething && (width < 0 || width > MAX_LINE_WIDTH))
{
- LOG(LOG_NOT_IMPLEMENTED, "TextBlock::createTextLine supports a single line only");
- return getSys()->getNullRef();
+ throwError<ArgumentError>(kOutOfRangeError,"Invalid width");
}
+ // TODO handle non TextElement Content
+ if (th->content.isNull() || !th->content->is<TextElement>() || th->content->as<TextElement>()->text.empty())
+ return NULL;
+ tiny_string linetext = th->content->as<TextElement>()->text;
+ if (fitSomething && linetext == "")
+ linetext = " ";
+
+ LOG(LOG_NOT_IMPLEMENTED,"splitting textblock in multiple lines not implemented");
+ th->content->as<TextElement>()->text = "";
th->incRef();
- TextLine *textLine = Class<TextLine>::getInstanceS(th->content, _MNR(th));
+ TextLine *textLine = Class<TextLine>::getInstanceS(linetext, _MNR(th));
textLine->width = (uint32_t)width;
+ textLine->previousLine = previousLine;
textLine->updateSizes();
+ if (textLine->width > textLine->textWidth)
+ {
+ delete textLine;
+ th->decRef();
+ return NULL;
+ }
+ if (!previousLine.isNull())
+ previousLine->nextLine == textLine;
return textLine;
}
+ASFUNCTIONBODY(TextBlock, recreateTextLine)
+{
+ TextBlock* th=static_cast<TextBlock*>(obj);
+ _NR<TextLine> previousLine;
+ _NR<TextLine> textLine;
+ int32_t width;
+ number_t lineOffset;
+ bool fitSomething;
+ ARG_UNPACK (textLine) (previousLine, NullRef) (width, MAX_LINE_WIDTH) (lineOffset, 0.0) (fitSomething, false);
+
+ if (argslen > 2)
+ LOG(LOG_NOT_IMPLEMENTED, "TextBlock::recreateTextLine ignored some parameters");
+ LOG(LOG_NOT_IMPLEMENTED, "TextBlock::recreateTextLine doesn't check all parameters for validity");
+
+ // TODO handle non TextElement Content
+ if (th->content.isNull() || !th->content->is<TextElement>() || th->content->as<TextElement>()->text.empty())
+ return NULL;
+
+ if (!fitSomething && (width < 0 || width > MAX_LINE_WIDTH))
+ {
+ throwError<ArgumentError>(kOutOfRangeError,"Invalid width");
+ }
+
+ if (textLine.isNull())
+ {
+ throwError<ArgumentError>(kInvalidArgumentError,"Invalid argument: textLine");
+ }
+
+ if (th != textLine->textBlock.getPtr())
+ {
+ throwError<ArgumentError>(kInvalidArgumentError,"Invalid argument: textLine is in different textBlock");
+ }
+ if (fitSomething && textLine->text == "")
+ textLine->text = " ";
+ textLine->width = (uint32_t)width;
+ textLine->previousLine = previousLine;
+ textLine->updateSizes();
+ if (textLine->width > textLine->textWidth)
+ {
+ return NULL;
+ }
+ if (!previousLine.isNull())
+ previousLine->nextLine == textLine;
+ textLine->incRef();
+ return textLine.getPtr();
+}
void TextElement::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ContentElement>::getRef());
+ CLASS_SETUP(c, ContentElement, _constructor, CLASS_FINAL | CLASS_SEALED);
REGISTER_GETTER_SETTER(c, text);
}
@@ -137,32 +347,37 @@ ASFUNCTIONBODY(TextElement, _constructor)
return NULL;
}
-TextLine::TextLine(Class_base* c, _NR<ContentElement> content, _NR<TextBlock> owner)
- : DisplayObjectContainer(c), TextData()
+TextLine::TextLine(Class_base* c, tiny_string linetext, _NR<TextBlock> owner)
+ : DisplayObjectContainer(c), TextData(),nextLine(NULL),previousLine(NULL),userData(NULL)
{
textBlock = owner;
- if (content.isNull() || !content->is<TextElement>())
- {
- LOG(LOG_NOT_IMPLEMENTED, "TextLine supports only TextElements");
- return;
- }
-
- TextElement *textElement = content->as<TextElement>();
- text = textElement->text;
+ text = linetext;
updateSizes();
requestInvalidation(getSys());
}
void TextLine::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<DisplayObjectContainer>::getRef());
- REGISTER_GETTER(c, textBlock);
+ CLASS_SETUP(c, DisplayObjectContainer, _constructor, CLASS_FINAL | CLASS_SEALED);
c->setVariableByQName("MAX_LINE_WIDTH","",abstract_ui(MAX_LINE_WIDTH),CONSTANT_TRAIT);
+ c->setDeclaredMethodByQName("descent","",Class<IFunction>::getFunction(getDescent),GETTER_METHOD,true);
+ c->setDeclaredMethodByQName("ascent","",Class<IFunction>::getFunction(getAscent),GETTER_METHOD,true);
+ c->setDeclaredMethodByQName("textWidth","",Class<IFunction>::getFunction(getTextWidth),GETTER_METHOD,true);
+ c->setDeclaredMethodByQName("textHeight","",Class<IFunction>::getFunction(getTextHeight),GETTER_METHOD,true);
+ REGISTER_GETTER(c, textBlock);
+ REGISTER_GETTER(c, nextLine);
+ REGISTER_GETTER(c, previousLine);
+ REGISTER_GETTER_SETTER(c, validity);
+ REGISTER_GETTER_SETTER(c, userData);
}
+
ASFUNCTIONBODY_GETTER(TextLine, textBlock);
+ASFUNCTIONBODY_GETTER(TextLine, nextLine);
+ASFUNCTIONBODY_GETTER(TextLine, previousLine);
+ASFUNCTIONBODY_GETTER_SETTER(TextLine, validity);
+ASFUNCTIONBODY_GETTER_SETTER(TextLine, userData);
ASFUNCTIONBODY(TextLine, _constructor)
{
@@ -171,6 +386,31 @@ ASFUNCTIONBODY(TextLine, _constructor)
return NULL;
}
+ASFUNCTIONBODY(TextLine, getDescent)
+{
+ LOG(LOG_NOT_IMPLEMENTED,"TextLine.descent");
+ return abstract_d(0);
+}
+
+ASFUNCTIONBODY(TextLine, getAscent)
+{
+ TextLine* th=static_cast<TextLine*>(obj);
+ LOG(LOG_NOT_IMPLEMENTED,"TextLine.ascent");
+ return abstract_d(th->textHeight);
+}
+
+ASFUNCTIONBODY(TextLine, getTextWidth)
+{
+ TextLine* th=static_cast<TextLine*>(obj);
+ return abstract_d(th->textWidth);
+}
+
+ASFUNCTIONBODY(TextLine, getTextHeight)
+{
+ TextLine* th=static_cast<TextLine*>(obj);
+ return abstract_d(th->textHeight);
+}
+
void TextLine::updateSizes()
{
@@ -179,7 +419,12 @@ void TextLine::updateSizes()
h = height;
//Compute (text)width, (text)height
CairoPangoRenderer::getBounds(*this, w, h, tw, th);
+ if (w == 0)
+ w = tw;
+ if (h == 0)
+ h = th;
width = w; //TODO: check the case when w,h == 0
+
textWidth = w;
height = h;
textHeight = h;
@@ -243,3 +488,13 @@ _NR<DisplayObject> TextLine::hitTestImpl(_NR<DisplayObject> last, number_t x, nu
return DisplayObjectContainer::hitTestImpl(_MR(this), x, y, type);
}
}
+
+void TextLineValidity::sinit(Class_base* c)
+{
+ CLASS_SETUP_NO_CONSTRUCTOR(c, ASObject, CLASS_FINAL | CLASS_SEALED);
+ c->setVariableByQName("INVALID","",Class<ASString>::getInstanceS("invalid"),CONSTANT_TRAIT);
+ c->setVariableByQName("POSSIBLY_INVALID","",Class<ASString>::getInstanceS("possiblyInvalid"),CONSTANT_TRAIT);
+ c->setVariableByQName("STATIC","",Class<ASString>::getInstanceS("static"),CONSTANT_TRAIT);
+ c->setVariableByQName("VALID","",Class<ASString>::getInstanceS("valid"),CONSTANT_TRAIT);
+}
+
diff --git a/src/scripting/flash/text/flashtextengine.h b/src/scripting/flash/text/flashtextengine.h
index df28501..063af79 100644
--- a/src/scripting/flash/text/flashtextengine.h
+++ b/src/scripting/flash/text/flashtextengine.h
@@ -29,51 +29,141 @@
namespace lightspark
{
+class ElementFormat;
class ContentElement: public ASObject
{
public:
- ContentElement(Class_base* c): ASObject(c) {};
+ ContentElement(Class_base* c): ASObject(c),elementFormat(NULL) {}
static void sinit(Class_base* c);
- ASFUNCTION(_constructor);
+ ASPROPERTY_GETTER_SETTER(_NR<ElementFormat>,elementFormat);
};
+class FontDescription;
class ElementFormat: public ASObject
{
public:
- ElementFormat(Class_base* c): ASObject(c) {};
+ ElementFormat(Class_base* c);
static void sinit(Class_base* c);
ASFUNCTION(_constructor);
+ ASPROPERTY_GETTER_SETTER(tiny_string,alignmentBaseline);
+ ASPROPERTY_GETTER_SETTER(number_t,alpha);
+ ASPROPERTY_GETTER_SETTER(number_t,baselineShift);
+ ASPROPERTY_GETTER_SETTER(tiny_string,breakOpportunity);
+ ASPROPERTY_GETTER_SETTER(uint,color);
+ ASPROPERTY_GETTER_SETTER(tiny_string,digitCase);
+ ASPROPERTY_GETTER_SETTER(tiny_string,digitWidth);
+ ASPROPERTY_GETTER_SETTER(tiny_string,dominantBaseline);
+ ASPROPERTY_GETTER_SETTER(_NR<FontDescription>,fontDescription);
+ ASPROPERTY_GETTER_SETTER(number_t,fontSize);
+ ASPROPERTY_GETTER_SETTER(tiny_string,kerning);
+ ASPROPERTY_GETTER_SETTER(tiny_string,ligatureLevel);
+ ASPROPERTY_GETTER_SETTER(tiny_string,locale);
+ ASPROPERTY_GETTER_SETTER(bool,locked);
+ ASPROPERTY_GETTER_SETTER(tiny_string,textRotation);
+ ASPROPERTY_GETTER_SETTER(number_t,trackingLeft);
+ ASPROPERTY_GETTER_SETTER(number_t,trackingRight);
+ ASPROPERTY_GETTER_SETTER(tiny_string,typographicCase);
+};
+
+class FontLookup: public ASObject
+{
+public:
+ FontLookup(Class_base* c): ASObject(c) {}
+ static void sinit(Class_base* c);
};
class FontDescription: public ASObject
{
public:
- FontDescription(Class_base* c): ASObject(c) {};
+ FontDescription(Class_base* c): ASObject(c),
+ cffHinting("horizontalStem"), fontLookup("device"), fontName("_serif"), fontPosture("normal"), fontWeight("normal"),locked(false), renderingMode("cff") {}
static void sinit(Class_base* c);
ASFUNCTION(_constructor);
+ ASPROPERTY_GETTER_SETTER(tiny_string,cffHinting);
+ ASPROPERTY_GETTER_SETTER(tiny_string,fontLookup);
+ ASPROPERTY_GETTER_SETTER(tiny_string,fontName);
+ ASPROPERTY_GETTER_SETTER(tiny_string,fontPosture);
+ ASPROPERTY_GETTER_SETTER(tiny_string,fontWeight);
+ ASPROPERTY_GETTER_SETTER(bool,locked);
+ ASPROPERTY_GETTER_SETTER(tiny_string,renderingMode);
};
class FontWeight: public ASObject
{
public:
- FontWeight(Class_base* c): ASObject(c) {};
+ FontWeight(Class_base* c): ASObject(c) {}
+ static void sinit(Class_base* c);
+};
+
+class FontMetrics: public ASObject
+{
+public:
+ FontMetrics(Class_base* c): ASObject(c) {}
+ static void sinit(Class_base* c);
+ ASFUNCTION(_constructor);
+};
+
+class Kerning: public ASObject
+{
+public:
+ Kerning(Class_base* c): ASObject(c) {}
+ static void sinit(Class_base* c);
+};
+class LineJustification: public ASObject
+{
+public:
+ LineJustification(Class_base* c): ASObject(c) {}
+ static void sinit(Class_base* c);
+};
+
+class TextBaseline: public ASObject
+{
+public:
+ TextBaseline(Class_base* c): ASObject(c) {}
static void sinit(Class_base* c);
};
+class TextJustifier: public ASObject
+{
+public:
+ TextJustifier(Class_base* c): ASObject(c) {}
+ static void sinit(Class_base* c);
+ ASFUNCTION(_constructor);
+};
+
+class SpaceJustifier: public TextJustifier
+{
+public:
+ SpaceJustifier(Class_base* c): TextJustifier(c) {}
+ static void sinit(Class_base* c);
+ ASFUNCTION(_constructor);
+};
+
+class EastAsianJustifier: public TextJustifier
+{
+public:
+ EastAsianJustifier(Class_base* c): TextJustifier(c) {}
+ static void sinit(Class_base* c);
+ ASFUNCTION(_constructor);
+};
+
class TextBlock: public ASObject
{
public:
- TextBlock(Class_base* c): ASObject(c) {};
+ TextBlock(Class_base* c): ASObject(c),bidiLevel(0) {}
static void sinit(Class_base* c);
ASFUNCTION(_constructor);
ASFUNCTION(createTextLine);
+ ASFUNCTION(recreateTextLine);
ASPROPERTY_GETTER_SETTER(_NR<ContentElement>, content);
+ ASPROPERTY_GETTER_SETTER(_NR<TextJustifier>, textJustifier);
+ ASPROPERTY_GETTER_SETTER(int,bidiLevel);
};
class TextElement: public ContentElement
{
public:
- TextElement(Class_base* c): ContentElement(c) {};
+ TextElement(Class_base* c): ContentElement(c) {}
static void sinit(Class_base* c);
ASFUNCTION(_constructor);
ASPROPERTY_GETTER_SETTER(tiny_string,text);
@@ -90,12 +180,29 @@ private:
void renderImpl(RenderContext& ctxt) const;
_NR<DisplayObject> hitTestImpl(_NR<DisplayObject> last, number_t x, number_t y, DisplayObject::HIT_TYPE type);
public:
- TextLine(Class_base* c, _NR<ContentElement> content=NullRef, _NR<TextBlock> owner=NullRef);
+ TextLine(Class_base* c,tiny_string linetext = "", _NR<TextBlock> owner=NullRef);
static void sinit(Class_base* c);
void updateSizes();
ASFUNCTION(_constructor);
ASPROPERTY_GETTER(_NR<TextBlock>, textBlock);
+ ASPROPERTY_GETTER(_NR<TextLine>, nextLine);
+ ASPROPERTY_GETTER(_NR<TextLine>, previousLine);
+ ASPROPERTY_GETTER_SETTER(tiny_string,validity);
+ ASPROPERTY_GETTER_SETTER(_NR<ASObject>,userData);
+ ASFUNCTION(getDescent);
+ ASFUNCTION(getAscent);
+ ASFUNCTION(getTextWidth);
+ ASFUNCTION(getTextHeight);
+
};
+
+class TextLineValidity: public ASObject
+{
+public:
+ TextLineValidity(Class_base* c): ASObject(c) {}
+ static void sinit(Class_base* c);
};
+}
+
#endif
diff --git a/src/scripting/flash/accessibility/flashaccessibility.cpp b/src/scripting/flash/ui/ContextMenu.cpp
similarity index 51%
copy from src/scripting/flash/accessibility/flashaccessibility.cpp
copy to src/scripting/flash/ui/ContextMenu.cpp
index ebc460d..bac02c1 100644
--- a/src/scripting/flash/accessibility/flashaccessibility.cpp
+++ b/src/scripting/flash/ui/ContextMenu.cpp
@@ -1,8 +1,6 @@
/**************************************************************************
Lightspark, a free flash player implementation
- Copyright (C) 2009-2013 Alessandro Pignotti (a.pignotti at sssup.it)
-
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
@@ -17,35 +15,40 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
-#include "scripting/flash/accessibility/flashaccessibility.h"
+#include "ContextMenu.h"
#include "scripting/class.h"
#include "scripting/argconv.h"
+using namespace std;
using namespace lightspark;
-void AccessibilityProperties::sinit(Class_base* c)
+ContextMenu::ContextMenu(Class_base* c):EventDispatcher(c),customItems(Class<Array>::getInstanceS()),builtInItems(Class<ContextMenuBuiltInItems>::getInstanceS())
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASObject>::getRef());
- REGISTER_GETTER_SETTER(c,name);
}
-ASFUNCTIONBODY(AccessibilityProperties,_constructor)
+void ContextMenu::sinit(Class_base* c)
{
- LOG(LOG_NOT_IMPLEMENTED, _("AccessibilityProperties class is unimplemented."));
- return NULL;
+ CLASS_SETUP(c, EventDispatcher, _constructor, CLASS_FINAL);
+ c->setVariableByQName("isSupported","",abstract_b(false),CONSTANT_TRAIT);
+ c->setDeclaredMethodByQName("hideBuiltInItems","",Class<IFunction>::getFunction(hideBuiltInItems),NORMAL_METHOD,true);
+ REGISTER_GETTER_SETTER(c,customItems);
+ REGISTER_GETTER_SETTER(c,builtInItems);
}
-ASFUNCTIONBODY_GETTER_SETTER(AccessibilityProperties,name);
+ASFUNCTIONBODY_GETTER_SETTER(ContextMenu,customItems);
+ASFUNCTIONBODY_GETTER_SETTER(ContextMenu,builtInItems);
-void AccessibilityImplementation::sinit(Class_base* c)
+ASFUNCTIONBODY(ContextMenu,_constructor)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASObject>::getRef());
+ EventDispatcher::_constructor(obj, NULL, 0);
+ LOG(LOG_NOT_IMPLEMENTED,"ContextMenu constructor is a stub");
+ return NULL;
}
-ASFUNCTIONBODY(AccessibilityImplementation,_constructor)
+ASFUNCTIONBODY(ContextMenu,hideBuiltInItems)
{
- LOG(LOG_NOT_IMPLEMENTED, _("AccessibilityImplementation class is unimplemented."));
+ LOG(LOG_NOT_IMPLEMENTED,"ContextMenu hideBuiltInItems is a stub");
return NULL;
}
+
+
diff --git a/src/scripting/flash/sensors/flashsensors.h b/src/scripting/flash/ui/ContextMenu.h
similarity index 64%
copy from src/scripting/flash/sensors/flashsensors.h
copy to src/scripting/flash/ui/ContextMenu.h
index 9f9ef19..9d189c0 100644
--- a/src/scripting/flash/sensors/flashsensors.h
+++ b/src/scripting/flash/ui/ContextMenu.h
@@ -1,8 +1,6 @@
/**************************************************************************
Lightspark, a free flash player implementation
- Copyright (C) 2011-2013 Alessandro Pignotti (a.pignotti at sssup.it)
-
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
@@ -17,25 +15,28 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
-#ifndef SCRIPTING_FLASH_SENSORS_FLASHSENSORS_H
-#define SCRIPTING_FLASH_SENSORS_FLASHSENSORS_H 1
+#ifndef SCRIPTING_FLASH_UI_CONTEXTMENU_H
+#define SCRIPTING_FLASH_UI_CONTEXTMENU_H
-#include "compat.h"
#include "asobject.h"
#include "scripting/flash/events/flashevents.h"
-#include "thread_pool.h"
-#include "backends/netutils.h"
-#include "timer.h"
-#include "backends/interfaces/audio/IAudioPlugin.h"
+#include "scripting/flash/ui/ContextMenuBuiltInItems.h"
+#include "scripting/toplevel/Array.h"
namespace lightspark
{
-class Accelerometer: public ASObject {
- public:
- Accelerometer(Class_base* c);
- static void sinit(Class_base* c);
- static void buildTraits(ASObject* o);
- ASFUNCTION(_isSupported);
+class Array;
+
+class ContextMenu : public EventDispatcher
+{
+public:
+ ContextMenu(Class_base* c);
+ static void sinit(Class_base* c);
+ ASFUNCTION(_constructor);
+ ASFUNCTION(hideBuiltInItems);
+ ASPROPERTY_GETTER_SETTER(_NR<Array>,customItems);
+ ASPROPERTY_GETTER_SETTER(_NR<ContextMenuBuiltInItems>,builtInItems);
};
+
}
-#endif /* SCRIPTING_FLASH_SENSORS_FLASHSENSORS_H */
+#endif // SCRIPTING_FLASH_UI_CONTEXTMENU_H
diff --git a/src/scripting/flash/ui/ContextMenuBuiltInItems.cpp b/src/scripting/flash/ui/ContextMenuBuiltInItems.cpp
new file mode 100644
index 0000000..c98bb93
--- /dev/null
+++ b/src/scripting/flash/ui/ContextMenuBuiltInItems.cpp
@@ -0,0 +1,57 @@
+/**************************************************************************
+ Lightspark, a free flash player implementation
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+**************************************************************************/
+
+#include "ContextMenuItem.h"
+#include "scripting/class.h"
+#include "scripting/argconv.h"
+
+using namespace std;
+using namespace lightspark;
+
+ContextMenuBuiltInItems::ContextMenuBuiltInItems(Class_base* c):ASObject(c),
+ forwardAndBack(false),loop(false),play(false),print(false),quality(false),rewind(false),save(false),zoom(false)
+{
+}
+
+void ContextMenuBuiltInItems::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_FINAL);
+ REGISTER_GETTER_SETTER(c,forwardAndBack);
+ REGISTER_GETTER_SETTER(c,loop);
+ REGISTER_GETTER_SETTER(c,play);
+ REGISTER_GETTER_SETTER(c,print);
+ REGISTER_GETTER_SETTER(c,quality);
+ REGISTER_GETTER_SETTER(c,rewind);
+ REGISTER_GETTER_SETTER(c,save);
+ REGISTER_GETTER_SETTER(c,zoom);
+}
+
+ASFUNCTIONBODY_GETTER_SETTER(ContextMenuBuiltInItems,forwardAndBack);
+ASFUNCTIONBODY_GETTER_SETTER(ContextMenuBuiltInItems,loop);
+ASFUNCTIONBODY_GETTER_SETTER(ContextMenuBuiltInItems,play);
+ASFUNCTIONBODY_GETTER_SETTER(ContextMenuBuiltInItems,print);
+ASFUNCTIONBODY_GETTER_SETTER(ContextMenuBuiltInItems,quality);
+ASFUNCTIONBODY_GETTER_SETTER(ContextMenuBuiltInItems,rewind);
+ASFUNCTIONBODY_GETTER_SETTER(ContextMenuBuiltInItems,save);
+ASFUNCTIONBODY_GETTER_SETTER(ContextMenuBuiltInItems,zoom);
+
+ASFUNCTIONBODY(ContextMenuBuiltInItems,_constructor)
+{
+ return NULL;
+}
+
+
diff --git a/src/scripting/flash/accessibility/flashaccessibility.h b/src/scripting/flash/ui/ContextMenuBuiltInItems.h
similarity index 59%
copy from src/scripting/flash/accessibility/flashaccessibility.h
copy to src/scripting/flash/ui/ContextMenuBuiltInItems.h
index 19d00b8..c0dcc03 100644
--- a/src/scripting/flash/accessibility/flashaccessibility.h
+++ b/src/scripting/flash/ui/ContextMenuBuiltInItems.h
@@ -1,7 +1,7 @@
/**************************************************************************
Lightspark, a free flash player implementation
- Copyright (C) 2009-2013 Alessandro Pignotti (a.pignotti at sssup.it)
+ Copyright (C) 2013 Antti Ajanki (antti.ajanki at iki.fi)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
@@ -17,31 +17,30 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
-#ifndef SCRIPTING_FLASH_ACCESSIBILITY_FLASHACCESSIBILITY_H
-#define SCRIPTING_FLASH_ACCESSIBILITY_FLASHACCESSIBILITY_H 1
+#ifndef SCRIPTING_FLASH_UI_CONTEXTMENUBUILTINITEMS_H
+#define SCRIPTING_FLASH_UI_CONTEXTMENUBUILTINITEMS_H
#include "asobject.h"
namespace lightspark
{
-class AccessibilityProperties : public ASObject
+class ContextMenuBuiltInItems : public ASObject
{
private:
- ASPROPERTY_GETTER_SETTER(tiny_string,name);
+ ASPROPERTY_GETTER_SETTER(bool,forwardAndBack);
+ ASPROPERTY_GETTER_SETTER(bool,loop);
+ ASPROPERTY_GETTER_SETTER(bool,play);
+ ASPROPERTY_GETTER_SETTER(bool,print);
+ ASPROPERTY_GETTER_SETTER(bool,quality);
+ ASPROPERTY_GETTER_SETTER(bool,rewind);
+ ASPROPERTY_GETTER_SETTER(bool,save);
+ ASPROPERTY_GETTER_SETTER(bool,zoom);
public:
- AccessibilityProperties(Class_base* c):ASObject(c){}
- static void sinit(Class_base*);
- ASFUNCTION(_constructor);
-};
-
-class AccessibilityImplementation : public ASObject
-{
-public:
- AccessibilityImplementation(Class_base* c):ASObject(c){}
- static void sinit(Class_base*);
+ ContextMenuBuiltInItems(Class_base* c);
+ static void sinit(Class_base* c);
ASFUNCTION(_constructor);
};
}
-#endif /* SCRIPTING_FLASH_ACCESSIBILITY_FLASHACCESSIBILITY_H */
+#endif // SCRIPTING_FLASH_UI_CONTEXTMENUBUILTINITEMS_H
diff --git a/src/backends/rtmputils.h b/src/scripting/flash/ui/ContextMenuItem.cpp
similarity index 63%
copy from src/backends/rtmputils.h
copy to src/scripting/flash/ui/ContextMenuItem.cpp
index 7e9de51..b46afe6 100644
--- a/src/backends/rtmputils.h
+++ b/src/scripting/flash/ui/ContextMenuItem.cpp
@@ -1,8 +1,6 @@
/**************************************************************************
Lightspark, a free flash player implementation
- Copyright (C) 2011-2013 Alessandro Pignotti (a.pignotti at sssup.it)
-
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
@@ -17,25 +15,25 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
-#ifndef BACKENDS_RTMPUTILS_H
-#define BACKENDS_RTMPUTILS_H 1
+#include "ContextMenuItem.h"
+#include "scripting/class.h"
+#include "scripting/argconv.h"
-#include "backends/netutils.h"
+using namespace std;
+using namespace lightspark;
-namespace lightspark
+void ContextMenuItem::sinit(Class_base* c)
{
+ CLASS_SETUP(c, EventDispatcher, _constructor, CLASS_FINAL);
+ REGISTER_GETTER_SETTER(c, caption);
+}
-class ILoadable;
-
-class RTMPDownloader: public ThreadedDownloader
+ASFUNCTIONBODY(ContextMenuItem,_constructor)
{
-private:
- void execute();
- void threadAbort();
- tiny_string stream;
-public:
- RTMPDownloader(const tiny_string& _url, const tiny_string& _stream, ILoadable* o);
-};
-
-};
-#endif /* BACKENDS_RTMPUTILS_H */
+ EventDispatcher::_constructor(obj, NULL, 0);
+ LOG(LOG_NOT_IMPLEMENTED,"ContextMenuItem constructor is a stub");
+ return NULL;
+}
+
+ASFUNCTIONBODY_GETTER_SETTER(ContextMenuItem,caption);
+
diff --git a/src/backends/rtmputils.h b/src/scripting/flash/ui/ContextMenuItem.h
similarity index 65%
copy from src/backends/rtmputils.h
copy to src/scripting/flash/ui/ContextMenuItem.h
index 7e9de51..f2db4b5 100644
--- a/src/backends/rtmputils.h
+++ b/src/scripting/flash/ui/ContextMenuItem.h
@@ -1,7 +1,7 @@
/**************************************************************************
Lightspark, a free flash player implementation
- Copyright (C) 2011-2013 Alessandro Pignotti (a.pignotti at sssup.it)
+ Copyright (C) 2013 Antti Ajanki (antti.ajanki at iki.fi)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
@@ -17,25 +17,23 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
-#ifndef BACKENDS_RTMPUTILS_H
-#define BACKENDS_RTMPUTILS_H 1
+#ifndef SCRIPTING_FLASH_UI_CONTEXTMENUITEM_H
+#define SCRIPTING_FLASH_UI_CONTEXTMENUITEM_H
-#include "backends/netutils.h"
+#include "asobject.h"
+#include "scripting/flash/events/flashevents.h"
namespace lightspark
{
-class ILoadable;
-
-class RTMPDownloader: public ThreadedDownloader
+class ContextMenuItem : public EventDispatcher
{
-private:
- void execute();
- void threadAbort();
- tiny_string stream;
public:
- RTMPDownloader(const tiny_string& _url, const tiny_string& _stream, ILoadable* o);
+ ContextMenuItem(Class_base* c):EventDispatcher(c){}
+ static void sinit(Class_base* c);
+ ASFUNCTION(_constructor);
+ ASPROPERTY_GETTER_SETTER(tiny_string, caption);
};
-};
-#endif /* BACKENDS_RTMPUTILS_H */
+}
+#endif // SCRIPTING_FLASH_UI_CONTEXTMENUITEM_H
diff --git a/src/scripting/flash/ui/Keyboard.cpp b/src/scripting/flash/ui/Keyboard.cpp
index 0541cdb..5b1243c 100644
--- a/src/scripting/flash/ui/Keyboard.cpp
+++ b/src/scripting/flash/ui/Keyboard.cpp
@@ -27,8 +27,7 @@ using namespace lightspark;
void Keyboard::sinit(Class_base* c)
{
- c->setConstructor(NULL);
- c->setSuper(Class<ASObject>::getRef());
+ CLASS_SETUP(c, ASObject, _constructorNotInstantiatable, CLASS_FINAL | CLASS_SEALED);
c->setDeclaredMethodByQName("capsLock","",Class<IFunction>::getFunction(capsLock),GETTER_METHOD,true);
c->setDeclaredMethodByQName("hasVirtualKeyboard","",Class<IFunction>::getFunction(hasVirtualKeyboard),GETTER_METHOD,true);
c->setDeclaredMethodByQName("numLock","",Class<IFunction>::getFunction(numLock),GETTER_METHOD,true);
@@ -76,8 +75,7 @@ ASFUNCTIONBODY(Keyboard, isAccessible)
void KeyboardType::sinit(Class_base* c)
{
- c->setConstructor(NULL);
- c->setSuper(Class<ASObject>::getRef());
+ CLASS_SETUP(c, ASObject, _constructorNotInstantiatable, CLASS_FINAL | CLASS_SEALED);
c->setVariableByQName("ALPHANUMERIC","",Class<ASString>::getInstanceS("alphanumeric"),DECLARED_TRAIT);
c->setVariableByQName("KEYPAD","",Class<ASString>::getInstanceS("keypad"),DECLARED_TRAIT);
c->setVariableByQName("NONE","",Class<ASString>::getInstanceS("none"),DECLARED_TRAIT);
@@ -85,8 +83,7 @@ void KeyboardType::sinit(Class_base* c)
void KeyLocation::sinit(Class_base* c)
{
- c->setConstructor(NULL);
- c->setSuper(Class<ASObject>::getRef());
+ CLASS_SETUP_NO_CONSTRUCTOR(c, ASObject, CLASS_FINAL | CLASS_SEALED);
c->setVariableByQName("LEFT","",Class<UInteger>::getInstanceS(1),DECLARED_TRAIT);
c->setVariableByQName("NUM_PAD","",Class<UInteger>::getInstanceS(3),DECLARED_TRAIT);
c->setVariableByQName("RIGHT","",Class<UInteger>::getInstanceS(2),DECLARED_TRAIT);
diff --git a/src/scripting/flash/ui/Mouse.cpp b/src/scripting/flash/ui/Mouse.cpp
new file mode 100644
index 0000000..f53d61b
--- /dev/null
+++ b/src/scripting/flash/ui/Mouse.cpp
@@ -0,0 +1,75 @@
+/**************************************************************************
+ Lightspark, a free flash player implementation
+
+ Copyright (C) 2013 Antti Ajanki (antti.ajanki at iki.fi)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+**************************************************************************/
+
+#include "scripting/flash/ui/Mouse.h"
+#include "scripting/toplevel/ASString.h"
+#include "scripting/toplevel/Error.h"
+#include "scripting/class.h"
+#include "scripting/argconv.h"
+#include "swf.h"
+
+using namespace std;
+using namespace lightspark;
+
+void Mouse::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, ASObject, _constructorNotInstantiatable, CLASS_FINAL | CLASS_SEALED);
+ c->setDeclaredMethodByQName("hide","",Class<IFunction>::getFunction(hide),NORMAL_METHOD,false);
+ c->setDeclaredMethodByQName("show","",Class<IFunction>::getFunction(show),NORMAL_METHOD,false);
+ c->setDeclaredMethodByQName("cursor","",Class<IFunction>::getFunction(getCursor),GETTER_METHOD,false);
+ c->setDeclaredMethodByQName("cursor","",Class<IFunction>::getFunction(setCursor),SETTER_METHOD,false);
+ c->setDeclaredMethodByQName("supportsCursor","",Class<IFunction>::getFunction(getSupportsCursor),GETTER_METHOD,false);
+ c->setDeclaredMethodByQName("supportsNativeCursor","",Class<IFunction>::getFunction(getSupportsNativeCursor),GETTER_METHOD,false);
+}
+
+ASFUNCTIONBODY(Mouse, hide)
+{
+ getSys()->showMouseCursor(false);
+ return NULL;
+}
+
+ASFUNCTIONBODY(Mouse, show)
+{
+ getSys()->showMouseCursor(true);
+ return NULL;
+}
+
+ASFUNCTIONBODY(Mouse, getCursor)
+{
+ return Class<ASString>::getInstanceS("auto");
+}
+
+ASFUNCTIONBODY(Mouse, setCursor)
+{
+ tiny_string cursorName;
+ ARG_UNPACK(cursorName);
+ if (cursorName != "auto")
+ throwError<ArgumentError>(kInvalidEnumError, "cursor");
+ return NULL;
+}
+
+ASFUNCTIONBODY(Mouse, getSupportsCursor)
+{
+ return abstract_b(true);
+}
+
+ASFUNCTIONBODY(Mouse, getSupportsNativeCursor)
+{
+ return abstract_b(false); // until registerCursor() is implemented
+}
diff --git a/src/backends/rtmputils.h b/src/scripting/flash/ui/Mouse.h
similarity index 67%
copy from src/backends/rtmputils.h
copy to src/scripting/flash/ui/Mouse.h
index 7e9de51..e81d34e 100644
--- a/src/backends/rtmputils.h
+++ b/src/scripting/flash/ui/Mouse.h
@@ -1,7 +1,7 @@
/**************************************************************************
Lightspark, a free flash player implementation
- Copyright (C) 2011-2013 Alessandro Pignotti (a.pignotti at sssup.it)
+ Copyright (C) 2013 Antti Ajanki (antti.ajanki at iki.fi)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
@@ -17,25 +17,27 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
-#ifndef BACKENDS_RTMPUTILS_H
-#define BACKENDS_RTMPUTILS_H 1
+#ifndef SCRIPTING_FLASH_UI_MOUSE_H
+#define SCRIPTING_FLASH_UI_MOUSE_H 1
-#include "backends/netutils.h"
+#include "asobject.h"
namespace lightspark
{
-class ILoadable;
-
-class RTMPDownloader: public ThreadedDownloader
+class Mouse : public ASObject
{
-private:
- void execute();
- void threadAbort();
- tiny_string stream;
public:
- RTMPDownloader(const tiny_string& _url, const tiny_string& _stream, ILoadable* o);
+ Mouse(Class_base* c):ASObject(c){}
+ static void sinit(Class_base* c);
+ ASFUNCTION(hide);
+ ASFUNCTION(show);
+ ASFUNCTION(getCursor);
+ ASFUNCTION(setCursor);
+ ASFUNCTION(getSupportsCursor);
+ ASFUNCTION(getSupportsNativeCursor);
};
};
-#endif /* BACKENDS_RTMPUTILS_H */
+
+#endif /* SCRIPTING_FLASH_UI_MOUSE_H */
diff --git a/src/scripting/flash/utils/flashutils.cpp b/src/scripting/flash/utils/ByteArray.cpp
similarity index 52%
copy from src/scripting/flash/utils/flashutils.cpp
copy to src/scripting/flash/utils/ByteArray.cpp
index 2fd9976..020ed61 100644
--- a/src/scripting/flash/utils/flashutils.cpp
+++ b/src/scripting/flash/utils/ByteArray.cpp
@@ -34,63 +34,9 @@ using namespace lightspark;
#define BA_CHUNK_SIZE 4096
-const char* Endian::littleEndian = "littleEndian";
-const char* Endian::bigEndian = "bigEndian";
-void Endian::sinit(Class_base* c)
-{
- c->setConstructor(NULL);
- c->setVariableByQName("LITTLE_ENDIAN","",Class<ASString>::getInstanceS(littleEndian),DECLARED_TRAIT);
- c->setVariableByQName("BIG_ENDIAN","",Class<ASString>::getInstanceS(bigEndian),DECLARED_TRAIT);
-}
-
-void IExternalizable::linkTraits(Class_base* c)
-{
- lookupAndLink(c,"readExternal","flash.utils:IExternalizable");
- lookupAndLink(c,"writeExternal","flash.utils:IExternalizable");
-}
-
-void IDataInput::linkTraits(Class_base* c)
-{
- lookupAndLink(c,"bytesAvailable","flash.utils:IDataInput");
- lookupAndLink(c,"endian","flash.utils:IDataInput");
- lookupAndLink(c,"objectEncoding","flash.utils:IDataInput");
- lookupAndLink(c,"readBoolean","flash.utils:IDataInput");
- lookupAndLink(c,"readByte","flash.utils:IDataInput");
- lookupAndLink(c,"readBytes","flash.utils:IDataInput");
- lookupAndLink(c,"readDouble","flash.utils:IDataInput");
- lookupAndLink(c,"readFloat","flash.utils:IDataInput");
- lookupAndLink(c,"readInt","flash.utils:IDataInput");
- lookupAndLink(c,"readMultiByte","flash.utils:IDataInput");
- lookupAndLink(c,"readObject","flash.utils:IDataInput");
- lookupAndLink(c,"readShort","flash.utils:IDataInput");
- lookupAndLink(c,"readUnsignedByte","flash.utils:IDataInput");
- lookupAndLink(c,"readUnsignedInt","flash.utils:IDataInput");
- lookupAndLink(c,"readUnsignedShort","flash.utils:IDataInput");
- lookupAndLink(c,"readUTF","flash.utils:IDataInput");
- lookupAndLink(c,"readUTFBytes","flash.utils:IDataInput");
-}
-
-void IDataOutput::linkTraits(Class_base* c)
-{
- lookupAndLink(c,"endian","flash.utils:IDataOutput");
- lookupAndLink(c,"objectEncoding","flash.utils:IDataOutput");
- lookupAndLink(c,"writeBoolean","flash.utils:IDataOutput");
- lookupAndLink(c,"writeByte","flash.utils:IDataOutput");
- lookupAndLink(c,"writeBytes","flash.utils:IDataOutput");
- lookupAndLink(c,"writeDouble","flash.utils:IDataOutput");
- lookupAndLink(c,"writeFloat","flash.utils:IDataOutput");
- lookupAndLink(c,"writeInt","flash.utils:IDataOutput");
- lookupAndLink(c,"writeMultiByte","flash.utils:IDataOutput");
- lookupAndLink(c,"writeObject","flash.utils:IDataOutput");
- lookupAndLink(c,"writeShort","flash.utils:IDataOutput");
- lookupAndLink(c,"writeUnsignedInt","flash.utils:IDataOutput");
- lookupAndLink(c,"writeUTF","flash.utils:IDataOutput");
- lookupAndLink(c,"writeUTFBytes","flash.utils:IDataOutput");
-}
-
-ByteArray::ByteArray(Class_base* c, uint8_t* b, uint32_t l):ASObject(c),littleEndian(false),objectEncoding(ObjectEncoding::AMF3),
- position(0),bytes(b),real_len(l),len(l)
+ByteArray::ByteArray(Class_base* c, uint8_t* b, uint32_t l):ASObject(c),littleEndian(false),objectEncoding(ObjectEncoding::AMF3),currentObjectEncoding(ObjectEncoding::AMF3),
+ position(0),bytes(b),real_len(l),len(l),shareable(false)
{
#ifdef MEMORY_USAGE_PROFILING
c->memoryAccount->addBytes(l);
@@ -110,9 +56,7 @@ ByteArray::~ByteArray()
void ByteArray::sinit(Class_base* c)
{
- c->setConstructor(NULL);
- c->setSuper(Class<ASObject>::getRef());
-
+ CLASS_SETUP_NO_CONSTRUCTOR(c, ASObject, CLASS_SEALED);
c->setDeclaredMethodByQName("length","",Class<IFunction>::getFunction(_getLength),GETTER_METHOD,true);
c->setDeclaredMethodByQName("length","",Class<IFunction>::getFunction(_setLength),SETTER_METHOD,true);
c->setDeclaredMethodByQName("bytesAvailable","",Class<IFunction>::getFunction(_getBytesAvailable),GETTER_METHOD,true);
@@ -124,6 +68,7 @@ void ByteArray::sinit(Class_base* c)
c->setDeclaredMethodByQName("objectEncoding","",Class<IFunction>::getFunction(_setObjectEncoding),SETTER_METHOD,true);
c->setDeclaredMethodByQName("defaultObjectEncoding","",Class<IFunction>::getFunction(_getDefaultObjectEncoding),GETTER_METHOD,false);
c->setDeclaredMethodByQName("defaultObjectEncoding","",Class<IFunction>::getFunction(_setDefaultObjectEncoding),SETTER_METHOD,false);
+
getSys()->staticByteArrayDefaultObjectEncoding = ObjectEncoding::DEFAULT;
c->setDeclaredMethodByQName("clear","",Class<IFunction>::getFunction(clear),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("compress","",Class<IFunction>::getFunction(_compress),NORMAL_METHOD,true);
@@ -157,6 +102,10 @@ void ByteArray::sinit(Class_base* c)
c->setDeclaredMethodByQName("writeObject","",Class<IFunction>::getFunction(writeObject),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("writeShort","",Class<IFunction>::getFunction(writeShort),NORMAL_METHOD,true);
c->prototype->setVariableByQName("toString","",Class<IFunction>::getFunction(ByteArray::_toString),DYNAMIC_TRAIT);
+ REGISTER_GETTER_SETTER(c,shareable);
+ c->setDeclaredMethodByQName("atomicCompareAndSwapIntAt","",Class<IFunction>::getFunction(atomicCompareAndSwapIntAt),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("atomicCompareAndSwapLength","",Class<IFunction>::getFunction(atomicCompareAndSwapLength),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("toJSON",AS3,Class<IFunction>::getFunction(_toJSON),NORMAL_METHOD,true);
c->addImplementedInterface(InterfaceClass<IDataInput>::getClass());
IDataInput::linkTraits(c);
@@ -168,6 +117,15 @@ void ByteArray::buildTraits(ASObject* o)
{
}
+void ByteArray::lock()
+{
+ if (shareable) mutex.lock();
+}
+void ByteArray::unlock()
+{
+ if (shareable) mutex.unlock();
+}
+
uint8_t* ByteArray::getBuffer(unsigned int size, bool enableResize)
{
// the flash documentation doesn't tell how large ByteArrays are allowed to be
@@ -281,7 +239,9 @@ ASFUNCTIONBODY(ByteArray,_getPosition)
void ByteArray::setPosition(uint32_t p)
{
+ lock();
position=p;
+ unlock();
}
ASFUNCTIONBODY(ByteArray,_setPosition)
@@ -328,6 +288,7 @@ ASFUNCTIONBODY(ByteArray,_setObjectEncoding)
throwError<ArgumentError>(kInvalidEnumError, "objectEncoding");
th->objectEncoding=value;
+ th->currentObjectEncoding=value;
return NULL;
}
@@ -353,31 +314,37 @@ ASFUNCTIONBODY(ByteArray,_setLength)
{
ByteArray* th=static_cast<ByteArray*>(obj);
assert_and_throw(argslen==1);
+
uint32_t newLen=args[0]->toInt();
+ th->lock();
if(newLen==th->len) //Nothing to do
return NULL;
+ th->setLength(newLen);
+ th->unlock();
+ return NULL;
+}
+void ByteArray::setLength(uint32_t newLen)
+{
if (newLen > 0)
{
- th->getBuffer(newLen,true);
+ getBuffer(newLen,true);
}
else
{
- if (th->bytes)
+ if (bytes)
{
#ifdef MEMORY_USAGE_PROFILING
- th->getClass()->memoryAccount->removeBytes(th->real_len);
+ getClass()->memoryAccount->removeBytes(th->real_len);
#endif
- free(th->bytes);
+ free(bytes);
}
- th->bytes = NULL;
- th->len = newLen;
- th->real_len = newLen;
+ bytes = NULL;
+ real_len = newLen;
}
- if (th->position > th->len)
- th->position = (th->len > 0 ? th->len-1 : 0);
- return NULL;
+ len = newLen;
+ if (position > len)
+ position = (len > 0 ? len-1 : 0);
}
-
ASFUNCTIONBODY(ByteArray,_getLength)
{
ByteArray* th=static_cast<ByteArray*>(obj);
@@ -394,12 +361,15 @@ ASFUNCTIONBODY(ByteArray,readBoolean)
{
ByteArray* th=static_cast<ByteArray*>(obj);
+ th->lock();
uint8_t ret;
if(!th->readByte(ret))
{
- throwError<ArgumentError>(kEOFError);
+ th->unlock();
+ throwError<EOFError>(kEOFError);
}
+ th->unlock();
return abstract_b(ret!=0);
}
@@ -411,6 +381,7 @@ ASFUNCTIONBODY(ByteArray,readBytes)
uint32_t length;
ARG_UNPACK(out)(offset, 0)(length, 0);
+ th->lock();
if(length == 0)
{
assert(th->len >= th->position);
@@ -420,16 +391,19 @@ ASFUNCTIONBODY(ByteArray,readBytes)
//Error checks
if(th->position+length > th->len)
{
- throwError<ArgumentError>(kEOFError);
+ th->unlock();
+ throwError<EOFError>(kEOFError);
}
if((uint64_t)length+offset > 0xFFFFFFFF)
{
+ th->unlock();
throw Class<RangeError>::getInstanceS("length+offset");
}
uint8_t* buf=out->getBuffer(length+offset,true);
memcpy(buf+offset,th->bytes+th->position,length);
th->position+=length;
+ th->unlock();
return NULL;
}
@@ -453,11 +427,13 @@ ASFUNCTIONBODY(ByteArray,readUTF)
ByteArray* th=static_cast<ByteArray*>(obj);
tiny_string res;
+ th->lock();
if (!th->readUTF(res))
{
- throwError<ArgumentError>(kEOFError);
+ th->unlock();
+ throwError<EOFError>(kEOFError);
}
-
+ th->unlock();
return Class<ASString>::getInstanceS(res);
}
@@ -467,13 +443,16 @@ ASFUNCTIONBODY(ByteArray,readUTFBytes)
uint32_t length;
ARG_UNPACK (length);
+ th->lock();
if(th->position+length > th->len)
{
- throwError<ArgumentError>(kEOFError);
+ th->unlock();
+ throwError<EOFError>(kEOFError);
}
uint8_t *bufStart=th->bytes+th->position;
th->position+=length;
+ th->unlock();
return Class<ASString>::getInstanceS((char *)bufStart,length);
}
@@ -497,7 +476,9 @@ ASFUNCTIONBODY(ByteArray,writeUTF)
assert_and_throw(argslen==1);
assert_and_throw(args[0]->getObjectType()==T_STRING);
ASString* str=Class<ASString>::cast(args[0]);
+ th->lock();
th->writeUTF(str->data);
+ th->unlock();
return NULL;
}
@@ -508,9 +489,11 @@ ASFUNCTIONBODY(ByteArray,writeUTFBytes)
assert_and_throw(argslen==1);
assert_and_throw(args[0]->getObjectType()==T_STRING);
ASString* str=Class<ASString>::cast(args[0]);
+ th->lock();
th->getBuffer(th->position+str->data.numBytes(),true);
memcpy(th->bytes+th->position,str->data.raw_buf(),str->data.numBytes());
th->position+=str->data.numBytes();
+ th->unlock();
return NULL;
}
@@ -525,9 +508,11 @@ ASFUNCTIONBODY(ByteArray,writeMultiByte)
// TODO: should convert from UTF-8 to charset
LOG(LOG_NOT_IMPLEMENTED, "ByteArray.writeMultiByte doesn't convert charset");
+ th->lock();
th->getBuffer(th->position+value.numBytes(),true);
memcpy(th->bytes+th->position,value.raw_buf(),value.numBytes());
th->position+=value.numBytes();
+ th->unlock();
return NULL;
}
@@ -552,7 +537,9 @@ ASFUNCTIONBODY(ByteArray,writeObject)
ByteArray* th=static_cast<ByteArray*>(obj);
//Validate parameters
assert_and_throw(argslen==1);
+ th->lock();
th->writeObject(args[0]);
+ th->unlock();
return NULL;
}
@@ -571,7 +558,9 @@ ASFUNCTIONBODY(ByteArray,writeShort)
int32_t value;
ARG_UNPACK(value);
+ th->lock();
th->writeShort((static_cast<uint16_t>(value & 0xffff)));
+ th->unlock();
return NULL;
}
@@ -600,9 +589,11 @@ ASFUNCTIONBODY(ByteArray,writeBytes)
if(length == 0)
length=(out->getLength()-offset);
uint8_t* buf=out->getBuffer(offset+length,false);
+ th->lock();
th->getBuffer(th->position+length,true);
memcpy(th->bytes+th->position,buf+offset,length);
th->position+=length;
+ th->unlock();
return NULL;
}
@@ -620,7 +611,9 @@ ASFUNCTIONBODY(ByteArray,writeByte)
int32_t value=args[0]->toInt();
+ th->lock();
th->writeByte(value&0xff);
+ th->unlock();
return NULL;
}
@@ -631,10 +624,12 @@ ASFUNCTIONBODY(ByteArray,writeBoolean)
bool b;
ARG_UNPACK (b);
+ th->lock();
if (b)
th->writeByte(1);
else
th->writeByte(0);
+ th->unlock();
return NULL;
}
@@ -648,9 +643,11 @@ ASFUNCTIONBODY(ByteArray,writeDouble)
uint64_t *intptr=reinterpret_cast<uint64_t*>(&value);
uint64_t value2=th->endianIn(*intptr);
+ th->lock();
th->getBuffer(th->position+8,true);
memcpy(th->bytes+th->position,&value2,8);
th->position+=8;
+ th->unlock();
return NULL;
}
@@ -664,9 +661,11 @@ ASFUNCTIONBODY(ByteArray,writeFloat)
uint32_t *intptr=reinterpret_cast<uint32_t*>(&value);
uint32_t value2=th->endianIn(*intptr);
+ th->lock();
th->getBuffer(th->position+4,true);
memcpy(th->bytes+th->position,&value2,4);
th->position+=4;
+ th->unlock();
return NULL;
}
@@ -678,9 +677,11 @@ ASFUNCTIONBODY(ByteArray,writeInt)
uint32_t value=th->endianIn(static_cast<uint32_t>(args[0]->toInt()));
+ th->lock();
th->getBuffer(th->position+4,true);
memcpy(th->bytes+th->position,&value,4);
th->position+=4;
+ th->unlock();
return NULL;
}
@@ -697,11 +698,21 @@ ASFUNCTIONBODY(ByteArray,writeUnsignedInt)
ByteArray* th=static_cast<ByteArray*>(obj);
assert_and_throw(argslen==1);
+ th->lock();
uint32_t value=th->endianIn(args[0]->toUInt());
th->writeUnsignedInt(value);
+ th->unlock();
return NULL;
}
+bool ByteArray::peekByte(uint8_t& b)
+{
+ if (len <= position+1)
+ return false;
+
+ b=bytes[position+1];
+ return true;
+}
bool ByteArray::readByte(uint8_t& b)
{
if (len <= position)
@@ -745,11 +756,14 @@ ASFUNCTIONBODY(ByteArray, readByte)
ByteArray* th=static_cast<ByteArray*>(obj);
assert_and_throw(argslen==0);
+ th->lock();
uint8_t ret;
if(!th->readByte(ret))
{
- throwError<ArgumentError>(kEOFError);
+ th->unlock();
+ throwError<EOFError>(kEOFError);
}
+ th->unlock();
return abstract_i((int8_t)ret);
}
@@ -758,9 +772,11 @@ ASFUNCTIONBODY(ByteArray,readDouble)
ByteArray* th=static_cast<ByteArray*>(obj);
assert_and_throw(argslen==0);
+ th->lock();
if(th->len < th->position+8)
{
- throwError<ArgumentError>(kEOFError);
+ th->unlock();
+ throwError<EOFError>(kEOFError);
}
uint64_t ret;
@@ -769,6 +785,7 @@ ASFUNCTIONBODY(ByteArray,readDouble)
ret = th->endianOut(ret);
double *doubleptr=reinterpret_cast<double*>(&ret);
+ th->unlock();
return abstract_d(*doubleptr);
}
@@ -777,9 +794,11 @@ ASFUNCTIONBODY(ByteArray,readFloat)
ByteArray* th=static_cast<ByteArray*>(obj);
assert_and_throw(argslen==0);
+ th->lock();
if(th->len < th->position+4)
{
- throwError<ArgumentError>(kEOFError);
+ th->unlock();
+ throwError<EOFError>(kEOFError);
}
uint32_t ret;
@@ -788,6 +807,7 @@ ASFUNCTIONBODY(ByteArray,readFloat)
ret = th->endianOut(ret);
float *floatptr=reinterpret_cast<float*>(&ret);
+ th->unlock();
return abstract_d(*floatptr);
}
@@ -796,15 +816,17 @@ ASFUNCTIONBODY(ByteArray,readInt)
ByteArray* th=static_cast<ByteArray*>(obj);
assert_and_throw(argslen==0);
+ th->lock();
if(th->len < th->position+4)
{
- throwError<ArgumentError>(kEOFError);
+ th->unlock();
+ throwError<EOFError>(kEOFError);
}
uint32_t ret;
memcpy(&ret,th->bytes+th->position,4);
th->position+=4;
-
+ th->unlock();
return abstract_i((int32_t)th->endianOut(ret));
}
@@ -826,11 +848,14 @@ ASFUNCTIONBODY(ByteArray,readShort)
assert_and_throw(argslen==0);
uint16_t ret;
+ th->lock();
if(!th->readShort(ret))
{
- throwError<ArgumentError>(kEOFError);
+ th->unlock();
+ throwError<EOFError>(kEOFError);
}
+ th->unlock();
return abstract_i((int16_t)ret);
}
@@ -840,9 +865,11 @@ ASFUNCTIONBODY(ByteArray,readUnsignedByte)
assert_and_throw(argslen==0);
uint8_t ret;
+ th->lock();
if (!th->readByte(ret))
{
- throwError<ArgumentError>(kEOFError);
+ th->unlock();
+ throwError<EOFError>(kEOFError);
}
return abstract_ui(ret);
}
@@ -865,9 +892,13 @@ ASFUNCTIONBODY(ByteArray,readUnsignedInt)
assert_and_throw(argslen==0);
uint32_t ret;
+ th->lock();
if(!th->readUnsignedInt(ret))
- throwError<ArgumentError>(kEOFError);
-
+ {
+ th->unlock();
+ throwError<EOFError>(kEOFError);
+ }
+ th->unlock();
return abstract_ui(ret);
}
@@ -877,9 +908,11 @@ ASFUNCTIONBODY(ByteArray,readUnsignedShort)
assert_and_throw(argslen==0);
uint16_t ret;
+ th->lock();
if(!th->readShort(ret))
{
- throwError<ArgumentError>(kEOFError);
+ th->unlock();
+ throwError<EOFError>(kEOFError);
}
return abstract_ui(ret);
@@ -892,9 +925,11 @@ ASFUNCTIONBODY(ByteArray,readMultiByte)
tiny_string charset;
ARG_UNPACK(strlen)(charset);
+ th->lock();
if(th->len < th->position+strlen)
{
- throwError<ArgumentError>(kEOFError);
+ th->unlock();
+ throwError<EOFError>(kEOFError);
}
// TODO: should convert from charset to UTF-8
@@ -906,19 +941,25 @@ ASFUNCTIONBODY(ByteArray,readObject)
{
ByteArray* th=static_cast<ByteArray*>(obj);
assert_and_throw(argslen==0);
+ th->lock();
if(th->bytes==NULL)
{
- throwError<ArgumentError>(kEOFError);
+ th->unlock();
+ // it seems that contrary to the specs Adobe returns Undefined when reading from an empty ByteArray
+ return getSys()->getUndefinedRef();
+ //throwError<EOFError>(kEOFError);
}
- assert_and_throw(th->objectEncoding==ObjectEncoding::AMF3);
+ //assert_and_throw(th->objectEncoding==ObjectEncoding::AMF3);
Amf3Deserializer d(th);
_NR<ASObject> ret(NullRef);
try
{
ret=d.readObject();
+ th->unlock();
}
catch(LightsparkException& e)
{
+ th->unlock();
LOG(LOG_ERROR,"Exception caught while parsing AMF3: " << e.cause);
//TODO: throw AS exception
}
@@ -1184,7 +1225,9 @@ ASFUNCTIONBODY(ByteArray,_compress)
// flash throws an error if compress is called with a compression algorithm,
// and always uses the zlib algorithm
// but tamarin tests do not catch it, so we simply ignore any parameters provided
+ th->lock();
th->compress_zlib();
+ th->unlock();
return NULL;
}
@@ -1194,27 +1237,34 @@ ASFUNCTIONBODY(ByteArray,_uncompress)
// flash throws an error if uncompress is called with a compression algorithm,
// and always uses the zlib algorithm
// but tamarin tests do not catch it, so we simply ignore any parameters provided
+ th->lock();
th->uncompress_zlib();
+ th->unlock();
return NULL;
}
ASFUNCTIONBODY(ByteArray,_deflate)
{
ByteArray* th=static_cast<ByteArray*>(obj);
+ th->lock();
th->compress_zlib();
+ th->unlock();
return NULL;
}
ASFUNCTIONBODY(ByteArray,_inflate)
{
ByteArray* th=static_cast<ByteArray*>(obj);
+ th->lock();
th->uncompress_zlib();
+ th->unlock();
return NULL;
}
ASFUNCTIONBODY(ByteArray,clear)
{
ByteArray* th=static_cast<ByteArray*>(obj);
+ th->lock();
if(th->bytes)
{
#ifdef MEMORY_USAGE_PROFILING
@@ -1226,44 +1276,22 @@ ASFUNCTIONBODY(ByteArray,clear)
th->len=0;
th->real_len=0;
th->position=0;
+ th->unlock();
return NULL;
}
-void Timer::tick()
-{
- //This will be executed once if repeatCount was originally 1
- //Otherwise it's executed until stopMe is set to true
- this->incRef();
- getVm()->addEvent(_MR(this),_MR(Class<TimerEvent>::getInstanceS("timer")));
-
- currentCount++;
- if(repeatCount!=0)
- {
- if(currentCount==repeatCount)
- {
- this->incRef();
- getVm()->addEvent(_MR(this),_MR(Class<TimerEvent>::getInstanceS("timerComplete")));
- stopMe=true;
- running=false;
- }
- }
-}
-
-void Timer::tickFence()
-{
- tickJobInstance = NullRef;
-}
-
// this seems to be how AS3 handles generic pop calls in Array class
ASFUNCTIONBODY(ByteArray,pop)
{
ByteArray* th=static_cast<ByteArray*>(obj);
uint8_t res = 0;
+ th->lock();
if (th->readByte(res))
{
memmove(th->bytes,(th->bytes+1),th->getLength()-1);
th->len--;
}
+ th->unlock();
return abstract_ui(res);
}
@@ -1272,12 +1300,15 @@ ASFUNCTIONBODY(ByteArray,pop)
ASFUNCTIONBODY(ByteArray,push)
{
ByteArray* th=static_cast<ByteArray*>(obj);
+ th->lock();
th->getBuffer(th->len+argslen,true);
for (unsigned int i = 0; i < argslen; i++)
{
th->bytes[th->len+i] = (uint8_t)args[i]->toInt();
}
- return abstract_ui(th->getLength());
+ uint32_t res = th->getLength();
+ th->unlock();
+ return abstract_ui(res);
}
// this seems to be how AS3 handles generic shift calls in Array class
@@ -1285,11 +1316,13 @@ ASFUNCTIONBODY(ByteArray,shift)
{
ByteArray* th=static_cast<ByteArray*>(obj);
uint8_t res = 0;
+ th->lock();
if (th->readByte(res))
{
memmove(th->bytes,(th->bytes+1),th->getLength()-1);
th->len--;
}
+ th->unlock();
return abstract_ui(res);
}
@@ -1297,823 +1330,63 @@ ASFUNCTIONBODY(ByteArray,shift)
ASFUNCTIONBODY(ByteArray,unshift)
{
ByteArray* th=static_cast<ByteArray*>(obj);
+ th->lock();
th->getBuffer(th->len+argslen,true);
for (unsigned int i = 0; i < argslen; i++)
{
memmove((th->bytes+argslen),(th->bytes),th->len);
th->bytes[i] = (uint8_t)args[i]->toInt();
}
- return abstract_ui(th->getLength());
-}
-
-void Timer::sinit(Class_base* c)
-{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<EventDispatcher>::getRef());
- c->setDeclaredMethodByQName("currentCount","",Class<IFunction>::getFunction(_getCurrentCount),GETTER_METHOD,true);
- c->setDeclaredMethodByQName("repeatCount","",Class<IFunction>::getFunction(_getRepeatCount),GETTER_METHOD,true);
- c->setDeclaredMethodByQName("repeatCount","",Class<IFunction>::getFunction(_setRepeatCount),SETTER_METHOD,true);
- c->setDeclaredMethodByQName("running","",Class<IFunction>::getFunction(_getRunning),GETTER_METHOD,true);
- c->setDeclaredMethodByQName("delay","",Class<IFunction>::getFunction(_getDelay),GETTER_METHOD,true);
- c->setDeclaredMethodByQName("delay","",Class<IFunction>::getFunction(_setDelay),SETTER_METHOD,true);
- c->setDeclaredMethodByQName("start","",Class<IFunction>::getFunction(start),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("reset","",Class<IFunction>::getFunction(reset),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("stop","",Class<IFunction>::getFunction(stop),NORMAL_METHOD,true);
-}
-
-ASFUNCTIONBODY(Timer,_constructor)
-{
- EventDispatcher::_constructor(obj,NULL,0);
- Timer* th=static_cast<Timer*>(obj);
-
- th->delay=args[0]->toInt();
- if(argslen>=2)
- th->repeatCount=args[1]->toInt();
-
- return NULL;
-}
-
-ASFUNCTIONBODY(Timer,_getCurrentCount)
-{
- Timer* th=static_cast<Timer*>(obj);
- return abstract_i(th->currentCount);
-}
-
-ASFUNCTIONBODY(Timer,_getRepeatCount)
-{
- Timer* th=static_cast<Timer*>(obj);
- return abstract_i(th->repeatCount);
-}
-
-ASFUNCTIONBODY(Timer,_setRepeatCount)
-{
- assert_and_throw(argslen==1);
- int32_t count=args[0]->toInt();
- Timer* th=static_cast<Timer*>(obj);
- th->repeatCount=count;
- if(th->repeatCount>0 && th->repeatCount<=th->currentCount)
- {
- getSys()->removeJob(th);
- th->running=false;
- th->tickJobInstance = NullRef;
- }
- return NULL;
-}
-
-ASFUNCTIONBODY(Timer,_getRunning)
-{
- Timer* th=static_cast<Timer*>(obj);
- return abstract_b(th->running);
-}
-
-ASFUNCTIONBODY(Timer,_getDelay)
-{
- Timer* th=static_cast<Timer*>(obj);
- return abstract_i(th->delay);
-}
-
-ASFUNCTIONBODY(Timer,_setDelay)
-{
- assert_and_throw(argslen==1);
- int32_t newdelay = args[0]->toInt();
- if (newdelay<=0)
- throw Class<RangeError>::getInstanceS("delay must be positive", 2066);
-
- Timer* th=static_cast<Timer*>(obj);
- th->delay=newdelay;
-
- return NULL;
-}
-
-ASFUNCTIONBODY(Timer,start)
-{
- Timer* th=static_cast<Timer*>(obj);
- if(th->running)
- return NULL;
- th->running=true;
- th->stopMe=false;
- th->incRef();
- th->tickJobInstance = _MNR(th);
- if(th->repeatCount==1)
- getSys()->addWait(th->delay,th);
- else
- getSys()->addTick(th->delay,th);
- return NULL;
+ uint32_t res = th->getLength();
+ th->unlock();
+ return abstract_ui(res);
}
+ASFUNCTIONBODY_GETTER_SETTER(ByteArray,shareable);
-ASFUNCTIONBODY(Timer,reset)
+ASFUNCTIONBODY(ByteArray,atomicCompareAndSwapIntAt)
{
- Timer* th=static_cast<Timer*>(obj);
- if(th->running)
- {
- //This spin waits if the timer is running right now
- getSys()->removeJob(th);
- //NOTE: although no new events will be sent now there might be old events in the queue.
- //Is this behaviour right?
- //This is not anymore used by the timer, so it can die
- th->tickJobInstance = NullRef;
- th->running=false;
- }
- th->currentCount=0;
- return NULL;
-}
+ ByteArray* th=static_cast<ByteArray*>(obj);
-ASFUNCTIONBODY(Timer,stop)
-{
- Timer* th=static_cast<Timer*>(obj);
- if(th->running)
- {
- //This spin waits if the timer is running right now
- getSys()->removeJob(th);
- //NOTE: although no new events will be sent now there might be old events in the queue.
- //Is this behaviour right?
-
- //This is not anymore used by the timer, so it can die
- th->tickJobInstance = NullRef;
- th->running=false;
- }
- return NULL;
-}
+ int32_t byteindex,expectedValue,newvalue;
+ ARG_UNPACK(byteindex)(expectedValue)(newvalue);
-ASFUNCTIONBODY(lightspark,getQualifiedClassName)
-{
- //CHECK: what to do if ns is empty
- ASObject* target=args[0];
- Class_base* c;
- SWFOBJECT_TYPE otype=target->getObjectType();
- if(otype==T_NULL)
- return Class<ASString>::getInstanceS("null");
- else if(otype==T_UNDEFINED)
- // Testing shows that this really returns "void"!
- return Class<ASString>::getInstanceS("void");
- else if(otype!=T_CLASS)
+ if (byteindex < 0 || byteindex%4)
{
- assert_and_throw(target->getClass());
- c=target->getClass();
+ throwError<RangeError>(kInvalidRangeError, obj->getClassName());
}
- else
- c=static_cast<Class_base*>(target);
-
- return Class<ASString>::getInstanceS(c->getQualifiedClassName());
-}
-
-ASFUNCTIONBODY(lightspark,getQualifiedSuperclassName)
-{
- //CHECK: what to do is ns is empty
- ASObject* target=args[0];
- Class_base* c;
- if(target->getObjectType()!=T_CLASS)
+ th->lock();
+ if(byteindex >= (int32_t)th->len-4)
{
- assert_and_throw(target->getClass());
- c=target->getClass()->super.getPtr();
+ th->unlock();
+ throwError<RangeError>(kInvalidRangeError, obj->getClassName());
}
- else
- c=static_cast<Class_base*>(target)->super.getPtr();
-
- assert_and_throw(c);
-
- return Class<ASString>::getInstanceS(c->getQualifiedClassName());
-}
+ int32_t ret;
+ memcpy(&ret,th->bytes+byteindex,4);
-ASFUNCTIONBODY(lightspark,getDefinitionByName)
-{
- assert_and_throw(args && argslen==1);
- const tiny_string& tmp=args[0]->toString();
- multiname name(NULL);
- name.name_type=multiname::NAME_STRING;
-
- tiny_string nsName;
- tiny_string tmpName;
- stringToQName(tmp,tmpName,nsName);
- name.name_s_id=getSys()->getUniqueStringId(tmpName);
- name.ns.push_back(nsNameAndKind(nsName,NAMESPACE));
-
- LOG(LOG_CALLS,_("Looking for definition of ") << name);
- ASObject* target;
- ASObject* o=ABCVm::getCurrentApplicationDomain(getVm()->currentCallContext)->getVariableAndTargetByMultiname(name,target);
-
- //TODO: should raise an exception, for now just return undefined
- if(o==NULL)
+ if (ret == expectedValue)
{
- LOG(LOG_ERROR,_("Definition for '") << name << _("' not found."));
- return getSys()->getUndefinedRef();
+ memcpy(th->bytes+byteindex,&newvalue,4);
}
-
- assert_and_throw(o->getObjectType()==T_CLASS);
-
- LOG(LOG_CALLS,_("Getting definition for ") << name);
- o->incRef();
- return o;
-}
-
-ASFUNCTIONBODY(lightspark,describeType)
-{
- assert_and_throw(argslen==1);
- return args[0]->describeType();
-}
-
-ASFUNCTIONBODY(lightspark,getTimer)
-{
- uint64_t ret=compat_msectiming() - getSys()->startTime;
+ th->unlock();
return abstract_i(ret);
}
-
-Dictionary::Dictionary(Class_base* c):ASObject(c),
- data(std::less<dictType::key_type>(), reporter_allocator<dictType::value_type>(c->memoryAccount))
-{
-}
-
-void Dictionary::finalize()
-{
- ASObject::finalize();
- data.clear();
-}
-
-void Dictionary::sinit(Class_base* c)
-{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASObject>::getRef());
-}
-
-void Dictionary::buildTraits(ASObject* o)
-{
-}
-
-ASFUNCTIONBODY(Dictionary,_constructor)
-{
- return NULL;
-}
-
-Dictionary::dictType::iterator Dictionary::findKey(ASObject *o)
-{
- Dictionary::dictType::iterator it = data.begin();
- for(; it!=data.end(); ++it)
- {
- if (it->first->isEqualStrict(o))
- return it;
- }
-
- return data.end();
-}
-
-void Dictionary::setVariableByMultiname_i(const multiname& name, int32_t value)
-{
- assert_and_throw(implEnable);
- Dictionary::setVariableByMultiname(name,abstract_i(value),CONST_NOT_ALLOWED);
-}
-
-void Dictionary::setVariableByMultiname(const multiname& name, ASObject* o, CONST_ALLOWED_FLAG allowConst)
-{
- assert_and_throw(implEnable);
- if(name.name_type==multiname::NAME_OBJECT)
- {
- name.name_o->incRef();
- _R<ASObject> name_o(name.name_o);
-
- Dictionary::dictType::iterator it=findKey(name_o.getPtr());
- if(it!=data.end())
- it->second=_MR(o);
- else
- data.insert(make_pair(name_o,_MR(o)));
- }
- else
- {
- //Primitive types _must_ be handled by the normal ASObject path
- //REFERENCE: Dictionary Object on AS3 reference
- assert(name.name_type==multiname::NAME_STRING ||
- name.name_type==multiname::NAME_INT ||
- name.name_type==multiname::NAME_NUMBER);
- ASObject::setVariableByMultiname(name, o, allowConst);
- }
-}
-
-bool Dictionary::deleteVariableByMultiname(const multiname& name)
-{
- assert_and_throw(implEnable);
-
- if(name.name_type==multiname::NAME_OBJECT)
- {
- name.name_o->incRef();
- _R<ASObject> name_o(name.name_o);
-
- Dictionary::dictType::iterator it=findKey(name_o.getPtr());
- if(it != data.end())
- {
- data.erase(it);
- return true;
- }
- return false;
- }
- else
- {
- //Primitive types _must_ be handled by the normal ASObject path
- //REFERENCE: Dictionary Object on AS3 reference
- assert(name.name_type==multiname::NAME_STRING ||
- name.name_type==multiname::NAME_INT ||
- name.name_type==multiname::NAME_NUMBER);
- return ASObject::deleteVariableByMultiname(name);
- }
-}
-
-_NR<ASObject> Dictionary::getVariableByMultiname(const multiname& name, GET_VARIABLE_OPTION opt)
-{
- if((opt & ASObject::SKIP_IMPL)==0 && implEnable)
- {
- if(name.name_type==multiname::NAME_OBJECT)
- {
- name.name_o->incRef();
- _R<ASObject> name_o(name.name_o);
-
- Dictionary::dictType::iterator it=findKey(name_o.getPtr());
- if(it != data.end())
- return it->second;
- else
- return NullRef;
- }
- else
- {
- //Primitive types _must_ be handled by the normal ASObject path
- //REFERENCE: Dictionary Object on AS3 reference
- assert(name.name_type==multiname::NAME_STRING ||
- name.name_type==multiname::NAME_INT ||
- name.name_type==multiname::NAME_NUMBER);
- return ASObject::getVariableByMultiname(name, opt);
- }
- }
- //Try with the base implementation
- return ASObject::getVariableByMultiname(name, opt);
-}
-
-bool Dictionary::hasPropertyByMultiname(const multiname& name, bool considerDynamic, bool considerPrototype)
-{
- if(considerDynamic==false)
- return ASObject::hasPropertyByMultiname(name, considerDynamic, considerPrototype);
-
- if(name.name_type==multiname::NAME_OBJECT)
- {
- name.name_o->incRef();
- _R<ASObject> name_o(name.name_o);
-
- Dictionary::dictType::iterator it=findKey(name_o.getPtr());
- return it != data.end();
- }
- else
- {
- //Primitive types _must_ be handled by the normal ASObject path
- //REFERENCE: Dictionary Object on AS3 reference
- assert(name.name_type==multiname::NAME_STRING ||
- name.name_type==multiname::NAME_INT ||
- name.name_type==multiname::NAME_NUMBER);
- return ASObject::hasPropertyByMultiname(name, considerDynamic, considerPrototype);
- }
-}
-
-uint32_t Dictionary::nextNameIndex(uint32_t cur_index)
+ASFUNCTIONBODY(ByteArray,atomicCompareAndSwapLength)
{
- assert_and_throw(implEnable);
- if(cur_index<data.size())
- return cur_index+1;
- else
- {
- //Fall back on object properties
- uint32_t ret=ASObject::nextNameIndex(cur_index-data.size());
- if(ret==0)
- return 0;
- else
- return ret+data.size();
-
- }
-}
-
-_R<ASObject> Dictionary::nextName(uint32_t index)
-{
- assert_and_throw(implEnable);
- if(index<=data.size())
- {
- map<_R<ASObject>,_R<ASObject> >::iterator it=data.begin();
- for(unsigned int i=1;i<index;i++)
- ++it;
-
- return it->first;
- }
- else
- {
- //Fall back on object properties
- return ASObject::nextName(index-data.size());
- }
-}
-
-_R<ASObject> Dictionary::nextValue(uint32_t index)
-{
- assert_and_throw(implEnable);
- if(index<=data.size())
- {
- map<_R<ASObject>,_R<ASObject> >::iterator it=data.begin();
- for(unsigned int i=1;i<index;i++)
- ++it;
-
- return it->second;
- }
- else
- {
- //Fall back on object properties
- return ASObject::nextValue(index-data.size());
- }
-}
-
-tiny_string Dictionary::toString()
-{
- std::stringstream retstr;
- retstr << "{";
- map<_R<ASObject>,_R<ASObject> >::iterator it=data.begin();
- while(it != data.end())
- {
- if(it != data.begin())
- retstr << ", ";
- retstr << "{" << it->first->toString() << ", " << it->second->toString() << "}";
- ++it;
- }
- retstr << "}";
-
- return retstr.str();
-}
-
-void Proxy::sinit(Class_base* c)
-{
- //c->constructor=Class<IFunction>::getFunction(_constructor);
- c->setConstructor(NULL);
-}
-
-void Proxy::buildTraits(ASObject* o)
-{
-}
-
-void Proxy::setVariableByMultiname(const multiname& name, ASObject* o, CONST_ALLOWED_FLAG allowConst)
-{
- //If a variable named like this already exist, use that
- if(ASObject::hasPropertyByMultiname(name, true, false) || !implEnable)
- {
- ASObject::setVariableByMultiname(name,o,allowConst);
- return;
- }
-
- //Check if there is a custom setter defined, skipping implementation to avoid recursive calls
- multiname setPropertyName(NULL);
- setPropertyName.name_type=multiname::NAME_STRING;
- setPropertyName.name_s_id=getSys()->getUniqueStringId("setProperty");
- setPropertyName.ns.push_back(nsNameAndKind(flash_proxy,NAMESPACE));
- _NR<ASObject> proxySetter=getVariableByMultiname(setPropertyName,ASObject::SKIP_IMPL);
-
- if(proxySetter.isNull())
- {
- ASObject::setVariableByMultiname(name,o,allowConst);
- return;
- }
-
- assert_and_throw(proxySetter->getObjectType()==T_FUNCTION);
-
- IFunction* f=static_cast<IFunction*>(proxySetter.getPtr());
-
- //Well, I don't how to pass multiname to an as function. I'll just pass the name as a string
- ASObject* args[2];
- args[0]=Class<ASString>::getInstanceS(name.normalizedName());
- args[1]=o;
- //We now suppress special handling
- implEnable=false;
- LOG(LOG_CALLS,_("Proxy::setProperty"));
- incRef();
- _R<ASObject> ret=_MR( f->call(this,args,2) );
- assert_and_throw(ret->is<Undefined>());
- implEnable=true;
-}
-
-_NR<ASObject> Proxy::getVariableByMultiname(const multiname& name, GET_VARIABLE_OPTION opt)
-{
- //It seems that various kind of implementation works only with the empty namespace
- assert_and_throw(name.ns.size()>0);
- if(!name.ns[0].hasEmptyName() || ASObject::hasPropertyByMultiname(name, true, true) || !implEnable || (opt & ASObject::SKIP_IMPL)!=0)
- return ASObject::getVariableByMultiname(name,opt);
-
- //Check if there is a custom getter defined, skipping implementation to avoid recursive calls
- multiname getPropertyName(NULL);
- getPropertyName.name_type=multiname::NAME_STRING;
- getPropertyName.name_s_id=getSys()->getUniqueStringId("getProperty");
- getPropertyName.ns.push_back(nsNameAndKind(flash_proxy,NAMESPACE));
- _NR<ASObject> o=getVariableByMultiname(getPropertyName,ASObject::SKIP_IMPL);
-
- if(o.isNull())
- return ASObject::getVariableByMultiname(name,opt);
-
- assert_and_throw(o->getObjectType()==T_FUNCTION);
-
- IFunction* f=static_cast<IFunction*>(o.getPtr());
-
- //Well, I don't how to pass multiname to an as function. I'll just pass the name as a string
- ASObject* arg=Class<ASString>::getInstanceS(name.normalizedName());
- //We now suppress special handling
- implEnable=false;
- LOG(LOG_CALLS,"Proxy::getProperty");
- incRef();
- _NR<ASObject> ret=_MNR(f->call(this,&arg,1));
- implEnable=true;
- return ret;
-}
-
-bool Proxy::hasPropertyByMultiname(const multiname& name, bool considerDynamic, bool considerPrototype)
-{
- //If a variable named like this already exist, use that
- bool asobject_has_property=ASObject::hasPropertyByMultiname(name, considerDynamic, considerPrototype);
- if(asobject_has_property || !implEnable)
- return asobject_has_property;
-
- //Check if there is a custom hasProperty defined, skipping implementation to avoid recursive calls
- multiname hasPropertyName(NULL);
- hasPropertyName.name_type=multiname::NAME_STRING;
- hasPropertyName.name_s_id=getSys()->getUniqueStringId("hasProperty");
- hasPropertyName.ns.push_back(nsNameAndKind(flash_proxy,NAMESPACE));
- _NR<ASObject> proxyHasProperty=getVariableByMultiname(hasPropertyName,ASObject::SKIP_IMPL);
-
- if(proxyHasProperty.isNull())
- {
- return false;
- }
-
- assert_and_throw(proxyHasProperty->getObjectType()==T_FUNCTION);
-
- IFunction* f=static_cast<IFunction*>(proxyHasProperty.getPtr());
-
- //Well, I don't how to pass multiname to an as function. I'll just pass the name as a string
- ASObject* arg=Class<ASString>::getInstanceS(name.normalizedName());
- //We now suppress special handling
- implEnable=false;
- LOG(LOG_CALLS,_("Proxy::hasProperty"));
- incRef();
- _NR<ASObject> ret=_MNR(f->call(this,&arg,1));
- implEnable=true;
- Boolean* b = static_cast<Boolean*>(ret.getPtr());
- return b->val;
-}
-bool Proxy::deleteVariableByMultiname(const multiname& name)
-{
- //If a variable named like this already exist, use that
- if(ASObject::hasPropertyByMultiname(name, true, false) || !implEnable)
- {
- return ASObject::deleteVariableByMultiname(name);
- }
-
- //Check if there is a custom deleter defined, skipping implementation to avoid recursive calls
- multiname deletePropertyName(NULL);
- deletePropertyName.name_type=multiname::NAME_STRING;
- deletePropertyName.name_s_id=getSys()->getUniqueStringId("deleteProperty");
- deletePropertyName.ns.push_back(nsNameAndKind(flash_proxy,NAMESPACE));
- _NR<ASObject> proxyDeleter=getVariableByMultiname(deletePropertyName,ASObject::SKIP_IMPL);
-
- if(proxyDeleter.isNull())
- {
- return ASObject::deleteVariableByMultiname(name);
- }
-
- assert_and_throw(proxyDeleter->getObjectType()==T_FUNCTION);
-
- IFunction* f=static_cast<IFunction*>(proxyDeleter.getPtr());
-
- //Well, I don't how to pass multiname to an as function. I'll just pass the name as a string
- ASObject* arg=Class<ASString>::getInstanceS(name.normalizedName());
- //We now suppress special handling
- implEnable=false;
- LOG(LOG_CALLS,_("Proxy::deleteProperty"));
- incRef();
- _NR<ASObject> ret=_MNR(f->call(this,&arg,1));
- implEnable=true;
- Boolean* b = static_cast<Boolean*>(ret.getPtr());
- return b->val;
-}
-
-uint32_t Proxy::nextNameIndex(uint32_t cur_index)
-{
- assert_and_throw(implEnable);
- LOG(LOG_CALLS,"Proxy::nextNameIndex");
- //Check if there is a custom enumerator, skipping implementation to avoid recursive calls
- multiname nextNameIndexName(NULL);
- nextNameIndexName.name_type=multiname::NAME_STRING;
- nextNameIndexName.name_s_id=getSys()->getUniqueStringId("nextNameIndex");
- nextNameIndexName.ns.push_back(nsNameAndKind(flash_proxy,NAMESPACE));
- _NR<ASObject> o=getVariableByMultiname(nextNameIndexName,ASObject::SKIP_IMPL);
- assert_and_throw(!o.isNull() && o->getObjectType()==T_FUNCTION);
- IFunction* f=static_cast<IFunction*>(o.getPtr());
- ASObject* arg=abstract_i(cur_index);
- this->incRef();
- ASObject* ret=f->call(this,&arg,1);
- uint32_t newIndex=ret->toInt();
- ret->decRef();
- return newIndex;
-}
-
-_R<ASObject> Proxy::nextName(uint32_t index)
-{
- assert_and_throw(implEnable);
- LOG(LOG_CALLS, _("Proxy::nextName"));
- //Check if there is a custom enumerator, skipping implementation to avoid recursive calls
- multiname nextNameName(NULL);
- nextNameName.name_type=multiname::NAME_STRING;
- nextNameName.name_s_id=getSys()->getUniqueStringId("nextName");
- nextNameName.ns.push_back(nsNameAndKind(flash_proxy,NAMESPACE));
- _NR<ASObject> o=getVariableByMultiname(nextNameName,ASObject::SKIP_IMPL);
- assert_and_throw(!o.isNull() && o->getObjectType()==T_FUNCTION);
- IFunction* f=static_cast<IFunction*>(o.getPtr());
- ASObject* arg=abstract_i(index);
- incRef();
- return _MR(f->call(this,&arg,1));
-}
-
-_R<ASObject> Proxy::nextValue(uint32_t index)
-{
- assert_and_throw(implEnable);
- LOG(LOG_CALLS, _("Proxy::nextValue"));
- //Check if there is a custom enumerator, skipping implementation to avoid recursive calls
- multiname nextValueName(NULL);
- nextValueName.name_type=multiname::NAME_STRING;
- nextValueName.name_s_id=getSys()->getUniqueStringId("nextValue");
- nextValueName.ns.push_back(nsNameAndKind(flash_proxy,NAMESPACE));
- _NR<ASObject> o=getVariableByMultiname(nextValueName,ASObject::SKIP_IMPL);
- assert_and_throw(!o.isNull() && o->getObjectType()==T_FUNCTION);
- IFunction* f=static_cast<IFunction*>(o.getPtr());
- ASObject* arg=abstract_i(index);
- incRef();
- return _MR(f->call(this,&arg,1));
-}
-
-ASFUNCTIONBODY(lightspark,setInterval)
-{
- assert_and_throw(argslen >= 2 && args[0]->getObjectType()==T_FUNCTION);
-
- //Build arguments array
- ASObject** callbackArgs = g_newa(ASObject*,argslen-2);
- uint32_t i;
- for(i=0; i<argslen-2; i++)
- {
- callbackArgs[i] = args[i+2];
- //incRef all passed arguments
- args[i+2]->incRef();
- }
-
- //incRef the function
- args[0]->incRef();
- IFunction* callback=static_cast<IFunction*>(args[0]);
- //Add interval through manager
- uint32_t id = getSys()->intervalManager->setInterval(_MR(callback), callbackArgs, argslen-2,
- _MR(getSys()->getNullRef()), args[1]->toInt());
- return abstract_i(id);
-}
-
-ASFUNCTIONBODY(lightspark,setTimeout)
-{
- assert_and_throw(argslen >= 2);
-
- //Build arguments array
- ASObject** callbackArgs = g_newa(ASObject*,argslen-2);
- uint32_t i;
- for(i=0; i<argslen-2; i++)
- {
- callbackArgs[i] = args[i+2];
- //incRef all passed arguments
- args[i+2]->incRef();
- }
-
- //incRef the function
- args[0]->incRef();
- IFunction* callback=static_cast<IFunction*>(args[0]);
- //Add timeout through manager
- uint32_t id = getSys()->intervalManager->setTimeout(_MR(callback), callbackArgs, argslen-2,
- _MR(getSys()->getNullRef()), args[1]->toInt());
- return abstract_i(id);
-}
-
-ASFUNCTIONBODY(lightspark,clearInterval)
-{
- assert_and_throw(argslen == 1);
- getSys()->intervalManager->clearInterval(args[0]->toInt(), IntervalRunner::INTERVAL, true);
- return NULL;
-}
-
-ASFUNCTIONBODY(lightspark,clearTimeout)
-{
- assert_and_throw(argslen == 1);
- getSys()->intervalManager->clearInterval(args[0]->toInt(), IntervalRunner::TIMEOUT, true);
- return NULL;
-}
-
-IntervalRunner::IntervalRunner(IntervalRunner::INTERVALTYPE _type, uint32_t _id, _R<IFunction> _callback, ASObject** _args,
- const unsigned int _argslen, _R<ASObject> _obj, uint32_t _interval):
- EventDispatcher(NULL),type(_type), id(_id), callback(_callback),obj(_obj),argslen(_argslen),interval(_interval)
-{
- args = new ASObject*[argslen];
- for(uint32_t i=0; i<argslen; i++)
- args[i] = _args[i];
-}
-
-IntervalRunner::~IntervalRunner()
-{
- for(uint32_t i=0; i<argslen; i++)
- args[i]->decRef();
- delete[] args;
-}
-
-void IntervalRunner::tick()
-{
- //incRef all arguments
- uint32_t i;
- for(i=0; i < argslen; i++)
- {
- args[i]->incRef();
- }
- _R<FunctionEvent> event(new (getSys()->unaccountedMemory) FunctionEvent(callback, obj, args, argslen));
- getVm()->addEvent(NullRef,event);
- if(type == TIMEOUT)
- {
- //TODO: IntervalRunner deletes itself. Is this allowed?
- //Delete ourselves from the active intervals list
- getSys()->intervalManager->clearInterval(id, TIMEOUT, false);
- //No actions may be performed after this point
- }
-}
-
-void IntervalRunner::tickFence()
-{
- delete this;
-}
-
-IntervalManager::IntervalManager() : currentID(1)
-{
-}
+ ByteArray* th=static_cast<ByteArray*>(obj);
+ int32_t expectedLength,newLength;
+ ARG_UNPACK(expectedLength)(newLength);
-IntervalManager::~IntervalManager()
-{
- //Run through all running intervals and remove their tickjob, delete their intervalRunner and erase their entry
- std::map<uint32_t,IntervalRunner*>::iterator it = runners.begin();
- while(it != runners.end())
+ th->lock();
+ int32_t ret = th->len;
+ if (ret == expectedLength)
{
- getSys()->removeJob((*it).second);
- runners.erase(it++);
+ th->setLength(newLength);
}
+ th->unlock();
+ return abstract_i(ret);
}
-uint32_t IntervalManager::setInterval(_R<IFunction> callback, ASObject** args, const unsigned int argslen, _R<ASObject> obj, uint32_t interval)
-{
- Mutex::Lock l(mutex);
-
- uint32_t id = getFreeID();
- IntervalRunner* runner = new (getSys()->unaccountedMemory)
- IntervalRunner(IntervalRunner::INTERVAL, id, callback, args, argslen, obj, interval);
-
- //Add runner as tickjob
- getSys()->addTick(interval, runner);
- //Add runner to map
- runners[id] = runner;
- //Increment currentID
- currentID++;
-
- return currentID-1;
-}
-uint32_t IntervalManager::setTimeout(_R<IFunction> callback, ASObject** args, const unsigned int argslen, _R<ASObject> obj, uint32_t interval)
-{
- Mutex::Lock l(mutex);
-
- uint32_t id = getFreeID();
- IntervalRunner* runner = new (getSys()->unaccountedMemory)
- IntervalRunner(IntervalRunner::TIMEOUT, id, callback, args, argslen, obj, interval);
-
- //Add runner as waitjob
- getSys()->addWait(interval, runner);
- //Add runner to map
- runners[id] = runner;
- //increment currentID
- currentID++;
-
- return currentID-1;
-}
-
-uint32_t IntervalManager::getFreeID()
-{
- //At the first run every currentID will be available. But eventually the currentID will wrap around.
- //Thats why we need to check if the currentID isn't used yet
- while(currentID == 0 || runners.count(currentID) != 0)
- currentID++;
- return currentID;
-}
-
-void IntervalManager::clearInterval(uint32_t id, IntervalRunner::INTERVALTYPE type, bool removeJob)
+ASFUNCTIONBODY(ByteArray,_toJSON)
{
- Mutex::Lock l(mutex);
-
- std::map<uint32_t,IntervalRunner*>::iterator it = runners.find(id);
- //If the entry exists and the types match, remove its tickjob, delete its intervalRunner and erase their entry
- if(it != runners.end() && (*it).second->getType() == type)
- {
- if(removeJob)
- {
- getSys()->removeJob((*it).second);
- }
- runners.erase(it);
- }
+ return Class<ASString>::getInstanceS("ByteArray");
}
diff --git a/src/scripting/flash/utils/ByteArray.h b/src/scripting/flash/utils/ByteArray.h
new file mode 100644
index 0000000..6628d52
--- /dev/null
+++ b/src/scripting/flash/utils/ByteArray.h
@@ -0,0 +1,156 @@
+/**************************************************************************
+ Lightspark, a free flash player implementation
+
+ Copyright (C) 2009-2013 Alessandro Pignotti (a.pignotti at sssup.it)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+**************************************************************************/
+
+#ifndef SCRIPTING_FLASH_UTILS_BYTEARRAY_H
+#define SCRIPTING_FLASH_UTILS_BYTEARRAY_H 1
+
+#include "compat.h"
+#include "swftypes.h"
+#include "scripting/flash/utils/flashutils.h"
+
+namespace lightspark
+{
+
+class ByteArray: public ASObject, public IDataInput, public IDataOutput
+{
+friend class LoaderThread;
+friend class URLLoader;
+friend class ApplicationDomain;
+friend class LoaderInfo;
+protected:
+ bool littleEndian;
+ uint8_t objectEncoding;
+ uint8_t currentObjectEncoding;
+ uint32_t position;
+ uint8_t* bytes;
+ uint32_t real_len;
+ uint32_t len;
+ void compress_zlib();
+ void uncompress_zlib();
+ Mutex mutex;
+ void lock();
+ void unlock();
+ void setLength(uint32_t newLen);
+public:
+ ByteArray(Class_base* c, uint8_t* b = NULL, uint32_t l = 0);
+ ~ByteArray();
+ //Helper interface for serialization
+ bool peekByte(uint8_t& b);
+ bool readByte(uint8_t& b);
+ bool readShort(uint16_t& ret);
+ bool readUnsignedInt(uint32_t& ret);
+ bool readU29(uint32_t& ret);
+ bool readUTF(tiny_string& ret);
+ void writeByte(uint8_t b);
+ void writeShort(uint16_t val);
+ void writeUnsignedInt(uint32_t val);
+ void writeUTF(const tiny_string& str);
+ uint32_t writeObject(ASObject* obj);
+ void writeStringVR(std::map<tiny_string, uint32_t>& stringMap, const tiny_string& s);
+ void writeXMLString(std::map<const ASObject*, uint32_t>& objMap, ASObject *xml, const tiny_string& s);
+ void writeU29(uint32_t val);
+ uint32_t getPosition() const;
+ void setPosition(uint32_t p);
+
+ uint8_t getCurrentObjectEncoding() const { return currentObjectEncoding; }
+ void setCurrentObjectEncoding(uint8_t encoding) { currentObjectEncoding = encoding; }
+
+ ASFUNCTION(_getBytesAvailable);
+ ASFUNCTION(_getLength);
+ ASFUNCTION(_setLength);
+ ASFUNCTION(_getPosition);
+ ASFUNCTION(_setPosition);
+ ASFUNCTION(_getEndian);
+ ASFUNCTION(_setEndian);
+ ASFUNCTION(_getObjectEncoding);
+ ASFUNCTION(_setObjectEncoding);
+ ASFUNCTION(_getDefaultObjectEncoding);
+ ASFUNCTION(_setDefaultObjectEncoding);
+ ASFUNCTION(_compress);
+ ASFUNCTION(_uncompress);
+ ASFUNCTION(_deflate);
+ ASFUNCTION(_inflate);
+ ASFUNCTION(clear);
+ ASFUNCTION(readBoolean);
+ ASFUNCTION(readByte);
+ ASFUNCTION(readBytes);
+ ASFUNCTION(readDouble);
+ ASFUNCTION(readFloat);
+ ASFUNCTION(readInt);
+ ASFUNCTION(readMultiByte);
+ ASFUNCTION(readObject);
+ ASFUNCTION(readShort);
+ ASFUNCTION(readUnsignedByte);
+ ASFUNCTION(readUnsignedInt);
+ ASFUNCTION(readUnsignedShort);
+ ASFUNCTION(readUTF);
+ ASFUNCTION(readUTFBytes);
+ ASFUNCTION(writeBoolean);
+ ASFUNCTION(writeByte);
+ ASFUNCTION(writeBytes);
+ ASFUNCTION(writeDouble);
+ ASFUNCTION(writeFloat);
+ ASFUNCTION(writeInt);
+ ASFUNCTION(writeUnsignedInt);
+ ASFUNCTION(writeMultiByte);
+ ASFUNCTION(writeObject);
+ ASFUNCTION(writeShort);
+ ASFUNCTION(writeUTF);
+ ASFUNCTION(writeUTFBytes);
+ ASFUNCTION(_toString);
+ ASPROPERTY_GETTER_SETTER(bool,shareable);
+ ASFUNCTION(atomicCompareAndSwapIntAt);
+ ASFUNCTION(atomicCompareAndSwapLength);
+ ASFUNCTION(_toJSON);
+
+ // these are internal methods used if the generic Array-Methods are called on a ByteArray
+ ASFUNCTION(pop);
+ ASFUNCTION(push);
+ ASFUNCTION(shift);
+ ASFUNCTION(unshift);
+ /**
+ Get ownership over the passed buffer
+ @param buf Pointer to the buffer to acquire, ownership and delete authority is acquired
+ @param bufLen Lenght of the buffer
+ @pre buf must be allocated using new[]
+ */
+ void acquireBuffer(uint8_t* buf, int bufLen);
+ uint8_t* getBuffer(unsigned int size, bool enableResize);
+ uint32_t getLength() const { return len; }
+
+ uint16_t endianIn(uint16_t value);
+ uint32_t endianIn(uint32_t value);
+ uint64_t endianIn(uint64_t value);
+
+ uint16_t endianOut(uint16_t value);
+ uint32_t endianOut(uint32_t value);
+ uint64_t endianOut(uint64_t value);
+
+ static void sinit(Class_base* c);
+ static void buildTraits(ASObject* o);
+ _NR<ASObject> getVariableByMultiname(const multiname& name, GET_VARIABLE_OPTION opt=NONE);
+ int32_t getVariableByMultiname_i(const multiname& name);
+ void setVariableByMultiname(const multiname& name, ASObject* o, CONST_ALLOWED_FLAG allowConst);
+ void setVariableByMultiname_i(const multiname& name, int32_t value);
+ bool hasPropertyByMultiname(const multiname& name, bool considerDynamic, bool considerPrototype);
+};
+
+}
+
+#endif /* SCRIPTING_FLASH_UTILS_BYTEARRAY_H */
diff --git a/src/scripting/flash/utils/Dictionary.cpp b/src/scripting/flash/utils/Dictionary.cpp
new file mode 100644
index 0000000..c5e7eb9
--- /dev/null
+++ b/src/scripting/flash/utils/Dictionary.cpp
@@ -0,0 +1,344 @@
+/**************************************************************************
+ Lightspark, a free flash player implementation
+
+ Copyright (C) 2009-2013 Alessandro Pignotti (a.pignotti at sssup.it)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+**************************************************************************/
+
+#include "scripting/abc.h"
+#include "asobject.h"
+#include "scripting/class.h"
+#include "compat.h"
+#include "parsing/amf3_generator.h"
+#include "scripting/argconv.h"
+#include "scripting/flash/errors/flasherrors.h"
+#include "scripting/flash/utils/Dictionary.h"
+
+using namespace std;
+using namespace lightspark;
+
+Dictionary::Dictionary(Class_base* c):ASObject(c),
+ data(std::less<dictType::key_type>(), reporter_allocator<dictType::value_type>(c->memoryAccount))
+{
+}
+
+void Dictionary::finalize()
+{
+ ASObject::finalize();
+ data.clear();
+}
+
+void Dictionary::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_DYNAMIC_NOT_FINAL);
+ c->setDeclaredMethodByQName("toJSON",AS3,Class<IFunction>::getFunction(_toJSON),NORMAL_METHOD,true);
+}
+
+void Dictionary::buildTraits(ASObject* o)
+{
+}
+
+ASFUNCTIONBODY(Dictionary,_constructor)
+{
+ return NULL;
+}
+
+ASFUNCTIONBODY(Dictionary,_toJSON)
+{
+ return Class<ASString>::getInstanceS("Dictionary");
+}
+
+Dictionary::dictType::iterator Dictionary::findKey(ASObject *o)
+{
+ Dictionary::dictType::iterator it = data.begin();
+ for(; it!=data.end(); ++it)
+ {
+ if (it->first->isEqualStrict(o))
+ return it;
+ }
+
+ return data.end();
+}
+
+void Dictionary::setVariableByMultiname_i(const multiname& name, int32_t value)
+{
+ assert_and_throw(implEnable);
+ Dictionary::setVariableByMultiname(name,abstract_i(value),CONST_NOT_ALLOWED);
+}
+
+void Dictionary::setVariableByMultiname(const multiname& name, ASObject* o, CONST_ALLOWED_FLAG allowConst)
+{
+ assert_and_throw(implEnable);
+ if(name.name_type==multiname::NAME_OBJECT)
+ {
+ multiname tmpname(NULL);
+ tmpname.ns.push_back(nsNameAndKind("",NAMESPACE));
+ switch (name.name_o->getObjectType())
+ {
+ case T_BOOLEAN:
+ case T_UINTEGER:
+ case T_INTEGER:
+ tmpname.name_type=multiname::NAME_INT;
+ tmpname.name_i = name.name_o->toInt();
+ ASObject::setVariableByMultiname(tmpname, o, allowConst);
+ return;
+ case T_NUMBER:
+ tmpname.name_type=multiname::NAME_NUMBER;
+ tmpname.name_d = name.name_o->toNumber();
+ ASObject::setVariableByMultiname(tmpname, o, allowConst);
+ return;
+ case T_STRING:
+ tmpname.name_type=multiname::NAME_STRING;
+ tmpname.name_s_id = getSys()->getUniqueStringId(name.name_o->toString());
+ ASObject::setVariableByMultiname(tmpname, o, allowConst);
+ return;
+ default:
+ break;
+ }
+ name.name_o->incRef();
+ _R<ASObject> name_o(name.name_o);
+
+ Dictionary::dictType::iterator it=findKey(name_o.getPtr());
+ if(it!=data.end())
+ it->second=_MR(o);
+ else
+ data.insert(make_pair(name_o,_MR(o)));
+ }
+ else
+ {
+ //Primitive types _must_ be handled by the normal ASObject path
+ //REFERENCE: Dictionary Object on AS3 reference
+ assert(name.name_type==multiname::NAME_STRING ||
+ name.name_type==multiname::NAME_INT ||
+ name.name_type==multiname::NAME_NUMBER);
+ ASObject::setVariableByMultiname(name, o, allowConst);
+ }
+}
+
+bool Dictionary::deleteVariableByMultiname(const multiname& name)
+{
+ assert_and_throw(implEnable);
+
+ if(name.name_type==multiname::NAME_OBJECT)
+ {
+ multiname tmpname(NULL);
+ tmpname.ns.push_back(nsNameAndKind("",NAMESPACE));
+ switch (name.name_o->getObjectType())
+ {
+ case T_BOOLEAN:
+ case T_UINTEGER:
+ case T_INTEGER:
+ tmpname.name_type=multiname::NAME_INT;
+ tmpname.name_i = name.name_o->toInt();
+ return ASObject::deleteVariableByMultiname(tmpname);
+ case T_NUMBER:
+ tmpname.name_type=multiname::NAME_NUMBER;
+ tmpname.name_d = name.name_o->toNumber();
+ return ASObject::deleteVariableByMultiname(tmpname);
+ case T_STRING:
+ tmpname.name_type=multiname::NAME_STRING;
+ tmpname.name_s_id = getSys()->getUniqueStringId(name.name_o->toString());
+ return ASObject::deleteVariableByMultiname(tmpname);
+ default:
+ break;
+ }
+ name.name_o->incRef();
+ _R<ASObject> name_o(name.name_o);
+
+ Dictionary::dictType::iterator it=findKey(name_o.getPtr());
+ if(it != data.end())
+ {
+ data.erase(it);
+ return true;
+ }
+ return false;
+ }
+ else
+ {
+ //Primitive types _must_ be handled by the normal ASObject path
+ //REFERENCE: Dictionary Object on AS3 reference
+ assert(name.name_type==multiname::NAME_STRING ||
+ name.name_type==multiname::NAME_INT ||
+ name.name_type==multiname::NAME_NUMBER);
+ return ASObject::deleteVariableByMultiname(name);
+ }
+}
+
+_NR<ASObject> Dictionary::getVariableByMultiname(const multiname& name, GET_VARIABLE_OPTION opt)
+{
+ if((opt & ASObject::SKIP_IMPL)==0 && implEnable)
+ {
+ if(name.name_type==multiname::NAME_OBJECT)
+ {
+ multiname tmpname(NULL);
+ tmpname.ns.push_back(nsNameAndKind("",NAMESPACE));
+ switch (name.name_o->getObjectType())
+ {
+ case T_BOOLEAN:
+ case T_UINTEGER:
+ case T_INTEGER:
+ tmpname.name_type=multiname::NAME_INT;
+ tmpname.name_i = name.name_o->toInt();
+ return ASObject::getVariableByMultiname(tmpname, opt);
+ case T_NUMBER:
+ tmpname.name_type=multiname::NAME_NUMBER;
+ tmpname.name_d = name.name_o->toNumber();
+ return ASObject::getVariableByMultiname(tmpname, opt);
+ case T_STRING:
+ tmpname.name_type=multiname::NAME_STRING;
+ tmpname.name_s_id = getSys()->getUniqueStringId(name.name_o->toString());
+ return ASObject::getVariableByMultiname(tmpname, opt);
+ default:
+ break;
+ }
+ name.name_o->incRef();
+ _R<ASObject> name_o(name.name_o);
+
+ Dictionary::dictType::iterator it=findKey(name_o.getPtr());
+ if(it != data.end())
+ return it->second;
+ else
+ return NullRef;
+ }
+ else
+ {
+ //Primitive types _must_ be handled by the normal ASObject path
+ //REFERENCE: Dictionary Object on AS3 reference
+ assert(name.name_type==multiname::NAME_STRING ||
+ name.name_type==multiname::NAME_INT ||
+ name.name_type==multiname::NAME_NUMBER);
+ return ASObject::getVariableByMultiname(name, opt);
+ }
+ }
+ //Try with the base implementation
+ return ASObject::getVariableByMultiname(name, opt);
+}
+
+bool Dictionary::hasPropertyByMultiname(const multiname& name, bool considerDynamic, bool considerPrototype)
+{
+ if(considerDynamic==false)
+ return ASObject::hasPropertyByMultiname(name, considerDynamic, considerPrototype);
+
+ if(name.name_type==multiname::NAME_OBJECT)
+ {
+ multiname tmpname(NULL);
+ tmpname.ns.push_back(nsNameAndKind("",NAMESPACE));
+ switch (name.name_o->getObjectType())
+ {
+ case T_BOOLEAN:
+ case T_UINTEGER:
+ case T_INTEGER:
+ tmpname.name_type=multiname::NAME_INT;
+ tmpname.name_i = name.name_o->toInt();
+ return ASObject::hasPropertyByMultiname(tmpname, considerDynamic, considerPrototype);
+ case T_NUMBER:
+ tmpname.name_type=multiname::NAME_NUMBER;
+ tmpname.name_d = name.name_o->toNumber();
+ return ASObject::hasPropertyByMultiname(tmpname, considerDynamic, considerPrototype);
+ case T_STRING:
+ tmpname.name_type=multiname::NAME_STRING;
+ tmpname.name_s_id = getSys()->getUniqueStringId(name.name_o->toString());
+ return ASObject::hasPropertyByMultiname(tmpname, considerDynamic, considerPrototype);
+ default:
+ break;
+ }
+
+ name.name_o->incRef();
+ _R<ASObject> name_o(name.name_o);
+
+ Dictionary::dictType::iterator it=findKey(name_o.getPtr());
+ return it != data.end();
+ }
+ else
+ {
+ //Primitive types _must_ be handled by the normal ASObject path
+ //REFERENCE: Dictionary Object on AS3 reference
+ assert(name.name_type==multiname::NAME_STRING ||
+ name.name_type==multiname::NAME_INT ||
+ name.name_type==multiname::NAME_NUMBER);
+ return ASObject::hasPropertyByMultiname(name, considerDynamic, considerPrototype);
+ }
+}
+
+uint32_t Dictionary::nextNameIndex(uint32_t cur_index)
+{
+ assert_and_throw(implEnable);
+ if(cur_index<data.size())
+ return cur_index+1;
+ else
+ {
+ //Fall back on object properties
+ uint32_t ret=ASObject::nextNameIndex(cur_index-data.size());
+ if(ret==0)
+ return 0;
+ else
+ return ret+data.size();
+
+ }
+}
+
+_R<ASObject> Dictionary::nextName(uint32_t index)
+{
+ assert_and_throw(implEnable);
+ if(index<=data.size())
+ {
+ map<_R<ASObject>,_R<ASObject> >::iterator it=data.begin();
+ for(unsigned int i=1;i<index;i++)
+ ++it;
+
+ return it->first;
+ }
+ else
+ {
+ //Fall back on object properties
+ return ASObject::nextName(index-data.size());
+ }
+}
+
+_R<ASObject> Dictionary::nextValue(uint32_t index)
+{
+ assert_and_throw(implEnable);
+ if(index<=data.size())
+ {
+ map<_R<ASObject>,_R<ASObject> >::iterator it=data.begin();
+ for(unsigned int i=1;i<index;i++)
+ ++it;
+
+ return it->second;
+ }
+ else
+ {
+ //Fall back on object properties
+ return ASObject::nextValue(index-data.size());
+ }
+}
+
+tiny_string Dictionary::toString()
+{
+ std::stringstream retstr;
+ retstr << "{";
+ map<_R<ASObject>,_R<ASObject> >::iterator it=data.begin();
+ while(it != data.end())
+ {
+ if(it != data.begin())
+ retstr << ", ";
+ retstr << "{" << it->first->toString() << ", " << it->second->toString() << "}";
+ ++it;
+ }
+ retstr << "}";
+
+ return retstr.str();
+}
+
diff --git a/src/scripting/flash/utils/Dictionary.h b/src/scripting/flash/utils/Dictionary.h
new file mode 100644
index 0000000..a3732d4
--- /dev/null
+++ b/src/scripting/flash/utils/Dictionary.h
@@ -0,0 +1,64 @@
+/**************************************************************************
+ Lightspark, a free flash player implementation
+
+ Copyright (C) 2009-2013 Alessandro Pignotti (a.pignotti at sssup.it)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+**************************************************************************/
+
+#ifndef SCRIPTING_FLASH_UTILS_DICTIONARY_H
+#define SCRIPTING_FLASH_UTILS_DICTIONARY_H 1
+
+#include "compat.h"
+#include "swftypes.h"
+
+
+namespace lightspark
+{
+
+class Dictionary: public ASObject
+{
+friend class ABCVm;
+private:
+ typedef std::map<_R<ASObject>,_R<ASObject>,std::less<_R<ASObject>>,
+ reporter_allocator<std::pair<const _R<ASObject>, _R<ASObject>>>> dictType;
+ dictType data;
+ dictType::iterator findKey(ASObject *);
+public:
+ Dictionary(Class_base* c);
+ void finalize();
+ static void sinit(Class_base*);
+ static void buildTraits(ASObject* o);
+ ASFUNCTION(_constructor);
+ ASFUNCTION(_toJSON);
+
+ _NR<ASObject> getVariableByMultiname(const multiname& name, GET_VARIABLE_OPTION opt=NONE);
+ int32_t getVariableByMultiname_i(const multiname& name)
+ {
+ assert_and_throw(implEnable);
+ throw UnsupportedException("getVariableByMultiName_i not supported for Dictionary");
+ }
+ void setVariableByMultiname(const multiname& name, ASObject* o, CONST_ALLOWED_FLAG allowConst);
+ void setVariableByMultiname_i(const multiname& name, int32_t value);
+ bool deleteVariableByMultiname(const multiname& name);
+ bool hasPropertyByMultiname(const multiname& name, bool considerDynamic, bool considerPrototype);
+ tiny_string toString();
+ uint32_t nextNameIndex(uint32_t cur_index);
+ _R<ASObject> nextName(uint32_t index);
+ _R<ASObject> nextValue(uint32_t index);
+};
+
+}
+
+#endif /* SCRIPTING_FLASH_UTILS_DICTIONARY_H */
diff --git a/src/scripting/flash/utils/IntervalManager.cpp b/src/scripting/flash/utils/IntervalManager.cpp
new file mode 100644
index 0000000..5b07a54
--- /dev/null
+++ b/src/scripting/flash/utils/IntervalManager.cpp
@@ -0,0 +1,106 @@
+/**************************************************************************
+ Lightspark, a free flash player implementation
+
+ Copyright (C) 2009-2013 Alessandro Pignotti (a.pignotti at sssup.it)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+**************************************************************************/
+
+#include "scripting/abc.h"
+#include "scripting/flash/utils/flashutils.h"
+#include "scripting/flash/utils/IntervalManager.h"
+#include "asobject.h"
+#include "scripting/class.h"
+#include "compat.h"
+#include "parsing/amf3_generator.h"
+#include "scripting/argconv.h"
+#include "scripting/flash/errors/flasherrors.h"
+
+using namespace std;
+using namespace lightspark;
+
+IntervalManager::IntervalManager() : currentID(1)
+{
+}
+
+IntervalManager::~IntervalManager()
+{
+ //Run through all running intervals and remove their tickjob, delete their intervalRunner and erase their entry
+ std::map<uint32_t,IntervalRunner*>::iterator it = runners.begin();
+ while(it != runners.end())
+ {
+ getSys()->removeJob((*it).second);
+ runners.erase(it++);
+ }
+}
+
+uint32_t IntervalManager::setInterval(_R<IFunction> callback, ASObject** args, const unsigned int argslen, _R<ASObject> obj, uint32_t interval)
+{
+ Mutex::Lock l(mutex);
+
+ uint32_t id = getFreeID();
+ IntervalRunner* runner = new (getSys()->unaccountedMemory)
+ IntervalRunner(IntervalRunner::INTERVAL, id, callback, args, argslen, obj, interval);
+
+ //Add runner as tickjob
+ getSys()->addTick(interval, runner);
+ //Add runner to map
+ runners[id] = runner;
+ //Increment currentID
+ currentID++;
+
+ return currentID-1;
+}
+uint32_t IntervalManager::setTimeout(_R<IFunction> callback, ASObject** args, const unsigned int argslen, _R<ASObject> obj, uint32_t interval)
+{
+ Mutex::Lock l(mutex);
+
+ uint32_t id = getFreeID();
+ IntervalRunner* runner = new (getSys()->unaccountedMemory)
+ IntervalRunner(IntervalRunner::TIMEOUT, id, callback, args, argslen, obj, interval);
+
+ //Add runner as waitjob
+ getSys()->addWait(interval, runner);
+ //Add runner to map
+ runners[id] = runner;
+ //increment currentID
+ currentID++;
+
+ return currentID-1;
+}
+
+uint32_t IntervalManager::getFreeID()
+{
+ //At the first run every currentID will be available. But eventually the currentID will wrap around.
+ //Thats why we need to check if the currentID isn't used yet
+ while(currentID == 0 || runners.count(currentID) != 0)
+ currentID++;
+ return currentID;
+}
+
+void IntervalManager::clearInterval(uint32_t id, IntervalRunner::INTERVALTYPE type, bool removeJob)
+{
+ Mutex::Lock l(mutex);
+
+ std::map<uint32_t,IntervalRunner*>::iterator it = runners.find(id);
+ //If the entry exists and the types match, remove its tickjob, delete its intervalRunner and erase their entry
+ if(it != runners.end() && (*it).second->getType() == type)
+ {
+ if(removeJob)
+ {
+ getSys()->removeJob((*it).second);
+ }
+ runners.erase(it);
+ }
+}
diff --git a/src/scripting/flash/accessibility/flashaccessibility.h b/src/scripting/flash/utils/IntervalManager.h
similarity index 57%
copy from src/scripting/flash/accessibility/flashaccessibility.h
copy to src/scripting/flash/utils/IntervalManager.h
index 19d00b8..fc4e798 100644
--- a/src/scripting/flash/accessibility/flashaccessibility.h
+++ b/src/scripting/flash/utils/IntervalManager.h
@@ -17,31 +17,32 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
-#ifndef SCRIPTING_FLASH_ACCESSIBILITY_FLASHACCESSIBILITY_H
-#define SCRIPTING_FLASH_ACCESSIBILITY_FLASHACCESSIBILITY_H 1
+#ifndef SCRIPTING_FLASH_UTILS_INTERVALMANAGER_H
+#define SCRIPTING_FLASH_UTILS_INTERVALMANAGER_H 1
+
+#include "compat.h"
+#include "swftypes.h"
+#include "scripting/flash/utils/IntervalRunner.h"
-#include "asobject.h"
namespace lightspark
{
-class AccessibilityProperties : public ASObject
+class IntervalManager
{
private:
- ASPROPERTY_GETTER_SETTER(tiny_string,name);
-public:
- AccessibilityProperties(Class_base* c):ASObject(c){}
- static void sinit(Class_base*);
- ASFUNCTION(_constructor);
-};
-
-class AccessibilityImplementation : public ASObject
-{
+ Mutex mutex;
+ std::map<uint32_t,IntervalRunner*> runners;
+ uint32_t currentID;
public:
- AccessibilityImplementation(Class_base* c):ASObject(c){}
- static void sinit(Class_base*);
- ASFUNCTION(_constructor);
+ IntervalManager();
+ ~IntervalManager();
+ uint32_t setInterval(_R<IFunction> callback, ASObject** args, const unsigned int argslen, _R<ASObject> obj, const uint32_t interval);
+ uint32_t setTimeout(_R<IFunction> callback, ASObject** args, const unsigned int argslen, _R<ASObject> obj, const uint32_t interval);
+ uint32_t getFreeID();
+ void clearInterval(uint32_t id, IntervalRunner::INTERVALTYPE type, bool removeJob);
};
}
-#endif /* SCRIPTING_FLASH_ACCESSIBILITY_FLASHACCESSIBILITY_H */
+
+#endif /* SCRIPTING_FLASH_UTILS_INTERVALMANAGER_H */
diff --git a/src/scripting/flash/utils/IntervalRunner.cpp b/src/scripting/flash/utils/IntervalRunner.cpp
new file mode 100644
index 0000000..99165f2
--- /dev/null
+++ b/src/scripting/flash/utils/IntervalRunner.cpp
@@ -0,0 +1,72 @@
+/**************************************************************************
+ Lightspark, a free flash player implementation
+
+ Copyright (C) 2009-2013 Alessandro Pignotti (a.pignotti at sssup.it)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+**************************************************************************/
+
+#include "scripting/abc.h"
+#include "scripting/flash/utils/flashutils.h"
+#include "asobject.h"
+#include "scripting/class.h"
+#include "compat.h"
+#include "parsing/amf3_generator.h"
+#include "scripting/argconv.h"
+#include "scripting/flash/errors/flasherrors.h"
+
+using namespace std;
+using namespace lightspark;
+
+
+IntervalRunner::IntervalRunner(IntervalRunner::INTERVALTYPE _type, uint32_t _id, _R<IFunction> _callback, ASObject** _args,
+ const unsigned int _argslen, _R<ASObject> _obj, uint32_t _interval):
+ EventDispatcher(NULL),type(_type), id(_id), callback(_callback),obj(_obj),argslen(_argslen),interval(_interval)
+{
+ args = new ASObject*[argslen];
+ for(uint32_t i=0; i<argslen; i++)
+ args[i] = _args[i];
+}
+
+IntervalRunner::~IntervalRunner()
+{
+ for(uint32_t i=0; i<argslen; i++)
+ args[i]->decRef();
+ delete[] args;
+}
+
+void IntervalRunner::tick()
+{
+ //incRef all arguments
+ uint32_t i;
+ for(i=0; i < argslen; i++)
+ {
+ args[i]->incRef();
+ }
+ _R<FunctionEvent> event(new (getSys()->unaccountedMemory) FunctionEvent(callback, obj, args, argslen));
+ getVm()->addEvent(NullRef,event);
+ if(type == TIMEOUT)
+ {
+ //TODO: IntervalRunner deletes itself. Is this allowed?
+ //Delete ourselves from the active intervals list
+ getSys()->intervalManager->clearInterval(id, TIMEOUT, false);
+ //No actions may be performed after this point
+ }
+}
+
+void IntervalRunner::tickFence()
+{
+ delete this;
+}
+
diff --git a/src/scripting/toplevel/UInteger.h b/src/scripting/flash/utils/IntervalRunner.h
similarity index 55%
copy from src/scripting/toplevel/UInteger.h
copy to src/scripting/flash/utils/IntervalRunner.h
index fe0fbcc..93191a5 100644
--- a/src/scripting/toplevel/UInteger.h
+++ b/src/scripting/flash/utils/IntervalRunner.h
@@ -17,41 +17,40 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
-#ifndef SCRIPTING_TOPLEVEL_UINTEGER_H
-#define SCRIPTING_TOPLEVEL_UINTEGER_H 1
+#ifndef SCRIPTING_FLASH_UTILS_INTERVALRUNNER_H
+#define SCRIPTING_FLASH_UTILS_INTERVALRUNNER_H 1
+
#include "compat.h"
-#include "asobject.h"
+#include "swftypes.h"
+
namespace lightspark
{
-class UInteger: public ASObject
+class IntervalRunner : public ITickJob, public EventDispatcher
{
-friend ASObject* abstract_ui(uint32_t i);
public:
- uint32_t val;
- UInteger(Class_base* c,uint32_t v=0):ASObject(c),val(v){type=T_UINTEGER;}
-
- static void sinit(Class_base* c);
- tiny_string toString();
- static tiny_string toString(uint32_t val);
- int32_t toInt()
- {
- return val;
- }
- uint32_t toUInt()
- {
- return val;
- }
- TRISTATE isLess(ASObject* r);
- bool isEqual(ASObject* o);
- ASFUNCTION(_constructor);
- ASFUNCTION(generator);
- ASFUNCTION(_toString);
- ASFUNCTION(_valueOf);
- std::string toDebugString() { return toString()+"ui"; }
- //CHECK: should this have a special serialization?
+ enum INTERVALTYPE { INTERVAL, TIMEOUT };
+private:
+ // IntervalRunner will delete itself in tickFence, others
+ // should not call the destructor.
+ ~IntervalRunner();
+ INTERVALTYPE type;
+ uint32_t id;
+ _R<IFunction> callback;
+ ASObject** args;
+ _R<ASObject> obj;
+ const unsigned int argslen;
+ uint32_t interval;
+public:
+ IntervalRunner(INTERVALTYPE _type, uint32_t _id, _R<IFunction> _callback, ASObject** _args,
+ const unsigned int _argslen, _R<ASObject> _obj, const uint32_t _interval);
+ void tick();
+ void tickFence();
+ INTERVALTYPE getType() { return type; }
};
+
}
-#endif /* SCRIPTING_TOPLEVEL_UINTEGER_H */
+
+#endif /* SCRIPTING_FLASH_UTILS_FLASHUTILS_H */
diff --git a/src/scripting/flash/utils/Proxy.cpp b/src/scripting/flash/utils/Proxy.cpp
new file mode 100644
index 0000000..77fa04f
--- /dev/null
+++ b/src/scripting/flash/utils/Proxy.cpp
@@ -0,0 +1,251 @@
+/**************************************************************************
+ Lightspark, a free flash player implementation
+
+ Copyright (C) 2009-2013 Alessandro Pignotti (a.pignotti at sssup.it)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+**************************************************************************/
+
+#include "scripting/abc.h"
+#include "scripting/flash/utils/flashutils.h"
+#include "scripting/flash/utils/Proxy.h"
+#include "asobject.h"
+#include "scripting/class.h"
+#include "compat.h"
+#include "parsing/amf3_generator.h"
+#include "scripting/argconv.h"
+#include "scripting/flash/errors/flasherrors.h"
+#include <sstream>
+#include <zlib.h>
+#include <glib.h>
+
+using namespace std;
+using namespace lightspark;
+
+
+
+void Proxy::sinit(Class_base* c)
+{
+ CLASS_SETUP_NO_CONSTRUCTOR(c, ASObject,CLASS_DYNAMIC_NOT_FINAL);
+}
+
+void Proxy::buildTraits(ASObject* o)
+{
+}
+
+void Proxy::setVariableByMultiname(const multiname& name, ASObject* o, CONST_ALLOWED_FLAG allowConst)
+{
+ //If a variable named like this already exist, use that
+ if(ASObject::hasPropertyByMultiname(name, true, false) || !implEnable)
+ {
+ ASObject::setVariableByMultiname(name,o,allowConst);
+ return;
+ }
+
+ //Check if there is a custom setter defined, skipping implementation to avoid recursive calls
+ multiname setPropertyName(NULL);
+ setPropertyName.name_type=multiname::NAME_STRING;
+ setPropertyName.name_s_id=getSys()->getUniqueStringId("setProperty");
+ setPropertyName.ns.push_back(nsNameAndKind(flash_proxy,NAMESPACE));
+ _NR<ASObject> proxySetter=getVariableByMultiname(setPropertyName,ASObject::SKIP_IMPL);
+
+ if(proxySetter.isNull())
+ {
+ ASObject::setVariableByMultiname(name,o,allowConst);
+ return;
+ }
+
+ assert_and_throw(proxySetter->getObjectType()==T_FUNCTION);
+
+ IFunction* f=static_cast<IFunction*>(proxySetter.getPtr());
+
+ ASObject* namearg = Class<ASString>::getInstanceS(name.normalizedName());
+ namearg->setProxyProperty(name);
+ ASObject* args[2];
+ args[0]=namearg;
+ args[1]=o;
+ //We now suppress special handling
+ implEnable=false;
+ LOG(LOG_CALLS,_("Proxy::setProperty"));
+ incRef();
+ _R<ASObject> ret=_MR( f->call(this,args,2) );
+ assert_and_throw(ret->is<Undefined>());
+ implEnable=true;
+}
+
+_NR<ASObject> Proxy::getVariableByMultiname(const multiname& name, GET_VARIABLE_OPTION opt)
+{
+ //It seems that various kind of implementation works only with the empty namespace
+ assert_and_throw(name.ns.size()>0);
+ _NR<ASObject> o;
+ LOG(LOG_CALLS,"Proxy::getVar "<< name << " " << this->toDebugString());
+ if(ASObject::hasPropertyByMultiname(name, true, true) || !implEnable || (opt & ASObject::SKIP_IMPL)!=0)
+ o = ASObject::getVariableByMultiname(name,opt);
+ if (!o.isNull() || !implEnable || (opt & ASObject::SKIP_IMPL)!=0)
+ return o;
+
+ //Check if there is a custom getter defined, skipping implementation to avoid recursive calls
+ multiname getPropertyName(NULL);
+ getPropertyName.name_type=multiname::NAME_STRING;
+ getPropertyName.name_s_id=getSys()->getUniqueStringId("getProperty");
+ getPropertyName.ns.push_back(nsNameAndKind(flash_proxy,NAMESPACE));
+ o=getVariableByMultiname(getPropertyName,ASObject::SKIP_IMPL);
+
+ if(o.isNull())
+ return ASObject::getVariableByMultiname(name,opt);
+
+ assert_and_throw(o->getObjectType()==T_FUNCTION);
+
+ IFunction* f=static_cast<IFunction*>(o.getPtr());
+
+ ASObject* namearg = Class<ASString>::getInstanceS(name.normalizedName());
+ namearg->setProxyProperty(name);
+ ASObject* arg = namearg;
+ //We now suppress special handling
+ implEnable=false;
+ LOG(LOG_CALLS,"Proxy::getProperty "<< name.normalizedName() << " " << this->toDebugString());
+ incRef();
+ _NR<ASObject> ret=_MNR(f->call(this,&arg,1));
+ implEnable=true;
+ return ret;
+}
+
+bool Proxy::hasPropertyByMultiname(const multiname& name, bool considerDynamic, bool considerPrototype)
+{
+ if (name.normalizedName() == "isAttribute")
+ return true;
+ //If a variable named like this already exist, use that
+ bool asobject_has_property=ASObject::hasPropertyByMultiname(name, considerDynamic, considerPrototype);
+ if(asobject_has_property || !implEnable)
+ return asobject_has_property;
+
+ //Check if there is a custom hasProperty defined, skipping implementation to avoid recursive calls
+ multiname hasPropertyName(NULL);
+ hasPropertyName.name_type=multiname::NAME_STRING;
+ hasPropertyName.name_s_id=getSys()->getUniqueStringId("hasProperty");
+ hasPropertyName.ns.push_back(nsNameAndKind(flash_proxy,NAMESPACE));
+ _NR<ASObject> proxyHasProperty=getVariableByMultiname(hasPropertyName,ASObject::SKIP_IMPL);
+
+ if(proxyHasProperty.isNull())
+ {
+ return false;
+ }
+
+ assert_and_throw(proxyHasProperty->getObjectType()==T_FUNCTION);
+
+ IFunction* f=static_cast<IFunction*>(proxyHasProperty.getPtr());
+
+ ASObject* namearg = Class<ASString>::getInstanceS(name.normalizedName());
+ namearg->setProxyProperty(name);
+ ASObject* arg = namearg;
+ //We now suppress special handling
+ implEnable=false;
+ LOG(LOG_CALLS,_("Proxy::hasProperty"));
+ incRef();
+ _NR<ASObject> ret=_MNR(f->call(this,&arg,1));
+ implEnable=true;
+ Boolean* b = static_cast<Boolean*>(ret.getPtr());
+ return b->val;
+}
+bool Proxy::deleteVariableByMultiname(const multiname& name)
+{
+ //If a variable named like this already exist, use that
+ if(ASObject::hasPropertyByMultiname(name, true, false) || !implEnable)
+ {
+ return ASObject::deleteVariableByMultiname(name);
+ }
+
+ //Check if there is a custom deleter defined, skipping implementation to avoid recursive calls
+ multiname deletePropertyName(NULL);
+ deletePropertyName.name_type=multiname::NAME_STRING;
+ deletePropertyName.name_s_id=getSys()->getUniqueStringId("deleteProperty");
+ deletePropertyName.ns.push_back(nsNameAndKind(flash_proxy,NAMESPACE));
+ _NR<ASObject> proxyDeleter=getVariableByMultiname(deletePropertyName,ASObject::SKIP_IMPL);
+
+ if(proxyDeleter.isNull())
+ {
+ return ASObject::deleteVariableByMultiname(name);
+ }
+
+ assert_and_throw(proxyDeleter->getObjectType()==T_FUNCTION);
+
+ IFunction* f=static_cast<IFunction*>(proxyDeleter.getPtr());
+
+ ASObject* namearg = Class<ASString>::getInstanceS(name.normalizedName());
+ namearg->setProxyProperty(name);
+ ASObject* arg = namearg;
+ //We now suppress special handling
+ implEnable=false;
+ LOG(LOG_CALLS,_("Proxy::deleteProperty"));
+ incRef();
+ _NR<ASObject> ret=_MNR(f->call(this,&arg,1));
+ implEnable=true;
+ Boolean* b = static_cast<Boolean*>(ret.getPtr());
+ return b->val;
+}
+
+uint32_t Proxy::nextNameIndex(uint32_t cur_index)
+{
+ assert_and_throw(implEnable);
+ LOG(LOG_CALLS,"Proxy::nextNameIndex");
+ //Check if there is a custom enumerator, skipping implementation to avoid recursive calls
+ multiname nextNameIndexName(NULL);
+ nextNameIndexName.name_type=multiname::NAME_STRING;
+ nextNameIndexName.name_s_id=getSys()->getUniqueStringId("nextNameIndex");
+ nextNameIndexName.ns.push_back(nsNameAndKind(flash_proxy,NAMESPACE));
+ _NR<ASObject> o=getVariableByMultiname(nextNameIndexName,ASObject::SKIP_IMPL);
+ assert_and_throw(!o.isNull() && o->getObjectType()==T_FUNCTION);
+ IFunction* f=static_cast<IFunction*>(o.getPtr());
+ ASObject* arg=abstract_i(cur_index);
+ this->incRef();
+ ASObject* ret=f->call(this,&arg,1);
+ uint32_t newIndex=ret->toInt();
+ ret->decRef();
+ return newIndex;
+}
+
+_R<ASObject> Proxy::nextName(uint32_t index)
+{
+ assert_and_throw(implEnable);
+ LOG(LOG_CALLS, _("Proxy::nextName"));
+ //Check if there is a custom enumerator, skipping implementation to avoid recursive calls
+ multiname nextNameName(NULL);
+ nextNameName.name_type=multiname::NAME_STRING;
+ nextNameName.name_s_id=getSys()->getUniqueStringId("nextName");
+ nextNameName.ns.push_back(nsNameAndKind(flash_proxy,NAMESPACE));
+ _NR<ASObject> o=getVariableByMultiname(nextNameName,ASObject::SKIP_IMPL);
+ assert_and_throw(!o.isNull() && o->getObjectType()==T_FUNCTION);
+ IFunction* f=static_cast<IFunction*>(o.getPtr());
+ ASObject* arg=abstract_i(index);
+ incRef();
+ return _MR(f->call(this,&arg,1));
+}
+
+_R<ASObject> Proxy::nextValue(uint32_t index)
+{
+ assert_and_throw(implEnable);
+ LOG(LOG_CALLS, _("Proxy::nextValue"));
+ //Check if there is a custom enumerator, skipping implementation to avoid recursive calls
+ multiname nextValueName(NULL);
+ nextValueName.name_type=multiname::NAME_STRING;
+ nextValueName.name_s_id=getSys()->getUniqueStringId("nextValue");
+ nextValueName.ns.push_back(nsNameAndKind(flash_proxy,NAMESPACE));
+ _NR<ASObject> o=getVariableByMultiname(nextValueName,ASObject::SKIP_IMPL);
+ assert_and_throw(!o.isNull() && o->getObjectType()==T_FUNCTION);
+ IFunction* f=static_cast<IFunction*>(o.getPtr());
+ ASObject* arg=abstract_i(index);
+ incRef();
+ return _MR(f->call(this,&arg,1));
+}
+
diff --git a/src/scripting/flash/utils/Proxy.h b/src/scripting/flash/utils/Proxy.h
new file mode 100644
index 0000000..ccb3613
--- /dev/null
+++ b/src/scripting/flash/utils/Proxy.h
@@ -0,0 +1,61 @@
+/**************************************************************************
+ Lightspark, a free flash player implementation
+
+ Copyright (C) 2009-2013 Alessandro Pignotti (a.pignotti at sssup.it)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+**************************************************************************/
+
+#ifndef SCRIPTING_FLASH_UTILS_PROXY_H
+#define SCRIPTING_FLASH_UTILS_PROXY_H 1
+
+#include "compat.h"
+#include "swftypes.h"
+
+namespace lightspark
+{
+
+class Proxy: public ASObject
+{
+friend class ABCVm;
+public:
+ Proxy(Class_base* c):ASObject(c){}
+ static void sinit(Class_base*);
+ static void buildTraits(ASObject* o);
+// ASFUNCTION(_constructor);
+ _NR<ASObject> getVariableByMultiname(const multiname& name, GET_VARIABLE_OPTION opt=NONE);
+ int32_t getVariableByMultiname_i(const multiname& name)
+ {
+ assert_and_throw(implEnable);
+ throw UnsupportedException("getVariableByMultiName_i not supported for Proxy");
+ }
+ void setVariableByMultiname(const multiname& name, ASObject* o, CONST_ALLOWED_FLAG allowConst);
+ void setVariableByMultiname_i(const multiname& name, int32_t value)
+ {
+ setVariableByMultiname(name,abstract_i(value),CONST_NOT_ALLOWED);
+ }
+
+ bool deleteVariableByMultiname(const multiname& name);
+ bool hasPropertyByMultiname(const multiname& name, bool considerDynamic, bool considerPrototype);
+ tiny_string toString()
+ {
+ throw UnsupportedException("Proxy is missing some stuff");
+ }
+ uint32_t nextNameIndex(uint32_t cur_index);
+ _R<ASObject> nextName(uint32_t index);
+ _R<ASObject> nextValue(uint32_t index);
+};
+}
+
+#endif /* SCRIPTING_FLASH_UTILS_PROXY_H */
diff --git a/src/scripting/flash/utils/Timer.cpp b/src/scripting/flash/utils/Timer.cpp
new file mode 100644
index 0000000..775dd52
--- /dev/null
+++ b/src/scripting/flash/utils/Timer.cpp
@@ -0,0 +1,185 @@
+/**************************************************************************
+ Lightspark, a free flash player implementation
+
+ Copyright (C) 2009-2013 Alessandro Pignotti (a.pignotti at sssup.it)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+**************************************************************************/
+
+#include "scripting/abc.h"
+#include "asobject.h"
+#include "scripting/class.h"
+#include "compat.h"
+#include "parsing/amf3_generator.h"
+#include "scripting/argconv.h"
+#include "scripting/flash/errors/flasherrors.h"
+#include "scripting/flash/utils/Timer.h"
+
+using namespace std;
+using namespace lightspark;
+
+void Timer::tick()
+{
+ //This will be executed once if repeatCount was originally 1
+ //Otherwise it's executed until stopMe is set to true
+ this->incRef();
+ getVm()->addEvent(_MR(this),_MR(Class<TimerEvent>::getInstanceS("timer")));
+
+ currentCount++;
+ if(repeatCount!=0)
+ {
+ if(currentCount==repeatCount)
+ {
+ this->incRef();
+ getVm()->addEvent(_MR(this),_MR(Class<TimerEvent>::getInstanceS("timerComplete")));
+ stopMe=true;
+ running=false;
+ }
+ }
+}
+
+void Timer::tickFence()
+{
+ tickJobInstance = NullRef;
+}
+
+
+void Timer::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, EventDispatcher, _constructor, CLASS_SEALED);
+ c->setDeclaredMethodByQName("currentCount","",Class<IFunction>::getFunction(_getCurrentCount),GETTER_METHOD,true);
+ c->setDeclaredMethodByQName("repeatCount","",Class<IFunction>::getFunction(_getRepeatCount),GETTER_METHOD,true);
+ c->setDeclaredMethodByQName("repeatCount","",Class<IFunction>::getFunction(_setRepeatCount),SETTER_METHOD,true);
+ c->setDeclaredMethodByQName("running","",Class<IFunction>::getFunction(_getRunning),GETTER_METHOD,true);
+ c->setDeclaredMethodByQName("delay","",Class<IFunction>::getFunction(_getDelay),GETTER_METHOD,true);
+ c->setDeclaredMethodByQName("delay","",Class<IFunction>::getFunction(_setDelay),SETTER_METHOD,true);
+ c->setDeclaredMethodByQName("start","",Class<IFunction>::getFunction(start),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("reset","",Class<IFunction>::getFunction(reset),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("stop","",Class<IFunction>::getFunction(stop),NORMAL_METHOD,true);
+}
+
+ASFUNCTIONBODY(Timer,_constructor)
+{
+ EventDispatcher::_constructor(obj,NULL,0);
+ Timer* th=static_cast<Timer*>(obj);
+
+ th->delay=args[0]->toInt();
+ if(argslen>=2)
+ th->repeatCount=args[1]->toInt();
+
+ return NULL;
+}
+
+ASFUNCTIONBODY(Timer,_getCurrentCount)
+{
+ Timer* th=static_cast<Timer*>(obj);
+ return abstract_i(th->currentCount);
+}
+
+ASFUNCTIONBODY(Timer,_getRepeatCount)
+{
+ Timer* th=static_cast<Timer*>(obj);
+ return abstract_i(th->repeatCount);
+}
+
+ASFUNCTIONBODY(Timer,_setRepeatCount)
+{
+ assert_and_throw(argslen==1);
+ int32_t count=args[0]->toInt();
+ Timer* th=static_cast<Timer*>(obj);
+ th->repeatCount=count;
+ if(th->repeatCount>0 && th->repeatCount<=th->currentCount)
+ {
+ getSys()->removeJob(th);
+ th->running=false;
+ th->tickJobInstance = NullRef;
+ }
+ return NULL;
+}
+
+ASFUNCTIONBODY(Timer,_getRunning)
+{
+ Timer* th=static_cast<Timer*>(obj);
+ return abstract_b(th->running);
+}
+
+ASFUNCTIONBODY(Timer,_getDelay)
+{
+ Timer* th=static_cast<Timer*>(obj);
+ return abstract_i(th->delay);
+}
+
+ASFUNCTIONBODY(Timer,_setDelay)
+{
+ assert_and_throw(argslen==1);
+ int32_t newdelay = args[0]->toInt();
+ if (newdelay<=0)
+ throw Class<RangeError>::getInstanceS("delay must be positive", 2066);
+
+ Timer* th=static_cast<Timer*>(obj);
+ th->delay=newdelay;
+
+ return NULL;
+}
+
+ASFUNCTIONBODY(Timer,start)
+{
+ Timer* th=static_cast<Timer*>(obj);
+ if(th->running)
+ return NULL;
+ th->running=true;
+ th->stopMe=false;
+ th->incRef();
+ th->tickJobInstance = _MNR(th);
+ if(th->repeatCount==1)
+ getSys()->addWait(th->delay,th);
+ else
+ getSys()->addTick(th->delay,th);
+ return NULL;
+}
+
+ASFUNCTIONBODY(Timer,reset)
+{
+ Timer* th=static_cast<Timer*>(obj);
+ if(th->running)
+ {
+ //This spin waits if the timer is running right now
+ getSys()->removeJob(th);
+ //NOTE: although no new events will be sent now there might be old events in the queue.
+ //Is this behaviour right?
+ //This is not anymore used by the timer, so it can die
+ th->tickJobInstance = NullRef;
+ th->running=false;
+ }
+ th->currentCount=0;
+ return NULL;
+}
+
+ASFUNCTIONBODY(Timer,stop)
+{
+ Timer* th=static_cast<Timer*>(obj);
+ if(th->running)
+ {
+ //This spin waits if the timer is running right now
+ getSys()->removeJob(th);
+ //NOTE: although no new events will be sent now there might be old events in the queue.
+ //Is this behaviour right?
+
+ //This is not anymore used by the timer, so it can die
+ th->tickJobInstance = NullRef;
+ th->running=false;
+ }
+ return NULL;
+}
+
diff --git a/src/scripting/toplevel/UInteger.h b/src/scripting/flash/utils/Timer.h
similarity index 54%
copy from src/scripting/toplevel/UInteger.h
copy to src/scripting/flash/utils/Timer.h
index fe0fbcc..da7b750 100644
--- a/src/scripting/toplevel/UInteger.h
+++ b/src/scripting/flash/utils/Timer.h
@@ -17,41 +17,49 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
-#ifndef SCRIPTING_TOPLEVEL_UINTEGER_H
-#define SCRIPTING_TOPLEVEL_UINTEGER_H 1
+#ifndef SCRIPTING_FLASH_UTILS_TIMER_H
+#define SCRIPTING_FLASH_UTILS_TIMER_H 1
+
#include "compat.h"
-#include "asobject.h"
+#include "swftypes.h"
+#include "scripting/flash/events/flashevents.h"
+#include "thread_pool.h"
+#include "timer.h"
+
namespace lightspark
{
-class UInteger: public ASObject
+
+class Timer: public EventDispatcher, public ITickJob
{
-friend ASObject* abstract_ui(uint32_t i);
+private:
+ void tick();
+ void tickFence();
+ //tickJobInstance keeps a reference to self while this
+ //instance is being used by the timer thread.
+ _NR<Timer> tickJobInstance;
+protected:
+ bool running;
+ uint32_t delay;
+ uint32_t repeatCount;
+ uint32_t currentCount;
public:
- uint32_t val;
- UInteger(Class_base* c,uint32_t v=0):ASObject(c),val(v){type=T_UINTEGER;}
-
+ Timer(Class_base* c):EventDispatcher(c),running(false),delay(0),repeatCount(0),currentCount(0){};
static void sinit(Class_base* c);
- tiny_string toString();
- static tiny_string toString(uint32_t val);
- int32_t toInt()
- {
- return val;
- }
- uint32_t toUInt()
- {
- return val;
- }
- TRISTATE isLess(ASObject* r);
- bool isEqual(ASObject* o);
ASFUNCTION(_constructor);
- ASFUNCTION(generator);
- ASFUNCTION(_toString);
- ASFUNCTION(_valueOf);
- std::string toDebugString() { return toString()+"ui"; }
- //CHECK: should this have a special serialization?
+ ASFUNCTION(_getCurrentCount);
+ ASFUNCTION(_getRepeatCount);
+ ASFUNCTION(_setRepeatCount);
+ ASFUNCTION(_getRunning);
+ ASFUNCTION(_getDelay);
+ ASFUNCTION(_setDelay);
+ ASFUNCTION(start);
+ ASFUNCTION(reset);
+ ASFUNCTION(stop);
};
+
}
-#endif /* SCRIPTING_TOPLEVEL_UINTEGER_H */
+
+#endif /* SCRIPTING_FLASH_UTILS_TIMER_H */
diff --git a/src/scripting/flash/utils/flashutils.cpp b/src/scripting/flash/utils/flashutils.cpp
index 2fd9976..f3b9c4d 100644
--- a/src/scripting/flash/utils/flashutils.cpp
+++ b/src/scripting/flash/utils/flashutils.cpp
@@ -39,7 +39,7 @@ const char* Endian::bigEndian = "bigEndian";
void Endian::sinit(Class_base* c)
{
- c->setConstructor(NULL);
+ CLASS_SETUP_NO_CONSTRUCTOR(c, ASObject, CLASS_SEALED | CLASS_FINAL);
c->setVariableByQName("LITTLE_ENDIAN","",Class<ASString>::getInstanceS(littleEndian),DECLARED_TRAIT);
c->setVariableByQName("BIG_ENDIAN","",Class<ASString>::getInstanceS(bigEndian),DECLARED_TRAIT);
}
@@ -89,1351 +89,7 @@ void IDataOutput::linkTraits(Class_base* c)
lookupAndLink(c,"writeUTFBytes","flash.utils:IDataOutput");
}
-ByteArray::ByteArray(Class_base* c, uint8_t* b, uint32_t l):ASObject(c),littleEndian(false),objectEncoding(ObjectEncoding::AMF3),
- position(0),bytes(b),real_len(l),len(l)
-{
-#ifdef MEMORY_USAGE_PROFILING
- c->memoryAccount->addBytes(l);
-#endif
-}
-
-ByteArray::~ByteArray()
-{
- if(bytes)
- {
-#ifdef MEMORY_USAGE_PROFILING
- getClass()->memoryAccount->removeBytes(real_len);
-#endif
- free(bytes);
- }
-}
-
-void ByteArray::sinit(Class_base* c)
-{
- c->setConstructor(NULL);
- c->setSuper(Class<ASObject>::getRef());
-
- c->setDeclaredMethodByQName("length","",Class<IFunction>::getFunction(_getLength),GETTER_METHOD,true);
- c->setDeclaredMethodByQName("length","",Class<IFunction>::getFunction(_setLength),SETTER_METHOD,true);
- c->setDeclaredMethodByQName("bytesAvailable","",Class<IFunction>::getFunction(_getBytesAvailable),GETTER_METHOD,true);
- c->setDeclaredMethodByQName("position","",Class<IFunction>::getFunction(_getPosition),GETTER_METHOD,true);
- c->setDeclaredMethodByQName("position","",Class<IFunction>::getFunction(_setPosition),SETTER_METHOD,true);
- c->setDeclaredMethodByQName("endian","",Class<IFunction>::getFunction(_getEndian),GETTER_METHOD,true);
- c->setDeclaredMethodByQName("endian","",Class<IFunction>::getFunction(_setEndian),SETTER_METHOD,true);
- c->setDeclaredMethodByQName("objectEncoding","",Class<IFunction>::getFunction(_getObjectEncoding),GETTER_METHOD,true);
- c->setDeclaredMethodByQName("objectEncoding","",Class<IFunction>::getFunction(_setObjectEncoding),SETTER_METHOD,true);
- c->setDeclaredMethodByQName("defaultObjectEncoding","",Class<IFunction>::getFunction(_getDefaultObjectEncoding),GETTER_METHOD,false);
- c->setDeclaredMethodByQName("defaultObjectEncoding","",Class<IFunction>::getFunction(_setDefaultObjectEncoding),SETTER_METHOD,false);
- getSys()->staticByteArrayDefaultObjectEncoding = ObjectEncoding::DEFAULT;
- c->setDeclaredMethodByQName("clear","",Class<IFunction>::getFunction(clear),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("compress","",Class<IFunction>::getFunction(_compress),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("uncompress","",Class<IFunction>::getFunction(_uncompress),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("deflate","",Class<IFunction>::getFunction(_deflate),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("inflate","",Class<IFunction>::getFunction(_inflate),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("readBoolean","",Class<IFunction>::getFunction(readBoolean),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("readBytes","",Class<IFunction>::getFunction(readBytes),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("readByte","",Class<IFunction>::getFunction(readByte),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("readDouble","",Class<IFunction>::getFunction(readDouble),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("readFloat","",Class<IFunction>::getFunction(readFloat),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("readInt","",Class<IFunction>::getFunction(readInt),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("readMultiByte","",Class<IFunction>::getFunction(readMultiByte),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("readShort","",Class<IFunction>::getFunction(readShort),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("readUnsignedByte","",Class<IFunction>::getFunction(readUnsignedByte),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("readUnsignedInt","",Class<IFunction>::getFunction(readUnsignedInt),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("readUnsignedShort","",Class<IFunction>::getFunction(readUnsignedShort),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("readObject","",Class<IFunction>::getFunction(readObject),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("readUTF","",Class<IFunction>::getFunction(readUTF),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("readUTFBytes","",Class<IFunction>::getFunction(readUTFBytes),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("writeBoolean","",Class<IFunction>::getFunction(writeBoolean),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("writeUTF","",Class<IFunction>::getFunction(writeUTF),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("writeUTFBytes","",Class<IFunction>::getFunction(writeUTFBytes),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("writeBytes","",Class<IFunction>::getFunction(writeBytes),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("writeByte","",Class<IFunction>::getFunction(writeByte),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("writeDouble","",Class<IFunction>::getFunction(writeDouble),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("writeFloat","",Class<IFunction>::getFunction(writeFloat),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("writeInt","",Class<IFunction>::getFunction(writeInt),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("writeMultiByte","",Class<IFunction>::getFunction(writeMultiByte),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("writeUnsignedInt","",Class<IFunction>::getFunction(writeUnsignedInt),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("writeObject","",Class<IFunction>::getFunction(writeObject),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("writeShort","",Class<IFunction>::getFunction(writeShort),NORMAL_METHOD,true);
- c->prototype->setVariableByQName("toString","",Class<IFunction>::getFunction(ByteArray::_toString),DYNAMIC_TRAIT);
-
- c->addImplementedInterface(InterfaceClass<IDataInput>::getClass());
- IDataInput::linkTraits(c);
- c->addImplementedInterface(InterfaceClass<IDataOutput>::getClass());
- IDataOutput::linkTraits(c);
-}
-
-void ByteArray::buildTraits(ASObject* o)
-{
-}
-
-uint8_t* ByteArray::getBuffer(unsigned int size, bool enableResize)
-{
- // the flash documentation doesn't tell how large ByteArrays are allowed to be
- // so we simply don't allow bytearrays larger than 1GiB
- // maybe we should set this smaller
- if (size > 0x4000000)
- throwError<ASError>(kOutOfMemoryError);
- // The first allocation is exactly the size we need,
- // the subsequent reallocations happen in increments of BA_CHUNK_SIZE bytes
- uint32_t prevLen = len;
- if(bytes==NULL)
- {
- len=size;
- real_len=len;
- bytes = (uint8_t*) malloc(len);
-#ifdef MEMORY_USAGE_PROFILING
- getClass()->memoryAccount->addBytes(len);
-#endif
- }
- else if(enableResize==false)
- {
- assert_and_throw(size<=len);
- }
- else if(real_len<size) // && enableResize==true
- {
-#ifdef MEMORY_USAGE_PROFILING
- uint32_t prev_real_len = real_len;
-#endif
- while(real_len < size)
- real_len += BA_CHUNK_SIZE;
- // Reallocate the buffer, in chunks of BA_CHUNK_SIZE bytes
- uint8_t* bytes2 = (uint8_t*) realloc(bytes, real_len);
-#ifdef MEMORY_USAGE_PROFILING
- getClass()->memoryAccount->addBytes(real_len-prev_real_len);
-#endif
- assert_and_throw(bytes2);
- bytes = bytes2;
- len=size;
- bytes=bytes2;
- }
- else if(len<size)
- {
- len=size;
- }
- if(prevLen<size)
- {
- //Extend
- memset(bytes+prevLen,0,size-prevLen);
- }
- return bytes;
-}
-
-uint16_t ByteArray::endianIn(uint16_t value)
-{
- if(littleEndian)
- return GUINT16_TO_LE(value);
- else
- return GUINT16_TO_BE(value);
-}
-
-uint32_t ByteArray::endianIn(uint32_t value)
-{
- if(littleEndian)
- return GUINT32_TO_LE(value);
- else
- return GUINT32_TO_BE(value);
-}
-
-uint64_t ByteArray::endianIn(uint64_t value)
-{
- if(littleEndian)
- return GUINT64_TO_LE(value);
- else
- return GUINT64_TO_BE(value);
-}
-
-uint16_t ByteArray::endianOut(uint16_t value)
-{
- if(littleEndian)
- return GUINT16_FROM_LE(value);
- else
- return GUINT16_FROM_BE(value);
-}
-
-uint32_t ByteArray::endianOut(uint32_t value)
-{
- if(littleEndian)
- return GUINT32_FROM_LE(value);
- else
- return GUINT32_FROM_BE(value);
-}
-
-uint64_t ByteArray::endianOut(uint64_t value)
-{
- if(littleEndian)
- return GUINT64_FROM_LE(value);
- else
- return GUINT64_FROM_BE(value);
-}
-
-uint32_t ByteArray::getPosition() const
-{
- return position;
-}
-
-ASFUNCTIONBODY(ByteArray,_getPosition)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- return abstract_i(th->getPosition());
-}
-
-void ByteArray::setPosition(uint32_t p)
-{
- position=p;
-}
-
-ASFUNCTIONBODY(ByteArray,_setPosition)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- uint32_t pos=args[0]->toUInt();
- th->setPosition(pos);
- return NULL;
-}
-
-ASFUNCTIONBODY(ByteArray,_getEndian)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- if(th->littleEndian)
- return Class<ASString>::getInstanceS(Endian::littleEndian);
- else
- return Class<ASString>::getInstanceS(Endian::bigEndian);
-}
-
-ASFUNCTIONBODY(ByteArray,_setEndian)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- if(args[0]->toString() == Endian::littleEndian)
- th->littleEndian = true;
- else if(args[0]->toString() == Endian::bigEndian)
- th->littleEndian = false;
- else
- throwError<ArgumentError>(kInvalidEnumError, "endian");
- return NULL;
-}
-
-ASFUNCTIONBODY(ByteArray,_getObjectEncoding)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- return abstract_ui(th->objectEncoding);
-}
-
-ASFUNCTIONBODY(ByteArray,_setObjectEncoding)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- uint32_t value;
- ARG_UNPACK(value);
- if(value!=ObjectEncoding::AMF0 && value!=ObjectEncoding::AMF3)
- throwError<ArgumentError>(kInvalidEnumError, "objectEncoding");
-
- th->objectEncoding=value;
- return NULL;
-}
-
-ASFUNCTIONBODY(ByteArray,_getDefaultObjectEncoding)
-{
- return abstract_i(getSys()->staticNetConnectionDefaultObjectEncoding);
-}
-
-ASFUNCTIONBODY(ByteArray,_setDefaultObjectEncoding)
-{
- assert_and_throw(argslen == 1);
- int32_t value = args[0]->toInt();
- if(value == 0)
- getSys()->staticByteArrayDefaultObjectEncoding = ObjectEncoding::AMF0;
- else if(value == 3)
- getSys()->staticByteArrayDefaultObjectEncoding = ObjectEncoding::AMF3;
- else
- throw RunTimeException("Invalid object encoding");
- return NULL;
-}
-
-ASFUNCTIONBODY(ByteArray,_setLength)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- assert_and_throw(argslen==1);
- uint32_t newLen=args[0]->toInt();
- if(newLen==th->len) //Nothing to do
- return NULL;
- if (newLen > 0)
- {
- th->getBuffer(newLen,true);
- }
- else
- {
- if (th->bytes)
- {
-#ifdef MEMORY_USAGE_PROFILING
- th->getClass()->memoryAccount->removeBytes(th->real_len);
-#endif
- free(th->bytes);
- }
- th->bytes = NULL;
- th->len = newLen;
- th->real_len = newLen;
- }
- if (th->position > th->len)
- th->position = (th->len > 0 ? th->len-1 : 0);
- return NULL;
-}
-
-ASFUNCTIONBODY(ByteArray,_getLength)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- return abstract_i(th->len);
-}
-
-ASFUNCTIONBODY(ByteArray,_getBytesAvailable)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- return abstract_i(th->len-th->position);
-}
-
-ASFUNCTIONBODY(ByteArray,readBoolean)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
-
- uint8_t ret;
- if(!th->readByte(ret))
- {
- throwError<ArgumentError>(kEOFError);
- }
-
- return abstract_b(ret!=0);
-}
-
-ASFUNCTIONBODY(ByteArray,readBytes)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- _NR<ByteArray> out;
- uint32_t offset;
- uint32_t length;
- ARG_UNPACK(out)(offset, 0)(length, 0);
-
- if(length == 0)
- {
- assert(th->len >= th->position);
- length = th->len - th->position;
- }
-
- //Error checks
- if(th->position+length > th->len)
- {
- throwError<ArgumentError>(kEOFError);
- }
- if((uint64_t)length+offset > 0xFFFFFFFF)
- {
- throw Class<RangeError>::getInstanceS("length+offset");
- }
-
- uint8_t* buf=out->getBuffer(length+offset,true);
- memcpy(buf+offset,th->bytes+th->position,length);
- th->position+=length;
-
- return NULL;
-}
-
-bool ByteArray::readUTF(tiny_string& ret)
-{
- uint16_t stringLen;
- if(!readShort(stringLen))
- return false;
- if(len < (position+stringLen))
- return false;
- //Very inefficient copy
- //TODO: optmize
- ret=string((char*)bytes+position, (size_t)stringLen);
- position+=stringLen;
- return true;
-}
-
-ASFUNCTIONBODY(ByteArray,readUTF)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
-
- tiny_string res;
- if (!th->readUTF(res))
- {
- throwError<ArgumentError>(kEOFError);
- }
-
- return Class<ASString>::getInstanceS(res);
-}
-
-ASFUNCTIONBODY(ByteArray,readUTFBytes)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- uint32_t length;
-
- ARG_UNPACK (length);
- if(th->position+length > th->len)
- {
- throwError<ArgumentError>(kEOFError);
- }
-
- uint8_t *bufStart=th->bytes+th->position;
- th->position+=length;
- return Class<ASString>::getInstanceS((char *)bufStart,length);
-}
-
-void ByteArray::writeUTF(const tiny_string& str)
-{
- getBuffer(position+str.numBytes()+2,true);
- if(str.numBytes() > 65535)
- {
- throwError<RangeError>(kParamRangeError);
- }
- uint16_t numBytes=endianIn((uint16_t)str.numBytes());
- memcpy(bytes+position,&numBytes,2);
- memcpy(bytes+position+2,str.raw_buf(),str.numBytes());
- position+=str.numBytes()+2;
-}
-
-ASFUNCTIONBODY(ByteArray,writeUTF)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- //Validate parameters
- assert_and_throw(argslen==1);
- assert_and_throw(args[0]->getObjectType()==T_STRING);
- ASString* str=Class<ASString>::cast(args[0]);
- th->writeUTF(str->data);
- return NULL;
-}
-
-ASFUNCTIONBODY(ByteArray,writeUTFBytes)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- //Validate parameters
- assert_and_throw(argslen==1);
- assert_and_throw(args[0]->getObjectType()==T_STRING);
- ASString* str=Class<ASString>::cast(args[0]);
- th->getBuffer(th->position+str->data.numBytes(),true);
- memcpy(th->bytes+th->position,str->data.raw_buf(),str->data.numBytes());
- th->position+=str->data.numBytes();
-
- return NULL;
-}
-
-ASFUNCTIONBODY(ByteArray,writeMultiByte)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- tiny_string value;
- tiny_string charset;
- ARG_UNPACK(value)(charset);
-
- // TODO: should convert from UTF-8 to charset
- LOG(LOG_NOT_IMPLEMENTED, "ByteArray.writeMultiByte doesn't convert charset");
-
- th->getBuffer(th->position+value.numBytes(),true);
- memcpy(th->bytes+th->position,value.raw_buf(),value.numBytes());
- th->position+=value.numBytes();
-
- return NULL;
-}
-
-uint32_t ByteArray::writeObject(ASObject* obj)
-{
- //Return the length of the serialized object
-
- //TODO: support AMF0
- assert_and_throw(objectEncoding==ObjectEncoding::AMF3);
- //TODO: support custom serialization
- map<tiny_string, uint32_t> stringMap;
- map<const ASObject*, uint32_t> objMap;
- map<const Class_base*, uint32_t> traitsMap;
- uint32_t oldPosition=position;
- obj->serialize(this, stringMap, objMap,traitsMap);
- return position-oldPosition;
-}
-
-ASFUNCTIONBODY(ByteArray,writeObject)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- //Validate parameters
- assert_and_throw(argslen==1);
- th->writeObject(args[0]);
-
- return NULL;
-}
-
-void ByteArray::writeShort(uint16_t val)
-{
- int16_t value2 = endianIn(val);
- getBuffer(position+2,true);
- memcpy(bytes+position,&value2,2);
- position+=2;
-}
-
-ASFUNCTIONBODY(ByteArray,writeShort)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- int32_t value;
- ARG_UNPACK(value);
-
- th->writeShort((static_cast<uint16_t>(value & 0xffff)));
- return NULL;
-}
-
-ASFUNCTIONBODY(ByteArray,writeBytes)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- //Validate parameters
- assert_and_throw(argslen>=1 && argslen<=3);
- assert_and_throw(args[0]->getClass()->isSubClass(Class<ByteArray>::getClass()));
- ByteArray* out=Class<ByteArray>::cast(args[0]);
- uint32_t offset=0;
- uint32_t length=0;
- if(argslen>=2)
- offset=args[1]->toUInt();
- if(argslen==3)
- length=args[2]->toUInt();
-
- // We need to clamp offset to the beginning of the bytes array
- if(offset > out->getLength()-1)
- offset = 0;
- // We need to clamp length to the end of the bytes array
- if(length > out->getLength()-offset)
- length = 0;
-
- //If the length is 0 the whole buffer must be copied
- if(length == 0)
- length=(out->getLength()-offset);
- uint8_t* buf=out->getBuffer(offset+length,false);
- th->getBuffer(th->position+length,true);
- memcpy(th->bytes+th->position,buf+offset,length);
- th->position+=length;
-
- return NULL;
-}
-
-void ByteArray::writeByte(uint8_t b)
-{
- getBuffer(position+1,true);
- bytes[position++] = b;
-}
-
-ASFUNCTIONBODY(ByteArray,writeByte)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- assert_and_throw(argslen==1);
-
- int32_t value=args[0]->toInt();
-
- th->writeByte(value&0xff);
-
- return NULL;
-}
-
-ASFUNCTIONBODY(ByteArray,writeBoolean)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- bool b;
- ARG_UNPACK (b);
-
- if (b)
- th->writeByte(1);
- else
- th->writeByte(0);
-
- return NULL;
-}
-
-ASFUNCTIONBODY(ByteArray,writeDouble)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- assert_and_throw(argslen==1);
-
- double value = args[0]->toNumber();
- uint64_t *intptr=reinterpret_cast<uint64_t*>(&value);
- uint64_t value2=th->endianIn(*intptr);
-
- th->getBuffer(th->position+8,true);
- memcpy(th->bytes+th->position,&value2,8);
- th->position+=8;
-
- return NULL;
-}
-
-ASFUNCTIONBODY(ByteArray,writeFloat)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- assert_and_throw(argslen==1);
-
- float value = args[0]->toNumber();
- uint32_t *intptr=reinterpret_cast<uint32_t*>(&value);
- uint32_t value2=th->endianIn(*intptr);
-
- th->getBuffer(th->position+4,true);
- memcpy(th->bytes+th->position,&value2,4);
- th->position+=4;
-
- return NULL;
-}
-
-ASFUNCTIONBODY(ByteArray,writeInt)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- assert_and_throw(argslen==1);
-
- uint32_t value=th->endianIn(static_cast<uint32_t>(args[0]->toInt()));
-
- th->getBuffer(th->position+4,true);
- memcpy(th->bytes+th->position,&value,4);
- th->position+=4;
-
- return NULL;
-}
-
-void ByteArray::writeUnsignedInt(uint32_t val)
-{
- getBuffer(position+4,true);
- memcpy(bytes+position,&val,4);
- position+=4;
-}
-
-ASFUNCTIONBODY(ByteArray,writeUnsignedInt)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- assert_and_throw(argslen==1);
-
- uint32_t value=th->endianIn(args[0]->toUInt());
- th->writeUnsignedInt(value);
- return NULL;
-}
-
-bool ByteArray::readByte(uint8_t& b)
-{
- if (len <= position)
- return false;
-
- b=bytes[position++];
- return true;
-}
-
-bool ByteArray::readU29(uint32_t& ret)
-{
- //Be careful! This is different from u32 parsing.
- //Here the most significant bits appears before in the stream!
- ret=0;
- for(uint32_t i=0;i<4;i++)
- {
- if (len <= position)
- return false;
-
- uint8_t tmp=bytes[position++];
- ret <<= 7;
- if(i<3)
- {
- ret |= tmp&0x7f;
- if((tmp&0x80)==0)
- break;
- }
- else
- {
- ret |= tmp;
- //Sign extend
- if(tmp&0x80)
- ret|=0xe0000000;
- }
- }
- return true;
-}
-
-ASFUNCTIONBODY(ByteArray, readByte)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- assert_and_throw(argslen==0);
-
- uint8_t ret;
- if(!th->readByte(ret))
- {
- throwError<ArgumentError>(kEOFError);
- }
- return abstract_i((int8_t)ret);
-}
-
-ASFUNCTIONBODY(ByteArray,readDouble)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- assert_and_throw(argslen==0);
-
- if(th->len < th->position+8)
- {
- throwError<ArgumentError>(kEOFError);
- }
-
- uint64_t ret;
- memcpy(&ret,th->bytes+th->position,8);
- th->position+=8;
- ret = th->endianOut(ret);
-
- double *doubleptr=reinterpret_cast<double*>(&ret);
- return abstract_d(*doubleptr);
-}
-
-ASFUNCTIONBODY(ByteArray,readFloat)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- assert_and_throw(argslen==0);
-
- if(th->len < th->position+4)
- {
- throwError<ArgumentError>(kEOFError);
- }
-
- uint32_t ret;
- memcpy(&ret,th->bytes+th->position,4);
- th->position+=4;
- ret = th->endianOut(ret);
-
- float *floatptr=reinterpret_cast<float*>(&ret);
- return abstract_d(*floatptr);
-}
-
-ASFUNCTIONBODY(ByteArray,readInt)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- assert_and_throw(argslen==0);
-
- if(th->len < th->position+4)
- {
- throwError<ArgumentError>(kEOFError);
- }
-
- uint32_t ret;
- memcpy(&ret,th->bytes+th->position,4);
- th->position+=4;
-
- return abstract_i((int32_t)th->endianOut(ret));
-}
-
-bool ByteArray::readShort(uint16_t& ret)
-{
- if (len < position+2)
- return false;
-
- uint16_t tmp;
- memcpy(&tmp,bytes+position,2);
- ret=endianOut(tmp);
- position+=2;
- return true;
-}
-
-ASFUNCTIONBODY(ByteArray,readShort)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- assert_and_throw(argslen==0);
-
- uint16_t ret;
- if(!th->readShort(ret))
- {
- throwError<ArgumentError>(kEOFError);
- }
-
- return abstract_i((int16_t)ret);
-}
-
-ASFUNCTIONBODY(ByteArray,readUnsignedByte)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- assert_and_throw(argslen==0);
-
- uint8_t ret;
- if (!th->readByte(ret))
- {
- throwError<ArgumentError>(kEOFError);
- }
- return abstract_ui(ret);
-}
-
-bool ByteArray::readUnsignedInt(uint32_t& ret)
-{
- if(len < position+4)
- return false;
-
- uint32_t tmp;
- memcpy(&tmp,bytes+position,4);
- ret=endianOut(tmp);
- position+=4;
- return true;
-}
-
-ASFUNCTIONBODY(ByteArray,readUnsignedInt)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- assert_and_throw(argslen==0);
-
- uint32_t ret;
- if(!th->readUnsignedInt(ret))
- throwError<ArgumentError>(kEOFError);
-
- return abstract_ui(ret);
-}
-
-ASFUNCTIONBODY(ByteArray,readUnsignedShort)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- assert_and_throw(argslen==0);
-
- uint16_t ret;
- if(!th->readShort(ret))
- {
- throwError<ArgumentError>(kEOFError);
- }
-
- return abstract_ui(ret);
-}
-
-ASFUNCTIONBODY(ByteArray,readMultiByte)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- uint32_t strlen;
- tiny_string charset;
- ARG_UNPACK(strlen)(charset);
-
- if(th->len < th->position+strlen)
- {
- throwError<ArgumentError>(kEOFError);
- }
-
- // TODO: should convert from charset to UTF-8
- LOG(LOG_NOT_IMPLEMENTED, "ByteArray.readMultiByte doesn't convert charset");
- return Class<ASString>::getInstanceS((char*)th->bytes+th->position,strlen);
-}
-
-ASFUNCTIONBODY(ByteArray,readObject)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- assert_and_throw(argslen==0);
- if(th->bytes==NULL)
- {
- throwError<ArgumentError>(kEOFError);
- }
- assert_and_throw(th->objectEncoding==ObjectEncoding::AMF3);
- Amf3Deserializer d(th);
- _NR<ASObject> ret(NullRef);
- try
- {
- ret=d.readObject();
- }
- catch(LightsparkException& e)
- {
- LOG(LOG_ERROR,"Exception caught while parsing AMF3: " << e.cause);
- //TODO: throw AS exception
- }
-
- if(ret.isNull())
- {
- LOG(LOG_ERROR,"No objects in the AMF3 data. Returning Undefined");
- return getSys()->getUndefinedRef();
- }
- ret->incRef();
- return ret.getPtr();
-}
-
-ASFUNCTIONBODY(ByteArray,_toString)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- //TODO: check for Byte Order Mark
- return Class<ASString>::getInstanceS((char*)th->bytes,th->len);
-}
-
-bool ByteArray::hasPropertyByMultiname(const multiname& name, bool considerDynamic, bool considerPrototype)
-{
- if(considerDynamic==false)
- return ASObject::hasPropertyByMultiname(name, considerDynamic, considerPrototype);
-
- unsigned int index=0;
- if(!Array::isValidMultiname(name,index))
- return ASObject::hasPropertyByMultiname(name, considerDynamic, considerPrototype);
-
- return index<len;
-}
-
-_NR<ASObject> ByteArray::getVariableByMultiname(const multiname& name, GET_VARIABLE_OPTION opt)
-{
- assert_and_throw(implEnable);
- unsigned int index=0;
- if((opt & ASObject::SKIP_IMPL)!=0 || !Array::isValidMultiname(name,index))
- return ASObject::getVariableByMultiname(name,opt);
-
- if(index<len)
- {
- uint8_t value = bytes[index];
- return _MNR(abstract_ui(static_cast<uint32_t>(value)));
- }
- else
- return _MNR(getSys()->getUndefinedRef());
-}
-
-int32_t ByteArray::getVariableByMultiname_i(const multiname& name)
-{
- assert_and_throw(implEnable);
- unsigned int index=0;
- if(!Array::isValidMultiname(name,index))
- return ASObject::getVariableByMultiname_i(name);
-
- if(index<len)
- {
- uint8_t value = bytes[index];
- return static_cast<uint32_t>(value);
- }
- else
- return _MNR(getSys()->getUndefinedRef());
-}
-
-void ByteArray::setVariableByMultiname(const multiname& name, ASObject* o, CONST_ALLOWED_FLAG allowConst)
-{
- assert_and_throw(implEnable);
- unsigned int index=0;
- if(!Array::isValidMultiname(name,index))
- return ASObject::setVariableByMultiname(name,o,allowConst);
-
- if(index>=len)
- {
- uint32_t prevLen = len;
- getBuffer(index+1, true);
- // Fill the gap between the end of the current data and the index with zeros
- memset(bytes+prevLen, 0, index-prevLen);
- }
-
- // Fill the byte pointed to by index with the truncated uint value of the object.
- uint8_t value = static_cast<uint8_t>(o->toUInt() & 0xff);
- bytes[index] = value;
-
- o->decRef();
-}
-
-void ByteArray::setVariableByMultiname_i(const multiname& name, int32_t value)
-{
- setVariableByMultiname(name, abstract_i(value),ASObject::CONST_NOT_ALLOWED);
-}
-
-void ByteArray::acquireBuffer(uint8_t* buf, int bufLen)
-{
- if(bytes)
- {
-#ifdef MEMORY_USAGE_PROFILING
- getClass()->memoryAccount->removeBytes(real_len);
-#endif
- free(bytes);
- }
- bytes=buf;
- real_len=bufLen;
- len=bufLen;
-#ifdef MEMORY_USAGE_PROFILING
- getClass()->memoryAccount->addBytes(real_len);
-#endif
- position=0;
-}
-
-void ByteArray::writeU29(uint32_t val)
-{
- for(uint32_t i=0;i<4;i++)
- {
- uint8_t b;
- if(i<3)
- {
- uint32_t tmp=(val >> ((3-i)*7));
- if(tmp==0)
- continue;
-
- b=(tmp&0x7f)|0x80;
- }
- else
- b=val&0x7f;
-
- writeByte(b);
- }
-}
-
-void ByteArray::writeStringVR(map<tiny_string, uint32_t>& stringMap, const tiny_string& s)
-{
- const uint32_t len=s.numBytes();
- if(len >= 1<<28)
- throwError<RangeError>(kParamRangeError);
-
- //Check if the string is already in the map
- auto it=stringMap.find(s);
- if(it!=stringMap.end())
- {
- //The first bit must be 0, the next 29 bits
- //store the index of the string in the map
- writeU29(it->second << 1);
- }
- else
- {
- //The AMF3 spec says that the empty string is never sent by reference
- //So add the string to the map only if it's not the empty string
- if(len)
- stringMap.insert(make_pair(s, stringMap.size()));
-
- //The first bit must be 1, the next 29 bits
- //store the number of bytes of the string
- writeU29((len<<1) | 1);
-
- getBuffer(position+len,true);
- memcpy(bytes+position,s.raw_buf(),len);
- position+=len;
- }
-}
-
-void ByteArray::writeXMLString(std::map<const ASObject*, uint32_t>& objMap,
- ASObject *xml,
- const tiny_string& xmlstr)
-{
- if(xmlstr.numBytes() >= 1<<28)
- throwError<RangeError>(kParamRangeError);
-
- //Check if the XML object has been already serialized
- auto it=objMap.find(xml);
- if(it!=objMap.end())
- {
- //The least significant bit is 0 to signal a reference
- writeU29(it->second << 1);
- }
- else
- {
- //Add the XML object to the map
- objMap.insert(make_pair(xml, objMap.size()));
-
- //The first bit must be 1, the next 29 bits
- //store the number of bytes of the string
- writeU29((xmlstr.numBytes()<<1) | 1);
-
- getBuffer(position+xmlstr.numBytes(),true);
- memcpy(bytes+position,xmlstr.raw_buf(),xmlstr.numBytes());
- position+=xmlstr.numBytes();
- }
-}
-
-void ByteArray::compress_zlib()
-{
- if(len==0)
- return;
-
- unsigned long buflen=compressBound(len);
- uint8_t *compressed=(uint8_t*) malloc(buflen);
- assert_and_throw(compressed);
-
- if(compress(compressed, &buflen, bytes, len)!=Z_OK)
- {
- free(compressed);
- throw RunTimeException("zlib compress failed");
- }
-
- acquireBuffer(compressed, buflen);
- position=buflen;
-}
-
-void ByteArray::uncompress_zlib()
-{
- z_stream strm;
- int status;
-
- if(len==0)
- return;
-
- strm.zalloc=Z_NULL;
- strm.zfree=Z_NULL;
- strm.opaque=Z_NULL;
- strm.avail_in=len;
- strm.next_in=bytes;
- strm.total_out=0;
- status=inflateInit(&strm);
- if(status==Z_VERSION_ERROR)
- throw Class<IOError>::getInstanceS("not valid compressed data");
- else if(status!=Z_OK)
- throw RunTimeException("zlib uncompress failed");
-
- vector<uint8_t> buf(3*len);
- do
- {
- strm.next_out=&buf[strm.total_out];
- strm.avail_out=buf.size()-strm.total_out;
- status=inflate(&strm, Z_NO_FLUSH);
-
- if(status!=Z_OK && status!=Z_STREAM_END)
- {
- inflateEnd(&strm);
- throw Class<IOError>::getInstanceS("not valid compressed data");
- }
-
- if(strm.avail_out==0)
- buf.resize(buf.size()+len);
- } while(status!=Z_STREAM_END);
-
- inflateEnd(&strm);
-
- len=strm.total_out;
-#ifdef MEMORY_USAGE_PROFILING
- getClass()->memoryAccount->addBytes(len-real_len);
-#endif
- real_len = len;
- uint8_t* bytes2=(uint8_t*) realloc(bytes, len);
- assert_and_throw(bytes2);
- bytes = bytes2;
- memcpy(bytes, &buf[0], len);
- position=0;
-}
-
-ASFUNCTIONBODY(ByteArray,_compress)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- // flash throws an error if compress is called with a compression algorithm,
- // and always uses the zlib algorithm
- // but tamarin tests do not catch it, so we simply ignore any parameters provided
- th->compress_zlib();
- return NULL;
-}
-
-ASFUNCTIONBODY(ByteArray,_uncompress)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- // flash throws an error if uncompress is called with a compression algorithm,
- // and always uses the zlib algorithm
- // but tamarin tests do not catch it, so we simply ignore any parameters provided
- th->uncompress_zlib();
- return NULL;
-}
-
-ASFUNCTIONBODY(ByteArray,_deflate)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- th->compress_zlib();
- return NULL;
-}
-
-ASFUNCTIONBODY(ByteArray,_inflate)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- th->uncompress_zlib();
- return NULL;
-}
-
-ASFUNCTIONBODY(ByteArray,clear)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- if(th->bytes)
- {
-#ifdef MEMORY_USAGE_PROFILING
- th->getClass()->memoryAccount->removeBytes(th->real_len);
-#endif
- free(th->bytes);
- }
- th->bytes = NULL;
- th->len=0;
- th->real_len=0;
- th->position=0;
- return NULL;
-}
-
-void Timer::tick()
-{
- //This will be executed once if repeatCount was originally 1
- //Otherwise it's executed until stopMe is set to true
- this->incRef();
- getVm()->addEvent(_MR(this),_MR(Class<TimerEvent>::getInstanceS("timer")));
-
- currentCount++;
- if(repeatCount!=0)
- {
- if(currentCount==repeatCount)
- {
- this->incRef();
- getVm()->addEvent(_MR(this),_MR(Class<TimerEvent>::getInstanceS("timerComplete")));
- stopMe=true;
- running=false;
- }
- }
-}
-
-void Timer::tickFence()
-{
- tickJobInstance = NullRef;
-}
-
-// this seems to be how AS3 handles generic pop calls in Array class
-ASFUNCTIONBODY(ByteArray,pop)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- uint8_t res = 0;
- if (th->readByte(res))
- {
- memmove(th->bytes,(th->bytes+1),th->getLength()-1);
- th->len--;
- }
- return abstract_ui(res);
-
-}
-
-// this seems to be how AS3 handles generic push calls in Array class
-ASFUNCTIONBODY(ByteArray,push)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- th->getBuffer(th->len+argslen,true);
- for (unsigned int i = 0; i < argslen; i++)
- {
- th->bytes[th->len+i] = (uint8_t)args[i]->toInt();
- }
- return abstract_ui(th->getLength());
-}
-
-// this seems to be how AS3 handles generic shift calls in Array class
-ASFUNCTIONBODY(ByteArray,shift)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- uint8_t res = 0;
- if (th->readByte(res))
- {
- memmove(th->bytes,(th->bytes+1),th->getLength()-1);
- th->len--;
- }
- return abstract_ui(res);
-}
-
-// this seems to be how AS3 handles generic unshift calls in Array class
-ASFUNCTIONBODY(ByteArray,unshift)
-{
- ByteArray* th=static_cast<ByteArray*>(obj);
- th->getBuffer(th->len+argslen,true);
- for (unsigned int i = 0; i < argslen; i++)
- {
- memmove((th->bytes+argslen),(th->bytes),th->len);
- th->bytes[i] = (uint8_t)args[i]->toInt();
- }
- return abstract_ui(th->getLength());
-}
-
-void Timer::sinit(Class_base* c)
-{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<EventDispatcher>::getRef());
- c->setDeclaredMethodByQName("currentCount","",Class<IFunction>::getFunction(_getCurrentCount),GETTER_METHOD,true);
- c->setDeclaredMethodByQName("repeatCount","",Class<IFunction>::getFunction(_getRepeatCount),GETTER_METHOD,true);
- c->setDeclaredMethodByQName("repeatCount","",Class<IFunction>::getFunction(_setRepeatCount),SETTER_METHOD,true);
- c->setDeclaredMethodByQName("running","",Class<IFunction>::getFunction(_getRunning),GETTER_METHOD,true);
- c->setDeclaredMethodByQName("delay","",Class<IFunction>::getFunction(_getDelay),GETTER_METHOD,true);
- c->setDeclaredMethodByQName("delay","",Class<IFunction>::getFunction(_setDelay),SETTER_METHOD,true);
- c->setDeclaredMethodByQName("start","",Class<IFunction>::getFunction(start),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("reset","",Class<IFunction>::getFunction(reset),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("stop","",Class<IFunction>::getFunction(stop),NORMAL_METHOD,true);
-}
-
-ASFUNCTIONBODY(Timer,_constructor)
-{
- EventDispatcher::_constructor(obj,NULL,0);
- Timer* th=static_cast<Timer*>(obj);
-
- th->delay=args[0]->toInt();
- if(argslen>=2)
- th->repeatCount=args[1]->toInt();
-
- return NULL;
-}
-
-ASFUNCTIONBODY(Timer,_getCurrentCount)
-{
- Timer* th=static_cast<Timer*>(obj);
- return abstract_i(th->currentCount);
-}
-
-ASFUNCTIONBODY(Timer,_getRepeatCount)
-{
- Timer* th=static_cast<Timer*>(obj);
- return abstract_i(th->repeatCount);
-}
-
-ASFUNCTIONBODY(Timer,_setRepeatCount)
-{
- assert_and_throw(argslen==1);
- int32_t count=args[0]->toInt();
- Timer* th=static_cast<Timer*>(obj);
- th->repeatCount=count;
- if(th->repeatCount>0 && th->repeatCount<=th->currentCount)
- {
- getSys()->removeJob(th);
- th->running=false;
- th->tickJobInstance = NullRef;
- }
- return NULL;
-}
-
-ASFUNCTIONBODY(Timer,_getRunning)
-{
- Timer* th=static_cast<Timer*>(obj);
- return abstract_b(th->running);
-}
-
-ASFUNCTIONBODY(Timer,_getDelay)
-{
- Timer* th=static_cast<Timer*>(obj);
- return abstract_i(th->delay);
-}
-
-ASFUNCTIONBODY(Timer,_setDelay)
-{
- assert_and_throw(argslen==1);
- int32_t newdelay = args[0]->toInt();
- if (newdelay<=0)
- throw Class<RangeError>::getInstanceS("delay must be positive", 2066);
-
- Timer* th=static_cast<Timer*>(obj);
- th->delay=newdelay;
-
- return NULL;
-}
-
-ASFUNCTIONBODY(Timer,start)
-{
- Timer* th=static_cast<Timer*>(obj);
- if(th->running)
- return NULL;
- th->running=true;
- th->stopMe=false;
- th->incRef();
- th->tickJobInstance = _MNR(th);
- if(th->repeatCount==1)
- getSys()->addWait(th->delay,th);
- else
- getSys()->addTick(th->delay,th);
- return NULL;
-}
-
-ASFUNCTIONBODY(Timer,reset)
-{
- Timer* th=static_cast<Timer*>(obj);
- if(th->running)
- {
- //This spin waits if the timer is running right now
- getSys()->removeJob(th);
- //NOTE: although no new events will be sent now there might be old events in the queue.
- //Is this behaviour right?
- //This is not anymore used by the timer, so it can die
- th->tickJobInstance = NullRef;
- th->running=false;
- }
- th->currentCount=0;
- return NULL;
-}
-ASFUNCTIONBODY(Timer,stop)
-{
- Timer* th=static_cast<Timer*>(obj);
- if(th->running)
- {
- //This spin waits if the timer is running right now
- getSys()->removeJob(th);
- //NOTE: although no new events will be sent now there might be old events in the queue.
- //Is this behaviour right?
-
- //This is not anymore used by the timer, so it can die
- th->tickJobInstance = NullRef;
- th->running=false;
- }
- return NULL;
-}
ASFUNCTIONBODY(lightspark,getQualifiedClassName)
{
@@ -1492,11 +148,9 @@ ASFUNCTIONBODY(lightspark,getDefinitionByName)
ASObject* target;
ASObject* o=ABCVm::getCurrentApplicationDomain(getVm()->currentCallContext)->getVariableAndTargetByMultiname(name,target);
- //TODO: should raise an exception, for now just return undefined
if(o==NULL)
{
- LOG(LOG_ERROR,_("Definition for '") << name << _("' not found."));
- return getSys()->getUndefinedRef();
+ throwError<ReferenceError>(kClassNotFoundError, tmp);
}
assert_and_throw(o->getObjectType()==T_CLASS);
@@ -1518,430 +172,6 @@ ASFUNCTIONBODY(lightspark,getTimer)
return abstract_i(ret);
}
-Dictionary::Dictionary(Class_base* c):ASObject(c),
- data(std::less<dictType::key_type>(), reporter_allocator<dictType::value_type>(c->memoryAccount))
-{
-}
-
-void Dictionary::finalize()
-{
- ASObject::finalize();
- data.clear();
-}
-
-void Dictionary::sinit(Class_base* c)
-{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASObject>::getRef());
-}
-
-void Dictionary::buildTraits(ASObject* o)
-{
-}
-
-ASFUNCTIONBODY(Dictionary,_constructor)
-{
- return NULL;
-}
-
-Dictionary::dictType::iterator Dictionary::findKey(ASObject *o)
-{
- Dictionary::dictType::iterator it = data.begin();
- for(; it!=data.end(); ++it)
- {
- if (it->first->isEqualStrict(o))
- return it;
- }
-
- return data.end();
-}
-
-void Dictionary::setVariableByMultiname_i(const multiname& name, int32_t value)
-{
- assert_and_throw(implEnable);
- Dictionary::setVariableByMultiname(name,abstract_i(value),CONST_NOT_ALLOWED);
-}
-
-void Dictionary::setVariableByMultiname(const multiname& name, ASObject* o, CONST_ALLOWED_FLAG allowConst)
-{
- assert_and_throw(implEnable);
- if(name.name_type==multiname::NAME_OBJECT)
- {
- name.name_o->incRef();
- _R<ASObject> name_o(name.name_o);
-
- Dictionary::dictType::iterator it=findKey(name_o.getPtr());
- if(it!=data.end())
- it->second=_MR(o);
- else
- data.insert(make_pair(name_o,_MR(o)));
- }
- else
- {
- //Primitive types _must_ be handled by the normal ASObject path
- //REFERENCE: Dictionary Object on AS3 reference
- assert(name.name_type==multiname::NAME_STRING ||
- name.name_type==multiname::NAME_INT ||
- name.name_type==multiname::NAME_NUMBER);
- ASObject::setVariableByMultiname(name, o, allowConst);
- }
-}
-
-bool Dictionary::deleteVariableByMultiname(const multiname& name)
-{
- assert_and_throw(implEnable);
-
- if(name.name_type==multiname::NAME_OBJECT)
- {
- name.name_o->incRef();
- _R<ASObject> name_o(name.name_o);
-
- Dictionary::dictType::iterator it=findKey(name_o.getPtr());
- if(it != data.end())
- {
- data.erase(it);
- return true;
- }
- return false;
- }
- else
- {
- //Primitive types _must_ be handled by the normal ASObject path
- //REFERENCE: Dictionary Object on AS3 reference
- assert(name.name_type==multiname::NAME_STRING ||
- name.name_type==multiname::NAME_INT ||
- name.name_type==multiname::NAME_NUMBER);
- return ASObject::deleteVariableByMultiname(name);
- }
-}
-
-_NR<ASObject> Dictionary::getVariableByMultiname(const multiname& name, GET_VARIABLE_OPTION opt)
-{
- if((opt & ASObject::SKIP_IMPL)==0 && implEnable)
- {
- if(name.name_type==multiname::NAME_OBJECT)
- {
- name.name_o->incRef();
- _R<ASObject> name_o(name.name_o);
-
- Dictionary::dictType::iterator it=findKey(name_o.getPtr());
- if(it != data.end())
- return it->second;
- else
- return NullRef;
- }
- else
- {
- //Primitive types _must_ be handled by the normal ASObject path
- //REFERENCE: Dictionary Object on AS3 reference
- assert(name.name_type==multiname::NAME_STRING ||
- name.name_type==multiname::NAME_INT ||
- name.name_type==multiname::NAME_NUMBER);
- return ASObject::getVariableByMultiname(name, opt);
- }
- }
- //Try with the base implementation
- return ASObject::getVariableByMultiname(name, opt);
-}
-
-bool Dictionary::hasPropertyByMultiname(const multiname& name, bool considerDynamic, bool considerPrototype)
-{
- if(considerDynamic==false)
- return ASObject::hasPropertyByMultiname(name, considerDynamic, considerPrototype);
-
- if(name.name_type==multiname::NAME_OBJECT)
- {
- name.name_o->incRef();
- _R<ASObject> name_o(name.name_o);
-
- Dictionary::dictType::iterator it=findKey(name_o.getPtr());
- return it != data.end();
- }
- else
- {
- //Primitive types _must_ be handled by the normal ASObject path
- //REFERENCE: Dictionary Object on AS3 reference
- assert(name.name_type==multiname::NAME_STRING ||
- name.name_type==multiname::NAME_INT ||
- name.name_type==multiname::NAME_NUMBER);
- return ASObject::hasPropertyByMultiname(name, considerDynamic, considerPrototype);
- }
-}
-
-uint32_t Dictionary::nextNameIndex(uint32_t cur_index)
-{
- assert_and_throw(implEnable);
- if(cur_index<data.size())
- return cur_index+1;
- else
- {
- //Fall back on object properties
- uint32_t ret=ASObject::nextNameIndex(cur_index-data.size());
- if(ret==0)
- return 0;
- else
- return ret+data.size();
-
- }
-}
-
-_R<ASObject> Dictionary::nextName(uint32_t index)
-{
- assert_and_throw(implEnable);
- if(index<=data.size())
- {
- map<_R<ASObject>,_R<ASObject> >::iterator it=data.begin();
- for(unsigned int i=1;i<index;i++)
- ++it;
-
- return it->first;
- }
- else
- {
- //Fall back on object properties
- return ASObject::nextName(index-data.size());
- }
-}
-
-_R<ASObject> Dictionary::nextValue(uint32_t index)
-{
- assert_and_throw(implEnable);
- if(index<=data.size())
- {
- map<_R<ASObject>,_R<ASObject> >::iterator it=data.begin();
- for(unsigned int i=1;i<index;i++)
- ++it;
-
- return it->second;
- }
- else
- {
- //Fall back on object properties
- return ASObject::nextValue(index-data.size());
- }
-}
-
-tiny_string Dictionary::toString()
-{
- std::stringstream retstr;
- retstr << "{";
- map<_R<ASObject>,_R<ASObject> >::iterator it=data.begin();
- while(it != data.end())
- {
- if(it != data.begin())
- retstr << ", ";
- retstr << "{" << it->first->toString() << ", " << it->second->toString() << "}";
- ++it;
- }
- retstr << "}";
-
- return retstr.str();
-}
-
-void Proxy::sinit(Class_base* c)
-{
- //c->constructor=Class<IFunction>::getFunction(_constructor);
- c->setConstructor(NULL);
-}
-
-void Proxy::buildTraits(ASObject* o)
-{
-}
-
-void Proxy::setVariableByMultiname(const multiname& name, ASObject* o, CONST_ALLOWED_FLAG allowConst)
-{
- //If a variable named like this already exist, use that
- if(ASObject::hasPropertyByMultiname(name, true, false) || !implEnable)
- {
- ASObject::setVariableByMultiname(name,o,allowConst);
- return;
- }
-
- //Check if there is a custom setter defined, skipping implementation to avoid recursive calls
- multiname setPropertyName(NULL);
- setPropertyName.name_type=multiname::NAME_STRING;
- setPropertyName.name_s_id=getSys()->getUniqueStringId("setProperty");
- setPropertyName.ns.push_back(nsNameAndKind(flash_proxy,NAMESPACE));
- _NR<ASObject> proxySetter=getVariableByMultiname(setPropertyName,ASObject::SKIP_IMPL);
-
- if(proxySetter.isNull())
- {
- ASObject::setVariableByMultiname(name,o,allowConst);
- return;
- }
-
- assert_and_throw(proxySetter->getObjectType()==T_FUNCTION);
-
- IFunction* f=static_cast<IFunction*>(proxySetter.getPtr());
-
- //Well, I don't how to pass multiname to an as function. I'll just pass the name as a string
- ASObject* args[2];
- args[0]=Class<ASString>::getInstanceS(name.normalizedName());
- args[1]=o;
- //We now suppress special handling
- implEnable=false;
- LOG(LOG_CALLS,_("Proxy::setProperty"));
- incRef();
- _R<ASObject> ret=_MR( f->call(this,args,2) );
- assert_and_throw(ret->is<Undefined>());
- implEnable=true;
-}
-
-_NR<ASObject> Proxy::getVariableByMultiname(const multiname& name, GET_VARIABLE_OPTION opt)
-{
- //It seems that various kind of implementation works only with the empty namespace
- assert_and_throw(name.ns.size()>0);
- if(!name.ns[0].hasEmptyName() || ASObject::hasPropertyByMultiname(name, true, true) || !implEnable || (opt & ASObject::SKIP_IMPL)!=0)
- return ASObject::getVariableByMultiname(name,opt);
-
- //Check if there is a custom getter defined, skipping implementation to avoid recursive calls
- multiname getPropertyName(NULL);
- getPropertyName.name_type=multiname::NAME_STRING;
- getPropertyName.name_s_id=getSys()->getUniqueStringId("getProperty");
- getPropertyName.ns.push_back(nsNameAndKind(flash_proxy,NAMESPACE));
- _NR<ASObject> o=getVariableByMultiname(getPropertyName,ASObject::SKIP_IMPL);
-
- if(o.isNull())
- return ASObject::getVariableByMultiname(name,opt);
-
- assert_and_throw(o->getObjectType()==T_FUNCTION);
-
- IFunction* f=static_cast<IFunction*>(o.getPtr());
-
- //Well, I don't how to pass multiname to an as function. I'll just pass the name as a string
- ASObject* arg=Class<ASString>::getInstanceS(name.normalizedName());
- //We now suppress special handling
- implEnable=false;
- LOG(LOG_CALLS,"Proxy::getProperty");
- incRef();
- _NR<ASObject> ret=_MNR(f->call(this,&arg,1));
- implEnable=true;
- return ret;
-}
-
-bool Proxy::hasPropertyByMultiname(const multiname& name, bool considerDynamic, bool considerPrototype)
-{
- //If a variable named like this already exist, use that
- bool asobject_has_property=ASObject::hasPropertyByMultiname(name, considerDynamic, considerPrototype);
- if(asobject_has_property || !implEnable)
- return asobject_has_property;
-
- //Check if there is a custom hasProperty defined, skipping implementation to avoid recursive calls
- multiname hasPropertyName(NULL);
- hasPropertyName.name_type=multiname::NAME_STRING;
- hasPropertyName.name_s_id=getSys()->getUniqueStringId("hasProperty");
- hasPropertyName.ns.push_back(nsNameAndKind(flash_proxy,NAMESPACE));
- _NR<ASObject> proxyHasProperty=getVariableByMultiname(hasPropertyName,ASObject::SKIP_IMPL);
-
- if(proxyHasProperty.isNull())
- {
- return false;
- }
-
- assert_and_throw(proxyHasProperty->getObjectType()==T_FUNCTION);
-
- IFunction* f=static_cast<IFunction*>(proxyHasProperty.getPtr());
-
- //Well, I don't how to pass multiname to an as function. I'll just pass the name as a string
- ASObject* arg=Class<ASString>::getInstanceS(name.normalizedName());
- //We now suppress special handling
- implEnable=false;
- LOG(LOG_CALLS,_("Proxy::hasProperty"));
- incRef();
- _NR<ASObject> ret=_MNR(f->call(this,&arg,1));
- implEnable=true;
- Boolean* b = static_cast<Boolean*>(ret.getPtr());
- return b->val;
-}
-bool Proxy::deleteVariableByMultiname(const multiname& name)
-{
- //If a variable named like this already exist, use that
- if(ASObject::hasPropertyByMultiname(name, true, false) || !implEnable)
- {
- return ASObject::deleteVariableByMultiname(name);
- }
-
- //Check if there is a custom deleter defined, skipping implementation to avoid recursive calls
- multiname deletePropertyName(NULL);
- deletePropertyName.name_type=multiname::NAME_STRING;
- deletePropertyName.name_s_id=getSys()->getUniqueStringId("deleteProperty");
- deletePropertyName.ns.push_back(nsNameAndKind(flash_proxy,NAMESPACE));
- _NR<ASObject> proxyDeleter=getVariableByMultiname(deletePropertyName,ASObject::SKIP_IMPL);
-
- if(proxyDeleter.isNull())
- {
- return ASObject::deleteVariableByMultiname(name);
- }
-
- assert_and_throw(proxyDeleter->getObjectType()==T_FUNCTION);
-
- IFunction* f=static_cast<IFunction*>(proxyDeleter.getPtr());
-
- //Well, I don't how to pass multiname to an as function. I'll just pass the name as a string
- ASObject* arg=Class<ASString>::getInstanceS(name.normalizedName());
- //We now suppress special handling
- implEnable=false;
- LOG(LOG_CALLS,_("Proxy::deleteProperty"));
- incRef();
- _NR<ASObject> ret=_MNR(f->call(this,&arg,1));
- implEnable=true;
- Boolean* b = static_cast<Boolean*>(ret.getPtr());
- return b->val;
-}
-
-uint32_t Proxy::nextNameIndex(uint32_t cur_index)
-{
- assert_and_throw(implEnable);
- LOG(LOG_CALLS,"Proxy::nextNameIndex");
- //Check if there is a custom enumerator, skipping implementation to avoid recursive calls
- multiname nextNameIndexName(NULL);
- nextNameIndexName.name_type=multiname::NAME_STRING;
- nextNameIndexName.name_s_id=getSys()->getUniqueStringId("nextNameIndex");
- nextNameIndexName.ns.push_back(nsNameAndKind(flash_proxy,NAMESPACE));
- _NR<ASObject> o=getVariableByMultiname(nextNameIndexName,ASObject::SKIP_IMPL);
- assert_and_throw(!o.isNull() && o->getObjectType()==T_FUNCTION);
- IFunction* f=static_cast<IFunction*>(o.getPtr());
- ASObject* arg=abstract_i(cur_index);
- this->incRef();
- ASObject* ret=f->call(this,&arg,1);
- uint32_t newIndex=ret->toInt();
- ret->decRef();
- return newIndex;
-}
-
-_R<ASObject> Proxy::nextName(uint32_t index)
-{
- assert_and_throw(implEnable);
- LOG(LOG_CALLS, _("Proxy::nextName"));
- //Check if there is a custom enumerator, skipping implementation to avoid recursive calls
- multiname nextNameName(NULL);
- nextNameName.name_type=multiname::NAME_STRING;
- nextNameName.name_s_id=getSys()->getUniqueStringId("nextName");
- nextNameName.ns.push_back(nsNameAndKind(flash_proxy,NAMESPACE));
- _NR<ASObject> o=getVariableByMultiname(nextNameName,ASObject::SKIP_IMPL);
- assert_and_throw(!o.isNull() && o->getObjectType()==T_FUNCTION);
- IFunction* f=static_cast<IFunction*>(o.getPtr());
- ASObject* arg=abstract_i(index);
- incRef();
- return _MR(f->call(this,&arg,1));
-}
-
-_R<ASObject> Proxy::nextValue(uint32_t index)
-{
- assert_and_throw(implEnable);
- LOG(LOG_CALLS, _("Proxy::nextValue"));
- //Check if there is a custom enumerator, skipping implementation to avoid recursive calls
- multiname nextValueName(NULL);
- nextValueName.name_type=multiname::NAME_STRING;
- nextValueName.name_s_id=getSys()->getUniqueStringId("nextValue");
- nextValueName.ns.push_back(nsNameAndKind(flash_proxy,NAMESPACE));
- _NR<ASObject> o=getVariableByMultiname(nextValueName,ASObject::SKIP_IMPL);
- assert_and_throw(!o.isNull() && o->getObjectType()==T_FUNCTION);
- IFunction* f=static_cast<IFunction*>(o.getPtr());
- ASObject* arg=abstract_i(index);
- incRef();
- return _MR(f->call(this,&arg,1));
-}
ASFUNCTIONBODY(lightspark,setInterval)
{
@@ -2003,117 +233,15 @@ ASFUNCTIONBODY(lightspark,clearTimeout)
return NULL;
}
-IntervalRunner::IntervalRunner(IntervalRunner::INTERVALTYPE _type, uint32_t _id, _R<IFunction> _callback, ASObject** _args,
- const unsigned int _argslen, _R<ASObject> _obj, uint32_t _interval):
- EventDispatcher(NULL),type(_type), id(_id), callback(_callback),obj(_obj),argslen(_argslen),interval(_interval)
-{
- args = new ASObject*[argslen];
- for(uint32_t i=0; i<argslen; i++)
- args[i] = _args[i];
-}
-
-IntervalRunner::~IntervalRunner()
-{
- for(uint32_t i=0; i<argslen; i++)
- args[i]->decRef();
- delete[] args;
-}
-
-void IntervalRunner::tick()
-{
- //incRef all arguments
- uint32_t i;
- for(i=0; i < argslen; i++)
- {
- args[i]->incRef();
- }
- _R<FunctionEvent> event(new (getSys()->unaccountedMemory) FunctionEvent(callback, obj, args, argslen));
- getVm()->addEvent(NullRef,event);
- if(type == TIMEOUT)
- {
- //TODO: IntervalRunner deletes itself. Is this allowed?
- //Delete ourselves from the active intervals list
- getSys()->intervalManager->clearInterval(id, TIMEOUT, false);
- //No actions may be performed after this point
- }
-}
-
-void IntervalRunner::tickFence()
-{
- delete this;
-}
-
-IntervalManager::IntervalManager() : currentID(1)
-{
-}
-
-IntervalManager::~IntervalManager()
-{
- //Run through all running intervals and remove their tickjob, delete their intervalRunner and erase their entry
- std::map<uint32_t,IntervalRunner*>::iterator it = runners.begin();
- while(it != runners.end())
- {
- getSys()->removeJob((*it).second);
- runners.erase(it++);
- }
-}
-
-uint32_t IntervalManager::setInterval(_R<IFunction> callback, ASObject** args, const unsigned int argslen, _R<ASObject> obj, uint32_t interval)
-{
- Mutex::Lock l(mutex);
-
- uint32_t id = getFreeID();
- IntervalRunner* runner = new (getSys()->unaccountedMemory)
- IntervalRunner(IntervalRunner::INTERVAL, id, callback, args, argslen, obj, interval);
-
- //Add runner as tickjob
- getSys()->addTick(interval, runner);
- //Add runner to map
- runners[id] = runner;
- //Increment currentID
- currentID++;
-
- return currentID-1;
-}
-uint32_t IntervalManager::setTimeout(_R<IFunction> callback, ASObject** args, const unsigned int argslen, _R<ASObject> obj, uint32_t interval)
-{
- Mutex::Lock l(mutex);
-
- uint32_t id = getFreeID();
- IntervalRunner* runner = new (getSys()->unaccountedMemory)
- IntervalRunner(IntervalRunner::TIMEOUT, id, callback, args, argslen, obj, interval);
-
- //Add runner as waitjob
- getSys()->addWait(interval, runner);
- //Add runner to map
- runners[id] = runner;
- //increment currentID
- currentID++;
-
- return currentID-1;
-}
-
-uint32_t IntervalManager::getFreeID()
+ASFUNCTIONBODY(lightspark,escapeMultiByte)
{
- //At the first run every currentID will be available. But eventually the currentID will wrap around.
- //Thats why we need to check if the currentID isn't used yet
- while(currentID == 0 || runners.count(currentID) != 0)
- currentID++;
- return currentID;
+ tiny_string str;
+ ARG_UNPACK (str, "undefined");
+ return Class<ASString>::getInstanceS(URLInfo::encode(str, URLInfo::ENCODE_ESCAPE));
}
-
-void IntervalManager::clearInterval(uint32_t id, IntervalRunner::INTERVALTYPE type, bool removeJob)
+ASFUNCTIONBODY(lightspark,unescapeMultiByte)
{
- Mutex::Lock l(mutex);
-
- std::map<uint32_t,IntervalRunner*>::iterator it = runners.find(id);
- //If the entry exists and the types match, remove its tickjob, delete its intervalRunner and erase their entry
- if(it != runners.end() && (*it).second->getType() == type)
- {
- if(removeJob)
- {
- getSys()->removeJob((*it).second);
- }
- runners.erase(it);
- }
+ tiny_string str;
+ ARG_UNPACK (str, "undefined");
+ return Class<ASString>::getInstanceS(URLInfo::decode(str, URLInfo::ENCODE_ESCAPE));
}
diff --git a/src/scripting/flash/utils/flashutils.h b/src/scripting/flash/utils/flashutils.h
index 7b62359..29b4a47 100644
--- a/src/scripting/flash/utils/flashutils.h
+++ b/src/scripting/flash/utils/flashutils.h
@@ -22,11 +22,8 @@
#include "compat.h"
#include "swftypes.h"
-#include "scripting/flash/events/flashevents.h"
-#include "thread_pool.h"
-#include "timer.h"
+#include "asobject.h"
-#include <map>
namespace lightspark
{
@@ -59,203 +56,7 @@ public:
static void linkTraits(Class_base* c);
};
-class ByteArray: public ASObject, public IDataInput, public IDataOutput
-{
-friend class LoaderThread;
-friend class URLLoader;
-protected:
- bool littleEndian;
- uint8_t objectEncoding;
- uint32_t position;
- uint8_t* bytes;
- uint32_t real_len;
- uint32_t len;
- void compress_zlib();
- void uncompress_zlib();
-public:
- ByteArray(Class_base* c, uint8_t* b = NULL, uint32_t l = 0);
- ~ByteArray();
- //Helper interface for serialization
- bool readByte(uint8_t& b);
- bool readShort(uint16_t& ret);
- bool readUnsignedInt(uint32_t& ret);
- bool readU29(uint32_t& ret);
- bool readUTF(tiny_string& ret);
- void writeByte(uint8_t b);
- void writeShort(uint16_t val);
- void writeUnsignedInt(uint32_t val);
- void writeUTF(const tiny_string& str);
- uint32_t writeObject(ASObject* obj);
- void writeStringVR(std::map<tiny_string, uint32_t>& stringMap, const tiny_string& s);
- void writeXMLString(std::map<const ASObject*, uint32_t>& objMap, ASObject *xml, const tiny_string& s);
- void writeU29(uint32_t val);
- uint32_t getPosition() const;
- void setPosition(uint32_t p);
-
- ASFUNCTION(_getBytesAvailable);
- ASFUNCTION(_getLength);
- ASFUNCTION(_setLength);
- ASFUNCTION(_getPosition);
- ASFUNCTION(_setPosition);
- ASFUNCTION(_getEndian);
- ASFUNCTION(_setEndian);
- ASFUNCTION(_getObjectEncoding);
- ASFUNCTION(_setObjectEncoding);
- ASFUNCTION(_getDefaultObjectEncoding);
- ASFUNCTION(_setDefaultObjectEncoding);
- ASFUNCTION(_compress);
- ASFUNCTION(_uncompress);
- ASFUNCTION(_deflate);
- ASFUNCTION(_inflate);
- ASFUNCTION(clear);
- ASFUNCTION(readBoolean);
- ASFUNCTION(readByte);
- ASFUNCTION(readBytes);
- ASFUNCTION(readDouble);
- ASFUNCTION(readFloat);
- ASFUNCTION(readInt);
- ASFUNCTION(readMultiByte);
- ASFUNCTION(readObject);
- ASFUNCTION(readShort);
- ASFUNCTION(readUnsignedByte);
- ASFUNCTION(readUnsignedInt);
- ASFUNCTION(readUnsignedShort);
- ASFUNCTION(readUTF);
- ASFUNCTION(readUTFBytes);
- ASFUNCTION(writeBoolean);
- ASFUNCTION(writeByte);
- ASFUNCTION(writeBytes);
- ASFUNCTION(writeDouble);
- ASFUNCTION(writeFloat);
- ASFUNCTION(writeInt);
- ASFUNCTION(writeUnsignedInt);
- ASFUNCTION(writeMultiByte);
- ASFUNCTION(writeObject);
- ASFUNCTION(writeShort);
- ASFUNCTION(writeUTF);
- ASFUNCTION(writeUTFBytes);
- ASFUNCTION(_toString);
-
- // these are internal methods used if the generic Array-Methods are called on a ByteArray
- ASFUNCTION(pop);
- ASFUNCTION(push);
- ASFUNCTION(shift);
- ASFUNCTION(unshift);
- /**
- Get ownership over the passed buffer
- @param buf Pointer to the buffer to acquire, ownership and delete authority is acquired
- @param bufLen Lenght of the buffer
- @pre buf must be allocated using new[]
- */
- void acquireBuffer(uint8_t* buf, int bufLen);
- uint8_t* getBuffer(unsigned int size, bool enableResize);
- uint32_t getLength() const { return len; }
-
- uint16_t endianIn(uint16_t value);
- uint32_t endianIn(uint32_t value);
- uint64_t endianIn(uint64_t value);
-
- uint16_t endianOut(uint16_t value);
- uint32_t endianOut(uint32_t value);
- uint64_t endianOut(uint64_t value);
-
- static void sinit(Class_base* c);
- static void buildTraits(ASObject* o);
- _NR<ASObject> getVariableByMultiname(const multiname& name, GET_VARIABLE_OPTION opt=NONE);
- int32_t getVariableByMultiname_i(const multiname& name);
- void setVariableByMultiname(const multiname& name, ASObject* o, CONST_ALLOWED_FLAG allowConst);
- void setVariableByMultiname_i(const multiname& name, int32_t value);
- bool hasPropertyByMultiname(const multiname& name, bool considerDynamic, bool considerPrototype);
-};
-class Timer: public EventDispatcher, public ITickJob
-{
-private:
- void tick();
- void tickFence();
- //tickJobInstance keeps a reference to self while this
- //instance is being used by the timer thread.
- _NR<Timer> tickJobInstance;
-protected:
- bool running;
- uint32_t delay;
- uint32_t repeatCount;
- uint32_t currentCount;
-public:
- Timer(Class_base* c):EventDispatcher(c),running(false),delay(0),repeatCount(0),currentCount(0){};
- static void sinit(Class_base* c);
- ASFUNCTION(_constructor);
- ASFUNCTION(_getCurrentCount);
- ASFUNCTION(_getRepeatCount);
- ASFUNCTION(_setRepeatCount);
- ASFUNCTION(_getRunning);
- ASFUNCTION(_getDelay);
- ASFUNCTION(_setDelay);
- ASFUNCTION(start);
- ASFUNCTION(reset);
- ASFUNCTION(stop);
-};
-
-class Dictionary: public ASObject
-{
-friend class ABCVm;
-private:
- typedef std::map<_R<ASObject>,_R<ASObject>,std::less<_R<ASObject>>,
- reporter_allocator<std::pair<const _R<ASObject>, _R<ASObject>>>> dictType;
- dictType data;
- dictType::iterator findKey(ASObject *);
-public:
- Dictionary(Class_base* c);
- void finalize();
- static void sinit(Class_base*);
- static void buildTraits(ASObject* o);
- ASFUNCTION(_constructor);
- _NR<ASObject> getVariableByMultiname(const multiname& name, GET_VARIABLE_OPTION opt=NONE);
- int32_t getVariableByMultiname_i(const multiname& name)
- {
- assert_and_throw(implEnable);
- throw UnsupportedException("getVariableByMultiName_i not supported for Dictionary");
- }
- void setVariableByMultiname(const multiname& name, ASObject* o, CONST_ALLOWED_FLAG allowConst);
- void setVariableByMultiname_i(const multiname& name, int32_t value);
- bool deleteVariableByMultiname(const multiname& name);
- bool hasPropertyByMultiname(const multiname& name, bool considerDynamic, bool considerPrototype);
- tiny_string toString();
- uint32_t nextNameIndex(uint32_t cur_index);
- _R<ASObject> nextName(uint32_t index);
- _R<ASObject> nextValue(uint32_t index);
-};
-
-class Proxy: public ASObject
-{
-friend class ABCVm;
-public:
- Proxy(Class_base* c):ASObject(c){}
- static void sinit(Class_base*);
- static void buildTraits(ASObject* o);
-// ASFUNCTION(_constructor);
- _NR<ASObject> getVariableByMultiname(const multiname& name, GET_VARIABLE_OPTION opt=NONE);
- int32_t getVariableByMultiname_i(const multiname& name)
- {
- assert_and_throw(implEnable);
- throw UnsupportedException("getVariableByMultiName_i not supported for Proxy");
- }
- void setVariableByMultiname(const multiname& name, ASObject* o, CONST_ALLOWED_FLAG allowConst);
- void setVariableByMultiname_i(const multiname& name, int32_t value)
- {
- setVariableByMultiname(name,abstract_i(value),CONST_NOT_ALLOWED);
- }
-
- bool deleteVariableByMultiname(const multiname& name);
- bool hasPropertyByMultiname(const multiname& name, bool considerDynamic, bool considerPrototype);
- tiny_string toString()
- {
- throw UnsupportedException("Proxy is missing some stuff");
- }
- uint32_t nextNameIndex(uint32_t cur_index);
- _R<ASObject> nextName(uint32_t index);
- _R<ASObject> nextValue(uint32_t index);
-};
ASObject* getQualifiedClassName(ASObject*, ASObject* const* args, const unsigned int len);
ASObject* getQualifiedSuperclassName(ASObject*, ASObject* const* args, const unsigned int len);
@@ -266,45 +67,9 @@ ASObject* setTimeout(ASObject* obj,ASObject* const* args, const unsigned int arg
ASObject* clearInterval(ASObject* obj,ASObject* const* args, const unsigned int argslen);
ASObject* clearTimeout(ASObject* obj,ASObject* const* args, const unsigned int argslen);
ASObject* describeType(ASObject* obj,ASObject* const* args, const unsigned int argslen);
+ASObject* escapeMultiByte(ASObject* obj,ASObject* const* args, const unsigned int argslen);
+ASObject* unescapeMultiByte(ASObject* obj,ASObject* const* args, const unsigned int argslen);
-class IntervalRunner : public ITickJob, public EventDispatcher
-{
-public:
- enum INTERVALTYPE { INTERVAL, TIMEOUT };
-private:
- // IntervalRunner will delete itself in tickFence, others
- // should not call the destructor.
- ~IntervalRunner();
- INTERVALTYPE type;
- uint32_t id;
- _R<IFunction> callback;
- ASObject** args;
- _R<ASObject> obj;
- const unsigned int argslen;
- uint32_t interval;
-public:
- IntervalRunner(INTERVALTYPE _type, uint32_t _id, _R<IFunction> _callback, ASObject** _args,
- const unsigned int _argslen, _R<ASObject> _obj, const uint32_t _interval);
- void tick();
- void tickFence();
- INTERVALTYPE getType() { return type; }
-};
-
-class IntervalManager
-{
-private:
- Mutex mutex;
- std::map<uint32_t,IntervalRunner*> runners;
- uint32_t currentID;
-public:
- IntervalManager();
- ~IntervalManager();
- uint32_t setInterval(_R<IFunction> callback, ASObject** args, const unsigned int argslen, _R<ASObject> obj, const uint32_t interval);
- uint32_t setTimeout(_R<IFunction> callback, ASObject** args, const unsigned int argslen, _R<ASObject> obj, const uint32_t interval);
- uint32_t getFreeID();
- void clearInterval(uint32_t id, IntervalRunner::INTERVALTYPE type, bool removeJob);
-};
-
-};
+}
#endif /* SCRIPTING_FLASH_UTILS_FLASHUTILS_H */
diff --git a/src/scripting/flash/xml/flashxml.cpp b/src/scripting/flash/xml/flashxml.cpp
index 3d0f0e7..6fcd102 100644
--- a/src/scripting/flash/xml/flashxml.cpp
+++ b/src/scripting/flash/xml/flashxml.cpp
@@ -20,6 +20,7 @@
#include <libxml++/nodes/textnode.h>
#include "scripting/flash/xml/flashxml.h"
+#include "scripting/flash/utils/ByteArray.h"
#include "swf.h"
#include "compat.h"
#include "scripting/argconv.h"
@@ -40,8 +41,7 @@ void XMLNode::finalize()
void XMLNode::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASObject>::getRef());
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED);
c->setDeclaredMethodByQName("toString","",Class<IFunction>::getFunction(_toString),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("attributes","",Class<IFunction>::getFunction(attributes),GETTER_METHOD,true);
c->setDeclaredMethodByQName("childNodes","",Class<IFunction>::getFunction(XMLNode::childNodes),GETTER_METHOD,true);
@@ -262,8 +262,7 @@ XMLDocument::XMLDocument(Class_base* c, tiny_string s)
void XMLDocument::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<XMLNode>::getRef());
+ CLASS_SETUP(c, XMLNode, _constructor, CLASS_SEALED);
c->setDeclaredMethodByQName("parseXML","",Class<IFunction>::getFunction(parseXML),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("toString","",Class<IFunction>::getFunction(_toString),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("firstChild","",Class<IFunction>::getFunction(XMLDocument::firstChild),GETTER_METHOD,true);
@@ -298,7 +297,8 @@ void XMLDocument::serialize(ByteArray* out, std::map<tiny_string, uint32_t>& str
void XMLDocument::parseXMLImpl(const string& str)
{
- rootNode=buildFromString(str, ignoreWhite);
+ bool hasParent;
+ rootNode=buildFromString(str, ignoreWhite,&hasParent);
}
ASFUNCTIONBODY(XMLDocument,_toString)
diff --git a/src/scripting/toplevel/ASString.cpp b/src/scripting/toplevel/ASString.cpp
index 10afb69..d4fb11c 100644
--- a/src/scripting/toplevel/ASString.cpp
+++ b/src/scripting/toplevel/ASString.cpp
@@ -20,6 +20,7 @@
#include <pcre.h>
#include "scripting/toplevel/ASString.h"
+#include "scripting/flash/utils/ByteArray.h"
#include "compat.h"
#include "scripting/argconv.h"
#include "parsing/amf3_generator.h"
@@ -63,7 +64,7 @@ ASFUNCTIONBODY(ASString,_constructor)
{
ASString* th=static_cast<ASString*>(obj);
if(args && argslen==1)
- th->data=args[0]->toString().raw_buf();
+ th->data=args[0]->toString();
return NULL;
}
@@ -74,9 +75,7 @@ ASFUNCTIONBODY(ASString,_getLength)
void ASString::sinit(Class_base* c)
{
- c->isFinal = true;
- c->setSuper(Class<ASObject>::getRef());
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_FINAL | CLASS_SEALED);
c->setDeclaredMethodByQName("split",AS3,Class<IFunction>::getFunction(split,2),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("substr",AS3,Class<IFunction>::getFunction(substr,2),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("substring",AS3,Class<IFunction>::getFunction(substring,2),NORMAL_METHOD,true);
@@ -93,6 +92,7 @@ void ASString::sinit(Class_base* c)
c->setDeclaredMethodByQName("toLocaleUpperCase",AS3,Class<IFunction>::getFunction(toUpperCase),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("toLowerCase",AS3,Class<IFunction>::getFunction(toLowerCase),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("toUpperCase",AS3,Class<IFunction>::getFunction(toUpperCase),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("localeCompare",AS3,Class<IFunction>::getFunction(localeCompare),NORMAL_METHOD,true);
// According to specs fromCharCode belongs to AS3 namespace,
// but also empty namespace is seen in the wild and should be
// supported.
@@ -120,6 +120,7 @@ void ASString::sinit(Class_base* c)
c->prototype->setVariableByQName("toUpperCase","",Class<IFunction>::getFunction(toUpperCase),DYNAMIC_TRAIT);
c->prototype->setVariableByQName("toString","",Class<IFunction>::getFunction(_toString),DYNAMIC_TRAIT);
c->prototype->setVariableByQName("valueOf","",Class<IFunction>::getFunction(_toString),DYNAMIC_TRAIT);
+ c->prototype->setVariableByQName("localeCompare","",Class<IFunction>::getFunction(localeCompare_prototype),DYNAMIC_TRAIT);
}
void ASString::buildTraits(ASObject* o)
@@ -456,35 +457,70 @@ double ASString::toNumber() const
{
assert_and_throw(implEnable);
- /* TODO: data holds a utf8-character sequence, not ascii! */
- const char *s=data.raw_buf();
- char *end=NULL;
- while(g_ascii_isspace(*s))
- s++;
- double val=g_ascii_strtod(s, &end);
-
- // strtod converts case-insensitive "inf" and "infinity" to
- // inf, flash only accepts case-sensitive "Infinity".
- if(std::isinf(val)) {
- const char *tmp=s;
- while(g_ascii_isspace(*tmp))
- tmp++;
- if(*tmp=='+' || *tmp=='-')
- tmp++;
- if(strncasecmp(tmp, "inf", 3)==0 && strcmp(tmp, "Infinity")!=0)
+ const char *s = data.raw_buf();
+ while (*s && isEcmaSpace(g_utf8_get_char(s)))
+ s = g_utf8_next_char(s);
+
+ double val;
+ char *end = NULL;
+ val = parseStringInfinite(s, &end);
+
+ // If did not parse as infinite, try decimal
+ if (!std::isinf(val))
+ {
+ errno = 0;
+ val = g_ascii_strtod(s, &end);
+
+ if (errno == ERANGE)
+ {
+ if (val == HUGE_VAL)
+ val = numeric_limits<double>::infinity();
+ else if (val == -HUGE_VAL)
+ val = -numeric_limits<double>::infinity();
+ }
+ else if (std::isinf(val))
+ {
+ // strtod accepts values such as "inf" and lowercase
+ // "infinity" which are not valid values in Flash
return numeric_limits<double>::quiet_NaN();
+ }
}
// Fail if there is any rubbish after the converted number
while(*end) {
- if(!g_ascii_isspace(*end))
+ if(!isEcmaSpace(g_utf8_get_char(end)))
return numeric_limits<double>::quiet_NaN();
- end++;
+ end = g_utf8_next_char(end);
}
return val;
}
+number_t ASString::parseStringInfinite(const char *s, char **end) const
+{
+ if (end)
+ *end = const_cast<char *>(s);
+ double sign = 1.;
+ if (*s == '+')
+ {
+ sign = +1.;
+ s++;
+ }
+ else if (*s == '-')
+ {
+ sign = -1.;
+ s++;
+ }
+ if (strncmp(s, "Infinity", 8) == 0)
+ {
+ if (end)
+ *end = const_cast<char *>(s+8);
+ return sign*numeric_limits<double>::infinity();
+ }
+
+ return 0.; // not an infinite value
+}
+
int32_t ASString::toInt()
{
assert_and_throw(implEnable);
@@ -504,6 +540,8 @@ bool ASString::isEqual(ASObject* r)
{
case T_STRING:
{
+ if (!this->isConstructed())
+ return !r->isConstructed();
const ASString* s=static_cast<const ASString*>(r);
return s->data==data;
}
@@ -514,6 +552,8 @@ bool ASString::isEqual(ASObject* r)
return toNumber()==r->toNumber();
case T_NULL:
case T_UNDEFINED:
+ if (!this->isConstructed())
+ return true;
return false;
default:
return r->isEqual(this);
@@ -654,6 +694,27 @@ ASFUNCTIONBODY(ASString,toUpperCase)
tiny_string data = obj->toString();
return Class<ASString>::getInstanceS(data.uppercase());
}
+ASFUNCTIONBODY(ASString,localeCompare)
+{
+ tiny_string data = obj->toString();
+ tiny_string other;
+ ARG_UNPACK_MORE_ALLOWED(other);
+ if (argslen > 1)
+ LOG(LOG_NOT_IMPLEMENTED,"localeCompare with more than one parameter not implemented");
+ int ret = data.compare(other);
+ return abstract_i(ret);
+}
+ASFUNCTIONBODY(ASString,localeCompare_prototype)
+{
+ tiny_string data = obj->toString();
+ tiny_string other;
+ ARG_UNPACK_MORE_ALLOWED(other);
+ if (argslen > 1)
+ throwError<ArgumentError>(kWrongArgumentCountError, "localeCompare", "1",Integer::toString(argslen));
+
+ int ret = data.compare(other);
+ return abstract_i(ret);
+}
ASFUNCTIONBODY(ASString,fromCharCode)
{
@@ -819,3 +880,17 @@ ASFUNCTIONBODY(ASString,generator)
else
return Class<ASString>::getInstanceS(args[0]->toString());
}
+
+bool ASString::isEcmaSpace(uint32_t c)
+{
+ return (c == 0x09) || (c == 0x0B) || (c == 0x0C) || (c == 0x20) ||
+ (c == 0xA0) || (c == 0x1680) || (c == 0x180E) ||
+ ((c >= 0x2000) && (c <= 0x200B)) || (c == 0x202F) ||
+ (c == 0x205F) || (c == 0x3000) || (c == 0xFEFF) ||
+ isEcmaLineTerminator(c);
+}
+
+bool ASString::isEcmaLineTerminator(uint32_t c)
+{
+ return (c == 0x0A) || (c == 0x0D) || (c == 0x2028) || (c == 0x2029);
+}
diff --git a/src/scripting/toplevel/ASString.h b/src/scripting/toplevel/ASString.h
index 4733829..ab25958 100644
--- a/src/scripting/toplevel/ASString.h
+++ b/src/scripting/toplevel/ASString.h
@@ -34,6 +34,7 @@ class ASString: public ASObject
{
private:
tiny_string toString_priv() const;
+ number_t parseStringInfinite(const char *s, char **end) const;
public:
ASString(Class_base* c);
ASString(Class_base* c, const std::string& s);
@@ -62,6 +63,8 @@ public:
ASFUNCTION(toUpperCase);
ASFUNCTION(_toString);
ASFUNCTION(_getLength);
+ ASFUNCTION(localeCompare);
+ ASFUNCTION(localeCompare_prototype);
bool isEqual(ASObject* r);
TRISTATE isLess(ASObject* r);
number_t toNumber() const;
@@ -73,6 +76,8 @@ public:
std::map<const ASObject*, uint32_t>& objMap,
std::map<const Class_base*, uint32_t>& traitsMap);
std::string toDebugString() { return std::string("\"") + std::string(data) + "\""; }
+ static bool isEcmaSpace(uint32_t c);
+ static bool isEcmaLineTerminator(uint32_t c);
};
template<>
@@ -85,6 +90,8 @@ inline ASObject* Class<ASString>::coerce(ASObject* o) const
o->decRef();
return getSys()->getNullRef();
}
+ if(!o->isConstructed())
+ return o;
tiny_string n = o->toString();
o->decRef();
return Class<ASString>::getInstanceS(n);
diff --git a/src/scripting/toplevel/Array.cpp b/src/scripting/toplevel/Array.cpp
index 2dd5f36..8a7f1c8 100644
--- a/src/scripting/toplevel/Array.cpp
+++ b/src/scripting/toplevel/Array.cpp
@@ -37,10 +37,7 @@ Array::Array(Class_base* c):ASObject(c),
void Array::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- // public constants
- c->setSuper(Class<ASObject>::getRef());
-
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_DYNAMIC_NOT_FINAL);
c->setVariableByQName("CASEINSENSITIVE","",abstract_d(CASEINSENSITIVE),CONSTANT_TRAIT);
c->setVariableByQName("DESCENDING","",abstract_d(DESCENDING),CONSTANT_TRAIT);
c->setVariableByQName("NUMERIC","",abstract_d(NUMERIC),CONSTANT_TRAIT);
@@ -53,39 +50,47 @@ void Array::sinit(Class_base* c)
// public functions
c->setDeclaredMethodByQName("concat",AS3,Class<IFunction>::getFunction(_concat,1),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("every",AS3,Class<IFunction>::getFunction(every),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("filter",AS3,Class<IFunction>::getFunction(filter),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("forEach",AS3,Class<IFunction>::getFunction(forEach),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("indexOf",AS3,Class<IFunction>::getFunction(indexOf),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("lastIndexOf",AS3,Class<IFunction>::getFunction(lastIndexOf),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("every",AS3,Class<IFunction>::getFunction(every,1),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("filter",AS3,Class<IFunction>::getFunction(filter,1),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("forEach",AS3,Class<IFunction>::getFunction(forEach,1),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("indexOf",AS3,Class<IFunction>::getFunction(indexOf,1),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("lastIndexOf",AS3,Class<IFunction>::getFunction(lastIndexOf,1),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("join",AS3,Class<IFunction>::getFunction(join,1),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("map",AS3,Class<IFunction>::getFunction(_map,1),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("pop",AS3,Class<IFunction>::getFunction(_pop),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("push",AS3,Class<IFunction>::getFunction(_push_as3),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("push",AS3,Class<IFunction>::getFunction(_push_as3,1),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("reverse",AS3,Class<IFunction>::getFunction(_reverse),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("shift",AS3,Class<IFunction>::getFunction(shift),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("slice",AS3,Class<IFunction>::getFunction(slice,2),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("some",AS3,Class<IFunction>::getFunction(some),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("some",AS3,Class<IFunction>::getFunction(some,1),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("sort",AS3,Class<IFunction>::getFunction(_sort),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("sortOn",AS3,Class<IFunction>::getFunction(sortOn),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("splice",AS3,Class<IFunction>::getFunction(splice,2),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("toLocaleString",AS3,Class<IFunction>::getFunction(_toString),NORMAL_METHOD,true);
- c->prototype->setVariableByQName("toString","",Class<IFunction>::getFunction(_toString),DYNAMIC_TRAIT);
+ c->setDeclaredMethodByQName("toLocaleString",AS3,Class<IFunction>::getFunction(_toLocaleString),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("unshift",AS3,Class<IFunction>::getFunction(unshift),NORMAL_METHOD,true);
+ c->prototype->setVariableByQName("concat","",Class<IFunction>::getFunction(_concat,1),DYNAMIC_TRAIT);
+ c->prototype->setVariableByQName("every","",Class<IFunction>::getFunction(every,1),DYNAMIC_TRAIT);
+ c->prototype->setVariableByQName("filter","",Class<IFunction>::getFunction(filter,1),DYNAMIC_TRAIT);
+ c->prototype->setVariableByQName("forEach","",Class<IFunction>::getFunction(forEach,1),DYNAMIC_TRAIT);
+ c->prototype->setVariableByQName("indexOf","",Class<IFunction>::getFunction(indexOf,1),DYNAMIC_TRAIT);
+ c->prototype->setVariableByQName("lastIndexOf","",Class<IFunction>::getFunction(lastIndexOf,1),DYNAMIC_TRAIT);
+ c->prototype->setVariableByQName("join","",Class<IFunction>::getFunction(join,1),DYNAMIC_TRAIT);
+ c->prototype->setVariableByQName("map","",Class<IFunction>::getFunction(_map,1),DYNAMIC_TRAIT);
// workaround, pop was encountered not in the AS3 namespace before, need to investigate it further
c->setDeclaredMethodByQName("pop","",Class<IFunction>::getFunction(_pop),NORMAL_METHOD,true);
c->prototype->setVariableByQName("pop","",Class<IFunction>::getFunction(_pop),DYNAMIC_TRAIT);
- c->prototype->setVariableByQName("push","",Class<IFunction>::getFunction(_push),DYNAMIC_TRAIT);
+ c->prototype->setVariableByQName("push","",Class<IFunction>::getFunction(_push,1),DYNAMIC_TRAIT);
+ c->prototype->setVariableByQName("reverse","",Class<IFunction>::getFunction(_reverse),DYNAMIC_TRAIT);
c->prototype->setVariableByQName("shift","",Class<IFunction>::getFunction(shift),DYNAMIC_TRAIT);
- c->prototype->setVariableByQName("unshift","",Class<IFunction>::getFunction(unshift),DYNAMIC_TRAIT);
- c->prototype->setVariableByQName("concat","",Class<IFunction>::getFunction(_concat,1),DYNAMIC_TRAIT);
c->prototype->setVariableByQName("slice","",Class<IFunction>::getFunction(slice,2),DYNAMIC_TRAIT);
- c->prototype->setVariableByQName("splice","",Class<IFunction>::getFunction(splice,2),DYNAMIC_TRAIT);
- c->prototype->setVariableByQName("reverse","",Class<IFunction>::getFunction(_reverse),DYNAMIC_TRAIT);
- c->prototype->setVariableByQName("join","",Class<IFunction>::getFunction(join,1),DYNAMIC_TRAIT);
- c->prototype->setVariableByQName("map",AS3,Class<IFunction>::getFunction(_map,1),DYNAMIC_TRAIT);
+ c->prototype->setVariableByQName("some","",Class<IFunction>::getFunction(some,1),DYNAMIC_TRAIT);
c->prototype->setVariableByQName("sort","",Class<IFunction>::getFunction(_sort),DYNAMIC_TRAIT);
+ c->prototype->setVariableByQName("sortOn","",Class<IFunction>::getFunction(sortOn),DYNAMIC_TRAIT);
+ c->prototype->setVariableByQName("splice","",Class<IFunction>::getFunction(splice,2),DYNAMIC_TRAIT);
+ c->prototype->setVariableByQName("toLocaleString","",Class<IFunction>::getFunction(_toLocaleString),DYNAMIC_TRAIT);
+ c->prototype->setVariableByQName("toString","",Class<IFunction>::getFunction(_toString),DYNAMIC_TRAIT);
+ c->prototype->setVariableByQName("unshift","",Class<IFunction>::getFunction(unshift),DYNAMIC_TRAIT);
}
void Array::buildTraits(ASObject* o)
@@ -95,50 +100,37 @@ void Array::buildTraits(ASObject* o)
ASFUNCTIONBODY(Array,_constructor)
{
Array* th=static_cast<Array*>(obj);
-
- if(argslen==1 && (args[0]->getObjectType()==T_INTEGER || args[0]->getObjectType()==T_UINTEGER || args[0]->getObjectType()==T_NUMBER))
- {
- number_t size=args[0]->toNumber();
- if (size < 0 || size > UINT32_MAX)
- throwError<RangeError>(kArrayIndexNotIntegerError, Number::toString(size));
- LOG(LOG_CALLS,_("Creating array of length ") << size);
- th->resize((uint32_t)size);
- }
- else
- {
- LOG(LOG_CALLS,_("Called Array constructor"));
- th->resize(argslen);
- for(unsigned int i=0;i<argslen;i++)
- {
- args[i]->incRef();
- th->set(i,_MR(args[i]));
- }
- }
+ th->constructorImpl(args, argslen);
return NULL;
}
ASFUNCTIONBODY(Array,generator)
{
Array* th=Class<Array>::getInstanceS();
- if(argslen==1 && (args[0]->getObjectType()==T_INTEGER || args[0]->getObjectType()==T_UINTEGER || args[0]->getObjectType()==T_NUMBER))
+ th->constructorImpl(args, argslen);
+ return th;
+}
+
+void Array::constructorImpl(ASObject* const* args, const unsigned int argslen)
+{
+ if(argslen==1 && (args[0]->is<Integer>() || args[0]->is<UInteger>() || args[0]->is<Number>()))
{
- number_t size=args[0]->toNumber();
- if (size < 0 || size > UINT32_MAX)
- throwError<RangeError>(kArrayIndexNotIntegerError, Number::toString(size));
+ uint32_t size = args[0]->toUInt();
+ if ((number_t)size != args[0]->toNumber())
+ throwError<RangeError>(kArrayIndexNotIntegerError, Number::toString(args[0]->toNumber()));
LOG(LOG_CALLS,_("Creating array of length ") << size);
- th->resize((uint32_t)size);
+ resize(size);
}
else
{
LOG(LOG_CALLS,_("Called Array constructor"));
- th->resize(argslen);
+ resize(argslen);
for(unsigned int i=0;i<argslen;i++)
{
args[i]->incRef();
- th->set(i,_MR(args[i]));
+ set(i,_MR(args[i]));
}
}
- return th;
}
ASFUNCTIONBODY(Array,_concat)
@@ -187,22 +179,32 @@ ASFUNCTIONBODY(Array,_concat)
ASFUNCTIONBODY(Array,filter)
{
Array* th=static_cast<Array*>(obj);
- assert_and_throw(argslen==1 || argslen==2);
- IFunction* f = static_cast<IFunction*>(args[0]);
- ASObject* params[3];
Array* ret=Class<Array>::getInstanceS();
+ _NR<IFunction> f;
+ ARG_UNPACK(f);
+ if (f.isNull())
+ return ret;
+
+ ASObject* params[3];
ASObject *funcRet;
std::map<uint32_t, data_slot>::iterator it=th->data.begin();
for(;it != th->data.end();++it)
{
- assert_and_throw(it->second.type==DATA_OBJECT);
- params[0] = it->second.data;
- it->second.data->incRef();
+ if (it->second.type==DATA_OBJECT)
+ {
+ params[0] = it->second.data;
+ it->second.data->incRef();
+ }
+ else
+ params[0] =abstract_d(it->second.data_i);
params[1] = abstract_i(it->first);
params[2] = th;
th->incRef();
+ // ensure that return values are the original values
+ ASObject *origval = params[0];
+ origval->incRef();
if(argslen==1)
{
funcRet=f->call(getSys()->getNullRef(), params, 3);
@@ -215,10 +217,9 @@ ASFUNCTIONBODY(Array,filter)
if(funcRet)
{
if(Boolean_concrete(funcRet))
- {
- it->second.data->incRef();
- ret->push(_MR(it->second.data));
- }
+ ret->push(_MR(origval));
+ else
+ origval->decRef();
funcRet->decRef();
}
}
@@ -228,17 +229,24 @@ ASFUNCTIONBODY(Array,filter)
ASFUNCTIONBODY(Array, some)
{
Array* th=static_cast<Array*>(obj);
- assert_and_throw(argslen==1 || argslen==2);
- IFunction* f = static_cast<IFunction*>(args[0]);
+ _NR<IFunction> f;
+ ARG_UNPACK(f);
+ if (f.isNull())
+ return abstract_b(false);
+
ASObject* params[3];
ASObject *funcRet;
std::map<uint32_t, data_slot>::iterator it=th->data.begin();
for(;it != th->data.end();++it)
{
- assert_and_throw(it->second.type==DATA_OBJECT);
- params[0] = it->second.data;
- it->second.data->incRef();
+ if (it->second.type==DATA_OBJECT)
+ {
+ params[0] = it->second.data;
+ it->second.data->incRef();
+ }
+ else
+ params[0] =abstract_d(it->second.data_i);
params[1] = abstract_i(it->first);
params[2] = th;
th->incRef();
@@ -267,17 +275,24 @@ ASFUNCTIONBODY(Array, some)
ASFUNCTIONBODY(Array, every)
{
Array* th=static_cast<Array*>(obj);
- assert_and_throw(argslen==1 || argslen==2);
- IFunction* f = static_cast<IFunction*>(args[0]);
+ _NR<IFunction> f;
+ ARG_UNPACK(f);
+ if (f.isNull())
+ return abstract_b(true);
+
ASObject* params[3];
ASObject *funcRet;
std::map<uint32_t, data_slot>::iterator it=th->data.begin();
for(;it != th->data.end();++it)
{
- assert_and_throw(it->second.type==DATA_OBJECT);
- params[0] = it->second.data;
- it->second.data->incRef();
+ if (it->second.type==DATA_OBJECT)
+ {
+ params[0] = it->second.data;
+ it->second.data->incRef();
+ }
+ else
+ params[0] =abstract_d(it->second.data_i);
params[1] = abstract_i(it->first);
params[2] = th;
th->incRef();
@@ -311,9 +326,9 @@ ASFUNCTIONBODY(Array,_getLength)
ASFUNCTIONBODY(Array,_setLength)
{
- assert_and_throw(argslen == 1);
+ uint32_t newLen;
+ ARG_UNPACK(newLen);
Array* th=static_cast<Array*>(obj);
- uint32_t newLen=args[0]->toUInt();
//If newLen is equal to size do nothing
if(newLen==th->size())
return NULL;
@@ -323,17 +338,23 @@ ASFUNCTIONBODY(Array,_setLength)
ASFUNCTIONBODY(Array,forEach)
{
- assert_and_throw(argslen == 1 || argslen == 2);
Array* th=static_cast<Array*>(obj);
- IFunction* f = static_cast<IFunction*>(args[0]);
+ _NR<IFunction> f;
+ ARG_UNPACK(f);
+ if (f.isNull())
+ return NULL;
ASObject* params[3];
std::map<uint32_t, data_slot>::iterator it=th->data.begin();
for(;it != th->data.end();++it)
{
- assert_and_throw(it->second.type==DATA_OBJECT);
- params[0] = it->second.data;
- it->second.data->incRef();
+ if (it->second.type==DATA_OBJECT)
+ {
+ params[0] = it->second.data;
+ it->second.data->incRef();
+ }
+ else
+ params[0] =abstract_d(it->second.data_i);
params[1] = abstract_i(it->first);
params[2] = th;
th->incRef();
@@ -374,11 +395,11 @@ ASFUNCTIONBODY(Array, _reverse)
ASFUNCTIONBODY(Array,lastIndexOf)
{
Array* th=static_cast<Array*>(obj);
- assert_and_throw(argslen==1 || argslen==2);
+ _NR<ASObject> arg0;
+ ARG_UNPACK(arg0);
int ret=-1;
- ASObject* arg0=args[0];
- if(th->data.empty())
+ if(argslen == 1 && th->data.empty())
return abstract_d(0);
size_t i = th->size()-1;
@@ -410,7 +431,7 @@ ASFUNCTIONBODY(Array,lastIndexOf)
continue;
DATA_TYPE dtype = th->data[i].type;
assert_and_throw(dtype==DATA_OBJECT || dtype==DATA_INT);
- if((dtype == DATA_OBJECT && th->data[i].data->isEqualStrict(arg0)) ||
+ if((dtype == DATA_OBJECT && th->data[i].data->isEqualStrict(arg0.getPtr())) ||
(dtype == DATA_INT && arg0->toInt() == th->data[i].data_i))
{
ret=i;
@@ -494,14 +515,10 @@ int Array::capIndex(int i) const
ASFUNCTIONBODY(Array,slice)
{
Array* th=static_cast<Array*>(obj);
+ int startIndex;
+ int endIndex;
- int startIndex=0;
- int endIndex=16777215;
- if(argslen>0)
- startIndex=args[0]->toInt();
- if(argslen>1)
- endIndex=args[1]->toInt();
-
+ ARG_UNPACK(startIndex, 0) (endIndex, 16777215);
startIndex=th->capIndex(startIndex);
endIndex=th->capIndex(endIndex);
@@ -524,13 +541,11 @@ ASFUNCTIONBODY(Array,slice)
ASFUNCTIONBODY(Array,splice)
{
Array* th=static_cast<Array*>(obj);
- assert_and_throw(argslen >= 1);
- int startIndex=args[0]->toInt();
+ int startIndex;
+ int deleteCount;
//By default, delete all the element up to the end
- //Use the array len, it will be capped below
- int deleteCount=th->size();
- if(argslen > 1)
- deleteCount=args[1]->toUInt();
+ //DeleteCount defaults to the array len, it will be capped below
+ ARG_UNPACK_MORE_ALLOWED(startIndex) (deleteCount, th->size());
int totalSize=th->size();
Array* ret=Class<Array>::getInstanceS();
@@ -590,11 +605,10 @@ ASFUNCTIONBODY(Array,splice)
ASFUNCTIONBODY(Array,join)
{
Array* th=static_cast<Array*>(obj);
-
- tiny_string del = ",";
- if (argslen == 1)
- del=args[0]->toString();
string ret;
+ tiny_string del;
+ ARG_UNPACK(del, ",");
+
for(uint32_t i=0;i<th->size();i++)
{
_R<ASObject> o = th->at(i);
@@ -610,11 +624,10 @@ ASFUNCTIONBODY(Array,indexOf)
{
Array* th=static_cast<Array*>(obj);
int ret=-1;
- int32_t index=0;
- ASObject* arg0 = args[0];
- if (argslen > 1)
- index = args[1]->toInt();
-
+ int32_t index;
+ _NR<ASObject> arg0;
+ ARG_UNPACK(arg0) (index, 0);
+ if (index < 0) index = abs(index);
DATA_TYPE dtype;
std::map<uint32_t,data_slot>::iterator it;
@@ -625,8 +638,8 @@ ASFUNCTIONBODY(Array,indexOf)
data_slot sl = it->second;
dtype = sl.type;
assert_and_throw(dtype==DATA_OBJECT || dtype==DATA_INT);
- if((dtype == DATA_OBJECT && sl.data->isEqualStrict(arg0)) ||
- (dtype == DATA_INT && arg0->toInt() == sl.data_i))
+ if((dtype == DATA_OBJECT && sl.data->isEqualStrict(arg0.getPtr())) ||
+ (dtype == DATA_INT && abstract_d(sl.data_i)->isEqualStrict(arg0.getPtr())))
{
ret=it->first;
break;
@@ -765,7 +778,7 @@ bool Array::sortComparatorWrapper::operator()(const data_slot& d1, const data_sl
assert(comparator);
_NR<ASObject> ret=_MNR(comparator->call(getSys()->getNullRef(), objs, 2));
assert_and_throw(ret);
- return (ret->toInt()<0); //Less
+ return (ret->toNumber()<0); //Less
}
ASFUNCTIONBODY(Array,_sort)
@@ -877,8 +890,10 @@ bool Array::sortOnComparator::operator()(const data_slot& d1, const data_slot& d
ASFUNCTIONBODY(Array,sortOn)
{
+ if (argslen != 1 && argslen != 2)
+ throwError<ArgumentError>(kWrongArgumentCountError, "1",
+ Integer::toString(argslen));
Array* th=static_cast<Array*>(obj);
- assert_and_throw(argslen==1 || argslen==2);
std::vector<sorton_field> sortfields;
if(args[0]->is<Array>())
{
@@ -1133,6 +1148,20 @@ ASFUNCTIONBODY(Array,_toString)
return Class<ASString>::getInstanceS(th->toString_priv());
}
+ASFUNCTIONBODY(Array,_toLocaleString)
+{
+ if(Class<Number>::getClass()->prototype->getObj() == obj)
+ return Class<ASString>::getInstanceS("");
+ if(!obj->is<Array>())
+ {
+ LOG(LOG_NOT_IMPLEMENTED, "generic Array::toLocaleString");
+ return Class<ASString>::getInstanceS("");
+ }
+
+ Array* th=obj->as<Array>();
+ return Class<ASString>::getInstanceS(th->toString_priv(true));
+}
+
int32_t Array::getVariableByMultiname_i(const multiname& name)
{
assert_and_throw(implEnable);
@@ -1203,7 +1232,7 @@ _NR<ASObject> Array::getVariableByMultiname(const multiname& name, GET_VARIABLE_
ret->incRef();
break;
case DATA_INT:
- ret=abstract_i(sl.data_i);
+ ret=abstract_d(sl.data_i);
break;
}
}
@@ -1222,6 +1251,8 @@ void Array::setVariableByMultiname_i(const multiname& name, int32_t value)
ASObject::setVariableByMultiname_i(name,value);
return;
}
+ if (index==0xFFFFFFFF)
+ return;
if(index>=size())
resize(index+1);
@@ -1253,17 +1284,45 @@ bool Array::isValidMultiname(const multiname& name, uint32_t& index)
assert_and_throw(name.ns.size()!=0);
if(!name.ns[0].hasEmptyName())
return false;
+ if (name.name_type == multiname::NAME_STRING &&
+ !isIntegerWithoutLeadingZeros(name.normalizedName()))
+ return false;
return name.toUInt(index);
}
+bool Array::isIntegerWithoutLeadingZeros(const tiny_string& value)
+{
+ if (value.empty())
+ return false;
+ else if (value == "0")
+ return true;
+
+ bool first = true;
+ for (CharIterator it=value.begin(); it!=value.end(); ++it)
+ {
+ if (!it.isdigit() || (first && *it == '0'))
+ return false;
+
+ first = false;
+ }
+
+ return true;
+}
+
void Array::setVariableByMultiname(const multiname& name, ASObject* o, CONST_ALLOWED_FLAG allowConst)
{
assert_and_throw(implEnable);
uint32_t index=0;
if(!isValidMultiname(name,index))
return ASObject::setVariableByMultiname(name,o,allowConst);
-
+ // Derived classes may be sealed!
+ if (getClass() && getClass()->isSealed)
+ throwError<ReferenceError>(kWriteSealedError,
+ name.normalizedName(),
+ getClass()->getQualifiedClassName());
+ if (index==0xFFFFFFFF)
+ return;
if(index>=size())
resize((uint64_t)index+1);
@@ -1329,7 +1388,7 @@ tiny_string Array::toString()
return toString_priv();
}
-tiny_string Array::toString_priv() const
+tiny_string Array::toString_priv(bool localized) const
{
string ret;
for(uint32_t i=0;i<size();i++)
@@ -1340,7 +1399,12 @@ tiny_string Array::toString_priv() const
if(sl.type==DATA_OBJECT)
{
if(sl.data && !sl.data->is<Undefined>() && !sl.data->is<Null>())
- ret+=sl.data->toString().raw_buf();
+ {
+ if (localized)
+ ret += sl.data->toLocaleString().raw_buf();
+ else
+ ret += sl.data->toString().raw_buf();
+ }
}
else if(sl.type==DATA_INT)
{
@@ -1377,7 +1441,7 @@ _R<ASObject> Array::nextValue(uint32_t index)
}
}
else if(sl.type==DATA_INT)
- return _MR(abstract_i(sl.data_i));
+ return _MR(abstract_d(sl.data_i));
else
throw UnsupportedException("Unexpected data type");
}
@@ -1429,7 +1493,7 @@ _R<ASObject> Array::nextName(uint32_t index)
_R<ASObject> Array::at(unsigned int index) const
{
if(size()<=index)
- outofbounds();
+ outofbounds(index);
if (!data.count(index))
return _MR(getSys()->getUndefinedRef());
@@ -1445,20 +1509,25 @@ _R<ASObject> Array::at(unsigned int index) const
}
}
case DATA_INT:
- return _MR(abstract_i(sl.data_i));
+ return _MR(abstract_d(sl.data_i));
}
//We should be here only if data is an object and is NULL
return _MR(getSys()->getUndefinedRef());
}
-void Array::outofbounds() const
+void Array::outofbounds(unsigned int index) const
{
- throw ParseException("Array access out of bounds");
+ throwError<RangeError>(kInvalidArrayLengthError, Number::toString(index));
}
void Array::resize(uint64_t n)
{
+ // Bug-for-bug compatible wrapping. See Tamarin test
+ // as3/Array/length_mods.swf and Tamarin bug #685323.
+ if (n > 0xFFFFFFFF)
+ n = (n % 0x100000000);
+
std::map<uint32_t,data_slot>::reverse_iterator it;
std::map<uint32_t,data_slot>::iterator itstart = n ? data.end() : data.begin();
for ( it=data.rbegin() ; it != data.rend(); ++it )
@@ -1514,6 +1583,59 @@ void Array::serialize(ByteArray* out, std::map<tiny_string, uint32_t>& stringMap
}
}
+tiny_string Array::toJSON(std::vector<ASObject *> &path, IFunction *replacer, const tiny_string& spaces,const tiny_string& filter)
+{
+ if (has_toJSON())
+ {
+ return call_toJSON();
+ }
+
+ tiny_string res = "[";
+ std::map<uint32_t,data_slot>::iterator it;
+ // check for cylic reference
+ if (std::find(path.begin(),path.end(), this) != path.end())
+ throwError<TypeError>(kJSONCyclicStructure);
+ path.push_back(this);
+ bool bfirst = true;
+ tiny_string newline = (spaces.empty() ? "" : "\n");
+ for (it=data.begin() ; it != data.end(); ++it)
+ {
+ if(it->second.type==DATA_OBJECT && it->second.data)
+ {
+ tiny_string subres;
+ if (replacer != NULL)
+ {
+ ASObject* params[2];
+
+ params[0] = Class<Number>::getInstanceS(it->first);
+ params[0]->incRef();
+ params[1] = it->second.data;
+ params[1]->incRef();
+ ASObject *funcret=replacer->call(getSys()->getNullRef(), params, 2);
+ if (funcret)
+ subres = funcret->toJSON(path,NULL,spaces,filter);
+ }
+ else
+ subres = it->second.data->toJSON(path,replacer,spaces,filter);
+ if (!subres.empty())
+ {
+ if (!bfirst)
+ res += ",";
+ res += newline+spaces;
+
+ bfirst = false;
+ res += subres;
+ }
+ path.push_back(it->second.data);
+ }
+ }
+ if (!bfirst)
+ res += newline+spaces.substr_bytes(0,spaces.numBytes()/2);
+ res += "]";
+ return res;
+
+}
+
Array::~Array()
{
Array::finalize();
@@ -1531,4 +1653,26 @@ void Array::finalize()
data.clear();
}
+void Array::set(unsigned int index, _R<ASObject> o)
+{
+ if(index<currentsize)
+ {
+ if(!data.count(index))
+ data[index]=data_slot();
+ if(o->getObjectType()==T_INTEGER)
+ {
+ Integer* i=o->as<Integer>();
+ data[index].data_i=i->val;
+ data[index].type=DATA_INT;
+ }
+ else
+ {
+ o->incRef();
+ data[index].data=o.getPtr();
+ data[index].type=DATA_OBJECT;
+ }
+ }
+ else
+ outofbounds(index);
+}
diff --git a/src/scripting/toplevel/Array.h b/src/scripting/toplevel/Array.h
index 75dec81..e27ce27 100644
--- a/src/scripting/toplevel/Array.h
+++ b/src/scripting/toplevel/Array.h
@@ -48,19 +48,17 @@ struct sorton_field
sorton_field(const multiname& sortfieldname):isNumeric(false),isCaseInsensitive(false),isDescending(false),fieldname(sortfieldname){}
};
-
class Array: public ASObject
{
friend class ABCVm;
protected:
- uint32_t currentsize;
+ uint64_t currentsize;
typedef std::map<uint32_t,data_slot,std::less<uint32_t>,
reporter_allocator<std::pair<const uint32_t, data_slot>>> arrayType;
arrayType data;
- void outofbounds() const;
+ void outofbounds(unsigned int index) const;
~Array();
private:
- enum SORTTYPE { CASEINSENSITIVE=1, DESCENDING=2, UNIQUESORT=4, RETURNINDEXEDARRAY=8, NUMERIC=16 };
class sortComparatorDefault
{
private:
@@ -87,9 +85,12 @@ private:
sortOnComparator(const std::vector<sorton_field>& sf):fields(sf){}
bool operator()(const data_slot& d1, const data_slot& d2);
};
- tiny_string toString_priv() const;
+ void constructorImpl(ASObject* const* args, const unsigned int argslen);
+ tiny_string toString_priv(bool localized=false) const;
int capIndex(int i) const;
+ static bool isIntegerWithoutLeadingZeros(const tiny_string& value);
public:
+ enum SORTTYPE { CASEINSENSITIVE=1, DESCENDING=2, UNIQUESORT=4, RETURNINDEXEDARRAY=8, NUMERIC=16 };
Array(Class_base* c);
void finalize();
//These utility methods are also used by ByteArray
@@ -120,33 +121,21 @@ public:
ASFUNCTION(lastIndexOf);
ASFUNCTION(_map);
ASFUNCTION(_toString);
+ ASFUNCTION(_toLocaleString);
ASFUNCTION(slice);
ASFUNCTION(every);
ASFUNCTION(some);
_R<ASObject> at(unsigned int index) const;
- void set(unsigned int index, _R<ASObject> o)
- {
- if(index<currentsize)
- {
- if(!data.count(index))
- data[index]=data_slot();
- o->incRef();
- data[index].data=o.getPtr();
- data[index].type=DATA_OBJECT;
- }
- else
- outofbounds();
- }
+ void set(unsigned int index, _R<ASObject> o);
uint64_t size() const
{
return currentsize;
}
void push(_R<ASObject> o)
{
- o->incRef();
- data[currentsize] = data_slot(o.getPtr());
currentsize++;
+ set(currentsize-1,o);
}
void resize(uint64_t n);
_NR<ASObject> getVariableByMultiname(const multiname& name, GET_VARIABLE_OPTION opt);
@@ -163,6 +152,7 @@ public:
void serialize(ByteArray* out, std::map<tiny_string, uint32_t>& stringMap,
std::map<const ASObject*, uint32_t>& objMap,
std::map<const Class_base*, uint32_t>& traitsMap);
+ virtual tiny_string toJSON(std::vector<ASObject *> &path,IFunction* replacer, const tiny_string &spaces,const tiny_string& filter);
};
diff --git a/src/scripting/toplevel/Boolean.cpp b/src/scripting/toplevel/Boolean.cpp
index 5f31167..cffc28d 100644
--- a/src/scripting/toplevel/Boolean.cpp
+++ b/src/scripting/toplevel/Boolean.cpp
@@ -19,6 +19,7 @@
#include "scripting/toplevel/Boolean.h"
#include "scripting/toplevel/toplevel.h"
+#include "scripting/flash/utils/ByteArray.h"
#include "scripting/class.h"
#include "scripting/argconv.h"
#include "parsing/amf3_generator.h"
@@ -51,7 +52,16 @@ bool lightspark::Boolean_concrete(const ASObject* o)
case T_UINTEGER:
return o->as<UInteger>()->val != 0;
case T_STRING:
+ if (!o->isConstructed())
+ return false;
return !o->as<ASString>()->data.empty();
+ case T_FUNCTION:
+ case T_ARRAY:
+ case T_OBJECT:
+ // not constructed objects return false
+ if (!o->isConstructed())
+ return false;
+ return true;
default:
//everything else is an Object regarding to the spec
return true;
@@ -69,11 +79,10 @@ ASFUNCTIONBODY(Boolean,generator)
void Boolean::sinit(Class_base* c)
{
- c->isFinal=true;
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASObject>::getRef());
- c->prototype->setVariableByQName("toString",AS3,Class<IFunction>::getFunction(_toString),DYNAMIC_TRAIT);
- c->prototype->setVariableByQName("valueOf",AS3,Class<IFunction>::getFunction(_valueOf),DYNAMIC_TRAIT);
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED | CLASS_FINAL);
+ c->setDeclaredMethodByQName("toString",AS3,Class<IFunction>::getFunction(_toString),NORMAL_METHOD,true);
+ c->prototype->setVariableByQName("toString","",Class<IFunction>::getFunction(_toString),DYNAMIC_TRAIT);
+ c->prototype->setVariableByQName("valueOf","",Class<IFunction>::getFunction(_valueOf),DYNAMIC_TRAIT);
}
ASFUNCTIONBODY(Boolean,_constructor)
@@ -133,6 +142,9 @@ bool Boolean::isEqual(ASObject* r)
return b->val==val;
}
case T_STRING:
+ if (!r->isConstructed())
+ return false;
+ return val==r->toNumber();
case T_INTEGER:
case T_UINTEGER:
case T_NUMBER:
diff --git a/src/scripting/toplevel/Date.cpp b/src/scripting/toplevel/Date.cpp
index bceaba8..fd3f773 100644
--- a/src/scripting/toplevel/Date.cpp
+++ b/src/scripting/toplevel/Date.cpp
@@ -39,9 +39,7 @@ Date::~Date()
void Date::sinit(Class_base* c)
{
- c->isFinal=true;
- c->setSuper(Class<ASObject>::getRef());
- c->setConstructor(Class<IFunction>::getFunction(_constructor,7));
+ CLASS_SETUP_CONSTRUCTOR_LENGTH(c, ASObject, _constructor, 7, CLASS_FINAL);
c->setDeclaredMethodByQName("getTimezoneOffset",AS3,Class<IFunction>::getFunction(getTimezoneOffset),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("valueOf",AS3,Class<IFunction>::getFunction(valueOf),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("getTime",AS3,Class<IFunction>::getFunction(getTime),NORMAL_METHOD,true);
@@ -821,9 +819,14 @@ ASFUNCTIONBODY(Date,valueOf)
ASObject* Date::msSinceEpoch()
{
- return abstract_d(milliseconds+extrayears/400*MS_IN_400_YEARS);
+ return abstract_d(getMsSinceEpoch());
+}
+number_t Date::getMsSinceEpoch()
+{
+ return milliseconds+extrayears/400*MS_IN_400_YEARS;
}
+
tiny_string Date::toString()
{
assert_and_throw(implEnable);
@@ -1094,6 +1097,23 @@ number_t Date::parse(tiny_string str)
return res;
}
+bool Date::isEqual(ASObject* r)
+{
+ check();
+ //if we are comparing the same object the answer is true
+ if(this==r)
+ return true;
+ if (r->is<Date>())
+ return getMsSinceEpoch() == r->as<Date>()->getMsSinceEpoch();
+ return ASObject::isEqual(r);
+}
+
+TRISTATE Date::isLess(ASObject* o)
+{
+ if (o->is<Date>())
+ return (getMsSinceEpoch() < o->as<Date>()->getMsSinceEpoch())?TTRUE:TFALSE;
+ return ASObject::isLess(o);
+}
void Date::serialize(ByteArray* out, std::map<tiny_string, uint32_t>& stringMap,
std::map<const ASObject*, uint32_t>& objMap,
diff --git a/src/scripting/toplevel/Date.h b/src/scripting/toplevel/Date.h
index d456b53..2f72df7 100644
--- a/src/scripting/toplevel/Date.h
+++ b/src/scripting/toplevel/Date.h
@@ -35,6 +35,7 @@ private:
GDateTime *datetime;
GDateTime *datetimeUTC;
ASObject *msSinceEpoch();
+ number_t getMsSinceEpoch();
tiny_string toString_priv(bool utc, const char* formatstr) const;
void MakeDate(int64_t year, int64_t month, int64_t day, int64_t hour, int64_t minute, int64_t second, int64_t millisecond, bool bIsLocalTime);
void MakeDateFromMilliseconds(int64_t ms);
@@ -103,6 +104,9 @@ public:
ASFUNCTION(toLocaleString);
ASFUNCTION(toLocaleDateString);
ASFUNCTION(toLocaleTimeString);
+
+ bool isEqual(ASObject* r);
+ TRISTATE isLess(ASObject* r);
tiny_string toString();
//Serialization interface
void serialize(ByteArray* out, std::map<tiny_string, uint32_t>& stringMap,
diff --git a/src/scripting/toplevel/Error.cpp b/src/scripting/toplevel/Error.cpp
index 3865195..c74b257 100644
--- a/src/scripting/toplevel/Error.cpp
+++ b/src/scripting/toplevel/Error.cpp
@@ -89,11 +89,11 @@ ASFUNCTIONBODY(ASError,getStackTrace)
tiny_string ASError::toString(bool debugMsg)
{
tiny_string ret;
- if( !message.empty() )
- ret = name + ": ";
+ ret = name;
if(errorID != 0)
- ret += tiny_string("Error #") + Integer::toString(errorID) + ": ";
- ret += message;
+ ret += tiny_string(": Error #") + Integer::toString(errorID);
+ if (!message.empty())
+ ret += tiny_string(": ") + message;
return ret;
}
@@ -140,10 +140,10 @@ void ASError::errorGenerator(ASError* obj, ASObject* const* args, const unsigned
void ASError::sinit(Class_base* c)
{
- c->setSuper(Class<ASObject>::getRef());
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setDeclaredMethodByQName("getStackTrace",AS3,Class<IFunction>::getFunction(getStackTrace),NORMAL_METHOD,true);
- c->prototype->setVariableByQName("toString",AS3,Class<IFunction>::getFunction(_toString),DYNAMIC_TRAIT);
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_DYNAMIC_NOT_FINAL);
+ c->setDeclaredMethodByQName("getStackTrace","",Class<IFunction>::getFunction(getStackTrace),NORMAL_METHOD,true);
+ c->prototype->setVariableByQName("toString","",Class<IFunction>::getFunction(_toString),DYNAMIC_TRAIT);
+ c->setDeclaredMethodByQName("toString","",Class<IFunction>::getFunction(_toString),NORMAL_METHOD,true);
REGISTER_GETTER(c, errorID);
REGISTER_GETTER_SETTER(c, message);
REGISTER_GETTER_SETTER(c, name);
@@ -177,8 +177,7 @@ ASFUNCTIONBODY(SecurityError,generator)
void SecurityError::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASError>::getRef());
+ CLASS_SETUP(c, ASError, _constructor, CLASS_DYNAMIC_NOT_FINAL);
}
void SecurityError::buildTraits(ASObject* o)
@@ -205,8 +204,7 @@ ASFUNCTIONBODY(ArgumentError,generator)
void ArgumentError::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASError>::getRef());
+ CLASS_SETUP(c, ASError, _constructor, CLASS_DYNAMIC_NOT_FINAL);
}
void ArgumentError::buildTraits(ASObject* o)
@@ -233,8 +231,7 @@ ASFUNCTIONBODY(DefinitionError,generator)
void DefinitionError::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASError>::getRef());
+ CLASS_SETUP(c, ASError, _constructor, CLASS_DYNAMIC_NOT_FINAL);
}
void DefinitionError::buildTraits(ASObject* o)
@@ -261,8 +258,7 @@ ASFUNCTIONBODY(EvalError,generator)
void EvalError::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASError>::getRef());
+ CLASS_SETUP(c, ASError, _constructor, CLASS_DYNAMIC_NOT_FINAL);
}
void EvalError::buildTraits(ASObject* o)
@@ -289,8 +285,7 @@ ASFUNCTIONBODY(RangeError,generator)
void RangeError::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASError>::getRef());
+ CLASS_SETUP(c, ASError, _constructor, CLASS_DYNAMIC_NOT_FINAL);
}
void RangeError::buildTraits(ASObject* o)
@@ -317,8 +312,7 @@ ASFUNCTIONBODY(ReferenceError,generator)
void ReferenceError::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASError>::getRef());
+ CLASS_SETUP(c, ASError, _constructor, CLASS_DYNAMIC_NOT_FINAL);
}
void ReferenceError::buildTraits(ASObject* o)
@@ -345,8 +339,7 @@ ASFUNCTIONBODY(SyntaxError,generator)
void SyntaxError::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASError>::getRef());
+ CLASS_SETUP(c, ASError, _constructor, CLASS_DYNAMIC_NOT_FINAL);
}
void SyntaxError::buildTraits(ASObject* o)
@@ -373,8 +366,7 @@ ASFUNCTIONBODY(TypeError,generator)
void TypeError::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASError>::getRef());
+ CLASS_SETUP(c, ASError, _constructor, CLASS_DYNAMIC_NOT_FINAL);
}
void TypeError::buildTraits(ASObject* o)
@@ -401,8 +393,7 @@ ASFUNCTIONBODY(URIError,generator)
void URIError::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASError>::getRef());
+ CLASS_SETUP(c, ASError, _constructor, CLASS_DYNAMIC_NOT_FINAL);
}
void URIError::buildTraits(ASObject* o)
@@ -429,8 +420,7 @@ ASFUNCTIONBODY(VerifyError,generator)
void VerifyError::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASError>::getRef());
+ CLASS_SETUP(c, ASError, _constructor, CLASS_DYNAMIC_NOT_FINAL);
}
void VerifyError::buildTraits(ASObject* o)
@@ -457,8 +447,7 @@ ASFUNCTIONBODY(UninitializedError,generator)
void UninitializedError::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASError>::getRef());
+ CLASS_SETUP(c, ASError, _constructor, CLASS_DYNAMIC_NOT_FINAL);
}
void UninitializedError::buildTraits(ASObject* o)
diff --git a/src/scripting/toplevel/Integer.cpp b/src/scripting/toplevel/Integer.cpp
index b920e45..d7efdb3 100644
--- a/src/scripting/toplevel/Integer.cpp
+++ b/src/scripting/toplevel/Integer.cpp
@@ -17,15 +17,20 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
+#include <cmath>
#include "parsing/amf3_generator.h"
#include "scripting/argconv.h"
#include "scripting/toplevel/Integer.h"
+#include "scripting/flash/utils/ByteArray.h"
using namespace std;
using namespace lightspark;
ASFUNCTIONBODY(Integer,_toString)
{
+ if(Class<Integer>::getClass()->prototype->getObj() == obj)
+ return Class<ASString>::getInstanceS("0");
+
Integer* th=static_cast<Integer*>(obj);
int radix=10;
if(argslen==1)
@@ -190,13 +195,19 @@ tiny_string Integer::toString(int32_t val)
void Integer::sinit(Class_base* c)
{
- c->isFinal = true;
- c->setSuper(Class<ASObject>::getRef());
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setVariableByQName("MAX_VALUE","",new (c->memoryAccount) Integer(c,numeric_limits<int32_t>::max()),CONSTANT_TRAIT);
- c->setVariableByQName("MIN_VALUE","",new (c->memoryAccount) Integer(c,numeric_limits<int32_t>::min()),CONSTANT_TRAIT);
- c->prototype->setVariableByQName("toString",AS3,Class<IFunction>::getFunction(Integer::_toString),DYNAMIC_TRAIT);
- c->prototype->setVariableByQName("valueOf",AS3,Class<IFunction>::getFunction(_valueOf),DYNAMIC_TRAIT);
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED | CLASS_FINAL);
+ c->setVariableByQName("MAX_VALUE","",abstract_i(numeric_limits<int32_t>::max()),CONSTANT_TRAIT);
+ c->setVariableByQName("MIN_VALUE","",abstract_i(numeric_limits<int32_t>::min()),CONSTANT_TRAIT);
+ c->setDeclaredMethodByQName("toString",AS3,Class<IFunction>::getFunction(_toString),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("toFixed",AS3,Class<IFunction>::getFunction(_toFixed,1),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("toExponential",AS3,Class<IFunction>::getFunction(_toExponential,1),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("toPrecision",AS3,Class<IFunction>::getFunction(_toPrecision,1),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("valueOf",AS3,Class<IFunction>::getFunction(_valueOf),NORMAL_METHOD,true);
+ c->prototype->setVariableByQName("toExponential","",Class<IFunction>::getFunction(Integer::_toExponential, 1),DYNAMIC_TRAIT);
+ c->prototype->setVariableByQName("toFixed","",Class<IFunction>::getFunction(Integer::_toFixed, 1),DYNAMIC_TRAIT);
+ c->prototype->setVariableByQName("toPrecision","",Class<IFunction>::getFunction(Integer::_toPrecision, 1),DYNAMIC_TRAIT);
+ c->prototype->setVariableByQName("toString","",Class<IFunction>::getFunction(Integer::_toString),DYNAMIC_TRAIT);
+ c->prototype->setVariableByQName("valueOf","",Class<IFunction>::getFunction(_valueOf),DYNAMIC_TRAIT);
}
void Integer::serialize(ByteArray* out, std::map<tiny_string, uint32_t>& stringMap,
@@ -213,7 +224,7 @@ void Integer::serialize(ByteArray* out, std::map<tiny_string, uint32_t>& stringM
bool Integer::fromStringFlashCompatible(const char* cur, int64_t& ret, int radix)
{
//Skip whitespace chars
- while(g_unichar_isspace(g_utf8_get_char(cur)))
+ while(ASString::isEcmaSpace(g_utf8_get_char(cur)))
cur = g_utf8_next_char(cur);
int64_t multiplier=1;
@@ -251,8 +262,42 @@ int32_t Integer::stringToASInteger(const char* cur, int radix)
int64_t value;
bool valid=Integer::fromStringFlashCompatible(cur, value, 0);
- if(valid==false || value<INT32_MIN || value>INT32_MAX)
+ if (!valid)
return 0;
else
- return static_cast<int32_t>(value);
+ return static_cast<int32_t>(value & 0xFFFFFFFF);
+}
+
+ASFUNCTIONBODY(Integer,_toExponential)
+{
+ Integer *th=obj->as<Integer>();
+ double v = (double)th->val;
+ int32_t fractionDigits;
+ ARG_UNPACK(fractionDigits, 0);
+ if (argslen == 0 || args[0]->is<Undefined>())
+ {
+ if (v == 0)
+ fractionDigits = 1;
+ else
+ fractionDigits = imin(imax((int32_t)ceil(::log10(::fabs(v))), 1), 20);
+ }
+ return Class<ASString>::getInstanceS(Number::toExponentialString(v, fractionDigits));
+}
+
+ASFUNCTIONBODY(Integer,_toFixed)
+{
+ Integer *th=obj->as<Integer>();
+ int fractiondigits;
+ ARG_UNPACK (fractiondigits, 0);
+ return Class<ASString>::getInstanceS(Number::toFixedString(th->val, fractiondigits));
+}
+
+ASFUNCTIONBODY(Integer,_toPrecision)
+{
+ Integer *th=obj->as<Integer>();
+ if (argslen == 0 || args[0]->is<Undefined>())
+ return Class<ASString>::getInstanceS(th->toString());
+ int precision;
+ ARG_UNPACK (precision);
+ return Class<ASString>::getInstanceS(Number::toPrecisionString(th->val, precision));
}
diff --git a/src/scripting/toplevel/Integer.h b/src/scripting/toplevel/Integer.h
index 96e571a..4299057 100644
--- a/src/scripting/toplevel/Integer.h
+++ b/src/scripting/toplevel/Integer.h
@@ -49,6 +49,9 @@ public:
ASFUNCTION(_constructor);
ASFUNCTION(generator);
ASFUNCTION(_valueOf);
+ ASFUNCTION(_toExponential);
+ ASFUNCTION(_toFixed);
+ ASFUNCTION(_toPrecision);
std::string toDebugString() { return toString()+"i"; }
//Serialization interface
void serialize(ByteArray* out, std::map<tiny_string, uint32_t>& stringMap,
diff --git a/src/scripting/toplevel/JSON.cpp b/src/scripting/toplevel/JSON.cpp
new file mode 100644
index 0000000..193bee3
--- /dev/null
+++ b/src/scripting/toplevel/JSON.cpp
@@ -0,0 +1,774 @@
+/**************************************************************************
+ Lightspark, a free flash player implementation
+
+ Copyright (C) 2009-2013 Alessandro Pignotti (a.pignotti at sssup.it)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+**************************************************************************/
+
+#include "scripting/argconv.h"
+#include "scripting/toplevel/JSON.h"
+
+using namespace std;
+using namespace lightspark;
+
+JSON::JSON(Class_base* c):ASObject(c)
+{
+}
+
+
+void JSON::sinit(Class_base* c)
+{
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED | CLASS_FINAL);
+ c->setDeclaredMethodByQName("parse","",Class<IFunction>::getFunction(_parse,2),NORMAL_METHOD,false);
+ c->setDeclaredMethodByQName("stringify","",Class<IFunction>::getFunction(_stringify,3),NORMAL_METHOD,false);
+}
+void JSON::buildTraits(ASObject* o)
+{
+}
+ASFUNCTIONBODY(JSON,_constructor)
+{
+ throwError<ArgumentError>(kCantInstantiateError);
+ return NULL;
+}
+ASFUNCTIONBODY(JSON,generator)
+{
+ throwError<ArgumentError>(kCoerceArgumentCountError);
+ return NULL;
+}
+
+ASFUNCTIONBODY(JSON,_parse)
+{
+ tiny_string text;
+ IFunction* reviver = NULL;
+
+ if (argslen > 0 && (args[0]->is<Null>() ||args[0]->is<Undefined>()))
+ throwError<SyntaxError>(kJSONInvalidParseInput);
+ ARG_UNPACK(text);
+ if (argslen > 1)
+ {
+ if (!args[1]->is<IFunction>())
+ throwError<TypeError>(kCheckTypeFailedError);
+ reviver = args[1]->as<IFunction>();
+ }
+ ASObject* res = NULL;
+ multiname dummy(NULL);
+
+ parseAll(text,&res,dummy,reviver);
+ return res;
+}
+
+ASFUNCTIONBODY(JSON,_stringify)
+{
+ _NR<ASObject> value;
+ ARG_UNPACK(value);
+ if (value->has_toJSON())
+ return Class<ASString>::getInstanceS(value->call_toJSON());
+ std::vector<ASObject *> path;
+ tiny_string filter;
+ IFunction* replacer = NULL;
+ if (argslen > 1 && !args[1]->is<Null>() && !args[1]->is<Undefined>())
+ {
+ if (args[1]->is<IFunction>())
+ {
+ replacer = args[1]->as<IFunction>();
+ }
+ else if (args[1]->is<Array>())
+ {
+ filter = " ";
+ Array* ar = args[1]->as<Array>();
+ for (uint64_t i = 0; i < ar->size(); i++)
+ {
+ filter += ar->at(i)->toString();
+ filter += " ";
+ }
+ }
+ else
+ throwError<TypeError>(kJSONInvalidReplacer);
+ }
+
+ tiny_string spaces = "";
+ if (argslen > 2)
+ {
+ ASObject* space = args[2];
+ spaces = " ";
+ if (space->is<Number>() || space->is<Integer>() || space->is<UInteger>())
+ {
+ int32_t v = space->toInt();
+ if (v < 0) v = 0;
+ if (v > 10) v = 10;
+ spaces = spaces.substr_bytes(0,v);
+ }
+ else if (space->is<Boolean>() || space->is<Null>())
+ {
+ spaces = "";
+ }
+ else
+ {
+ if(space->has_toString())
+ {
+ _R<ASObject> ret = space->call_toString();
+ spaces = ret->toString();
+ }
+ else
+ spaces = space->toString();
+ if (spaces.numBytes() > 10)
+ spaces = spaces.substr_bytes(0,10);
+ }
+ }
+ tiny_string res = value->toJSON(path,replacer,spaces,filter);
+
+ return Class<ASString>::getInstanceS(res);
+}
+void JSON::parseAll(const tiny_string &jsonstring, ASObject** parent , const multiname& key, IFunction *reviver)
+{
+ int len = jsonstring.numBytes();
+ int pos = 0;
+ while (pos < len)
+ {
+ if (*parent && (*parent)->isPrimitive())
+ throwError<SyntaxError>(kJSONInvalidParseInput);
+ pos = parse(jsonstring, pos, parent , key, reviver);
+ while (jsonstring.charAt(pos) == ' ' ||
+ jsonstring.charAt(pos) == '\t' ||
+ jsonstring.charAt(pos) == '\n' ||
+ jsonstring.charAt(pos) == '\r'
+ )
+ pos++;
+ }
+}
+int JSON::parse(const tiny_string &jsonstring, int pos, ASObject** parent , const multiname& key, IFunction *reviver)
+{
+ while (jsonstring.charAt(pos) == ' ' ||
+ jsonstring.charAt(pos) == '\t' ||
+ jsonstring.charAt(pos) == '\n' ||
+ jsonstring.charAt(pos) == '\r'
+ )
+ pos++;
+ int len = jsonstring.numBytes();
+ if (pos < len)
+ {
+ char c = jsonstring.charAt(pos);
+ switch(c)
+ {
+ case '{':
+ pos = parseObject(jsonstring,pos,parent,key, reviver);
+ break;
+ case '[':
+ pos = parseArray(jsonstring,pos,parent,key, reviver);
+ break;
+ case '"':
+ pos = parseString(jsonstring,pos,parent,key);
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '-':
+ pos = parseNumber(jsonstring,pos,parent,key);
+ break;
+ case 't':
+ pos = parseTrue(jsonstring,pos,parent,key);
+ break;
+ case 'f':
+ pos = parseFalse(jsonstring,pos,parent,key);
+ break;
+ case 'n':
+ pos = parseNull(jsonstring,pos,parent,key);
+ break;
+ default:
+ throwError<SyntaxError>(kJSONInvalidParseInput);
+ }
+ }
+ if (reviver)
+ {
+ bool haskey = key.name_type!= multiname::NAME_OBJECT;
+ ASObject* params[2];
+
+ if (haskey)
+ {
+ params[0] = Class<ASString>::getInstanceS(key.normalizedName());
+ if ((*parent)->hasPropertyByMultiname(key,true,false))
+ {
+ params[1] = (*parent)->getVariableByMultiname(key).getPtr();
+ params[1]->incRef();
+ }
+ else
+ params[1] = getSys()->getNullRef();
+ }
+ else
+ {
+ params[0] = Class<ASString>::getInstanceS("");
+ params[1] = *parent;
+ params[1]->incRef();
+ }
+
+ ASObject *funcret=reviver->call(getSys()->getNullRef(), params, 2);
+ if(funcret)
+ {
+ if (haskey)
+ {
+ if (funcret->is<Undefined>())
+ {
+ (*parent)->deleteVariableByMultiname(key);
+ funcret->decRef();
+ }
+ else
+ {
+ (*parent)->setVariableByMultiname(key,funcret,ASObject::CONST_NOT_ALLOWED);
+ }
+ }
+ else
+ *parent= funcret;
+ }
+ }
+ return pos;
+}
+int JSON::parseTrue(const tiny_string &jsonstring, int pos,ASObject** parent,const multiname& key)
+{
+ int len = jsonstring.numBytes();
+ if (len >= pos+4)
+ {
+ if (jsonstring.charAt(pos) == 't' &&
+ jsonstring.charAt(pos + 1) == 'r' &&
+ jsonstring.charAt(pos + 2) == 'u' &&
+ jsonstring.charAt(pos + 3) == 'e')
+ {
+ pos += 4;
+ if (*parent == NULL)
+ *parent = abstract_b(true);
+ else
+ (*parent)->setVariableByMultiname(key,abstract_b(true),ASObject::CONST_NOT_ALLOWED);
+ }
+ else
+ throwError<SyntaxError>(kJSONInvalidParseInput);
+ }
+ else
+ throwError<SyntaxError>(kJSONInvalidParseInput);
+ return pos;
+}
+int JSON::parseFalse(const tiny_string &jsonstring, int pos,ASObject** parent,const multiname& key)
+{
+ int len = jsonstring.numBytes();
+ if (len >= pos+5)
+ {
+ if (jsonstring.charAt(pos) == 'f' &&
+ jsonstring.charAt(pos + 1) == 'a' &&
+ jsonstring.charAt(pos + 2) == 'l' &&
+ jsonstring.charAt(pos + 3) == 's' &&
+ jsonstring.charAt(pos + 4) == 'e')
+ {
+ pos += 5;
+ if (*parent == NULL)
+ *parent = abstract_b(false);
+ else
+ (*parent)->setVariableByMultiname(key,abstract_b(false),ASObject::CONST_NOT_ALLOWED);
+ }
+ else
+ throwError<SyntaxError>(kJSONInvalidParseInput);
+ }
+ else
+ throwError<SyntaxError>(kJSONInvalidParseInput);
+ return pos;
+}
+int JSON::parseNull(const tiny_string &jsonstring, int pos,ASObject** parent,const multiname& key)
+{
+ int len = jsonstring.numBytes();
+ if (len >= pos+4)
+ {
+ if (jsonstring.charAt(pos) == 'n' &&
+ jsonstring.charAt(pos + 1) == 'u' &&
+ jsonstring.charAt(pos + 2) == 'l' &&
+ jsonstring.charAt(pos + 3) == 'l')
+ {
+ pos += 4;
+ if (*parent == NULL)
+ *parent = getSys()->getNullRef();
+ else
+ (*parent)->setVariableByMultiname(key,getSys()->getNullRef(),ASObject::CONST_NOT_ALLOWED);
+ }
+ else
+ throwError<SyntaxError>(kJSONInvalidParseInput);
+ }
+ else
+ throwError<SyntaxError>(kJSONInvalidParseInput);
+ return pos;
+}
+int JSON::parseString(const tiny_string &jsonstring, int pos,ASObject** parent,const multiname& key, tiny_string* result)
+{
+ pos++; // ignore starting quotes
+ int len = jsonstring.numChars();
+ if (pos >= len)
+ throwError<SyntaxError>(kJSONInvalidParseInput);
+
+ tiny_string sub = jsonstring.substr(pos,len-pos);
+
+ tiny_string res;
+ bool done = false;
+ for (CharIterator it=sub.begin(); it!=sub.end(); it++)
+ {
+ pos++;
+ if (*it == '\"')
+ {
+ done = true;
+ break;
+ }
+ else if(*it == '\\')
+ {
+ it++;
+ pos++;
+ if(it == sub.end())
+ break;
+ if(*it == '\"')
+ res += '\"';
+ else if(*it == '\\')
+ res += '\\';
+ else if(*it == '/')
+ res += '/';
+ else if(*it == 'b')
+ res += '\b';
+ else if(*it == 'f')
+ res += '\f';
+ else if(*it == 'n')
+ res += '\n';
+ else if(*it == 'r')
+ res += '\r';
+ else if(*it == 't')
+ res += '\t';
+ else if(*it == 'u')
+ {
+ tiny_string strhex;
+ for (int i = 0; i < 4; i++)
+ {
+ it++; pos++;
+ if (it==sub.end())
+ throwError<SyntaxError>(kJSONInvalidParseInput);
+ switch(*it)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ strhex += *it;
+ break;
+ default:
+ throwError<SyntaxError>(kJSONInvalidParseInput);
+ }
+ if (it==sub.end())
+ throwError<SyntaxError>(kJSONInvalidParseInput);
+ }
+ int64_t hexnum;
+ if (Integer::fromStringFlashCompatible(strhex.raw_buf(),hexnum,16))
+ {
+ if (hexnum < 0x20 && hexnum != 0xf)
+ throwError<SyntaxError>(kJSONInvalidParseInput);
+ res += tiny_string::fromChar(hexnum);
+ }
+ else
+ break;
+ }
+ else
+ throwError<SyntaxError>(kJSONInvalidParseInput);
+ }
+ else if (*it < 0x20)
+ {
+ throwError<SyntaxError>(kJSONInvalidParseInput);
+ }
+ else
+ {
+ res += *it;
+ }
+ }
+ if (!done)
+ throwError<SyntaxError>(kJSONInvalidParseInput);
+
+ if (parent != NULL)
+ {
+ if (*parent == NULL)
+ *parent = Class<ASString>::getInstanceS(res);
+ else
+ (*parent)->setVariableByMultiname(key,Class<ASString>::getInstanceS(res),ASObject::CONST_NOT_ALLOWED);
+ }
+ if (result)
+ *result =res;
+ return pos;
+}
+int JSON::parseNumber(const tiny_string &jsonstring, int pos, ASObject** parent, const multiname& key)
+{
+ int len = jsonstring.numBytes();
+ tiny_string res;
+ bool done = false;
+ while (!done && pos < len)
+ {
+ char c = jsonstring.charAt(pos);
+ switch(c)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '-':
+ case '+':
+ case '.':
+ case 'E':
+ case 'e':
+ res += c;
+ pos++;
+ break;
+ default:
+ done = true;
+ break;
+ }
+ }
+ ASString* numstr = Class<ASString>::getInstanceS(res);
+ number_t num = numstr->toNumber();
+
+ if (std::isnan(num))
+ throwError<SyntaxError>(kJSONInvalidParseInput);
+
+ if (*parent == NULL)
+ *parent = Class<Number>::getInstanceS(num);
+ else
+ {
+ (*parent)->setVariableByMultiname(key,Class<Number>::getInstanceS(num),ASObject::CONST_NOT_ALLOWED);
+ }
+ return pos;
+}
+int JSON::parseObject(const tiny_string &jsonstring, int pos,ASObject** parent,const multiname& key, IFunction *reviver)
+{
+ int len = jsonstring.numChars();
+ pos++; // ignore '{' or ','
+ ASObject* subobj = Class<ASObject>::getInstanceS();
+ if (*parent == NULL)
+ *parent = subobj;
+ else
+ (*parent)->setVariableByMultiname(key,subobj,ASObject::CONST_NOT_ALLOWED);
+ multiname name(NULL);
+ name.name_type=multiname::NAME_STRING;
+ name.ns.push_back(nsNameAndKind("",NAMESPACE));
+ name.isAttribute = false;
+ bool done = false;
+ bool bfirst = true;
+ bool needkey = true;
+ bool needvalue = false;
+
+ while (!done && pos < len)
+ {
+ while (jsonstring.charAt(pos) == ' ' ||
+ jsonstring.charAt(pos) == '\t' ||
+ jsonstring.charAt(pos) == '\n' ||
+ jsonstring.charAt(pos) == '\r'
+ )
+ pos++;
+ char c = jsonstring.charAt(pos);
+ switch(c)
+ {
+ case '}':
+ if (!bfirst && (needkey || needvalue))
+ throwError<SyntaxError>(kJSONInvalidParseInput);
+ done = true;
+ pos++;
+ break;
+ case '\"':
+ {
+ tiny_string keyname;
+ pos = parseString(jsonstring,pos,NULL,name,&keyname);
+ name.name_s_id=getSys()->getUniqueStringId(keyname);
+ needkey = false;
+ needvalue = true;
+ }
+ break;
+ case ',':
+ if (needkey || needvalue)
+ throwError<SyntaxError>(kJSONInvalidParseInput);
+ pos++;
+ name.name_s_id=0;
+ needkey = true;
+ break;
+ case ':':
+ pos++;
+ pos = parse(jsonstring,pos,&subobj,name,reviver);
+ needvalue = false;
+ break;
+ default:
+ throwError<SyntaxError>(kJSONInvalidParseInput);
+ }
+ bfirst=false;
+ }
+ if (!done)
+ throwError<SyntaxError>(kJSONInvalidParseInput);
+
+ return pos;
+}
+
+int JSON::parseArray(const tiny_string &jsonstring, int pos, ASObject** parent, const multiname& key, IFunction *reviver)
+{
+ int len = jsonstring.numChars();
+ pos++; // ignore '['
+ ASObject* subobj = Class<Array>::getInstanceS();
+ if (*parent == NULL)
+ *parent = subobj;
+ else
+ (*parent)->setVariableByMultiname(key,subobj,ASObject::CONST_NOT_ALLOWED);
+ multiname name(NULL);
+ name.name_type=multiname::NAME_INT;
+ name.name_i = 0;
+ name.ns.push_back(nsNameAndKind("",NAMESPACE));
+ name.isAttribute = false;
+ bool done = false;
+ while (!done && pos < len)
+ {
+ while (jsonstring.charAt(pos) == ' ' ||
+ jsonstring.charAt(pos) == '\t' ||
+ jsonstring.charAt(pos) == '\n' ||
+ jsonstring.charAt(pos) == '\r'
+ )
+ pos++;
+ char c = jsonstring.charAt(pos);
+ switch(c)
+ {
+ case ']':
+ done = true;
+ pos++;
+ break;
+ case ',':
+ name.name_i++;
+ pos++;
+ break;
+ default:
+ pos = parse(jsonstring,pos,&subobj,name, reviver);
+ break;
+ }
+ }
+ if (!done)
+ throwError<SyntaxError>(kJSONInvalidParseInput);
+
+ return pos;
+}
+
+
+
+
+/*****
+
+static QString sanitizeString(QString str)
+{
+ str.replace(QLatin1String("\\"), QLatin1String("\\\\"));
+ str.replace(QLatin1String("\""), QLatin1String("\\\""));
+ str.replace(QLatin1String("\b"), QLatin1String("\\b"));
+ str.replace(QLatin1String("\f"), QLatin1String("\\f"));
+ str.replace(QLatin1String("\n"), QLatin1String("\\n"));
+ str.replace(QLatin1String("\r"), QLatin1String("\\r"));
+ str.replace(QLatin1String("\t"), QLatin1String("\\t"));
+ return QString(QLatin1String("\"%1\"")).arg(str);
+}
+
+static QByteArray join(const QList<QByteArray> &list, const QByteArray &sep)
+{
+ QByteArray res;
+ Q_FOREACH(const QByteArray &i, list)
+ {
+ if(!res.isEmpty())
+ {
+ res += sep;
+ }
+ res += i;
+ }
+ return res;
+}
+
+
+
+static DSVariantList parseArray(const QString &json, int &index, bool &success)
+{
+ DSVariantList list;
+
+ nextToken(json, index);
+
+ bool done = false;
+ while(!done)
+ {
+ int token = lookAhead(json, index);
+
+ if(token == JsonTokenNone)
+ {
+ success = false;
+ return DSVariantList();
+ }
+ else if(token == JsonTokenComma)
+ {
+ nextToken(json, index);
+ }
+ else if(token == JsonTokenSquaredClose)
+ {
+ nextToken(json, index);
+ break;
+ }
+ else
+ {
+ QVariant value = parseValue(json, index, success);
+
+ if(!success)
+ {
+ return DSVariantList();
+ }
+
+ list.push_back(value);
+ }
+ }
+
+ return list;
+}
+
+
+static QVariant parseNumber(const QString &json, int &index)
+{
+ eatWhitespace(json, index);
+
+ int lastIndex = lastIndexOfNumber(json, index);
+ int charLength = (lastIndex - index) + 1;
+ QString numberStr;
+
+ numberStr = json.mid(index, charLength);
+
+ index = lastIndex + 1;
+
+ if (numberStr.contains('.')) {
+ return QVariant(numberStr.toDouble(NULL));
+ } else if (numberStr.startsWith('-')) {
+ return QVariant(numberStr.toLongLong(NULL));
+ } else {
+ return QVariant(numberStr.toULongLong(NULL));
+ }
+}
+
+static int lastIndexOfNumber(const QString &json, int index)
+{
+ int lastIndex;
+
+ for(lastIndex = index; lastIndex < json.size(); lastIndex++)
+ {
+ if(QString("0123456789+-.eE").indexOf(json[lastIndex]) == -1)
+ {
+ break;
+ }
+ }
+
+ return lastIndex -1;
+}
+
+
+
+static int lookAhead(const QString &json, int index)
+{
+ int saveIndex = index;
+ return nextToken(json, saveIndex);
+}
+
+static int nextToken(const QString &json, int &index)
+{
+ eatWhitespace(json, index);
+
+ if(index == json.size())
+ {
+ return JsonTokenNone;
+ }
+
+ QChar c = json[index];
+ index++;
+ switch(c.toLatin1())
+ {
+ case '{': return JsonTokenCurlyOpen;
+ case '}': return JsonTokenCurlyClose;
+ case '[': return JsonTokenSquaredOpen;
+ case ']': return JsonTokenSquaredClose;
+ case ',': return JsonTokenComma;
+ case '"': return JsonTokenString;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ case '-': return JsonTokenNumber;
+ case ':': return JsonTokenColon;
+ }
+
+ index--;
+
+ int remainingLength = json.size() - index;
+
+ //True
+ if(remainingLength >= 4)
+ {
+ if (json[index] == 't' && json[index + 1] == 'r' &&
+ json[index + 2] == 'u' && json[index + 3] == 'e')
+ {
+ index += 4;
+ return JsonTokenTrue;
+ }
+ }
+
+ //False
+ if (remainingLength >= 5)
+ {
+ if (json[index] == 'f' && json[index + 1] == 'a' &&
+ json[index + 2] == 'l' && json[index + 3] == 's' &&
+ json[index + 4] == 'e')
+ {
+ index += 5;
+ return JsonTokenFalse;
+ }
+ }
+
+ //Null
+ if (remainingLength >= 4)
+ {
+ if (json[index] == 'n' && json[index + 1] == 'u' &&
+ json[index + 2] == 'l' && json[index + 3] == 'l')
+ {
+ index += 4;
+ return JsonTokenNull;
+ }
+ }
+
+ return JsonTokenNone;
+}
+*****/
diff --git a/src/scripting/toplevel/JSON.h b/src/scripting/toplevel/JSON.h
new file mode 100644
index 0000000..1614cc7
--- /dev/null
+++ b/src/scripting/toplevel/JSON.h
@@ -0,0 +1,51 @@
+/**************************************************************************
+ Lightspark, a free flash player implementation
+
+ Copyright (C) 2009-2013 Alessandro Pignotti (a.pignotti at sssup.it)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+**************************************************************************/
+
+#ifndef SCRIPTING_TOPLEVEL_JSON_H
+#define SCRIPTING_TOPLEVEL_JSON_H 1
+#include "compat.h"
+#include "asobject.h"
+
+namespace lightspark
+{
+
+class JSON : public ASObject
+{
+public:
+ JSON(Class_base* c);
+ static void sinit(Class_base* c);
+ static void buildTraits(ASObject* o);
+ ASFUNCTION(_constructor);
+ ASFUNCTION(generator);
+ ASFUNCTION(_parse);
+ ASFUNCTION(_stringify);
+private:
+ static void parseAll(const tiny_string &jsonstring, ASObject** parent , const multiname& key, IFunction *reviver);
+ static int parse(const tiny_string &jsonstring, int pos, ASObject **parent, const multiname &key,IFunction* reviver);
+ static int parseTrue(const tiny_string &jsonstring, int pos, ASObject **parent, const multiname &key);
+ static int parseFalse(const tiny_string &jsonstring, int pos, ASObject **parent, const multiname &key);
+ static int parseNull(const tiny_string &jsonstring, int pos, ASObject **parent, const multiname &key);
+ static int parseString(const tiny_string &jsonstring, int pos, ASObject **parent, const multiname &key, tiny_string *result = NULL);
+ static int parseNumber(const tiny_string &jsonstring, int pos, ASObject **parent, const multiname &key);
+ static int parseObject(const tiny_string &jsonstring, int pos, ASObject **parent, const multiname &key, IFunction *reviver);
+ static int parseArray(const tiny_string &jsonstring, int pos, ASObject **parent, const multiname &key, IFunction *reviver);
+};
+
+}
+#endif /* SCRIPTING_TOPLEVEL_JSON_H */
diff --git a/src/scripting/toplevel/Math.cpp b/src/scripting/toplevel/Math.cpp
index da4ffed..a4822b4 100644
--- a/src/scripting/toplevel/Math.cpp
+++ b/src/scripting/toplevel/Math.cpp
@@ -26,9 +26,7 @@ using namespace lightspark;
void Math::sinit(Class_base* c)
{
- c->isFinal=true;
- c->setSuper(Class<ASObject>::getRef());
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED | CLASS_FINAL);
// public constants
c->setVariableByQName("E","",abstract_d(2.71828182845905),CONSTANT_TRAIT);
c->setVariableByQName("LN10","",abstract_d(2.302585092994046),CONSTANT_TRAIT);
diff --git a/src/scripting/toplevel/Number.cpp b/src/scripting/toplevel/Number.cpp
index 7c4dbaa..d91b2ac 100644
--- a/src/scripting/toplevel/Number.cpp
+++ b/src/scripting/toplevel/Number.cpp
@@ -20,6 +20,7 @@
#include "parsing/amf3_generator.h"
#include "scripting/argconv.h"
#include "scripting/toplevel/Number.h"
+#include "scripting/flash/utils/ByteArray.h"
using namespace std;
using namespace lightspark;
@@ -258,24 +259,23 @@ tiny_string Number::toStringRadix(number_t val, int radix)
void Number::sinit(Class_base* c)
{
- c->isFinal = true;
- c->setSuper(Class<ASObject>::getRef());
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- //Must create and link the number the hard way
- Number* ninf=new (c->memoryAccount) Number(c, -numeric_limits<double>::infinity());
- Number* pinf=new (c->memoryAccount) Number(c, numeric_limits<double>::infinity());
- Number* pmax=new (c->memoryAccount) Number(c, numeric_limits<double>::max());
- Number* pmin=new (c->memoryAccount) Number(c, numeric_limits<double>::min());
- Number* pnan=new (c->memoryAccount) Number(c, numeric_limits<double>::quiet_NaN());
- c->setVariableByQName("NEGATIVE_INFINITY","",ninf,CONSTANT_TRAIT);
- c->setVariableByQName("POSITIVE_INFINITY","",pinf,CONSTANT_TRAIT);
- c->setVariableByQName("MAX_VALUE","",pmax,CONSTANT_TRAIT);
- c->setVariableByQName("MIN_VALUE","",pmin,CONSTANT_TRAIT);
- c->setVariableByQName("NaN","",pnan,CONSTANT_TRAIT);
- c->prototype->setVariableByQName("toString",AS3,Class<IFunction>::getFunction(Number::_toString),DYNAMIC_TRAIT);
- c->prototype->setVariableByQName("toLocaleString",AS3,Class<IFunction>::getFunction(Number::_toString),DYNAMIC_TRAIT);
- c->prototype->setVariableByQName("toFixed",AS3,Class<IFunction>::getFunction(Number::toFixed),DYNAMIC_TRAIT);
- c->prototype->setVariableByQName("valueOf",AS3,Class<IFunction>::getFunction(_valueOf),DYNAMIC_TRAIT);
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED | CLASS_FINAL);
+ c->setVariableByQName("NEGATIVE_INFINITY","",abstract_d(-numeric_limits<double>::infinity()),CONSTANT_TRAIT);
+ c->setVariableByQName("POSITIVE_INFINITY","",abstract_d(numeric_limits<double>::infinity()),CONSTANT_TRAIT);
+ c->setVariableByQName("MAX_VALUE","",abstract_d(numeric_limits<double>::max()),CONSTANT_TRAIT);
+ c->setVariableByQName("MIN_VALUE","",abstract_d(numeric_limits<double>::min()),CONSTANT_TRAIT);
+ c->setVariableByQName("NaN","",abstract_d(numeric_limits<double>::quiet_NaN()),CONSTANT_TRAIT);
+ c->setDeclaredMethodByQName("toString",AS3,Class<IFunction>::getFunction(_toString),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("toFixed",AS3,Class<IFunction>::getFunction(toFixed,1),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("toExponential",AS3,Class<IFunction>::getFunction(toExponential,1),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("toPrecision",AS3,Class<IFunction>::getFunction(toPrecision,1),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("valueOf",AS3,Class<IFunction>::getFunction(_valueOf),NORMAL_METHOD,true);
+ c->prototype->setVariableByQName("toString","",Class<IFunction>::getFunction(Number::_toString),DYNAMIC_TRAIT);
+ c->prototype->setVariableByQName("toLocaleString","",Class<IFunction>::getFunction(Number::_toString),DYNAMIC_TRAIT);
+ c->prototype->setVariableByQName("toFixed","",Class<IFunction>::getFunction(Number::toFixed, 1),DYNAMIC_TRAIT);
+ c->prototype->setVariableByQName("toExponential","",Class<IFunction>::getFunction(Number::toExponential, 1),DYNAMIC_TRAIT);
+ c->prototype->setVariableByQName("toPrecision","",Class<IFunction>::getFunction(Number::toPrecision, 1),DYNAMIC_TRAIT);
+ c->prototype->setVariableByQName("valueOf","",Class<IFunction>::getFunction(_valueOf),DYNAMIC_TRAIT);
}
ASFUNCTIONBODY(Number,_constructor)
@@ -283,7 +283,9 @@ ASFUNCTIONBODY(Number,_constructor)
Number* th=static_cast<Number*>(obj);
if(argslen==0)
{
- //The number is already initialized to NaN
+ // not constructed Numbers are set to NaN, so we have to set it to the default value during dynamic construction
+ if (std::isnan(th->val))
+ th->val = 0.;
return NULL;
}
th->val=args[0]->toNumber();
@@ -293,39 +295,190 @@ ASFUNCTIONBODY(Number,_constructor)
ASFUNCTIONBODY(Number,toFixed)
{
number_t val = obj->toNumber();
- int fractiondigits=0;
+ int fractiondigits;
ARG_UNPACK (fractiondigits,0);
+ return Class<ASString>::getInstanceS(toFixedString(val, fractiondigits));
+}
+
+tiny_string Number::toFixedString(double v, int32_t fractiondigits)
+{
if (fractiondigits < 0 || fractiondigits > 20)
- throwError<RangeError>(kInvalidPrecisionError, Integer::toString(fractiondigits));
- if(std::isnan(val))
- return Class<ASString>::getInstanceS("NaN");
+ throwError<RangeError>(kInvalidPrecisionError);
+ if (std::isnan(v))
+ return "NaN";
+ if (v >= pow(10., 21))
+ return toString(v);
number_t fractpart, intpart;
- if (fractiondigits == 0)
- val+=0.5;
- fractpart = modf (val , &intpart);
+ double rounded = v + 0.5*pow(10., -fractiondigits);
+ fractpart = modf(rounded , &intpart);
tiny_string res("");
- number_t v = fabs(intpart);
char buf[40];
- snprintf(buf,40,"%ld",int64_t(v));
+ snprintf(buf,40,"%ld",int64_t(fabs(intpart)));
res += buf;
if (fractiondigits > 0)
{
- int x = fractiondigits;
+ number_t x = fractpart;
res += ".";
- while (fractiondigits)
+ for (int i=0; i<fractiondigits; i++)
{
- fractpart*=10.0;
- fractiondigits--;
+ x*=10.0;
+ int n = (int)x;
+ x -= n;
+ res += tiny_string::fromChar('0' + n);
}
- fractpart+=0.5;
- snprintf(buf,40,"%0*ld",x,int64_t(fractpart));
- res += buf;
}
- if ( val < 0)
+ if ( v < 0)
res = tiny_string::fromChar('-')+res;
- return Class<ASString>::getInstanceS(res);
+ return res;
+}
+
+ASFUNCTIONBODY(Number,toExponential)
+{
+ Number* th=obj->as<Number>();
+ double v = th->val;
+ int32_t fractionDigits;
+ ARG_UNPACK(fractionDigits, 0);
+ if (argslen == 0 || args[0]->is<Undefined>())
+ fractionDigits = imin(imax(Number::countSignificantDigits(v)-1, 1), 20);
+ return Class<ASString>::getInstanceS(toExponentialString(v, fractionDigits));
+}
+
+tiny_string Number::toExponentialString(double v, int32_t fractionDigits)
+{
+ if (std::isnan(v) || std::isinf(v))
+ return toString(v);
+
+ tiny_string res;
+ if (v < 0)
+ {
+ res = "-";
+ v = -v;
+ }
+
+ if (fractionDigits < 0 || fractionDigits > 20)
+ throwError<RangeError>(kInvalidPrecisionError);
+
+ char buf[40];
+ snprintf(buf,40,"%.*e", fractionDigits, v);
+ res += buf;
+ res = purgeExponentLeadingZeros(res);
+ return res;
+}
+
+tiny_string Number::purgeExponentLeadingZeros(const tiny_string& exponentialForm)
+{
+ uint32_t i = exponentialForm.find("e");
+ if (i == tiny_string::npos)
+ return exponentialForm;
+
+ tiny_string res;
+ res = exponentialForm.substr(0, i+1);
+
+ i++;
+ if (i >= exponentialForm.numChars())
+ return res;
+
+ uint32_t c = exponentialForm.charAt(i);
+ if (c == '-' || c == '+')
+ {
+ res += c;
+ i++;
+ }
+
+ bool leadingZero = true;
+ while (i < exponentialForm.numChars())
+ {
+ uint32_t c = exponentialForm.charAt(i);
+ if (!leadingZero || (leadingZero && c != '0'))
+ {
+ res += c;
+ leadingZero = false;
+ }
+
+ i++;
+ }
+
+ if (leadingZero)
+ res += '0';
+
+ return res;
+}
+
+/*
+ * Should return the number of significant decimal digits necessary to
+ * uniquely specify v. The actual implementation is a quick-and-dirty
+ * approximation.
+ */
+int32_t Number::countSignificantDigits(double v) {
+ char buf[40];
+ snprintf(buf,40,"%.20e", v);
+
+ char *p = &buf[0];
+ while (*p == '0' || *p == '.')
+ p++;
+
+ int32_t digits = 0;
+ int32_t consecutiveZeros = 0;
+ while ((('0' <= *p && *p <= '9') || *p == '.') && consecutiveZeros < 10)
+ {
+ if (*p != '.')
+ digits++;
+
+ if (*p == '0')
+ consecutiveZeros++;
+ else if (*p != '.')
+ consecutiveZeros = 0;
+ p++;
+ }
+
+ digits -= consecutiveZeros;
+
+ if (digits <= 0)
+ digits = 1;
+
+ return digits;
+}
+
+ASFUNCTIONBODY(Number,toPrecision)
+{
+ Number* th=obj->as<Number>();
+ double v = th->val;
+ if (argslen == 0 || args[0]->is<Undefined>())
+ return Class<ASString>::getInstanceS(toString(v));
+
+ int32_t precision;
+ ARG_UNPACK(precision);
+ return Class<ASString>::getInstanceS(toPrecisionString(v, precision));
+}
+
+tiny_string Number::toPrecisionString(double v, int32_t precision)
+{
+ if (precision < 1 || precision > 21)
+ {
+ throwError<RangeError>(kInvalidPrecisionError);
+ return NULL;
+ }
+ else if (std::isnan(v) || std::isinf(v))
+ return toString(v);
+ else if (::fabs(v) > pow(10., precision))
+ return toExponentialString(v, precision-1);
+ else if (v == 0)
+ {
+ tiny_string zero = "0.";
+ for (int i=0; i<precision; i++)
+ zero += "0";
+ return zero;
+ }
+ else
+ {
+ int n = (int)::ceil(::log10(::fabs(v)));
+ if (n < 0)
+ return toExponentialString(v, precision-1);
+ else
+ return toFixedString(v, precision-n);
+ }
}
ASFUNCTIONBODY(Number,_valueOf)
diff --git a/src/scripting/toplevel/Number.h b/src/scripting/toplevel/Number.h
index f03ddb0..ead2bb9 100644
--- a/src/scripting/toplevel/Number.h
+++ b/src/scripting/toplevel/Number.h
@@ -34,17 +34,24 @@ friend class ABCContext;
friend class ABCVm;
private:
static void purgeTrailingZeroes(char* buf);
+ static tiny_string purgeExponentLeadingZeros(const tiny_string& exponentialForm);
+ static int32_t countSignificantDigits(double v);
public:
- Number(Class_base* c, double v=0.):ASObject(c),val(v){type=T_NUMBER;}
+ Number(Class_base* c, double v=(std::numeric_limits<double>::quiet_NaN())):ASObject(c),val(v){type=T_NUMBER;}
static const number_t NaN;
double val;
ASFUNCTION(_constructor);
ASFUNCTION(_toString);
+ ASFUNCTION(toExponential);
+ ASFUNCTION(toPrecision);
ASFUNCTION(toFixed);
ASFUNCTION(_valueOf);
tiny_string toString();
static tiny_string toString(number_t val);
static tiny_string toStringRadix(number_t val, int radix);
+ static tiny_string toExponentialString(double v, int32_t fractionDigits);
+ static tiny_string toFixedString(double v, int32_t fractionDigits);
+ static tiny_string toPrecisionString(double v, int32_t precision);
static bool isInteger(number_t val)
{
return floor(val) == val;
diff --git a/src/scripting/toplevel/RegExp.cpp b/src/scripting/toplevel/RegExp.cpp
index 1e1c5d5..0d029a2 100644
--- a/src/scripting/toplevel/RegExp.cpp
+++ b/src/scripting/toplevel/RegExp.cpp
@@ -35,12 +35,16 @@ RegExp::RegExp(Class_base* c, const tiny_string& _re):ASObject(c),dotall(false),
void RegExp::sinit(Class_base* c)
{
- c->setSuper(Class<ASObject>::getRef());
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_DYNAMIC_NOT_FINAL);
+ c->setDeclaredMethodByQName("exec","",Class<IFunction>::getFunction(exec),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("exec",AS3,Class<IFunction>::getFunction(exec),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("test","",Class<IFunction>::getFunction(test),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("test",AS3,Class<IFunction>::getFunction(test),NORMAL_METHOD,true);
- c->prototype->setVariableByQName("toString",AS3,Class<IFunction>::getFunction(_toString),DYNAMIC_TRAIT);
+ c->setDeclaredMethodByQName("toString","",Class<IFunction>::getFunction(_toString),NORMAL_METHOD,true);
+ c->prototype->setVariableByQName("toString","",Class<IFunction>::getFunction(_toString),DYNAMIC_TRAIT);
+ c->prototype->setVariableByQName("exec","",Class<IFunction>::getFunction(exec),DYNAMIC_TRAIT);
c->prototype->setVariableByQName("exec",AS3,Class<IFunction>::getFunction(exec),DYNAMIC_TRAIT);
+ c->prototype->setVariableByQName("test","",Class<IFunction>::getFunction(test),DYNAMIC_TRAIT);
c->prototype->setVariableByQName("test",AS3,Class<IFunction>::getFunction(test),DYNAMIC_TRAIT);
REGISTER_GETTER(c,dotall);
REGISTER_GETTER(c,global);
@@ -257,6 +261,8 @@ ASFUNCTIONBODY(RegExp,test)
ASFUNCTIONBODY(RegExp,_toString)
{
+ if(Class<RegExp>::getClass()->prototype->getObj() == obj)
+ return Class<ASString>::getInstanceS("/(?:)/");
if(!obj->is<RegExp>())
throw Class<TypeError>::getInstanceS("RegExp.toString is not generic");
diff --git a/src/scripting/toplevel/UInteger.cpp b/src/scripting/toplevel/UInteger.cpp
index 3a1fc96..ebac801 100644
--- a/src/scripting/toplevel/UInteger.cpp
+++ b/src/scripting/toplevel/UInteger.cpp
@@ -17,6 +17,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
+#include <cmath>
#include "scripting/argconv.h"
#include "scripting/toplevel/UInteger.h"
@@ -115,17 +116,26 @@ ASFUNCTIONBODY(UInteger,_valueOf)
void UInteger::sinit(Class_base* c)
{
- c->isFinal = true;
- c->setSuper(Class<ASObject>::getRef());
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED | CLASS_FINAL);
c->setVariableByQName("MAX_VALUE","",abstract_ui(0xFFFFFFFF),CONSTANT_TRAIT);
c->setVariableByQName("MIN_VALUE","",abstract_ui(0),CONSTANT_TRAIT);
- c->prototype->setVariableByQName("toString",AS3,Class<IFunction>::getFunction(_toString),DYNAMIC_TRAIT);
- c->prototype->setVariableByQName("valueOf",AS3,Class<IFunction>::getFunction(_valueOf),DYNAMIC_TRAIT);
+ c->setDeclaredMethodByQName("toString",AS3,Class<IFunction>::getFunction(_toString),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("toFixed",AS3,Class<IFunction>::getFunction(_toFixed,1),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("toExponential",AS3,Class<IFunction>::getFunction(_toExponential,1),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("toPrecision",AS3,Class<IFunction>::getFunction(_toPrecision,1),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("valueOf",AS3,Class<IFunction>::getFunction(_valueOf),NORMAL_METHOD,true);
+ c->prototype->setVariableByQName("toExponential","",Class<IFunction>::getFunction(_toExponential, 1),DYNAMIC_TRAIT);
+ c->prototype->setVariableByQName("toFixed","",Class<IFunction>::getFunction(_toFixed, 1),DYNAMIC_TRAIT);
+ c->prototype->setVariableByQName("toPrecision","",Class<IFunction>::getFunction(_toPrecision, 1),DYNAMIC_TRAIT);
+ c->prototype->setVariableByQName("toString","",Class<IFunction>::getFunction(_toString),DYNAMIC_TRAIT);
+ c->prototype->setVariableByQName("valueOf","",Class<IFunction>::getFunction(_valueOf),DYNAMIC_TRAIT);
}
ASFUNCTIONBODY(UInteger,_toString)
{
+ if(Class<UInteger>::getClass()->prototype->getObj() == obj)
+ return Class<ASString>::getInstanceS("0");
+
UInteger* th=static_cast<UInteger*>(obj);
uint32_t radix;
ARG_UNPACK (radix,10);
@@ -160,3 +170,37 @@ bool UInteger::isEqual(ASObject* o)
return o->isEqual(this);
}
}
+
+ASFUNCTIONBODY(UInteger,_toExponential)
+{
+ UInteger *th=obj->as<UInteger>();
+ double v = (double)th->val;
+ int32_t fractionDigits;
+ ARG_UNPACK(fractionDigits, 0);
+ if (argslen == 0 || args[0]->is<Undefined>())
+ {
+ if (v == 0)
+ fractionDigits = 1;
+ else
+ fractionDigits = imin(imax((int32_t)ceil(::log10(v)), 1), 20);
+ }
+ return Class<ASString>::getInstanceS(Number::toExponentialString(v, fractionDigits));
+}
+
+ASFUNCTIONBODY(UInteger,_toFixed)
+{
+ UInteger *th=obj->as<UInteger>();
+ int fractiondigits;
+ ARG_UNPACK (fractiondigits, 0);
+ return Class<ASString>::getInstanceS(Number::toFixedString(th->val, fractiondigits));
+}
+
+ASFUNCTIONBODY(UInteger,_toPrecision)
+{
+ UInteger *th=obj->as<UInteger>();
+ if (argslen == 0 || args[0]->is<Undefined>())
+ return Class<ASString>::getInstanceS(th->toString());
+ int precision;
+ ARG_UNPACK (precision);
+ return Class<ASString>::getInstanceS(Number::toPrecisionString(th->val, precision));
+}
diff --git a/src/scripting/toplevel/UInteger.h b/src/scripting/toplevel/UInteger.h
index fe0fbcc..197c590 100644
--- a/src/scripting/toplevel/UInteger.h
+++ b/src/scripting/toplevel/UInteger.h
@@ -49,6 +49,9 @@ public:
ASFUNCTION(generator);
ASFUNCTION(_toString);
ASFUNCTION(_valueOf);
+ ASFUNCTION(_toExponential);
+ ASFUNCTION(_toFixed);
+ ASFUNCTION(_toPrecision);
std::string toDebugString() { return toString()+"ui"; }
//CHECK: should this have a special serialization?
};
diff --git a/src/scripting/toplevel/Vector.cpp b/src/scripting/toplevel/Vector.cpp
index 383982d..a97f12a 100644
--- a/src/scripting/toplevel/Vector.cpp
+++ b/src/scripting/toplevel/Vector.cpp
@@ -28,31 +28,48 @@ using namespace lightspark;
void Vector::sinit(Class_base* c)
{
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setSuper(Class<ASObject>::getRef());
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_FINAL);
c->setDeclaredMethodByQName("length","",Class<IFunction>::getFunction(getLength),GETTER_METHOD,true);
c->setDeclaredMethodByQName("length","",Class<IFunction>::getFunction(setLength),SETTER_METHOD,true);
c->setDeclaredMethodByQName("toString","",Class<IFunction>::getFunction(_toString),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("toString",AS3,Class<IFunction>::getFunction(_toString),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("fixed","",Class<IFunction>::getFunction(getFixed),GETTER_METHOD,true);
c->setDeclaredMethodByQName("fixed","",Class<IFunction>::getFunction(setFixed),SETTER_METHOD,true);
+ c->setDeclaredMethodByQName("concat","",Class<IFunction>::getFunction(_concat),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("concat",AS3,Class<IFunction>::getFunction(_concat),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("every","",Class<IFunction>::getFunction(every),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("every",AS3,Class<IFunction>::getFunction(every),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("filter","",Class<IFunction>::getFunction(filter),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("filter",AS3,Class<IFunction>::getFunction(filter),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("forEach","",Class<IFunction>::getFunction(forEach),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("forEach",AS3,Class<IFunction>::getFunction(forEach),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("indexOf","",Class<IFunction>::getFunction(indexOf),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("indexOf",AS3,Class<IFunction>::getFunction(indexOf),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("lastIndexOf","",Class<IFunction>::getFunction(lastIndexOf),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("lastIndexOf",AS3,Class<IFunction>::getFunction(lastIndexOf),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("join","",Class<IFunction>::getFunction(join),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("join",AS3,Class<IFunction>::getFunction(join),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("map","",Class<IFunction>::getFunction(_map),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("map",AS3,Class<IFunction>::getFunction(_map),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("pop","",Class<IFunction>::getFunction(_pop),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("pop",AS3,Class<IFunction>::getFunction(_pop),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("push","",Class<IFunction>::getFunction(push),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("push",AS3,Class<IFunction>::getFunction(push),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("reverse","",Class<IFunction>::getFunction(_reverse),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("reverse",AS3,Class<IFunction>::getFunction(_reverse),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("shift","",Class<IFunction>::getFunction(shift),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("shift",AS3,Class<IFunction>::getFunction(shift),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("slice","",Class<IFunction>::getFunction(slice),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("slice",AS3,Class<IFunction>::getFunction(slice),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("some","",Class<IFunction>::getFunction(some),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("some",AS3,Class<IFunction>::getFunction(some),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("sort","",Class<IFunction>::getFunction(_sort),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("sort",AS3,Class<IFunction>::getFunction(_sort),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("splice","",Class<IFunction>::getFunction(splice),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("splice",AS3,Class<IFunction>::getFunction(splice),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("toLocaleString","",Class<IFunction>::getFunction(_toString),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("toLocaleString",AS3,Class<IFunction>::getFunction(_toString),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("unshift","",Class<IFunction>::getFunction(unshift),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("unshift",AS3,Class<IFunction>::getFunction(unshift),NORMAL_METHOD,true);
@@ -77,7 +94,7 @@ void Vector::sinit(Class_base* c)
c->prototype->setVariableByQName("unshift",AS3,Class<IFunction>::getFunction(unshift),DYNAMIC_TRAIT);
}
-Vector::Vector(Class_base* c, Type *vtype):ASObject(c),vec_type(vtype),fixed(false),vec(reporter_allocator<ASObject*>(c->memoryAccount))
+Vector::Vector(Class_base* c, const Type *vtype):ASObject(c),vec_type(vtype),fixed(false),vec(reporter_allocator<ASObject*>(c->memoryAccount))
{
}
@@ -97,18 +114,16 @@ void Vector::finalize()
ASObject::finalize();
}
-void Vector::setTypes(const std::vector<Type*>& types)
+void Vector::setTypes(const std::vector<const Type *> &types)
{
assert(vec_type == NULL);
- assert_and_throw(types.size() == 1);
- vec_type = types[0];
+ if(types.size() == 1)
+ vec_type = types[0];
}
-
-bool Vector::sameType(const std::vector<Type*>& types) const
+bool Vector::sameType(const QName& classname) const
{
- return (types.size() == 1) && ((types[0] == vec_type) ||
- (vec_type == Type::anyType) ||
- (types[0] == Type::anyType));
+ tiny_string clsname = this->getClass()->getQualifiedClassName();
+ return (clsname.startsWith(classname.getQualifiedName().raw_buf()));
}
ASObject* Vector::generator(TemplatedClass<Vector>* o_class, ASObject* const* args, const unsigned int argslen)
@@ -117,7 +132,7 @@ ASObject* Vector::generator(TemplatedClass<Vector>* o_class, ASObject* const* ar
assert_and_throw(args[0]->getClass());
assert_and_throw(o_class->getTypes().size() == 1);
- Type* type = o_class->getTypes()[0];
+ const Type* type = o_class->getTypes()[0];
if(args[0]->getClass() == Class<Array>::getClass())
{
@@ -127,10 +142,10 @@ ASObject* Vector::generator(TemplatedClass<Vector>* o_class, ASObject* const* ar
Array* a = static_cast<Array*>(args[0]);
for(unsigned int i=0;i<a->size();++i)
{
- ASObject* obj = a->at(i).getPtr();
+ _R<ASObject> obj = a->at(i);
obj->incRef();
//Convert the elements of the array to the type of this vector
- ret->vec.push_back( type->coerce(obj) );
+ ret->vec.push_back( type->coerce(obj.getPtr()) );
}
return ret;
}
@@ -717,6 +732,45 @@ ASFUNCTIONBODY(Vector,indexOf)
}
return abstract_i(ret);
}
+bool Vector::sortComparatorDefault::operator()(ASObject* d1, ASObject* d2)
+{
+ if(isNumeric)
+ {
+ number_t a=d1->toNumber();
+
+ number_t b=d2->toNumber();
+
+ if(std::isnan(a) || std::isnan(b))
+ throw RunTimeException("Cannot sort non number with Array.NUMERIC option");
+ if(isDescending)
+ return b>a;
+ else
+ return a<b;
+ }
+ else
+ {
+ //Comparison is always in lexicographic order
+ tiny_string s1 = d1->toString();
+ tiny_string s2 = d2->toString();
+
+ if(isDescending)
+ {
+ //TODO: unicode support
+ if(isCaseInsensitive)
+ return s1.strcasecmp(s2)>0;
+ else
+ return s1>s2;
+ }
+ else
+ {
+ //TODO: unicode support
+ if(isCaseInsensitive)
+ return s1.strcasecmp(s2)<0;
+ else
+ return s1<s2;
+ }
+ }
+}
bool Vector::sortComparatorWrapper::operator()(ASObject* d1, ASObject* d2)
{
ASObject* objs[2];
@@ -747,10 +801,44 @@ ASFUNCTIONBODY(Vector,_sort)
throwError<ArgumentError>(kWrongArgumentCountError, "Vector.sort", "1", Integer::toString(argslen));
Vector* th=static_cast<Vector*>(obj);
- IFunction* comp=static_cast<IFunction*>(args[0]);
+ IFunction* comp=NULL;
+ bool isNumeric=false;
+ bool isCaseInsensitive=false;
+ bool isDescending=false;
+ if(args[0]->getObjectType()==T_FUNCTION) //Comparison func
+ {
+ assert_and_throw(comp==NULL);
+ comp=static_cast<IFunction*>(args[0]);
+ }
+ else
+ {
+ uint32_t options=args[0]->toInt();
+ if(options&Array::NUMERIC)
+ isNumeric=true;
+ if(options&Array::CASEINSENSITIVE)
+ isCaseInsensitive=true;
+ if(options&Array::DESCENDING)
+ isDescending=true;
+ if(options&(~(Array::NUMERIC|Array::CASEINSENSITIVE|Array::DESCENDING)))
+ throw UnsupportedException("Vector::sort not completely implemented");
+ }
+ std::vector<ASObject*> tmp = vector<ASObject*>(th->vec.size());
+ int i = 0;
+ for(auto it=th->vec.begin();it != th->vec.end();++it)
+ {
+ tmp[i++]= *it;
+ }
+ if(comp)
+ sort(tmp.begin(),tmp.end(),sortComparatorWrapper(comp,th->vec_type));
+ else
+ sort(tmp.begin(),tmp.end(),sortComparatorDefault(isNumeric,isCaseInsensitive,isDescending));
- sort(th->vec.begin(),th->vec.end(),sortComparatorWrapper(comp,th->vec_type));
+ th->vec.clear();
+ for(auto ittmp=tmp.begin();ittmp != tmp.end();++ittmp)
+ {
+ th->vec.push_back(*ittmp);
+ }
obj->incRef();
return obj;
}
@@ -782,10 +870,17 @@ ASFUNCTIONBODY(Vector,unshift)
ASFUNCTIONBODY(Vector,_map)
{
Vector* th=static_cast<Vector*>(obj);
- assert_and_throw(argslen==1 && args[0]->getObjectType()==T_FUNCTION);
- IFunction* func=static_cast<IFunction*>(args[0]);
+ _NR<IFunction> func;
+ _NR<ASObject> thisObject;
+
+ if (argslen >= 1 && !args[0]->is<IFunction>())
+ throwError<TypeError>(kCheckTypeFailedError, args[0]->getClassName(), "Function");
+
+ ARG_UNPACK(func)(thisObject,NullRef);
+
Vector* ret= (Vector*)obj->getClass()->getInstance(true,NULL,0);
+ ASObject* thisObj;
for(uint32_t i=0;i<th->size();i++)
{
ASObject* funcArgs[3];
@@ -804,7 +899,14 @@ ASFUNCTIONBODY(Vector,_map)
funcArgs[1]=abstract_i(i);
funcArgs[2]=th;
funcArgs[2]->incRef();
- ASObject* funcRet=func->call(getSys()->getNullRef(), funcArgs, 3);
+ if (thisObject.isNull())
+ thisObj = getSys()->getNullRef();
+ else
+ {
+ thisObj = thisObject.getPtr();
+ thisObj->incRef();
+ }
+ ASObject* funcRet=func->call(thisObj, funcArgs, 3);
assert_and_throw(funcRet);
ret->vec.push_back(funcRet);
}
@@ -975,3 +1077,11 @@ bool Vector::isValidMultiname(const multiname& name, uint32_t& index)
return validIndex;
}
+
+ASObject* Vector::at(unsigned int index, ASObject *defaultValue) const
+{
+ if (index < vec.size())
+ return vec.at(index);
+ else
+ return defaultValue;
+}
diff --git a/src/scripting/toplevel/Vector.h b/src/scripting/toplevel/Vector.h
index 4cfd87a..93e5cef 100644
--- a/src/scripting/toplevel/Vector.h
+++ b/src/scripting/toplevel/Vector.h
@@ -28,29 +28,39 @@ namespace lightspark
template<class T> class TemplatedClass;
class Vector: public ASObject
{
- Type* vec_type;
+ const Type* vec_type;
bool fixed;
std::vector<ASObject*, reporter_allocator<ASObject*>> vec;
int capIndex(int i) const;
+ class sortComparatorDefault
+ {
+ private:
+ bool isNumeric;
+ bool isCaseInsensitive;
+ bool isDescending;
+ public:
+ sortComparatorDefault(bool n, bool ci, bool d):isNumeric(n),isCaseInsensitive(ci),isDescending(d){}
+ bool operator()(ASObject* d1, ASObject* d2);
+ };
class sortComparatorWrapper
{
private:
IFunction* comparator;
- Type* vec_type;
+ const Type* vec_type;
public:
- sortComparatorWrapper(IFunction* c, Type* v):comparator(c),vec_type(v){}
+ sortComparatorWrapper(IFunction* c, const Type* v):comparator(c),vec_type(v){}
bool operator()(ASObject* d1, ASObject* d2);
};
public:
- Vector(Class_base* c, Type *vtype=NULL);
+ Vector(Class_base* c, const Type *vtype=NULL);
~Vector();
void finalize();
static void sinit(Class_base* c);
static void buildTraits(ASObject* o) {};
static ASObject* generator(TemplatedClass<Vector>* o_class, ASObject* const* args, const unsigned int argslen);
- void setTypes(const std::vector<Type*>& types);
- bool sameType(const std::vector<Type*>& types) const;
+ void setTypes(const std::vector<const Type*>& types);
+ bool sameType(const QName& classname) const;
//Overloads
tiny_string toString(bool debugMsg=false);
@@ -71,6 +81,9 @@ public:
{
return vec.at(index);
}
+ //Get value at index, or return defaultValue (a borrowed
+ //reference) if index is out-of-range
+ ASObject* at(unsigned int index, ASObject *defaultValue) const;
//Appends an object to the Vector. o is coerced to vec_type.
//Takes ownership of o.
@@ -78,7 +91,6 @@ public:
//TODO: do we need to implement generator?
ASFUNCTION(_constructor);
- ASFUNCTION(_applytype);
ASFUNCTION(push);
ASFUNCTION(_concat);
diff --git a/src/scripting/toplevel/XML.cpp b/src/scripting/toplevel/XML.cpp
index 16f0325..3864f2c 100644
--- a/src/scripting/toplevel/XML.cpp
+++ b/src/scripting/toplevel/XML.cpp
@@ -28,47 +28,70 @@
#include <libxml/tree.h>
#include <libxml++/parsers/domparser.h>
#include <libxml++/nodes/textnode.h>
+#include <libxml++/nodes/entityreference.h>
using namespace std;
using namespace lightspark;
-XML::XML(Class_base* c):ASObject(c),node(NULL),constructed(false),ignoreComments(true)
+static bool ignoreComments;
+static bool ignoreProcessingInstructions;
+static bool ignoreWhitespace;
+static int32_t prettyIndent;
+static bool prettyPrinting;
+
+void setDefaultXMLSettings()
{
+ ignoreComments = true;
+ ignoreProcessingInstructions = true;
+ ignoreWhitespace = true;
+ prettyIndent = 2;
+ prettyPrinting = true;
}
-XML::XML(Class_base* c,const string& str):ASObject(c),node(NULL),constructed(true)
+XML::XML(Class_base* c):ASObject(c),parentNode(0),nodetype((xmlElementType)0),constructed(false), hasParentNode(false)
{
- node=buildFromString(str, false);
}
-XML::XML(Class_base* c,_R<XML> _r, xmlpp::Node* _n):ASObject(c),root(_r),node(_n),constructed(true)
+XML::XML(Class_base* c, const std::string &str):ASObject(c),parentNode(0),nodetype((xmlElementType)0),constructed(false)
{
- assert(node);
+ createTree(buildFromString(str, false,&hasParentNode));
}
-XML::XML(Class_base* c,xmlpp::Node* _n):ASObject(c),constructed(true)
+XML::XML(Class_base* c,xmlpp::Node* _n):ASObject(c),parentNode(0),nodetype((xmlElementType)0),constructed(false)
{
- assert(_n);
- node=buildCopy(_n);
- assert(node);
+ createTree(_n);
}
void XML::finalize()
{
ASObject::finalize();
- root.reset();
}
void XML::sinit(Class_base* c)
{
- c->setSuper(Class<ASObject>::getRef());
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED | CLASS_FINAL);
+ setDefaultXMLSettings();
+
+ c->setDeclaredMethodByQName("ignoreComments","",Class<IFunction>::getFunction(_getIgnoreComments),GETTER_METHOD,false);
+ c->setDeclaredMethodByQName("ignoreComments","",Class<IFunction>::getFunction(_setIgnoreComments),SETTER_METHOD,false);
+ c->setDeclaredMethodByQName("ignoreProcessingInstructions","",Class<IFunction>::getFunction(_getIgnoreProcessingInstructions),GETTER_METHOD,false);
+ c->setDeclaredMethodByQName("ignoreProcessingInstructions","",Class<IFunction>::getFunction(_setIgnoreProcessingInstructions),SETTER_METHOD,false);
+ c->setDeclaredMethodByQName("ignoreWhitespace","",Class<IFunction>::getFunction(_getIgnoreWhitespace),GETTER_METHOD,false);
+ c->setDeclaredMethodByQName("ignoreWhitespace","",Class<IFunction>::getFunction(_setIgnoreWhitespace),SETTER_METHOD,false);
+ c->setDeclaredMethodByQName("prettyIndent","",Class<IFunction>::getFunction(_getPrettyIndent),GETTER_METHOD,false);
+ c->setDeclaredMethodByQName("prettyIndent","",Class<IFunction>::getFunction(_setPrettyIndent),SETTER_METHOD,false);
+ c->setDeclaredMethodByQName("prettyPrinting","",Class<IFunction>::getFunction(_getPrettyPrinting),GETTER_METHOD,false);
+ c->setDeclaredMethodByQName("prettyPrinting","",Class<IFunction>::getFunction(_setPrettyPrinting),SETTER_METHOD,false);
+ c->setDeclaredMethodByQName("settings","",Class<IFunction>::getFunction(_getSettings),NORMAL_METHOD,false);
+ c->setDeclaredMethodByQName("setSettings","",Class<IFunction>::getFunction(_setSettings),NORMAL_METHOD,false);
+ c->setDeclaredMethodByQName("defaultSettings","",Class<IFunction>::getFunction(_getDefaultSettings),NORMAL_METHOD,false);
+
c->prototype->setVariableByQName("toString","",Class<IFunction>::getFunction(_toString),DYNAMIC_TRAIT);
c->setDeclaredMethodByQName("toString",AS3,Class<IFunction>::getFunction(_toString),NORMAL_METHOD,true);
c->prototype->setVariableByQName("valueOf","",Class<IFunction>::getFunction(valueOf),DYNAMIC_TRAIT);
c->setDeclaredMethodByQName("valueOf",AS3,Class<IFunction>::getFunction(valueOf),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("toXMLString",AS3,Class<IFunction>::getFunction(toXMLString),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("nodeKind",AS3,Class<IFunction>::getFunction(nodeKind),NORMAL_METHOD,true);
+ c->prototype->setVariableByQName("nodeKind","",Class<IFunction>::getFunction(nodeKind),DYNAMIC_TRAIT); c->setDeclaredMethodByQName("nodeKind",AS3,Class<IFunction>::getFunction(nodeKind),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("child",AS3,Class<IFunction>::getFunction(child),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("children",AS3,Class<IFunction>::getFunction(children),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("childIndex",AS3,Class<IFunction>::getFunction(childIndex),NORMAL_METHOD,true);
@@ -81,19 +104,29 @@ void XML::sinit(Class_base* c)
c->setDeclaredMethodByQName("namespace",AS3,Class<IFunction>::getFunction(_namespace),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("normalize",AS3,Class<IFunction>::getFunction(_normalize),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("descendants",AS3,Class<IFunction>::getFunction(descendants),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("appendChild",AS3,Class<IFunction>::getFunction(appendChild),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("appendChild",AS3,Class<IFunction>::getFunction(_appendChild),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("parent",AS3,Class<IFunction>::getFunction(parent),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("inScopeNamespaces",AS3,Class<IFunction>::getFunction(inScopeNamespaces),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("addNamespace",AS3,Class<IFunction>::getFunction(addNamespace),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("hasSimpleContent",AS3,Class<IFunction>::getFunction(_hasSimpleContent),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("hasComplexContent",AS3,Class<IFunction>::getFunction(_hasComplexContent),NORMAL_METHOD,true);
+ c->prototype->setVariableByQName("hasSimpleContent",AS3,Class<IFunction>::getFunction(_hasSimpleContent),DYNAMIC_TRAIT);
+ c->prototype->setVariableByQName("hasComplexContent",AS3,Class<IFunction>::getFunction(_hasComplexContent),DYNAMIC_TRAIT);
c->setDeclaredMethodByQName("text",AS3,Class<IFunction>::getFunction(text),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("elements",AS3,Class<IFunction>::getFunction(elements),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("setLocalName",AS3,Class<IFunction>::getFunction(_setLocalName),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("setName",AS3,Class<IFunction>::getFunction(_setName),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("setNamespace",AS3,Class<IFunction>::getFunction(_setNamespace),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("copy",AS3,Class<IFunction>::getFunction(_copy),NORMAL_METHOD,true);
+ c->prototype->setVariableByQName("copy",AS3,Class<IFunction>::getFunction(_copy),DYNAMIC_TRAIT);
c->setDeclaredMethodByQName("setChildren",AS3,Class<IFunction>::getFunction(_setChildren),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("toJSON",AS3,Class<IFunction>::getFunction(_toJSON),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("insertChildAfter",AS3,Class<IFunction>::getFunction(insertChildAfter),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("insertChildBefore",AS3,Class<IFunction>::getFunction(insertChildBefore),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("namespaceDeclarations",AS3,Class<IFunction>::getFunction(namespaceDeclarations),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("removeNamespace",AS3,Class<IFunction>::getFunction(removeNamespace),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("comments",AS3,Class<IFunction>::getFunction(comments),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("processingInstructions",AS3,Class<IFunction>::getFunction(processingInstructions),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("propertyIsEnumerable",AS3,Class<IFunction>::getFunction(_propertyIsEnumerable),NORMAL_METHOD,true);
+ c->prototype->setVariableByQName("hasOwnProperty",AS3,Class<IFunction>::getFunction(_hasOwnProperty),DYNAMIC_TRAIT);
+ c->setDeclaredMethodByQName("prependChild",AS3,Class<IFunction>::getFunction(_prependChild),NORMAL_METHOD,true);
}
ASFUNCTIONBODY(XML,generator)
@@ -146,7 +179,7 @@ ASFUNCTIONBODY(XML,_constructor)
args[0]->is<Null>() ||
args[0]->is<Undefined>())
{
- th->node=th->buildFromString("", false);
+ th->createTree(th->buildFromString("", false,&th->hasParentNode));
}
else if(args[0]->getClass()->isSubClass(Class<ByteArray>::getClass()))
{
@@ -155,8 +188,8 @@ ASFUNCTIONBODY(XML,_constructor)
ByteArray* ba=Class<ByteArray>::cast(args[0]);
uint32_t len=ba->getLength();
const uint8_t* str=ba->getBuffer(len, false);
- th->node=th->buildFromString(std::string((const char*)str,len), false,
- getVm()->getDefaultXMLNamespace());
+ th->createTree(th->buildFromString(std::string((const char*)str,len), false,&th->hasParentNode,
+ getVm()->getDefaultXMLNamespace()));
}
else if(args[0]->is<ASString>() ||
args[0]->is<Number>() ||
@@ -166,23 +199,24 @@ ASFUNCTIONBODY(XML,_constructor)
{
//By specs, XML constructor will only convert to string Numbers or Booleans
//ints are not explicitly mentioned, but they seem to work
- th->node=th->buildFromString(args[0]->toString(), false,
- getVm()->getDefaultXMLNamespace());
+ th->createTree(th->buildFromString(args[0]->toString(), false,&th->hasParentNode,
+ getVm()->getDefaultXMLNamespace()));
}
else if(args[0]->is<XML>())
{
- th->node=th->buildCopy(args[0]->as<XML>()->node);
+ th->createTree(th->buildFromString(args[0]->as<XML>()->toXMLString_internal(), false,&th->hasParentNode,
+ getVm()->getDefaultXMLNamespace()));
}
else if(args[0]->is<XMLList>())
{
XMLList *list=args[0]->as<XMLList>();
_R<XML> reduced=list->reduceToXML();
- th->node=th->buildCopy(reduced->node);
+ th->createTree(th->buildFromString(reduced->toXMLString_internal(), false,&th->hasParentNode));
}
else
{
- th->node=th->buildFromString(args[0]->toString(), false,
- getVm()->getDefaultXMLNamespace());
+ th->createTree(th->buildFromString(args[0]->toString(), false,&th->hasParentNode,
+ getVm()->getDefaultXMLNamespace()));
}
return NULL;
}
@@ -191,23 +225,26 @@ ASFUNCTIONBODY(XML,nodeKind)
{
XML* th=Class<XML>::cast(obj);
assert_and_throw(argslen==0);
- assert(th->node);
- xmlNodePtr libXml2Node=th->node->cobj();
- switch(libXml2Node->type)
+ return Class<ASString>::getInstanceS(th->nodekindString());
+}
+const char *XML::nodekindString()
+{
+ switch(nodetype)
{
case XML_ATTRIBUTE_NODE:
- return Class<ASString>::getInstanceS("attribute");
+ return "attribute";
case XML_ELEMENT_NODE:
- return Class<ASString>::getInstanceS("element");
+ return "element";
+ case XML_CDATA_SECTION_NODE:
case XML_TEXT_NODE:
- return Class<ASString>::getInstanceS("text");
+ return "text";
case XML_COMMENT_NODE:
- return Class<ASString>::getInstanceS("comment");
+ return "comment";
case XML_PI_NODE:
- return Class<ASString>::getInstanceS("processing-instruction");
+ return "processing-instruction";
default:
{
- LOG(LOG_ERROR,"Unsupported XML type " << libXml2Node->type);
+ LOG(LOG_ERROR,"Unsupported XML type " << nodetype);
throw UnsupportedException("Unsupported XML node type");
}
}
@@ -222,27 +259,23 @@ ASFUNCTIONBODY(XML,localName)
{
XML* th=Class<XML>::cast(obj);
assert_and_throw(argslen==0);
- assert(th->node);
- xmlElementType nodetype=th->node->cobj()->type;
- if(nodetype==XML_TEXT_NODE || nodetype==XML_COMMENT_NODE)
+ if(th->nodetype==XML_TEXT_NODE || th->nodetype==XML_COMMENT_NODE)
return getSys()->getNullRef();
else
- return Class<ASString>::getInstanceS(th->node->get_name());
+ return Class<ASString>::getInstanceS(th->nodename);
}
ASFUNCTIONBODY(XML,name)
{
XML* th=Class<XML>::cast(obj);
assert_and_throw(argslen==0);
- assert(th->node);
- xmlElementType nodetype=th->node->cobj()->type;
//TODO: add namespace
- if(nodetype==XML_TEXT_NODE || nodetype==XML_COMMENT_NODE)
+ if(th->nodetype==XML_TEXT_NODE || th->nodetype==XML_COMMENT_NODE)
return getSys()->getNullRef();
else
{
ASQName* ret = Class<ASQName>::getInstanceS();
- ret->setByNode(th->node);
+ ret->setByXML(th);
return ret;
}
}
@@ -250,14 +283,16 @@ ASFUNCTIONBODY(XML,name)
ASFUNCTIONBODY(XML,descendants)
{
XML* th=Class<XML>::cast(obj);
- tiny_string name;
- ARG_UNPACK(name,"*");
- XMLVector ret;
- th->getDescendantsByQName(name,"",ret);
- return Class<XMLList>::getInstanceS(ret);
+ _NR<ASObject> name;
+ ARG_UNPACK(name,_NR<ASObject>(Class<ASString>::getInstanceS("*")));
+ XMLVector ret;
+ multiname mname(NULL);
+ name->applyProxyProperty(mname);
+ th->getDescendantsByQName(name->toString(),"",mname.isAttribute,ret);
+ return Class<XMLList>::getInstanceS(ret,th->getChildrenlist(),multiname(NULL));
}
-ASFUNCTIONBODY(XML,appendChild)
+ASFUNCTIONBODY(XML,_appendChild)
{
XML* th=Class<XML>::cast(obj);
assert_and_throw(argslen==1);
@@ -282,34 +317,50 @@ ASFUNCTIONBODY(XML,appendChild)
arg=_MR(Class<XML>::getInstanceS(args[0]->toString()));
}
- th->node->import_node(arg->node, true);
+ th->appendChild(arg);
th->incRef();
return th;
}
+void XML::appendChild(_R<XML> newChild)
+{
+ if (newChild->constructed)
+ {
+ this->incRef();
+ newChild->parentNode = _NR<XML>(this);
+ childrenlist->append(newChild);
+ }
+ else
+ newChild->decRef();
+}
+
/* returns the named attribute in an XMLList */
ASFUNCTIONBODY(XML,attribute)
{
XML* th = obj->as<XML>();
tiny_string attrname;
//see spec for QName handling
- if(argslen > 0 && args[0]->is<QName>())
- LOG(LOG_NOT_IMPLEMENTED,"XML.attribute called with QName");
ARG_UNPACK (attrname);
-
- xmlpp::Element* elem=dynamic_cast<xmlpp::Element*>(th->node);
- if(elem==NULL)
- return Class<XMLList>::getInstanceS();
- xmlpp::Attribute* attribute = elem->get_attribute(attrname);
- if(!attribute)
+ tiny_string tmpns;
+ if(argslen > 0 && args[0]->is<ASQName>())
{
- LOG(LOG_ERROR,"attribute " << attrname << " not found");
- return Class<XMLList>::getInstanceS();
+ tmpns= args[0]->as<ASQName>()->getURI();
+ attrname = args[0]->as<ASQName>()->getLocalName();
+
}
- XMLVector ret;
- ret.push_back(_MR(Class<XML>::getInstanceS(th->getRootNode(), attribute)));
- return Class<XMLList>::getInstanceS(ret);
+ XMLVector tmp;
+ XMLList* res = Class<XMLList>::getInstanceS(tmp,th->getChildrenlist(),multiname(NULL));
+ for (XMLList::XMLListVector::const_iterator it = th->attributelist->nodes.begin(); it != th->attributelist->nodes.end(); it++)
+ {
+ _R<XML> attr = *it;
+ if (attr->nodenamespace_uri == tmpns && (attrname== "*" || attr->nodename == attrname))
+ {
+ attr->incRef();
+ res->append(attr);
+ }
+ }
+ return res;
}
ASFUNCTIONBODY(XML,attributes)
@@ -320,144 +371,278 @@ ASFUNCTIONBODY(XML,attributes)
XMLList* XML::getAllAttributes()
{
- XML::XMLVector attributes=getAttributes();
- return Class<XMLList>::getInstanceS(attributes);
+ attributelist->incRef();
+ return attributelist.getPtr();
}
-XML::XMLVector XML::getAttributes(const tiny_string& name,
- const tiny_string& namespace_uri)
+const tiny_string XML::toXMLString_internal(bool pretty, tiny_string defaultnsprefix, const char *indent,bool bfirst)
{
- assert(node);
- //Use low level libxml2 access for speed
- const xmlNode* xmlN = node->cobj();
- XMLVector ret;
- //Only elements can have attributes
- if(xmlN->type!=XML_ELEMENT_NODE)
- return ret;
+ tiny_string res;
+ set<tiny_string> seen_prefix;
- _NR<XML> rootXML=getRootNode();
- for(xmlAttr* attr=xmlN->properties; attr!=NULL; attr=attr->next)
+ if (bfirst)
{
- if((name=="*" || name==attr->name) &&
- (namespace_uri=="*" || (namespace_uri=="" && attr->ns==NULL) || (attr->ns && namespace_uri==attr->ns->href)))
+ tiny_string defns = getVm()->getDefaultXMLNamespace();
+ XML* tmp = this;
+ bool bfound = false;
+ while(tmp)
{
- //NOTE: libxmlpp headers says that Node::create_wrapper
- //is supposed to be internal API. Still it's very useful and
- //we use it.
- xmlpp::Node::create_wrapper(reinterpret_cast<xmlNode*>(attr));
- xmlpp::Node* attrX=static_cast<xmlpp::Node*>(attr->_private);
- ret.push_back(_MR(Class<XML>::getInstanceS(rootXML, attrX)));
+ for (uint32_t j = 0; j < tmp->namespacedefs.size(); j++)
+ {
+ bool b;
+ _R<Namespace> tmpns = tmp->namespacedefs[j];
+ if (tmpns->getURI() == defns)
+ {
+ defaultnsprefix = tmpns->getPrefix(b);
+ bfound = true;
+ break;
+ }
+ }
+ if (!bfound && tmp->parentNode)
+ tmp = tmp->parentNode.getPtr();
+ else
+ break;
}
}
- return ret;
-}
-
-void XML::toXMLString_priv(xmlBufferPtr buf)
-{
- //NOTE: this function is not thread-safe, as it can modify the xmlNode
- xmlDocPtr xmlDoc=getRootNode()->parser.get_document()->cobj();
- assert(xmlDoc);
- xmlNodePtr cNode=node->cobj();
- int retVal;
- if(cNode->type == XML_ATTRIBUTE_NODE)
- {
- //cobj() return a xmlNodePtr for XML_ATTRIBUTE_NODE
- //even though its actually a different structure
- //containing only the first few member. Especially,
- //there is no nsDef member in that struct.
- retVal=xmlNodeBufGetContent(buf, cNode);
- }
- else
+ switch (nodetype)
{
- //As libxml2 does not automatically add the needed namespaces to the dump
- //we have to workaround the issue
-
- //Get the needed namespaces
- xmlNsPtr* neededNamespaces=xmlGetNsList(xmlDoc,cNode);
- //Save a copy of the namespaces actually defined in the node
- xmlNsPtr oldNsDef=cNode->nsDef;
-
- //Copy the namespaces (we need to modify them to create a customized list)
- vector<xmlNs> localNamespaces;
- if(neededNamespaces)
+ case XML_TEXT_NODE:
+ res = indent;
+ res += encodeToXML(nodevalue,false);
+ break;
+ case XML_ATTRIBUTE_NODE:
+ res += nodevalue;
+ break;
+ case XML_COMMENT_NODE:
+ res = indent;
+ res += "<!--";
+ res += nodevalue;
+ res += "-->";
+ break;
+ case XML_PI_NODE:
+ if (ignoreProcessingInstructions)
+ break;
+ res = indent;
+ res += "<?";
+ res +=this->nodename;
+ res += " ";
+ res += nodevalue;
+ res += "?>";
+ break;
+ case XML_ELEMENT_NODE:
{
- xmlNsPtr* cur=neededNamespaces;
- while(*cur)
+ tiny_string curprefix = this->nodenamespace_prefix;
+ res = indent;
+ res += "<";
+ if (this->nodenamespace_prefix.empty())
+ {
+ if (defaultnsprefix != "")
+ {
+ res += defaultnsprefix;
+ res += ":";
+ curprefix = defaultnsprefix;
+ }
+ }
+ else
+ {
+ res += this->nodenamespace_prefix;
+ res += ":";
+ }
+ res +=this->nodename;
+ for (uint32_t i = 0; i < this->namespacedefs.size(); i++)
+ {
+ bool b;
+ _R<Namespace> tmpns = this->namespacedefs[i];
+ tiny_string tmpprefix = tmpns->getPrefix(b);
+ if(tmpprefix == "" || tmpprefix==this->nodenamespace_prefix || seen_prefix.find(tmpprefix)!=seen_prefix.end())
+ continue;
+ seen_prefix.insert(tmpprefix);
+ res += " xmlns:";
+ res += tmpprefix;
+ res += "=\"";
+ res += tmpns->getURI();
+ res += "\"";
+ }
+ if (this->parentNode)
+ {
+ if (bfirst)
+ {
+ XML* tmp = this->parentNode.getPtr();
+ while(tmp)
+ {
+ for (uint32_t i = 0; i < tmp->namespacedefs.size(); i++)
+ {
+ bool b;
+ _R<Namespace> tmpns = tmp->namespacedefs[i];
+ tiny_string tmpprefix = tmpns->getPrefix(b);
+ if(tmpprefix != "" && seen_prefix.find(tmpprefix)==seen_prefix.end())
+ {
+ seen_prefix.insert(tmpprefix);
+ res += " xmlns:";
+ res += tmpprefix;
+ res += "=\"";
+ res += tmpns->getURI();
+ res += "\"";
+ }
+ }
+ if (tmp->parentNode)
+ tmp = tmp->parentNode.getPtr();
+ else
+ break;
+ }
+ }
+ else if (!curprefix.empty())
+ {
+ XML* tmp = this->parentNode.getPtr();
+ bool bfound = false;
+ while(tmp)
+ {
+ for (uint32_t i = 0; i < tmp->namespacedefs.size(); i++)
+ {
+ bool b;
+ _R<Namespace> tmpns = tmp->namespacedefs[i];
+ tiny_string tmpprefix = tmpns->getPrefix(b);
+ if(tmpprefix == curprefix)
+ {
+ seen_prefix.insert(tmpprefix);
+ bfound = true;
+ break;
+ }
+ }
+ if (!bfound && tmp->parentNode)
+ tmp = tmp->parentNode.getPtr();
+ else
+ break;
+ }
+ }
+ }
+ if (!this->nodenamespace_uri.empty() &&
+ ((this->nodenamespace_prefix.empty() && defaultnsprefix == "") ||
+ (!this->nodenamespace_prefix.empty() && seen_prefix.find(this->nodenamespace_prefix)==seen_prefix.end())))
+ {
+ if (!this->nodenamespace_prefix.empty())
+ {
+ seen_prefix.insert(this->nodenamespace_prefix);
+ res += " xmlns:";
+ res += this->nodenamespace_prefix;
+ }
+ else
+ res += " xmlns";
+ res += "=\"";
+ res += this->nodenamespace_uri;
+ res += "\"";
+ }
+ else if (defaultnsprefix != "" && seen_prefix.find(defaultnsprefix)==seen_prefix.end())
+ {
+ seen_prefix.insert(defaultnsprefix);
+ res += " xmlns:";
+ res += defaultnsprefix;
+ res += "=\"";
+ res += getVm()->getDefaultXMLNamespace();
+ res += "\"";
+ }
+ for (XMLList::XMLListVector::const_iterator it = attributelist->nodes.begin(); it != attributelist->nodes.end(); it++)
+ {
+ _R<XML> attr = *it;
+ res += " ";
+ if (attr->nodenamespace_prefix != "")
+ {
+ res += attr->nodenamespace_prefix;
+ res += ":";
+ }
+ res += attr->nodename;
+ res += "=\"";
+ res += encodeToXML(attr->nodevalue,true);
+ res += "\"";
+ }
+ if (childrenlist->nodes.size() == 0)
+ {
+ res += "/>";
+ break;
+ }
+ res += ">";
+ tiny_string newindent;
+ bool bindent = (pretty && prettyPrinting && prettyIndent >=0 &&
+ (childrenlist->nodes.size() >1 ||
+ (childrenlist->nodes[0]->nodetype != XML_TEXT_NODE && childrenlist->nodes[0]->nodetype != XML_CDATA_SECTION_NODE)));
+ if (bindent)
+ {
+ newindent = indent;
+ for (int32_t j = 0; j < prettyIndent; j++)
+ {
+ newindent += " ";
+ }
+ }
+ for (uint32_t i = 0; i < childrenlist->nodes.size(); i++)
+ {
+ if (bindent)
+ res += "\n";
+ _R<XML> child= childrenlist->nodes[i];
+ res += child->toXMLString_internal(pretty,defaultnsprefix,newindent.raw_buf(),false);
+ }
+ if (bindent)
+ {
+ res += "\n";
+ res += indent;
+ }
+ res += "</";
+ if (this->nodenamespace_prefix.empty())
+ {
+ if (defaultnsprefix != "")
+ {
+ res += defaultnsprefix;
+ res += ":";
+ }
+ }
+ else
{
- localNamespaces.emplace_back(**cur);
- cur++;
+ res += this->nodenamespace_prefix;
+ res += ":";
}
- for(uint32_t i=0;i<localNamespaces.size()-1;++i)
- localNamespaces[i].next=&localNamespaces[i+1];
- localNamespaces.back().next=NULL;
- //Free the namespaces arrary
- xmlFree(neededNamespaces);
- //Override the node defined namespaces
- cNode->nsDef=&localNamespaces.front();
+ res += this->nodename;
+ res += ">";
+ break;
}
- retVal=xmlNodeDump(buf, xmlDoc, cNode, 0, 0);
- //Restore the previously defined namespaces
- cNode->nsDef=oldNsDef;
+ case XML_CDATA_SECTION_NODE:
+ res += "<![CDATA[";
+ res += nodevalue;
+ res += "]]>";
+ break;
+ default:
+ LOG(LOG_NOT_IMPLEMENTED,"XML::toXMLString unhandled nodetype:"<<nodetype);
+ break;
}
- if(retVal==-1)
- throw RunTimeException("Error om XML::toXMLString_priv");
+ return res;
}
ASFUNCTIONBODY(XML,toXMLString)
{
XML* th=Class<XML>::cast(obj);
assert_and_throw(argslen==0);
- assert(th->node);
- //Allocate a page at the beginning
- xmlBufferPtr xmlBuffer=xmlBufferCreateSize(4096);
- th->toXMLString_priv(xmlBuffer);
- ASString* ret=Class<ASString>::getInstanceS((char*)xmlBuffer->content);
- xmlBufferFree(xmlBuffer);
+ tiny_string res = th->toXMLString_internal();
+ ASString* ret=Class<ASString>::getInstanceS(res);
return ret;
}
void XML::childrenImpl(XMLVector& ret, const tiny_string& name)
{
- assert(node);
- const xmlpp::Node::NodeList& list=node->get_children();
- xmlpp::Node::NodeList::const_iterator it=list.begin();
- _NR<XML> rootXML=getRootNode();
- for(;it!=list.end();++it)
+ for (uint32_t i = 0; i < childrenlist->nodes.size(); i++)
{
- if(name!="*" && (*it)->get_name() != name.raw_buf())
- continue;
-
- // Ignore white-space-only text nodes
- xmlpp::TextNode *textnode=dynamic_cast<xmlpp::TextNode*>(*it);
- if (textnode && textnode->is_white_space())
+ _R<XML> child= childrenlist->nodes[i];
+ if(name!="*" && child->nodename != name)
continue;
-
- ret.push_back(_MR(Class<XML>::getInstanceS(rootXML, *it)));
+ child->incRef();
+ ret.push_back(child);
}
}
void XML::childrenImpl(XMLVector& ret, uint32_t index)
{
- assert(node);
- _NR<XML> rootXML=getRootNode();
- uint32_t i=0;
- const xmlpp::Node::NodeList& list=node->get_children();
- xmlpp::Node::NodeList::const_iterator it=list.begin();
- while(it!=list.end())
+ if (constructed && index < childrenlist->nodes.size())
{
- xmlpp::TextNode* nodeText = dynamic_cast<xmlpp::TextNode*>(*it);
- if(!(nodeText && nodeText->is_white_space()))
- {
- if(i==index)
- {
- ret.push_back(_MR(Class<XML>::getInstanceS(rootXML, *it)));
- break;
- }
-
- ++i;
- }
-
- ++it;
+ _R<XML> child= childrenlist->nodes[index];
+ child->incRef();
+ ret.push_back(child);
}
}
@@ -473,11 +658,11 @@ ASFUNCTIONBODY(XML,child)
mname.name_type=multiname::NAME_STRING;
mname.ns.push_back(nsNameAndKind("",NAMESPACE));
mname.isAttribute=false;
- if(Array::isValidMultiname(mname, index))
+ if(XML::isValidMultiname(mname, index))
th->childrenImpl(ret, index);
else
th->childrenImpl(ret, arg0);
- XMLList* retObj=Class<XMLList>::getInstanceS(ret);
+ XMLList* retObj=Class<XMLList>::getInstanceS(ret,th->getChildrenlist(),mname);
return retObj;
}
@@ -487,38 +672,27 @@ ASFUNCTIONBODY(XML,children)
assert_and_throw(argslen==0);
XMLVector ret;
th->childrenImpl(ret, "*");
- XMLList* retObj=Class<XMLList>::getInstanceS(ret);
+ multiname mname(NULL);
+ mname.name_s_id=getSys()->getUniqueStringId("*");
+ mname.name_type=multiname::NAME_STRING;
+ mname.ns.push_back(nsNameAndKind("",NAMESPACE));
+ XMLList* retObj=Class<XMLList>::getInstanceS(ret,th->getChildrenlist(),mname);
return retObj;
}
ASFUNCTIONBODY(XML,childIndex)
{
XML* th=Class<XML>::cast(obj);
- xmlpp::Node *parent=th->node->get_parent();
- if (parent && (th->node->cobj()->type!=XML_ATTRIBUTE_NODE))
+ if (th->parentNode)
{
- xmlpp::Node::NodeList children=parent->get_children();
- xmlpp::Node::NodeList::const_iterator it;
- unsigned int n;
-
- it=children.begin();
- n=0;
- while(it!=children.end())
+ XML* parent = th->parentNode.getPtr();
+ for (uint32_t i = 0; i < parent->childrenlist->nodes.size(); i++)
{
- if((*it)==th->node)
- return abstract_i(n);
-
- // Ignore white-space text nodes
- xmlpp::TextNode *textnode=dynamic_cast<xmlpp::TextNode*>(*it);
- if (!(textnode && textnode->is_white_space()))
- {
- ++n;
- }
-
- ++it;
+ ASObject* o= parent->childrenlist->nodes[i].getPtr();
+ if (o == th)
+ return abstract_i(i);
}
}
-
return abstract_i(-1);
}
@@ -542,20 +716,15 @@ ASFUNCTIONBODY(XML,valueOf)
void XML::getText(XMLVector& ret)
{
- xmlpp::Node::NodeList nl = node->get_children();
- xmlpp::Node::NodeList::iterator i;
- _NR<XML> childroot = root;
- if(childroot.isNull())
+ for (uint32_t i = 0; i < childrenlist->nodes.size(); i++)
{
- this->incRef();
- childroot = _MR(this);
- }
- for(i=nl.begin(); i!= nl.end(); ++i)
- {
- xmlpp::TextNode* nodeText = dynamic_cast<xmlpp::TextNode*>(*i);
- //The official implementation seems to ignore whitespace-only textnodes
- if(nodeText && !nodeText->is_white_space())
- ret.push_back( _MR(Class<XML>::getInstanceS(childroot, nodeText)) );
+ _R<XML> child= childrenlist->nodes[i];
+ if (child->getNodeKind() == XML_TEXT_NODE ||
+ child->getNodeKind() == XML_CDATA_SECTION_NODE)
+ {
+ child->incRef();
+ ret.push_back( child );
+ }
}
}
@@ -565,7 +734,7 @@ ASFUNCTIONBODY(XML,text)
ARG_UNPACK;
XMLVector ret;
th->getText(ret);
- return Class<XMLList>::getInstanceS(ret);
+ return Class<XMLList>::getInstanceS(ret,th->getChildrenlist(),multiname(NULL));
}
ASFUNCTIONBODY(XML,elements)
@@ -578,19 +747,19 @@ ASFUNCTIONBODY(XML,elements)
name="";
th->getElementNodes(name, ret);
- return Class<XMLList>::getInstanceS(ret);
+ return Class<XMLList>::getInstanceS(ret,th->getChildrenlist(),multiname(NULL));
}
void XML::getElementNodes(const tiny_string& name, XMLVector& foundElements)
{
- _NR<XML> rootXML=getRootNode();
- const xmlpp::Node::NodeList& children=node->get_children();
- xmlpp::Node::NodeList::const_iterator it=children.begin();
- for(;it!=children.end();++it)
+ for (uint32_t i = 0; i < childrenlist->nodes.size(); i++)
{
- xmlElementType nodetype=(*it)->cobj()->type;
- if(nodetype==XML_ELEMENT_NODE && (name.empty() || name == (*it)->get_name()))
- foundElements.push_back(_MR(Class<XML>::getInstanceS(rootXML, *it)));
+ _R<XML> child= childrenlist->nodes[i];
+ if(child->nodetype==XML_ELEMENT_NODE && (name.empty() || name == child->nodename))
+ {
+ child->incRef();
+ foundElements.push_back( child );
+ }
}
}
@@ -600,29 +769,25 @@ ASFUNCTIONBODY(XML,inScopeNamespaces)
Array *namespaces = Class<Array>::getInstanceS();
set<tiny_string> seen_prefix;
- xmlDocPtr xmlDoc=th->getRootNode()->parser.get_document()->cobj();
- xmlNsPtr *nsarr=xmlGetNsList(xmlDoc, th->node->cobj());
- if(nsarr)
+ XML* tmp = th;
+ while(tmp)
{
- for(int i=0; nsarr[i]!=NULL; i++)
+ for (uint32_t i = 0; i < tmp->namespacedefs.size(); i++)
{
- if(!nsarr[i]->prefix)
- continue;
-
- tiny_string prefix((const char*)nsarr[i]->prefix, true);
- if(seen_prefix.find(prefix)==seen_prefix.end())
+ bool b;
+ _R<Namespace> tmpns = tmp->namespacedefs[i];
+ if(seen_prefix.find(tmpns->getPrefix(b))==seen_prefix.end())
{
- tiny_string uri((const char*)nsarr[i]->href, true);
- Namespace *ns=Class<Namespace>::getInstanceS(uri, prefix);
- namespaces->push(_MR(ns));
+ tmpns->incRef();
+ namespaces->push(tmpns);
+ seen_prefix.insert(tmp->nodenamespace_prefix);
}
-
- seen_prefix.insert(prefix);
}
-
- xmlFree(nsarr);
+ if (tmp->parentNode)
+ tmp = tmp->parentNode.getPtr();
+ else
+ break;
}
-
return namespaces;
}
@@ -632,34 +797,45 @@ ASFUNCTIONBODY(XML,addNamespace)
_NR<ASObject> newNamespace;
ARG_UNPACK(newNamespace);
- xmlpp::Element *element=dynamic_cast<xmlpp::Element*>(th->node);
- if(!element)
- return NULL;
-
- // TODO: check if the prefix already exists
- Namespace *ns=dynamic_cast<Namespace *>(newNamespace.getPtr());
- if(ns)
+ tiny_string ns_uri;
+ tiny_string ns_prefix;
+ if (newNamespace->is<Namespace>())
{
- tiny_string uri=ns->getURI();
- bool prefix_is_undefined=false;
- tiny_string prefix=ns->getPrefix(prefix_is_undefined);
- element->set_namespace_declaration(uri, prefix);
+ Namespace* tmpns = newNamespace->as<Namespace>();
+ bool b;
+ ns_prefix = tmpns->getPrefix(b);
+ ns_uri = tmpns->getURI();
}
- else
+ else if (newNamespace->is<ASQName>())
{
- tiny_string uri=newNamespace->toString();
- element->set_namespace_declaration(uri);
+ ns_uri = newNamespace->as<ASQName>()->getURI();
}
-
+ else
+ ns_uri = newNamespace->toString();
+ if (th->nodenamespace_prefix == ns_prefix)
+ th->nodenamespace_prefix="";
+ for (uint32_t i = 0; i < th->namespacedefs.size(); i++)
+ {
+ bool b;
+ _R<Namespace> tmpns = th->namespacedefs[i];
+ if (tmpns->getPrefix(b) == ns_prefix)
+ {
+ th->namespacedefs[i] = _R<Namespace>(Class<Namespace>::getInstanceS(ns_uri,ns_prefix));
+ return NULL;
+ }
+ }
+ th->namespacedefs.push_back(_R<Namespace>(Class<Namespace>::getInstanceS(ns_uri,ns_prefix)));
return NULL;
}
ASObject *XML::getParentNode()
{
- xmlpp::Node *parent=node->get_parent();
- if (parent)
- return Class<XML>::getInstanceS(getRootNode(), parent);
+ if (parentNode && parentNode->is<XML>())
+ {
+ parentNode->incRef();
+ return parentNode.getPtr();
+ }
else
return getSys()->getUndefinedRef();
}
@@ -687,54 +863,26 @@ ASFUNCTIONBODY(XML,_namespace)
tiny_string prefix;
ARG_UNPACK(prefix, "");
- xmlElementType nodetype=th->node->cobj()->type;
+ xmlElementType nodetype=th->nodetype;
if(prefix.empty() &&
nodetype!=XML_ELEMENT_NODE &&
nodetype!=XML_ATTRIBUTE_NODE)
{
return getSys()->getNullRef();
}
-
- tiny_string local_uri=th->node->get_namespace_uri();
- ASObject *ret=NULL;
- xmlDocPtr xmlDoc=th->getRootNode()->parser.get_document()->cobj();
- xmlNsPtr *nsarr=xmlGetNsList(xmlDoc, th->node->cobj());
- if(nsarr)
- {
- for(int i=0; nsarr[i]!=NULL; i++)
- {
- tiny_string ns_prefix;
- if(nsarr[i]->prefix)
- ns_prefix=tiny_string((const char*)nsarr[i]->prefix, true);
- tiny_string ns_uri((const char*)nsarr[i]->href, true);
- if(!prefix.empty() && ns_prefix==prefix)
- {
- ret=Class<Namespace>::getInstanceS(ns_uri, prefix);
- break;
- }
- else if(prefix.empty() && ns_uri==local_uri)
- {
- ret=Class<Namespace>::getInstanceS(ns_uri);
- break;
- }
- }
-
- xmlFree(nsarr);
- }
-
- if(!ret)
+ if (prefix.empty())
+ return Class<Namespace>::getInstanceS(th->nodenamespace_uri, th->nodenamespace_prefix);
+
+ for (uint32_t i = 0; i < th->namespacedefs.size(); i++)
{
- if(prefix.empty() && local_uri.empty())
- {
- ret=Class<Namespace>::getInstanceS();
- }
- else
+ bool b;
+ _R<Namespace> tmpns = th->namespacedefs[i];
+ if (tmpns->getPrefix(b) == prefix)
{
- ret=getSys()->getUndefinedRef();
+ return Class<Namespace>::getInstanceS(tmpns->getURI(), prefix);
}
}
-
- return ret;
+ return getSys()->getUndefinedRef();
}
ASFUNCTIONBODY(XML,_setLocalName)
@@ -743,7 +891,7 @@ ASFUNCTIONBODY(XML,_setLocalName)
_NR<ASObject> newName;
ARG_UNPACK(newName);
- xmlElementType nodetype=th->node->cobj()->type;
+ xmlElementType nodetype=th->nodetype;
if(nodetype==XML_TEXT_NODE || nodetype==XML_COMMENT_NODE)
return NULL;
@@ -768,8 +916,7 @@ void XML::setLocalName(const tiny_string& new_name)
{
throwError<TypeError>(kXMLInvalidName, new_name);
}
-
- node->set_name(new_name);
+ this->nodename = new_name;
}
ASFUNCTIONBODY(XML,_setName)
@@ -778,12 +925,12 @@ ASFUNCTIONBODY(XML,_setName)
_NR<ASObject> newName;
ARG_UNPACK(newName);
- xmlElementType nodetype=th->node->cobj()->type;
- if(nodetype==XML_TEXT_NODE || nodetype==XML_COMMENT_NODE)
+ if(th->nodetype==XML_TEXT_NODE || th->nodetype==XML_COMMENT_NODE)
return NULL;
tiny_string localname;
tiny_string ns_uri;
+ tiny_string ns_prefix = th->nodenamespace_prefix;
if(newName->is<ASQName>())
{
ASQName *qname=newName->as<ASQName>();
@@ -793,10 +940,11 @@ ASFUNCTIONBODY(XML,_setName)
else if (!newName->is<Undefined>())
{
localname=newName->toString();
+ ns_prefix= "";
}
th->setLocalName(localname);
- th->setNamespace(ns_uri);
+ th->setNamespace(ns_uri,ns_prefix);
return NULL;
}
@@ -807,12 +955,10 @@ ASFUNCTIONBODY(XML,_setNamespace)
_NR<ASObject> newNamespace;
ARG_UNPACK(newNamespace);
- xmlElementType nodetype=th->node->cobj()->type;
- if(nodetype==XML_TEXT_NODE ||
- nodetype==XML_COMMENT_NODE ||
- nodetype==XML_PI_NODE)
+ if(th->nodetype==XML_TEXT_NODE ||
+ th->nodetype==XML_COMMENT_NODE ||
+ th->nodetype==XML_PI_NODE)
return NULL;
-
tiny_string ns_uri;
tiny_string ns_prefix;
if(newNamespace->is<Namespace>())
@@ -826,45 +972,55 @@ ASFUNCTIONBODY(XML,_setNamespace)
{
ASQName *qname=newNamespace->as<ASQName>();
ns_uri=qname->getURI();
+ for (uint32_t i = 0; i < th->namespacedefs.size(); i++)
+ {
+ bool b;
+ _R<Namespace> tmpns = th->namespacedefs[i];
+ if (tmpns->getURI() == ns_uri)
+ {
+ ns_prefix = tmpns->getPrefix(b);
+ break;
+ }
+ }
}
else if (!newNamespace->is<Undefined>())
{
ns_uri=newNamespace->toString();
+ for (uint32_t i = 0; i < th->namespacedefs.size(); i++)
+ {
+ bool b;
+ _R<Namespace> tmpns = th->namespacedefs[i];
+ if (tmpns->getURI() == ns_uri)
+ {
+ ns_prefix = tmpns->getPrefix(b);
+ break;
+ }
+ }
}
-
th->setNamespace(ns_uri, ns_prefix);
+ if (th->nodetype==XML_ATTRIBUTE_NODE && th->parentNode)
+ {
+ XML* tmp = th->parentNode.getPtr();
+ for (uint32_t i = 0; i < tmp->namespacedefs.size(); i++)
+ {
+ bool b;
+ _R<Namespace> tmpns = tmp->namespacedefs[i];
+ if (tmpns->getPrefix(b) == ns_prefix)
+ {
+ tmp->namespacedefs[i] = _R<Namespace>(Class<Namespace>::getInstanceS(ns_uri,ns_prefix));
+ return NULL;
+ }
+ }
+ tmp->namespacedefs.push_back(_R<Namespace>(Class<Namespace>::getInstanceS(ns_uri,ns_prefix)));
+ }
return NULL;
}
void XML::setNamespace(const tiny_string& ns_uri, const tiny_string& ns_prefix)
{
- if(ns_uri.empty())
- {
- // libxml++ set_namespace() doesn't seem to be able to
- // reset the namespace to empty (default) namespace,
- // so we have to do this through libxml2
- xmlDocPtr xmlDoc=getRootNode()->parser.get_document()->cobj();
- xmlNsPtr default_ns=xmlSearchNs(xmlDoc, node->cobj(), NULL);
- xmlSetNs(node->cobj(), default_ns);
- }
- else
- {
- if(!ns_prefix.empty())
- {
- xmlpp::Element *element;
- element=dynamic_cast<xmlpp::Element *>(node);
- xmlpp::Attribute *attribute;
- attribute=dynamic_cast<xmlpp::Attribute *>(node);
- if(attribute)
- element=attribute->get_parent();
-
- if(element)
- element->set_namespace_declaration(ns_uri, ns_prefix);
- }
-
- node->set_namespace(getNamespacePrefixByURI(ns_uri, true));
- }
+ this->nodenamespace_prefix = ns_prefix;
+ this->nodenamespace_uri = ns_uri;
}
ASFUNCTIONBODY(XML,_copy)
@@ -873,9 +1029,9 @@ ASFUNCTIONBODY(XML,_copy)
return th->copy();
}
-XML *XML::copy() const
+XML *XML::copy()
{
- return Class<XML>::getInstanceS(node);
+ return Class<XML>::getInstanceS(this->toXMLString_internal(false));
}
ASFUNCTIONBODY(XML,_setChildren)
@@ -884,16 +1040,18 @@ ASFUNCTIONBODY(XML,_setChildren)
_NR<ASObject> newChildren;
ARG_UNPACK(newChildren);
- th->removeAllChildren();
+ th->childrenlist->clear();
if (newChildren->is<XML>())
{
XML *newChildrenXML=newChildren->as<XML>();
- th->node->import_node(newChildrenXML->node);
+ newChildrenXML->incRef();
+ th->appendChild(_R<XML>(newChildrenXML));
}
else if (newChildren->is<XMLList>())
{
XMLList *list=newChildren->as<XMLList>();
+ list->incRef();
list->appendNodesTo(th);
}
else
@@ -916,100 +1074,212 @@ ASFUNCTIONBODY(XML,_normalize)
void XML::normalize()
{
- normalizeRecursive(node);
-}
-
-void XML::normalizeRecursive(xmlpp::Node *node)
-{
- // TODO: merge adjacent text nodes
-
- xmlpp::Node::NodeList children=node->get_children();
- xmlpp::Node::NodeList::const_iterator it=children.begin();
- for(;it!=children.end();++it)
- {
- if (dynamic_cast<xmlpp::Element*>(*it))
- {
- normalizeRecursive(*it);
- }
- else
- {
- xmlpp::TextNode *textnode = dynamic_cast<xmlpp::TextNode*>(*it);
- if (textnode && textnode->is_white_space())
- node->remove_child(*it);
- }
- }
+ childrenlist->normalize();
}
void XML::addTextContent(const tiny_string& str)
{
assert(getNodeKind() == XML_TEXT_NODE);
- xmlNodeAddContentLen(node->cobj(), BAD_CAST str.raw_buf(), str.numBytes());
+ nodevalue += str;
}
-void XML::removeAllChildren()
+void XML::setTextContent(const tiny_string& content)
{
- xmlpp::Node::NodeList children=node->get_children();
- xmlpp::Node::NodeList::const_iterator it=children.begin();
- for(;it!=children.end();++it)
+ if (getNodeKind() == XML_TEXT_NODE ||
+ getNodeKind() == XML_ATTRIBUTE_NODE ||
+ getNodeKind() == XML_COMMENT_NODE ||
+ getNodeKind() == XML_PI_NODE ||
+ getNodeKind() == XML_CDATA_SECTION_NODE)
{
- node->remove_child(*it);
+ nodevalue = content;
}
}
+
bool XML::hasSimpleContent() const
{
- xmlElementType nodetype=node->cobj()->type;
- if(nodetype==XML_COMMENT_NODE || nodetype==XML_PI_NODE)
+ if (getNodeKind() == XML_COMMENT_NODE ||
+ getNodeKind() == XML_PI_NODE)
return false;
-
- const xmlpp::Node::NodeList& children=node->get_children();
- xmlpp::Node::NodeList::const_iterator it=children.begin();
- for(;it!=children.end();++it)
+ for(size_t i=0; i<childrenlist->nodes.size(); i++)
{
- if((*it)->cobj()->type==XML_ELEMENT_NODE)
+ if (childrenlist->nodes[i]->getNodeKind() == XML_ELEMENT_NODE)
return false;
}
-
return true;
}
bool XML::hasComplexContent() const
{
- const xmlpp::Node::NodeList& children=node->get_children();
- xmlpp::Node::NodeList::const_iterator it=children.begin();
- for(;it!=children.end();++it)
- {
- if((*it)->cobj()->type==XML_ELEMENT_NODE)
- return true;
- }
-
- return false;
+ return !hasSimpleContent();
}
xmlElementType XML::getNodeKind() const
{
- return node->cobj()->type;
+ return nodetype;
}
-void XML::recursiveGetDescendantsByQName(_R<XML> root, xmlpp::Node* node, const tiny_string& name, const tiny_string& ns,
- XMLVector& ret)
+
+void XML::getDescendantsByQName(const tiny_string& name, const tiny_string& ns, bool bIsAttribute, XMLVector& ret)
{
- //Check if this node is being requested. Both "" and "*" strings mean all
- if(name=="" || name=="*" || name == node->get_name())
- ret.push_back(_MR(Class<XML>::getInstanceS(root, node)));
- //NOTE: Creating a temporary list is quite a large overhead, but there is no way in libxml++ to access the first child
- const xmlpp::Node::NodeList& list=node->get_children();
- xmlpp::Node::NodeList::const_iterator it=list.begin();
- for(;it!=list.end();++it)
- recursiveGetDescendantsByQName(root, *it, name, ns, ret);
+ if (!constructed)
+ return;
+ if (bIsAttribute)
+ {
+ for (uint32_t i = 0; i < attributelist->nodes.size(); i++)
+ {
+ _R<XML> child= attributelist->nodes[i];
+ if(name=="" || name=="*" || (name == child->nodename && (ns == "*" || ns == child->nodenamespace_uri)))
+ {
+ child->incRef();
+ ret.push_back(child);
+ }
+ }
+ }
+ for (uint32_t i = 0; i < childrenlist->nodes.size(); i++)
+ {
+ _R<XML> child= childrenlist->nodes[i];
+ if(!bIsAttribute && (name=="" || name=="*" || (name == child->nodename && (ns == "*" || ns == child->nodenamespace_uri))))
+ {
+ child->incRef();
+ ret.push_back(child);
+ }
+ child->getDescendantsByQName(name, ns, bIsAttribute, ret);
+ }
}
-void XML::getDescendantsByQName(const tiny_string& name, const tiny_string& ns, XMLVector& ret)
+XML::XMLVector XML::getAttributes()
+{
+ multiname mn(NULL);
+ mn.name_type=multiname::NAME_STRING;
+ mn.ns.push_back(nsNameAndKind("",NAMESPACE));
+ mn.ns.push_back(nsNameAndKind(AS3,NAMESPACE));
+ mn.isAttribute = true;
+ return getAttributesByMultiname(mn);
+}
+XML::XMLVector XML::getAttributesByMultiname(const multiname& name)
+{
+ XMLVector ret;
+ tiny_string defns = "|";
+ defns += getVm()->getDefaultXMLNamespace();
+ defns += "|";
+ tiny_string normalizedName= "";
+ if (!name.isEmpty()) normalizedName= name.normalizedName();
+ if (normalizedName.startsWith("@"))
+ normalizedName = normalizedName.substr(1,normalizedName.end());
+ tiny_string namespace_uri="|";
+ uint32_t i = 0;
+ while (i < name.ns.size())
+ {
+ nsNameAndKindImpl ns=name.ns[i].getImpl();
+ if (ns.kind==NAMESPACE && ns.name != AS3)
+ {
+ if (ns.name.empty())
+ namespace_uri +=getVm()->getDefaultXMLNamespace();
+ else
+ namespace_uri +=ns.name;
+ namespace_uri += "|";
+ }
+ i++;
+ }
+ for (uint32_t i = 0; i < attributelist->nodes.size(); i++)
+ {
+ _R<XML> child= attributelist->nodes[i];
+ tiny_string childnamespace_uri = "|";
+ childnamespace_uri += child->nodenamespace_uri;
+ childnamespace_uri += "|";
+
+ bool bmatch = (
+ ((normalizedName=="") &&
+ ((namespace_uri.find(defns)!= tiny_string::npos) ||
+ (namespace_uri=="|*|") ||
+ (namespace_uri.find(childnamespace_uri) != tiny_string::npos)
+ )
+ )||
+ ((normalizedName=="*") &&
+ ((namespace_uri.find(defns)!= tiny_string::npos) ||
+ (namespace_uri=="|*|") ||
+ (namespace_uri.find(childnamespace_uri) != tiny_string::npos)
+ )
+ )||
+ ((normalizedName==child->nodename) &&
+ (
+ (namespace_uri=="|*|") ||
+ (namespace_uri=="|" && childnamespace_uri=="||") ||
+ (namespace_uri.find(childnamespace_uri) != tiny_string::npos)
+ )
+ )
+ );
+ if(bmatch)
+ {
+ child->incRef();
+ ret.push_back(child);
+ }
+ }
+ return ret;
+}
+XML::XMLVector XML::getValuesByMultiname(_NR<XMLList> nodelist, const multiname& name)
{
- assert(node);
- assert_and_throw(ns=="");
- recursiveGetDescendantsByQName(getRootNode(), node, name, ns, ret);
+ XMLVector ret;
+ tiny_string defns = "|";
+ defns += getVm()->getDefaultXMLNamespace();
+ defns += "|";
+ tiny_string normalizedName= "";
+ if (!name.isEmpty()) normalizedName= name.normalizedName();
+ if (normalizedName.startsWith("@"))
+ normalizedName = normalizedName.substr(1,normalizedName.end());
+ tiny_string namespace_uri="|";
+ uint32_t i = 0;
+ while (i < name.ns.size())
+ {
+ nsNameAndKindImpl ns=name.ns[i].getImpl();
+ if (ns.kind==NAMESPACE && ns.name != AS3)
+ {
+ if (ns.name.empty())
+ namespace_uri +=getVm()->getDefaultXMLNamespace();
+ else
+ namespace_uri +=ns.name;
+ namespace_uri += "|";
+ }
+ i++;
+ }
+
+ for (uint32_t i = 0; i < nodelist->nodes.size(); i++)
+ {
+ _R<XML> child= nodelist->nodes[i];
+ tiny_string childnamespace_uri = "|";
+ childnamespace_uri += child->nodenamespace_uri;
+ childnamespace_uri += "|";
+
+ bool bmatch = (
+ ((normalizedName=="") &&
+ ((namespace_uri.find(defns)!= tiny_string::npos) ||
+ (namespace_uri=="|*|") ||
+ (namespace_uri.find(childnamespace_uri) != tiny_string::npos)
+ )
+ )||
+ ((normalizedName=="*") &&
+ ((namespace_uri.find(defns)!= tiny_string::npos) ||
+ (namespace_uri=="|*|") ||
+ (namespace_uri.find(childnamespace_uri) != tiny_string::npos)
+ )
+ )||
+ ((normalizedName==child->nodename) &&
+ ((namespace_uri.find(defns)!= tiny_string::npos) ||
+ (namespace_uri=="|*|") ||
+ (namespace_uri=="|" && childnamespace_uri=="||") ||
+ (namespace_uri.find(childnamespace_uri) != tiny_string::npos)
+ )
+ )
+ );
+ if(bmatch)
+ {
+ child->incRef();
+ ret.push_back(child);
+ }
+ }
+ return ret;
}
_NR<ASObject> XML::getVariableByMultiname(const multiname& name, GET_VARIABLE_OPTION opt)
@@ -1030,46 +1300,21 @@ _NR<ASObject> XML::getVariableByMultiname(const multiname& name, GET_VARIABLE_OP
return res;
}
- if(node==NULL)
- {
- //This is possible if the XML object was created from an empty string
- return NullRef;
- }
-
bool isAttr=name.isAttribute;
unsigned int index=0;
- //Normalize the name to the string form
- tiny_string normalizedName=name.normalizedName();
- if(normalizedName=="*")
- normalizedName="";
-
- //Only the first namespace is used, is this right?
- tiny_string namespace_uri;
- if(name.ns.size() > 0 && !name.ns[0].hasEmptyName())
- {
- nsNameAndKindImpl ns=name.ns[0].getImpl();
- assert_and_throw(ns.kind==NAMESPACE);
- namespace_uri=ns.name;
- }
-
- // namespace set by "default xml namespace = ..."
- if(namespace_uri.empty())
- namespace_uri=getVm()->getDefaultXMLNamespace();
- const char *buf=normalizedName.raw_buf();
+ tiny_string normalizedName=name.normalizedName();
if(!normalizedName.empty() && normalizedName.charAt(0)=='@')
{
isAttr=true;
- buf+=1;
}
if(isAttr)
{
//Lookup attribute
- tiny_string ns_uri=namespace_uri.empty() ? "*" : namespace_uri;
- const XMLVector& attributes=getAttributes(buf, ns_uri);
- return _MNR(Class<XMLList>::getInstanceS(attributes));
+ const XMLVector& attributes=getAttributesByMultiname(name);
+ return _MNR(Class<XMLList>::getInstanceS(attributes,attributelist.getPtr(),name));
}
- else if(Array::isValidMultiname(name,index))
+ else if(XML::isValidMultiname(name,index))
{
// If the multiname is a valid array property, the XML
// object is treated as a single-item XMLList.
@@ -1079,37 +1324,16 @@ _NR<ASObject> XML::getVariableByMultiname(const multiname& name, GET_VARIABLE_OP
return _MNR(this);
}
else
- return NullRef;
+ return _MNR(getSys()->getUndefinedRef());
}
else
{
- //Lookup children
- _NR<XML> rootnode=getRootNode();
-
- //Use low level libxml2 access for speed
- const xmlNode* xmlN = node->cobj();
- XMLVector ret;
- for(xmlNode* child=xmlN->children; child!=NULL; child=child->next)
- {
- bool nameMatches = (normalizedName=="" || normalizedName==child->name);
- bool nsMatches = (namespace_uri=="*" ||
- (namespace_uri=="" && child->ns==NULL) ||
- (child->ns && namespace_uri==child->ns->href));
-
- if(nameMatches && nsMatches)
- {
- //NOTE: libxmlpp headers says that Node::create_wrapper
- //is supposed to be internal API. Still it's very useful and
- //we use it.
- xmlpp::Node::create_wrapper(child);
- xmlpp::Node* attrX=static_cast<xmlpp::Node*>(child->_private);
- ret.push_back(_MR(Class<XML>::getInstanceS(rootnode, attrX)));
- }
- }
+ const XMLVector& ret=getValuesByMultiname(childrenlist,name);
if(ret.empty() && (opt & XML_STRICT)!=0)
return NullRef;
- return _MNR(Class<XMLList>::getInstanceS(ret));
+ _R<XMLList> ch =_MNR(Class<XMLList>::getInstanceS(ret,this->getChildrenlist(),name));
+ return ch;
}
}
@@ -1126,9 +1350,11 @@ void XML::setVariableByMultiname(const multiname& name, ASObject* o, CONST_ALLOW
if(name.ns.size() > 0 && !name.ns[0].hasEmptyName())
{
nsNameAndKindImpl ns=name.ns[0].getImpl();
- assert_and_throw(ns.kind==NAMESPACE);
- ns_uri=ns.name;
- ns_prefix=getNamespacePrefixByURI(ns_uri);
+ if (ns.kind==NAMESPACE)
+ {
+ ns_uri=ns.name;
+ ns_prefix=getNamespacePrefixByURI(ns_uri);
+ }
}
// namespace set by "default xml namespace = ..."
@@ -1143,54 +1369,162 @@ void XML::setVariableByMultiname(const multiname& name, ASObject* o, CONST_ALLOW
isAttr=true;
buf+=1;
}
+
if(isAttr)
{
- //To have attributes we must be an Element
- xmlpp::Element* element=dynamic_cast<xmlpp::Element*>(node);
- assert_and_throw(element);
- element->set_attribute(buf, o->toString(), ns_prefix);
-
- if(ns_prefix.empty() && !ns_uri.empty())
+ bool found = false;
+ for (XMLList::XMLListVector::iterator it = attributelist->nodes.begin(); it != attributelist->nodes.end(); it++)
{
- element->set_namespace_declaration(ns_uri);
+ _R<XML> attr = *it;
+ if (attr->nodenamespace_uri == ns_uri && (attr->nodename == buf || (*buf==0)))
+ {
+ if(o->is<XMLList>())
+ {
+ _NR<XMLList> x = _NR<XMLList>(o->as<XMLList>());
+ for (auto it = x->nodes.begin(); it != x->nodes.end(); it++)
+ {
+ if (!found)
+ attr->nodevalue = (*it)->toString();
+ else
+ {
+ attr->nodevalue += " ";
+ attr->nodevalue += (*it)->toString();
+ }
+ found = true;
+ }
+ }
+ else
+ {
+ if (!found)
+ attr->nodevalue = o->toString();
+ else
+ {
+ attr->nodevalue += " ";
+ attr->nodevalue += o->toString();
+ }
+ found = true;
+ }
+
+ }
+ }
+ if (!found && !normalizedName.empty())
+ {
+ _NR<XML> tmp = _MR<XML>(Class<XML>::getInstanceS());
+ this->incRef();
+ tmp->parentNode = _MR<XML>(this);
+ tmp->nodetype = XML_ATTRIBUTE_NODE;
+ tmp->nodename = buf;
+ tmp->nodenamespace_uri = ns_uri;
+ tmp->nodenamespace_prefix = ns_prefix;
+ tmp->nodevalue = o->toString();
+ tmp->constructed = true;
+ attributelist->nodes.push_back(tmp);
}
}
- else if(Array::isValidMultiname(name,index))
+ else if(XML::isValidMultiname(name,index))
{
- LOG(LOG_NOT_IMPLEMENTED, "XML::setVariableByMultiname: array indexes");
+ childrenlist->setVariableByMultiname(name,o,allowConst);
}
else
{
- LOG(LOG_NOT_IMPLEMENTED, "XML::setVariableByMultiname: should replace if a node with the given name exists");
- if(o->is<XML>() || o->is<XMLList>())
- {
- LOG(LOG_NOT_IMPLEMENTED, "XML::setVariableByMultiname: assigning XML values not implemented");
- return;
- }
-
- xmlpp::Element* child = NULL;
- try
+ bool found = false;
+ XMLVector tmpnodes;
+ while (!childrenlist->nodes.empty())
{
- child=node->add_child(getSys()->getStringFromUniqueId(name.name_s_id), ns_prefix);
+ _R<XML> tmpnode = childrenlist->nodes.back();
+ if (tmpnode->nodenamespace_uri == ns_uri && tmpnode->nodename == normalizedName)
+ {
+ if(o->is<XMLList>())
+ {
+ if (!found)
+ {
+ _NR<XMLList> x = _NR<XMLList>(Class<XMLList>::getInstanceS(o->as<XMLList>()->toXMLString_internal(false)));
+ tmpnodes.insert(tmpnodes.end(), x->nodes.rbegin(),x->nodes.rend());
+ }
+ }
+ else if(o->is<XML>())
+ {
+ _NR<XML> tmp = _MR<XML>(o->as<XML>());
+ tmp->parentNode = _MR<XML>(this);
+ tmp->incRef();
+
+ if (!found)
+ tmpnodes.push_back(tmp);
+ }
+ else
+ {
+ if (tmpnode->childrenlist->nodes.size() == 1 && tmpnode->childrenlist->nodes[0]->nodetype == XML_TEXT_NODE)
+ tmpnode->childrenlist->nodes[0]->nodevalue = o->toString();
+ else
+ {
+ XML* newnode = Class<XML>::getInstanceS(o->toString());
+ tmpnode->childrenlist->clear();
+ tmpnode->setVariableByMultiname(name,newnode,allowConst);
+ }
+ if (!found)
+ {
+ tmpnode->incRef();
+ tmpnodes.push_back(tmpnode);
+ }
+ }
+ found = true;
+ }
+ else
+ {
+ tmpnode->incRef();
+ tmpnodes.push_back(tmpnode);
+ }
+ childrenlist->nodes.pop_back();
}
- catch (xmlpp::exception& e)
+ if (!found)
{
- LOG(LOG_NOT_IMPLEMENTED, "Adding child node failed: " << e.what());
- return;
- }
-
- child->add_child_text(o->toString());
-
- if(ns_prefix.empty() && !ns_uri.empty())
- {
- child->set_namespace_declaration(ns_uri);
+ if(o->is<XML>())
+ {
+ _R<XML> tmp = _MR<XML>(o->as<XML>());
+ tmp->parentNode = _MR<XML>(this);
+ tmp->incRef();
+ tmpnodes.insert(tmpnodes.begin(),tmp);
+ }
+ else
+ {
+ tiny_string tmpstr = "<";
+ if (!this->nodenamespace_prefix.empty())
+ {
+ tmpstr += ns_prefix;
+ tmpstr += ":";
+ }
+ tmpstr += normalizedName;
+ if (!ns_prefix.empty() && !ns_uri.empty())
+ {
+ tmpstr += " xmlns:";
+ tmpstr += ns_prefix;
+ tmpstr += "=\"";
+ tmpstr += ns_uri;
+ tmpstr += "\"";
+ }
+ tmpstr +=">";
+ tmpstr += encodeToXML(o->toString(),false);
+ tmpstr +="</";
+ if (!ns_prefix.empty())
+ {
+ tmpstr += ns_prefix;
+ tmpstr += ":";
+ }
+ tmpstr += normalizedName;
+ tmpstr +=">";
+ _NR<XML> tmp = _MR<XML>(Class<XML>::getInstanceS(tmpstr));
+ this->incRef();
+ tmp->parentNode = _MR<XML>(this);
+ tmpnodes.push_back(tmp);
+ }
}
+ childrenlist->nodes.insert(childrenlist->nodes.begin(), tmpnodes.rbegin(),tmpnodes.rend());
}
}
bool XML::hasPropertyByMultiname(const multiname& name, bool considerDynamic, bool considerPrototype)
{
- if(node==NULL || considerDynamic == false)
+ if(considerDynamic == false)
return ASObject::hasPropertyByMultiname(name, considerDynamic, considerPrototype);
//Only the first namespace is used, is this right?
@@ -1221,28 +1555,22 @@ bool XML::hasPropertyByMultiname(const multiname& name, bool considerDynamic, bo
if(isAttr)
{
//Lookup attribute
- assert(node);
- //To have attributes we must be an Element
- xmlpp::Element* element=dynamic_cast<xmlpp::Element*>(node);
- if(element)
+ for (XMLList::XMLListVector::const_iterator it = attributelist->nodes.begin(); it != attributelist->nodes.end(); it++)
{
- xmlpp::Attribute* attr=element->get_attribute(buf, ns_prefix);
- if(attr!=NULL)
+ _R<XML> attr = *it;
+ if (attr->nodenamespace_uri == ns_uri && attr->nodename == buf)
return true;
}
}
else
{
//Lookup children
- assert(node);
- //Use low level libxml2 access to optimize the code
- const xmlNode* cNode=node->cobj();
- for(const xmlNode* cur=cNode->children;cur!=NULL;cur=cur->next)
+ for (uint32_t i = 0; i < childrenlist->nodes.size(); i++)
{
- //NOTE: xmlStrEqual returns 1 when the strings are equal.
- bool name_match=xmlStrEqual(cur->name,(const xmlChar*)buf);
+ _R<XML> child= childrenlist->nodes[i];
+ bool name_match=(child->nodename == buf);
bool ns_match=ns_uri.empty() ||
- (cur->ns && xmlStrEqual(cur->ns->href, (const xmlChar*)ns_uri.raw_buf()));
+ (child->nodenamespace_uri == ns_uri);
if(name_match && ns_match)
return true;
}
@@ -1251,75 +1579,646 @@ bool XML::hasPropertyByMultiname(const multiname& name, bool considerDynamic, bo
//Try the normal path as the last resource
return ASObject::hasPropertyByMultiname(name, considerDynamic, considerPrototype);
}
+bool XML::deleteVariableByMultiname(const multiname& name)
+{
+ unsigned int index=0;
+ if(name.isAttribute)
+ {
+ //Only the first namespace is used, is this right?
+ tiny_string ns_uri;
+ tiny_string ns_prefix;
+ if(name.ns.size() > 0 && !name.ns[0].hasEmptyName())
+ {
+ nsNameAndKindImpl ns=name.ns[0].getImpl();
+ assert_and_throw(ns.kind==NAMESPACE);
+ ns_uri=ns.name;
+ ns_prefix=getNamespacePrefixByURI(ns_uri);
+ }
+ if (ns_uri.empty() && ns_prefix.empty())
+ {
+ ns_uri = getVm()->getDefaultXMLNamespace();
+ }
+ if (attributelist->nodes.size() > 0)
+ {
+ XMLList::XMLListVector::iterator it = attributelist->nodes.end();
+ while (it != attributelist->nodes.begin())
+ {
+ it--;
+ _R<XML> attr = *it;
+ if ((ns_uri=="" && name.normalizedName() == "") ||
+ (ns_uri=="" && name.normalizedName() == attr->nodename) ||
+ (attr->nodenamespace_uri == ns_uri && name.normalizedName() == "") ||
+ (attr->nodenamespace_uri == ns_uri && attr->nodename == name.normalizedName()))
+ {
+ attributelist->nodes.erase(it);
+ }
+ }
+ }
+ }
+ else if(XML::isValidMultiname(name,index))
+ {
+ childrenlist->nodes.erase(childrenlist->nodes.begin() + index);
+ }
+ else
+ {
+ //Only the first namespace is used, is this right?
+ tiny_string ns_uri;
+ if(name.ns.size() > 0 && !name.ns[0].hasEmptyName())
+ {
+ nsNameAndKindImpl ns=name.ns[0].getImpl();
+ assert_and_throw(ns.kind==NAMESPACE);
+ ns_uri=ns.name;
+ }
+ if (childrenlist->nodes.size() > 0)
+ {
+ XMLList::XMLListVector::iterator it = childrenlist->nodes.end();
+ while (it != childrenlist->nodes.begin())
+ {
+ it--;
+ _R<XML> node = *it;
+ if ((ns_uri=="" && name.normalizedName() == "") ||
+ (ns_uri=="" && name.normalizedName() == node->nodename) ||
+ (node->nodenamespace_uri == ns_uri && name.normalizedName() == "") ||
+ (node->nodenamespace_uri == ns_uri && node->nodename == name.normalizedName()))
+ {
+ childrenlist->nodes.erase(it);
+ }
+ }
+ }
+ }
+ return true;
+}
+bool XML::isValidMultiname(const multiname& name, uint32_t& index)
+{
+ //First of all the multiname has to contain the null namespace
+ //As the namespace vector is sorted, we check only the first one
+ if(name.ns.size()!=0 && !name.ns[0].hasEmptyName())
+ return false;
+
+ if (name.isEmpty())
+ return false;
+ bool validIndex=name.toUInt(index, true);
+ // Don't throw for non-numeric NAME_STRING or NAME_OBJECT
+ // because they can still be valid built-in property names.
+ if(!validIndex && (name.name_type==multiname::NAME_INT || name.name_type==multiname::NAME_NUMBER))
+ throwError<RangeError>(kOutOfRangeError, name.normalizedName(), "?");
+
+ return validIndex;
+}
tiny_string XML::getNamespacePrefixByURI(const tiny_string& uri, bool create)
{
tiny_string prefix;
bool found=false;
- xmlDocPtr xmlDoc=getRootNode()->parser.get_document()->cobj();
- xmlNsPtr* namespaces=xmlGetNsList(xmlDoc,node->cobj());
- if(namespaces)
+
+ XML* tmp = this;
+ while(tmp && tmp->is<XML>())
+ {
+ if(tmp->nodenamespace_uri==uri)
+ {
+ prefix=tmp->nodenamespace_prefix;
+ found = true;
+ break;
+ }
+ if (!tmp->parentNode)
+ break;
+ tmp = tmp->parentNode.getPtr();
+ }
+
+ if(!found && create)
+ {
+ nodenamespace_uri = uri;
+ }
+
+ return prefix;
+}
+
+ASFUNCTIONBODY(XML,_toString)
+{
+ XML* th=Class<XML>::cast(obj);
+ return Class<ASString>::getInstanceS(th->toString_priv());
+}
+
+ASFUNCTIONBODY(XML,_getIgnoreComments)
+{
+ return abstract_b(ignoreComments);
+}
+ASFUNCTIONBODY(XML,_setIgnoreComments)
+{
+ assert(args && argslen==1);
+ ignoreComments = Boolean_concrete(args[0]);
+ return NULL;
+}
+ASFUNCTIONBODY(XML,_getIgnoreProcessingInstructions)
+{
+ return abstract_b(ignoreProcessingInstructions);
+}
+ASFUNCTIONBODY(XML,_setIgnoreProcessingInstructions)
+{
+ assert(args && argslen==1);
+ ignoreProcessingInstructions = Boolean_concrete(args[0]);
+ return NULL;
+}
+ASFUNCTIONBODY(XML,_getIgnoreWhitespace)
+{
+ return abstract_b(ignoreWhitespace);
+}
+ASFUNCTIONBODY(XML,_setIgnoreWhitespace)
+{
+ assert(args && argslen==1);
+ ignoreWhitespace = Boolean_concrete(args[0]);
+ xmlKeepBlanksDefault(ignoreWhitespace ? 0 : 1);
+ return NULL;
+}
+ASFUNCTIONBODY(XML,_getPrettyIndent)
+{
+ return abstract_i(prettyIndent);
+}
+ASFUNCTIONBODY(XML,_setPrettyIndent)
+{
+ assert(args && argslen==1);
+ prettyIndent = args[0]->toInt();
+ return NULL;
+}
+ASFUNCTIONBODY(XML,_getPrettyPrinting)
+{
+ return abstract_b(prettyPrinting);
+}
+ASFUNCTIONBODY(XML,_setPrettyPrinting)
+{
+ assert(args && argslen==1);
+ prettyPrinting = Boolean_concrete(args[0]);
+ return NULL;
+}
+ASFUNCTIONBODY(XML,_getSettings)
+{
+ ASObject* res = Class<ASObject>::getInstanceS();
+ multiname mn(NULL);
+ mn.name_type=multiname::NAME_STRING;
+ mn.ns.push_back(nsNameAndKind("",NAMESPACE));
+ mn.ns.push_back(nsNameAndKind(AS3,NAMESPACE));
+ mn.isAttribute = true;
+
+ mn.name_s_id=getSys()->getUniqueStringId("ignoreComments");
+ res->setVariableByMultiname(mn,abstract_b(ignoreComments),CONST_NOT_ALLOWED);
+ mn.name_s_id=getSys()->getUniqueStringId("ignoreProcessingInstructions");
+ res->setVariableByMultiname(mn,abstract_b(ignoreProcessingInstructions),CONST_NOT_ALLOWED);
+ mn.name_s_id=getSys()->getUniqueStringId("ignoreWhitespace");
+ res->setVariableByMultiname(mn,abstract_b(ignoreWhitespace),CONST_NOT_ALLOWED);
+ mn.name_s_id=getSys()->getUniqueStringId("prettyIndent");
+ res->setVariableByMultiname(mn,abstract_i(prettyIndent),CONST_NOT_ALLOWED);
+ mn.name_s_id=getSys()->getUniqueStringId("prettyPrinting");
+ res->setVariableByMultiname(mn,abstract_b(prettyPrinting),CONST_NOT_ALLOWED);
+ return res;
+}
+ASFUNCTIONBODY(XML,_setSettings)
+{
+ if (argslen == 0)
+ {
+ setDefaultXMLSettings();
+ return getSys()->getNullRef();
+ }
+ _NR<ASObject> arg0;
+ ARG_UNPACK(arg0);
+ if (arg0->is<Null>() || arg0->is<Undefined>())
+ {
+ setDefaultXMLSettings();
+ return getSys()->getNullRef();
+ }
+ multiname mn(NULL);
+ mn.name_type=multiname::NAME_STRING;
+ mn.ns.push_back(nsNameAndKind("",NAMESPACE));
+ mn.ns.push_back(nsNameAndKind(AS3,NAMESPACE));
+ mn.isAttribute = true;
+ _NR<ASObject> o;
+
+ mn.name_s_id=getSys()->getUniqueStringId("ignoreComments");
+ if (arg0->hasPropertyByMultiname(mn,true,true))
+ {
+ o=arg0->getVariableByMultiname(mn,SKIP_IMPL);
+ ignoreComments = o->toInt();
+ }
+
+ mn.name_s_id=getSys()->getUniqueStringId("ignoreProcessingInstructions");
+ if (arg0->hasPropertyByMultiname(mn,true,true))
+ {
+ o=arg0->getVariableByMultiname(mn,SKIP_IMPL);
+ ignoreProcessingInstructions = o->toInt();
+ }
+
+ mn.name_s_id=getSys()->getUniqueStringId("ignoreWhitespace");
+ if (arg0->hasPropertyByMultiname(mn,true,true))
+ {
+ o=arg0->getVariableByMultiname(mn,SKIP_IMPL);
+ ignoreWhitespace = o->toInt();
+ }
+
+ mn.name_s_id=getSys()->getUniqueStringId("prettyIndent");
+ if (arg0->hasPropertyByMultiname(mn,true,true))
+ {
+ o=arg0->getVariableByMultiname(mn,SKIP_IMPL);
+ prettyIndent = o->toInt();
+ }
+
+ mn.name_s_id=getSys()->getUniqueStringId("prettyPrinting");
+ if (arg0->hasPropertyByMultiname(mn,true,true))
{
- for(int i=0; namespaces[i]!=NULL; i++)
+ o=arg0->getVariableByMultiname(mn,SKIP_IMPL);
+ prettyPrinting = o->toInt();
+ }
+ return getSys()->getNullRef();
+}
+ASFUNCTIONBODY(XML,_getDefaultSettings)
+{
+ ASObject* res = Class<ASObject>::getInstanceS();
+ multiname mn(NULL);
+ mn.name_type=multiname::NAME_STRING;
+ mn.ns.push_back(nsNameAndKind("",NAMESPACE));
+ mn.ns.push_back(nsNameAndKind(AS3,NAMESPACE));
+ mn.isAttribute = true;
+
+ mn.name_s_id=getSys()->getUniqueStringId("ignoreComments");
+ res->setVariableByMultiname(mn,abstract_b(true),CONST_NOT_ALLOWED);
+ mn.name_s_id=getSys()->getUniqueStringId("ignoreProcessingInstructions");
+ res->setVariableByMultiname(mn,abstract_b(true),CONST_NOT_ALLOWED);
+ mn.name_s_id=getSys()->getUniqueStringId("ignoreWhitespace");
+ res->setVariableByMultiname(mn,abstract_b(true),CONST_NOT_ALLOWED);
+ mn.name_s_id=getSys()->getUniqueStringId("prettyIndent");
+ res->setVariableByMultiname(mn,abstract_i(2),CONST_NOT_ALLOWED);
+ mn.name_s_id=getSys()->getUniqueStringId("prettyPrinting");
+ res->setVariableByMultiname(mn,abstract_b(true),CONST_NOT_ALLOWED);
+ return res;
+}
+ASFUNCTIONBODY(XML,_toJSON)
+{
+ return Class<ASString>::getInstanceS("XML");
+}
+
+void XML::CheckCyclicReference(XML* node)
+{
+ XML* tmp = node;
+ if (tmp == this)
+ throwError<TypeError>(kXMLIllegalCyclicalLoop);
+ for (auto it = tmp->childrenlist->nodes.begin(); it != tmp->childrenlist->nodes.end(); it++)
+ {
+ if ((*it).getPtr() == this)
+ throwError<TypeError>(kXMLIllegalCyclicalLoop);
+ CheckCyclicReference((*it).getPtr());
+ }
+}
+
+ASFUNCTIONBODY(XML,insertChildAfter)
+{
+ XML* th=Class<XML>::cast(obj);
+ _NR<ASObject> child1;
+ _NR<ASObject> child2;
+ ARG_UNPACK(child1)(child2);
+ if (th->nodetype != XML_ELEMENT_NODE)
+ return getSys()->getUndefinedRef();
+
+ if (child2->is<XML>())
+ th->CheckCyclicReference(child2->as<XML>());
+ else if (child2->is<XMLList>())
+ {
+ for (auto it = child2->as<XMLList>()->nodes.begin(); it < child2->as<XMLList>()->nodes.end(); it++)
+ {
+ th->CheckCyclicReference((*it).getPtr());
+ }
+ }
+ else
+ child2 = _NR<XML>(Class<XML>::getInstanceS(child2->toString()));
+ if (child1->is<Null>())
+ {
+ th->incRef();
+ child2->as<XML>()->parentNode = _NR<XML>(th);
+ if (child2->is<XML>())
+ {
+ th->incRef();
+ child2->incRef();
+ child2->as<XML>()->parentNode = _NR<XML>(th);
+ th->childrenlist->nodes.insert(th->childrenlist->nodes.begin(),_NR<XML>(child2->as<XML>()));
+ }
+ else if (child2->is<XMLList>())
{
- tiny_string nsuri((const char*)namespaces[i]->href);
- if(nsuri==uri)
+ for (auto it2 = child2->as<XMLList>()->nodes.begin(); it2 < child2->as<XMLList>()->nodes.end(); it2++)
{
- if(namespaces[i]->prefix)
+ th->incRef();
+ (*it2)->incRef();
+ (*it2)->parentNode = _NR<XML>(th);
+ }
+ th->childrenlist->nodes.insert(th->childrenlist->nodes.begin(),child2->as<XMLList>()->nodes.begin(), child2->as<XMLList>()->nodes.end());
+ }
+ th->incRef();
+ return th;
+ }
+ if (child1->is<XMLList>())
+ {
+ if (child1->as<XMLList>()->nodes.size()==0)
+ return getSys()->getUndefinedRef();
+ child1 = child1->as<XMLList>()->nodes[0];
+ }
+ for (auto it = th->childrenlist->nodes.begin(); it != th->childrenlist->nodes.end(); it++)
+ {
+ if ((*it).getPtr() == child1.getPtr())
+ {
+ th->incRef();
+ if (child2->is<XML>())
+ {
+ th->incRef();
+ child2->incRef();
+ child2->as<XML>()->parentNode = _NR<XML>(th);
+ th->childrenlist->nodes.insert(it+1,_NR<XML>(child2->as<XML>()));
+ }
+ else if (child2->is<XMLList>())
+ {
+ for (auto it2 = child2->as<XMLList>()->nodes.begin(); it2 < child2->as<XMLList>()->nodes.end(); it2++)
{
- prefix=tiny_string((const char*)namespaces[i]->prefix, true);
+ th->incRef();
+ (*it2)->incRef();
+ (*it2)->parentNode = _NR<XML>(th);
}
+ th->childrenlist->nodes.insert(it+1,child2->as<XMLList>()->nodes.begin(), child2->as<XMLList>()->nodes.end());
+ }
+ return th;
+ }
+ }
+ return getSys()->getUndefinedRef();
+}
+ASFUNCTIONBODY(XML,insertChildBefore)
+{
+ XML* th=Class<XML>::cast(obj);
+ _NR<ASObject> child1;
+ _NR<ASObject> child2;
+ ARG_UNPACK(child1)(child2);
+ if (th->nodetype != XML_ELEMENT_NODE)
+ return getSys()->getUndefinedRef();
+
+ if (child2->is<XML>())
+ th->CheckCyclicReference(child2->as<XML>());
+ else if (child2->is<XMLList>())
+ {
+ for (auto it = child2->as<XMLList>()->nodes.begin(); it < child2->as<XMLList>()->nodes.end(); it++)
+ {
+ th->CheckCyclicReference((*it).getPtr());
+ }
+ }
+ else
+ child2 = _NR<XML>(Class<XML>::getInstanceS(child2->toString()));
- found = true;
- break;
+ if (child1->is<Null>())
+ {
+ if (child2->is<XML>())
+ {
+ th->appendChild(_NR<XML>(child2->as<XML>()));
+ }
+ else if (child2->is<XMLList>())
+ {
+ for (auto it = child2->as<XMLList>()->nodes.begin(); it < child2->as<XMLList>()->nodes.end(); it++)
+ {
+ th->incRef();
+ (*it)->incRef();
+ (*it)->parentNode = _NR<XML>(th);
+ th->childrenlist->nodes.push_back(_NR<XML>(*it));
+ }
+ }
+ th->incRef();
+ return th;
+ }
+ if (child1->is<XMLList>())
+ {
+ if (child1->as<XMLList>()->nodes.size()==0)
+ return getSys()->getUndefinedRef();
+ child1 = child1->as<XMLList>()->nodes[0];
+ }
+ for (auto it = th->childrenlist->nodes.begin(); it != th->childrenlist->nodes.end(); it++)
+ {
+ if ((*it).getPtr() == child1.getPtr())
+ {
+ th->incRef();
+ if (child2->is<XML>())
+ {
+ th->incRef();
+ child2->incRef();
+ child2->as<XML>()->parentNode = _NR<XML>(th);
+ th->childrenlist->nodes.insert(it,_NR<XML>(child2->as<XML>()));
}
+ else if (child2->is<XMLList>())
+ {
+ for (auto it2 = child2->as<XMLList>()->nodes.begin(); it2 < child2->as<XMLList>()->nodes.end(); it2++)
+ {
+ th->incRef();
+ (*it2)->incRef();
+ (*it2)->parentNode = _NR<XML>(th);
+ }
+ th->childrenlist->nodes.insert(it,child2->as<XMLList>()->nodes.begin(), child2->as<XMLList>()->nodes.end());
+ }
+ return th;
}
+ }
+ return getSys()->getUndefinedRef();
+}
- xmlFree(namespaces);
+ASFUNCTIONBODY(XML,namespaceDeclarations)
+{
+ XML *th = obj->as<XML>();
+ Array *namespaces = Class<Array>::getInstanceS();
+ for (uint32_t i = 0; i < th->namespacedefs.size(); i++)
+ {
+ _R<Namespace> tmpns = th->namespacedefs[i];
+ bool b;
+ if (tmpns->getPrefix(b) != "")
+ {
+ tmpns->incRef();
+ namespaces->push(tmpns);
+ }
}
+ return namespaces;
+}
- if(!found && create)
+ASFUNCTIONBODY(XML,removeNamespace)
+{
+ XML *th = obj->as<XML>();
+ _NR<ASObject> arg1;
+ ARG_UNPACK(arg1);
+ Namespace* ns;
+ if (arg1->is<Namespace>())
+ ns = arg1->as<Namespace>();
+ else
+ ns = Class<Namespace>::getInstanceS(arg1->toString(), "");
+
+ th->RemoveNamespace(ns);
+ th->incRef();
+ return th;
+}
+void XML::RemoveNamespace(Namespace *ns)
+{
+ if (this->nodenamespace_uri == ns->getURI())
+ {
+ this->nodenamespace_uri = "";
+ this->nodenamespace_prefix = "";
+ }
+ for (auto it = namespacedefs.begin(); it != namespacedefs.end(); it++)
+ {
+ _R<Namespace> tmpns = *it;
+ if (tmpns->getURI() == ns->getURI())
+ {
+ namespacedefs.erase(it);
+ break;
+ }
+ }
+ if (childrenlist)
{
- xmlpp::Element *element=dynamic_cast<xmlpp::Element *>(node);
- xmlpp::Attribute *attribute=dynamic_cast<xmlpp::Attribute *>(node);
- if(attribute)
- element=attribute->get_parent();
- if(element)
- element->set_namespace_declaration(uri);
+ for (auto it = childrenlist->nodes.begin(); it != childrenlist->nodes.end(); it++)
+ {
+ (*it)->RemoveNamespace(ns);
+ }
}
+}
- return prefix;
+ASFUNCTIONBODY(XML,comments)
+{
+ XML* th=Class<XML>::cast(obj);
+ tiny_string name;
+ ARG_UNPACK(name,"*");
+ XMLVector ret;
+ th->getComments(ret);
+ return Class<XMLList>::getInstanceS(ret,th->getChildrenlist(),multiname(NULL));
+}
+void XML::getComments(XMLVector& ret)
+{
+ if (childrenlist)
+ {
+ for (auto it = childrenlist->nodes.begin(); it != childrenlist->nodes.end(); it++)
+ {
+ if ((*it)->getNodeKind() == XML_COMMENT_NODE)
+ {
+ (*it)->incRef();
+ ret.push_back(*it);
+ }
+ }
+ }
}
-ASFUNCTIONBODY(XML,_toString)
+ASFUNCTIONBODY(XML,processingInstructions)
{
XML* th=Class<XML>::cast(obj);
- return Class<ASString>::getInstanceS(th->toString_priv());
+ tiny_string name;
+ ARG_UNPACK(name,"*");
+ XMLVector ret;
+ th->getprocessingInstructions(ret,name);
+ return Class<XMLList>::getInstanceS(ret,th->getChildrenlist(),multiname(NULL));
+}
+void XML::getprocessingInstructions(XMLVector& ret, tiny_string name)
+{
+ if (childrenlist)
+ {
+ for (auto it = childrenlist->nodes.begin(); it != childrenlist->nodes.end(); it++)
+ {
+ if ((*it)->getNodeKind() == XML_PI_NODE && (name == "*" || name == (*it)->nodename))
+ {
+ (*it)->incRef();
+ ret.push_back(*it);
+ }
+ }
+ }
+}
+ASFUNCTIONBODY(XML,_propertyIsEnumerable)
+{
+ return abstract_b(argslen == 1 && args[0]->toString() == "0" );
+}
+ASFUNCTIONBODY(XML,_hasOwnProperty)
+{
+ tiny_string prop;
+ ARG_UNPACK(prop);
+
+ bool ret = false;
+ if (prop == "0")
+ ret = true;
+ else
+ {
+ multiname name(NULL);
+ name.name_type=multiname::NAME_STRING;
+ name.name_s_id=getSys()->getUniqueStringId(args[0]->toString());
+ name.ns.push_back(nsNameAndKind("",NAMESPACE));
+ name.ns.push_back(nsNameAndKind(AS3,NAMESPACE));
+ name.isAttribute=false;
+ ret=obj->hasPropertyByMultiname(name, true, true);
+ }
+ return abstract_b(ret);
}
tiny_string XML::toString_priv()
{
- //We have to use vanilla libxml2, libxml++ is not enough
- xmlNodePtr libXml2Node=node->cobj();
tiny_string ret;
- if(hasSimpleContent())
+ if (getNodeKind() == XML_TEXT_NODE ||
+ getNodeKind() == XML_ATTRIBUTE_NODE ||
+ getNodeKind() == XML_CDATA_SECTION_NODE)
+ {
+ ret=nodevalue;
+ }
+ else if (hasSimpleContent())
{
- xmlChar* content=xmlNodeGetContent(libXml2Node);
- ret=tiny_string((char*)content,true);
- xmlFree(content);
+ auto it = childrenlist->nodes.begin();
+ while(it != childrenlist->nodes.end())
+ {
+ if ((*it)->getNodeKind() != XML_COMMENT_NODE &&
+ (*it)->getNodeKind() != XML_PI_NODE)
+ ret += (*it)->toString_priv();
+ it++;
+ }
}
else
{
- assert_and_throw(!node->get_children().empty());
- xmlBufferPtr xmlBuffer=xmlBufferCreateSize(4096);
- toXMLString_priv(xmlBuffer);
- ret=tiny_string((char*)xmlBuffer->content,true);
- xmlBufferFree(xmlBuffer);
+ ret=toXMLString_internal();
}
return ret;
}
+const tiny_string XML::encodeToXML(const tiny_string value, bool bIsAttribute)
+{
+
+ tiny_string res;
+ auto it = value.begin();
+ while (it != value.end())
+ {
+ switch (*it)
+ {
+ case '<':
+ res += "<";
+ break;
+ case '>':
+ res += bIsAttribute ? ">" : ">";
+ break;
+ case '&':
+ res += "&";
+ break;
+ case '\"':
+ res += bIsAttribute ? """ : "\"";
+ break;
+ case '\r':
+ res += bIsAttribute ? "
" : "\r";
+ break;
+ case '\n':
+ res += bIsAttribute ? "
" : "\n";
+ break;
+ case '\t':
+ res += bIsAttribute ? "	" : "\t";
+ break;
+ default:
+ res += *it;
+ break;
+ }
+ it++;
+ }
+ return res;
+}
+
+bool XML::getPrettyPrinting()
+{
+ return prettyPrinting;
+}
+
tiny_string XML::toString()
{
return toString_priv();
@@ -1330,86 +2229,44 @@ int32_t XML::toInt()
if (!hasSimpleContent())
return 0;
- tiny_string str = toString();
+ tiny_string str = toString_priv();
return Integer::stringToASInteger(str.raw_buf(), 0);
}
-bool XML::nodesEqual(xmlpp::Node *a, xmlpp::Node *b) const
+bool XML::nodesEqual(XML *a, XML *b) const
{
assert(a && b);
// type
- if(a->cobj()->type!=b->cobj()->type)
+ if(a->nodetype!=b->nodetype)
return false;
// name
- if(a->get_name()!=b->get_name() ||
- (!a->get_name().empty() &&
- a->get_namespace_uri()!=b->get_namespace_uri()))
+ if(a->nodename!=b->nodename ||
+ (!a->nodename.empty() &&
+ a->nodenamespace_uri!=b->nodenamespace_uri))
return false;
// attributes
- xmlpp::Element *el1=dynamic_cast<xmlpp::Element *>(a);
- xmlpp::Element *el2=dynamic_cast<xmlpp::Element *>(b);
- if(el1 && el2)
+ if(a->nodetype==XML_ELEMENT_NODE)
{
- xmlpp::Element::AttributeList attrs1=el1->get_attributes();
- xmlpp::Element::AttributeList attrs2=el2->get_attributes();
- if(attrs1.size()!=attrs2.size())
+ if (a->attributelist->nodes.size() != b->attributelist->nodes.size())
return false;
-
- xmlpp::Element::AttributeList::iterator it=attrs1.begin();
- while(it!=attrs1.end())
+
+ for (int i = 0; i < (int)a->attributelist->nodes.size(); i++)
{
- xmlpp::Attribute *attr=el2->get_attribute((*it)->get_name(),
- (*it)->get_namespace_prefix());
- if(!attr || (*it)->get_value()!=attr->get_value())
+ _R<XML> oa= a->attributelist->nodes[i];
+ _R<XML> ob= b->attributelist->nodes[i];
+ if (!oa->isEqual(ob.getPtr()))
return false;
-
- ++it;
}
}
-
// content
- xmlpp::ContentNode *c1=dynamic_cast<xmlpp::ContentNode *>(a);
- xmlpp::ContentNode *c2=dynamic_cast<xmlpp::ContentNode *>(b);
- if(el1 && el2)
- {
- xmlpp::TextNode *text1=el1->get_child_text();
- xmlpp::TextNode *text2=el2->get_child_text();
-
- if(text1 && text2)
- {
- if(text1->get_content()!=text2->get_content())
- return false;
- }
- else if(text1 || text2)
- return false;
-
- }
- else if(c1 && c2)
- {
- if(c1->get_content()!=c2->get_content())
- return false;
- }
+ if (a->nodevalue != b->nodevalue)
+ return false;
// children
- xmlpp::Node::NodeList myChildren=a->get_children();
- xmlpp::Node::NodeList otherChildren=b->get_children();
- if(myChildren.size()!=otherChildren.size())
- return false;
-
- xmlpp::Node::NodeList::iterator it1=myChildren.begin();
- xmlpp::Node::NodeList::iterator it2=otherChildren.begin();
- while(it1!=myChildren.end())
- {
- if (!nodesEqual(*it1, *it2))
- return false;
- ++it1;
- ++it2;
- }
-
- return true;
+ return a->childrenlist->isEqual(b->childrenlist.getPtr());
}
uint32_t XML::nextNameIndex(uint32_t cur_index)
@@ -1443,7 +2300,7 @@ bool XML::isEqual(ASObject* r)
{
XML *x=dynamic_cast<XML *>(r);
if(x)
- return nodesEqual(node, x->node);
+ return nodesEqual(this, x);
XMLList *xl=dynamic_cast<XMLList *>(r);
if(xl)
@@ -1463,13 +2320,150 @@ void XML::serialize(ByteArray* out, std::map<tiny_string, uint32_t>& stringMap,
out->writeXMLString(objMap, this, toString());
}
-_NR<XML> XML::getRootNode()
+void XML::createTree(xmlpp::Node* node)
{
- if(root.isNull())
+ const xmlpp::Node::NodeList& list=node->get_children();
+ xmlpp::Node::NodeList::const_iterator it=list.begin();
+ childrenlist = _MR(Class<XMLList>::getInstanceS());
+ childrenlist->incRef();
+
+ this->nodetype = node->cobj()->type;
+ this->nodename = node->get_name();
+ this->nodenamespace_uri = node->get_namespace_uri();
+ this->nodenamespace_prefix = node ->get_namespace_prefix();
+
+ switch (this->nodetype)
{
- incRef();
- return _MR(this);
+ case XML_ATTRIBUTE_NODE:
+ case XML_TEXT_NODE:
+ {
+ xmlpp::ContentNode *textnode=dynamic_cast<xmlpp::ContentNode*>(node);
+ this->nodevalue = textnode->get_content();
+ if (ignoreWhitespace)
+ {
+ nodevalue = removeWhitespace(nodevalue);
+ if (nodevalue.empty())
+ return;
+ }
+ break;
+ }
+ case XML_PI_NODE:
+ {
+ xmlpp::ContentNode *textnode=dynamic_cast<xmlpp::ContentNode*>(node);
+ this->nodevalue = textnode->get_content();
+ break;
+ }
+ case XML_COMMENT_NODE:
+ case XML_CDATA_SECTION_NODE:
+ {
+ xmlpp::ContentNode *textnode=dynamic_cast<xmlpp::ContentNode*>(node);
+ this->nodevalue = textnode->get_content();
+ break;
+ }
+ default:
+ break;
+ }
+ for(;it!=list.end();++it)
+ {
+ if (ignoreProcessingInstructions && (*it)->cobj()->type == XML_PI_NODE)
+ continue;
+ if (ignoreComments && (*it)->cobj()->type == XML_COMMENT_NODE)
+ continue;
+ if (ignoreWhitespace && (*it)->cobj()->type == XML_TEXT_NODE)
+ {
+ xmlpp::ContentNode *textnode=dynamic_cast<xmlpp::ContentNode*>(*it);
+ tiny_string tmpstr = textnode->get_content();
+ if (ignoreWhitespace)
+ {
+ tmpstr = removeWhitespace(tmpstr);
+ if (tmpstr.empty())
+ continue;
+ }
+ }
+ _NR<XML> tmp = _MR<XML>(Class<XML>::getInstanceS(*it));
+ this->incRef();
+ tmp->parentNode = _MR<XML>(this);
+ childrenlist->append(_R<XML>(tmp));
+ }
+ const xmlNode* xmlN = node->cobj();
+
+ xmlNsPtr nsdefs = xmlN->nsDef;
+ while (nsdefs)
+ {
+ tiny_string uri;
+ if (nsdefs->href) uri= (char*)nsdefs->href;
+ tiny_string prefix;
+ if (nsdefs->prefix) prefix= (char*)nsdefs->prefix;
+ Namespace* ns = Class<Namespace>::getInstanceS(uri,prefix);
+ namespacedefs.push_back(_MR(ns));
+ nsdefs = nsdefs->next;
+ }
+ attributelist = _MR(Class<XMLList>::getInstanceS());
+ for(xmlAttr* attr=xmlN->properties; attr!=NULL; attr=attr->next)
+ {
+ _NR<XML> tmp = _MR<XML>(Class<XML>::getInstanceS());
+ this->incRef();
+ tmp->parentNode = _MR<XML>(this);
+ tmp->nodetype = XML_ATTRIBUTE_NODE;
+ tmp->nodename = (char*)attr->name;
+ if (attr->ns)
+ {
+ tmp->nodenamespace_uri = (char*)attr->ns->href;
+ tmp->nodenamespace_prefix = (char*)attr->ns->prefix;
+ }
+ else
+ tmp->nodenamespace_uri = getVm()->getDefaultXMLNamespace();
+
+ //NOTE: libxmlpp headers says that Node::create_wrapper
+ //is supposed to be internal API. Still it's very useful and
+ //we use it.
+ xmlpp::Node::create_wrapper(reinterpret_cast<xmlNode*>(attr));
+ xmlpp::Node* attrX=static_cast<xmlpp::Node*>(attr->_private);
+ xmlpp::Attribute *textnode=dynamic_cast<xmlpp::Attribute*>(attrX);
+ tmp->nodevalue = textnode->get_value();
+ tmp->constructed = true;
+ attributelist->nodes.push_back(tmp);
+ }
+ constructed=true;
+}
+
+ASFUNCTIONBODY(XML,_prependChild)
+{
+ XML* th=Class<XML>::cast(obj);
+ assert_and_throw(argslen==1);
+ _NR<XML> arg;
+ if(args[0]->getClass()==Class<XML>::getClass())
+ {
+ args[0]->incRef();
+ arg=_MR(Class<XML>::cast(args[0]));
+ }
+ else if(args[0]->getClass()==Class<XMLList>::getClass())
+ {
+ XMLList* list=Class<XMLList>::cast(args[0]);
+ list->appendNodesTo(th);
+ th->incRef();
+ return th;
+ }
+ else
+ {
+ //The appendChild specs says that any other type is converted to string
+ //NOTE: this is explicitly different from XML constructor, that will only convert to
+ //string Numbers and Booleans
+ arg=_MR(Class<XML>::getInstanceS(args[0]->toString()));
+ }
+
+ th->appendChild(arg);
+ th->incRef();
+ return th;
+}
+void XML::prependChild(_R<XML> newChild)
+{
+ if (newChild->constructed)
+ {
+ this->incRef();
+ newChild->parentNode = _NR<XML>(this);
+ childrenlist->append(newChild);
}
else
- return root;
+ newChild->decRef();
}
diff --git a/src/scripting/toplevel/XML.h b/src/scripting/toplevel/XML.h
index 5ff172a..e7f34cf 100644
--- a/src/scripting/toplevel/XML.h
+++ b/src/scripting/toplevel/XML.h
@@ -24,32 +24,36 @@
namespace lightspark
{
+class Namespace;
class XMLList;
class XML: public ASObject, public XMLBase
{
friend class XMLList;
public:
typedef std::vector<_R<XML>> XMLVector;
+ typedef std::vector<_R<Namespace>> NSVector;
private:
- //Pointer to the root XML element, the one that owns the parser that created this node
- _NR<XML> root;
- //The node this object represent
- xmlpp::Node* node;
- static void recursiveGetDescendantsByQName(_R<XML> root, xmlpp::Node* node, const tiny_string& name, const tiny_string& ns,
- XMLVector& ret);
+ _NR<XMLList> childrenlist;
+ _NR<XML> parentNode;
+ xmlElementType nodetype;
+ tiny_string nodename;
+ tiny_string nodevalue;
+ tiny_string nodenamespace_uri;
+ tiny_string nodenamespace_prefix;
+ _NR<XMLList> attributelist;
+ NSVector namespacedefs;
+
+ void createTree(xmlpp::Node* node);
tiny_string toString_priv();
+ const char* nodekindString();
+
bool constructed;
- bool nodesEqual(xmlpp::Node *a, xmlpp::Node *b) const;
- XMLVector getAttributes(const tiny_string& name="*",
- const tiny_string& namespace_uri="*");
+ bool nodesEqual(XML *a, XML *b) const;
+ XMLVector getAttributes();
+ XMLVector getAttributesByMultiname(const multiname& name);
+ XMLVector getValuesByMultiname(_NR<XMLList> nodelist, const multiname& name);
XMLList* getAllAttributes();
void getText(XMLVector& ret);
- _NR<XML> getRootNode();
- bool ignoreComments;
- bool ignoreProcessingInstructions;
- bool ignoreWhitespace;
- uint32_t prettyIndent;
- bool prettyPrinting;
/*
* @param name The name of the wanted children, "*" for all children
*
@@ -57,15 +61,22 @@ private:
void childrenImpl(XMLVector& ret, const tiny_string& name);
void childrenImpl(XMLVector& ret, uint32_t index);
tiny_string getNamespacePrefixByURI(const tiny_string& uri, bool create=false);
- void setLocalName(const tiny_string& localname);
- void setNamespace(const tiny_string& ns_uri, const tiny_string& ns_prefix="");
- void removeAllChildren();
- static void normalizeRecursive(xmlpp::Node *node);
+ void setLocalName(const tiny_string& localname);
+ void setNamespace(const tiny_string& ns_uri, const tiny_string& ns_prefix="");
+ // Append node or attribute to this. Concatenates adjacent
+ // text nodes.
+ void appendChild(_R<XML> child);
+ void prependChild(_R<XML> child);
+ static void normalizeRecursive(XML *node);
void addTextContent(const tiny_string& str);
+ bool hasParentNode;
+ void RemoveNamespace(Namespace *ns);
+ void getComments(XMLVector& ret);
+ void getprocessingInstructions(XMLVector& ret, tiny_string name);
+ void CheckCyclicReference(XML* node);
public:
XML(Class_base* c);
XML(Class_base* c,const std::string& str);
- XML(Class_base* c,_R<XML> _r, xmlpp::Node* _n);
XML(Class_base* c,xmlpp::Node* _n);
void finalize();
ASFUNCTION(_constructor);
@@ -79,7 +90,7 @@ public:
ASFUNCTION(_copy);
ASFUNCTION(attributes);
ASFUNCTION(attribute);
- ASFUNCTION(appendChild);
+ ASFUNCTION(_appendChild);
ASFUNCTION(length);
ASFUNCTION(localName);
ASFUNCTION(name);
@@ -99,21 +110,59 @@ public:
ASFUNCTION(_setName);
ASFUNCTION(_setNamespace);
ASFUNCTION(_setChildren);
- static void buildTraits(ASObject* o){};
+
+ ASFUNCTION(_getIgnoreComments);
+ ASFUNCTION(_setIgnoreComments);
+ ASFUNCTION(_getIgnoreProcessingInstructions);
+ ASFUNCTION(_setIgnoreProcessingInstructions);
+ ASFUNCTION(_getIgnoreWhitespace);
+ ASFUNCTION(_setIgnoreWhitespace);
+ ASFUNCTION(_getPrettyIndent);
+ ASFUNCTION(_setPrettyIndent);
+ ASFUNCTION(_getPrettyPrinting);
+ ASFUNCTION(_setPrettyPrinting);
+ ASFUNCTION(_getSettings);
+ ASFUNCTION(_setSettings);
+ ASFUNCTION(_getDefaultSettings);
+ ASFUNCTION(_toJSON);
+ ASFUNCTION(insertChildAfter);
+ ASFUNCTION(insertChildBefore);
+ ASFUNCTION(namespaceDeclarations);
+ ASFUNCTION(removeNamespace);
+ ASFUNCTION(comments);
+ ASFUNCTION(processingInstructions);
+ ASFUNCTION(_propertyIsEnumerable);
+ ASFUNCTION(_hasOwnProperty);
+ ASFUNCTION(_prependChild);
+
+ static void buildTraits(ASObject* o){}
static void sinit(Class_base* c);
- void getDescendantsByQName(const tiny_string& name, const tiny_string& ns, XMLVector& ret);
+
+ static const tiny_string encodeToXML(const tiny_string value, bool bIsAttribute);
+ static bool getPrettyPrinting();
+
+ const tiny_string getName() const { return nodename;}
+ const tiny_string getNamespaceURI() const { return nodenamespace_uri;}
+ XMLList* getChildrenlist() { return childrenlist ? childrenlist.getPtr() : NULL; }
+
+
+ void getDescendantsByQName(const tiny_string& name, const tiny_string& ns,bool bIsAttribute, XMLVector& ret);
void getElementNodes(const tiny_string& name, XMLVector& foundElements);
- _NR<ASObject> getVariableByMultiname(const multiname& name, GET_VARIABLE_OPTION opt);
+ _NR<ASObject> getVariableByMultiname(const multiname& name, GET_VARIABLE_OPTION opt=NONE);
bool hasPropertyByMultiname(const multiname& name, bool considerDynamic, bool considerPrototype);
void setVariableByMultiname(const multiname& name, ASObject* o, CONST_ALLOWED_FLAG allowConst);
+ bool deleteVariableByMultiname(const multiname& name);
+ static bool isValidMultiname(const multiname& name, uint32_t& index);
+
+ void setTextContent(const tiny_string& content);
tiny_string toString();
+ const tiny_string toXMLString_internal(bool pretty=true, tiny_string defaultnsprefix = "", const char* indent = "", bool bfirst = true);
int32_t toInt();
- void toXMLString_priv(xmlBufferPtr buf);
bool hasSimpleContent() const;
bool hasComplexContent() const;
- xmlElementType getNodeKind() const;
+ xmlElementType getNodeKind() const;
ASObject *getParentNode();
- XML *copy() const;
+ XML *copy();
void normalize();
bool isEqual(ASObject* r);
uint32_t nextNameIndex(uint32_t cur_index);
diff --git a/src/scripting/toplevel/XMLList.cpp b/src/scripting/toplevel/XMLList.cpp
index 0d594c1..231b89e 100644
--- a/src/scripting/toplevel/XMLList.cpp
+++ b/src/scripting/toplevel/XMLList.cpp
@@ -51,35 +51,49 @@ using namespace lightspark;
return NULL; \
}
-XMLList::XMLList(Class_base* c):ASObject(c),nodes(c->memoryAccount),constructed(false)
+XMLList::XMLList(Class_base* c):ASObject(c),nodes(c->memoryAccount),constructed(false),targetobject(NULL),targetproperty(c->memoryAccount)
{
}
-XMLList::XMLList(Class_base* cb,bool c):ASObject(cb),nodes(cb->memoryAccount),constructed(c)
+XMLList::XMLList(Class_base* cb,bool c):ASObject(cb),nodes(cb->memoryAccount),constructed(c),targetobject(NULL),targetproperty(cb->memoryAccount)
{
assert(c);
}
-XMLList::XMLList(Class_base* c, const std::string& str):ASObject(c),nodes(c->memoryAccount),constructed(true)
+XMLList::XMLList(Class_base* c, const std::string& str):ASObject(c),nodes(c->memoryAccount),constructed(true),targetobject(NULL),targetproperty(c->memoryAccount)
{
buildFromString(str);
}
-XMLList::XMLList(Class_base* c,const XML::XMLVector& r):
- ASObject(c),nodes(r.begin(),r.end(),c->memoryAccount),constructed(true)
+XMLList::XMLList(Class_base* c, const XML::XMLVector& r):
+ ASObject(c),nodes(r.begin(),r.end(),c->memoryAccount),constructed(true),targetobject(NULL),targetproperty(c->memoryAccount)
{
}
+XMLList::XMLList(Class_base* c, const XML::XMLVector& r, XMLList *targetobject, const multiname &targetproperty):
+ ASObject(c),nodes(r.begin(),r.end(),c->memoryAccount),constructed(true),targetobject(targetobject),targetproperty(c->memoryAccount)
+{
+ if (targetobject)
+ targetobject->incRef();
+ this->targetproperty.name_type = targetproperty.name_type;
+ this->targetproperty.isAttribute = targetproperty.isAttribute;
+ this->targetproperty.name_s_id = targetproperty.name_s_id;
+ for (auto it = targetproperty.ns.begin();it != targetproperty.ns.end(); it++)
+ {
+ this->targetproperty.ns.push_back(*it);
+ }
+}
void XMLList::finalize()
{
- nodes.clear();
+ if (targetobject)
+ targetobject->decRef();
+ //nodes.clear();
ASObject::finalize();
}
void XMLList::sinit(Class_base* c)
{
- c->setSuper(Class<ASObject>::getRef());
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED | CLASS_FINAL);
c->setDeclaredMethodByQName("length","",Class<IFunction>::getFunction(_getLength),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("attribute",AS3,Class<IFunction>::getFunction(attribute),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("attributes",AS3,Class<IFunction>::getFunction(attributes),NORMAL_METHOD,true);
@@ -89,7 +103,7 @@ void XMLList::sinit(Class_base* c)
c->setDeclaredMethodByQName("copy",AS3,Class<IFunction>::getFunction(copy),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("descendants",AS3,Class<IFunction>::getFunction(descendants),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("elements",AS3,Class<IFunction>::getFunction(elements),NORMAL_METHOD,true);
- c->setDeclaredMethodByQName("normalize",AS3,Class<IFunction>::getFunction(normalize),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("normalize",AS3,Class<IFunction>::getFunction(_normalize),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("parent",AS3,Class<IFunction>::getFunction(parent),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("hasSimpleContent",AS3,Class<IFunction>::getFunction(_hasSimpleContent),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("hasComplexContent",AS3,Class<IFunction>::getFunction(_hasComplexContent),NORMAL_METHOD,true);
@@ -99,39 +113,42 @@ void XMLList::sinit(Class_base* c)
c->setDeclaredMethodByQName("valueOf",AS3,Class<IFunction>::getFunction(valueOf),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("toXMLString",AS3,Class<IFunction>::getFunction(toXMLString),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("text",AS3,Class<IFunction>::getFunction(text),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("comments",AS3,Class<IFunction>::getFunction(comments),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("processingInstructions",AS3,Class<IFunction>::getFunction(processingInstructions),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("propertyIsEnumerable",AS3,Class<IFunction>::getFunction(_propertyIsEnumerable),NORMAL_METHOD,true);
REGISTER_XML_DELEGATE(addNamespace);
- REGISTER_XML_DELEGATE(appendChild);
+ REGISTER_XML_DELEGATE2(appendChild,_appendChild);
REGISTER_XML_DELEGATE(childIndex);
REGISTER_XML_DELEGATE(inScopeNamespaces);
- //REGISTER_XML_DELEGATE(insertChildAfter);
- //REGISTER_XML_DELEGATE(insertChildBefore);
+ REGISTER_XML_DELEGATE(insertChildAfter);
+ REGISTER_XML_DELEGATE(insertChildBefore);
REGISTER_XML_DELEGATE(localName);
REGISTER_XML_DELEGATE(name);
REGISTER_XML_DELEGATE2(namespace,_namespace);
- //REGISTER_XML_DELEGATE(namespaceDeclarations);
+ REGISTER_XML_DELEGATE(namespaceDeclarations);
REGISTER_XML_DELEGATE(nodeKind);
- //REGISTER_XML_DELEGATE(prependChild);
- //REGISTER_XML_DELEGATE(removeNamespace);
+ REGISTER_XML_DELEGATE2(prependChild,_appendChild);
+ REGISTER_XML_DELEGATE(removeNamespace);
//REGISTER_XML_DELEGATE(replace);
- REGISTER_XML_DELEGATE(_setChildren);
+ REGISTER_XML_DELEGATE2(setChildren,_setChildren);
REGISTER_XML_DELEGATE2(setLocalName,_setLocalName);
REGISTER_XML_DELEGATE2(setName,_setName);
REGISTER_XML_DELEGATE2(setNamespace,_setNamespace);
}
ASFUNCTIONBODY_XML_DELEGATE(addNamespace);
-ASFUNCTIONBODY_XML_DELEGATE(appendChild);
+ASFUNCTIONBODY_XML_DELEGATE(_appendChild);
ASFUNCTIONBODY_XML_DELEGATE(childIndex);
ASFUNCTIONBODY_XML_DELEGATE(inScopeNamespaces);
-//ASFUNCTIONBODY_XML_DELEGATE(insertChildAfter);
-//ASFUNCTIONBODY_XML_DELEGATE(insertChildBefore);
+ASFUNCTIONBODY_XML_DELEGATE(insertChildAfter);
+ASFUNCTIONBODY_XML_DELEGATE(insertChildBefore);
ASFUNCTIONBODY_XML_DELEGATE(localName);
ASFUNCTIONBODY_XML_DELEGATE(name);
ASFUNCTIONBODY_XML_DELEGATE(_namespace);
-//ASFUNCTIONBODY_XML_DELEGATE(namespaceDeclarations);
+ASFUNCTIONBODY_XML_DELEGATE(namespaceDeclarations);
ASFUNCTIONBODY_XML_DELEGATE(nodeKind);
-//ASFUNCTIONBODY_XML_DELEGATE(prependChild);
-//ASFUNCTIONBODY_XML_DELEGATE(removeNamespace);
+ASFUNCTIONBODY_XML_DELEGATE(_prependChild);
+ASFUNCTIONBODY_XML_DELEGATE(removeNamespace);
//ASFUNCTIONBODY_XML_DELEGATE(replace);
ASFUNCTIONBODY_XML_DELEGATE(_setChildren);
ASFUNCTIONBODY_XML_DELEGATE(_setLocalName);
@@ -151,6 +168,7 @@ ASFUNCTIONBODY(XMLList,_constructor)
args[0]->is<Null>() ||
args[0]->is<Undefined>())
{
+ th->constructed=true;
return NULL;
}
else if(args[0]->is<XML>())
@@ -183,7 +201,12 @@ void XMLList::buildFromString(const std::string& str)
{
xmlpp::DomParser parser;
std::string default_ns=getVm()->getDefaultXMLNamespace();
- std::string expanded="<parent xmlns=\"" + default_ns + "\">" + str + "</parent>";
+ std::string xmldecl;
+ std::string str_without_xmldecl = extractXMLDeclaration(str, xmldecl);
+ std::string expanded = xmldecl +
+ "<parent xmlns=\"" + default_ns + "\">" +
+ XMLBase::parserQuirks(str_without_xmldecl) +
+ "</parent>";
try
{
parser.parse_memory(expanded);
@@ -203,7 +226,47 @@ void XMLList::buildFromString(const std::string& str)
parser.get_document()->get_root_node()->get_children();
xmlpp::Node::NodeList::const_iterator it;
for(it=children.begin(); it!=children.end(); ++it)
- nodes.push_back(_MR(Class<XML>::getInstanceS(*it)));
+ {
+ _R<XML> tmp = _MR(Class<XML>::getInstanceS(*it));
+ if (tmp->constructed)
+ nodes.push_back(tmp);
+ }
+}
+
+std::string XMLList::extractXMLDeclaration(const std::string& xml, std::string& xmldecl_out)
+{
+ if (xml.compare(0, 2, "<?") != 0)
+ return xml;
+ std::string res = xml;
+ xmldecl_out = "";
+ size_t declEnd = 0;
+ size_t len = xml.length();
+ while (declEnd<len && declEnd != xml.npos)
+ {
+ if (g_unichar_isspace(xml[declEnd]))
+ declEnd++;
+ else
+ {
+ if (xml.compare(declEnd, 2, "<?") == 0)
+ {
+ size_t tmp = xml.find("?>",declEnd);
+ if (tmp == xml.npos)
+ break;
+ declEnd = tmp +2;
+ }
+ else
+ break;
+ }
+ }
+ if (declEnd && declEnd != xml.npos)
+ {
+ xmldecl_out = xml.substr(0, declEnd);
+ if (declEnd<len)
+ res = xml.substr(declEnd);
+ else
+ res = "";
+ }
+ return res;
}
_R<XML> XMLList::reduceToXML() const
@@ -279,12 +342,13 @@ ASFUNCTIONBODY(XMLList,generator)
ASFUNCTIONBODY(XMLList,descendants)
{
XMLList* th=Class<XMLList>::cast(obj);
- tiny_string name;
- assert_and_throw(argslen==0 || args[0]->getObjectType()!=T_QNAME);
- ARG_UNPACK(name,"*");
+ _NR<ASObject> name;
+ ARG_UNPACK(name,_NR<ASObject>(Class<ASString>::getInstanceS("*")));
XML::XMLVector ret;
- th->getDescendantsByQName(name,"",ret);
- return Class<XMLList>::getInstanceS(ret);
+ multiname mname(NULL);
+ name->applyProxyProperty(mname);
+ th->getDescendantsByQName(name->toString(),"",mname.isAttribute,ret);
+ return Class<XMLList>::getInstanceS(ret,th->targetobject,multiname(NULL));
}
ASFUNCTIONBODY(XMLList,elements)
@@ -295,11 +359,11 @@ ASFUNCTIONBODY(XMLList,elements)
XML::XMLVector elems;
auto it=th->nodes.begin();
- for(; it!=th->nodes.end(); ++it)
- {
+ for(; it!=th->nodes.end(); ++it)
+ {
(*it)->getElementNodes(name, elems);
}
- return Class<XMLList>::getInstanceS(elems);
+ return Class<XMLList>::getInstanceS(elems,th->targetobject,multiname(NULL));
}
ASFUNCTIONBODY(XMLList,parent)
@@ -313,8 +377,8 @@ ASFUNCTIONBODY(XMLList,parent)
ASObject *parent=(*it)->getParentNode();
++it;
- for(; it!=th->nodes.end(); ++it)
- {
+ for(; it!=th->nodes.end(); ++it)
+ {
ASObject *otherParent=(*it)->getParentNode();
if(!parent->isEqual(otherParent))
return getSys()->getUndefinedRef();
@@ -333,14 +397,28 @@ ASFUNCTIONBODY(XMLList,child)
{
XMLList* th = obj->as<XMLList>();
assert_and_throw(argslen==1);
- const tiny_string& arg0=args[0]->toString();
XML::XMLVector ret;
- auto it=th->nodes.begin();
- for(; it!=th->nodes.end(); ++it)
- {
- (*it)->childrenImpl(ret, arg0);
+ if(args[0]->is<Number>() ||
+ args[0]->is<Integer>() ||
+ args[0]->is<UInteger>())
+ {
+ uint32_t index =args[0]->toUInt();
+ auto it=th->nodes.begin();
+ for(; it!=th->nodes.end(); ++it)
+ {
+ (*it)->childrenImpl(ret, index);
+ }
}
- XMLList* retObj=Class<XMLList>::getInstanceS(ret);
+ else
+ {
+ const tiny_string& arg0=args[0]->toString();
+ auto it=th->nodes.begin();
+ for(; it!=th->nodes.end(); ++it)
+ {
+ (*it)->childrenImpl(ret, arg0);
+ }
+ }
+ XMLList* retObj=Class<XMLList>::getInstanceS(ret,th->targetobject,multiname(NULL));
return retObj;
}
@@ -350,11 +428,11 @@ ASFUNCTIONBODY(XMLList,children)
assert_and_throw(argslen==0);
XML::XMLVector ret;
auto it=th->nodes.begin();
- for(; it!=th->nodes.end(); ++it)
- {
+ for(; it!=th->nodes.end(); ++it)
+ {
(*it)->childrenImpl(ret, "*");
}
- XMLList* retObj=Class<XMLList>::getInstanceS(ret);
+ XMLList* retObj=Class<XMLList>::getInstanceS(ret,th->targetobject,multiname(NULL));
return retObj;
}
@@ -364,11 +442,11 @@ ASFUNCTIONBODY(XMLList,text)
ARG_UNPACK;
XML::XMLVector ret;
auto it=th->nodes.begin();
- for(; it!=th->nodes.end(); ++it)
- {
+ for(; it!=th->nodes.end(); ++it)
+ {
(*it)->getText(ret);
}
- return Class<XMLList>::getInstanceS(ret);
+ return Class<XMLList>::getInstanceS(ret,th->targetobject,multiname(NULL));
}
ASFUNCTIONBODY(XMLList,contains)
@@ -380,8 +458,8 @@ ASFUNCTIONBODY(XMLList,contains)
return abstract_b(false);
auto it=th->nodes.begin();
- for(; it!=th->nodes.end(); ++it)
- {
+ for(; it!=th->nodes.end(); ++it)
+ {
if((*it)->isEqual(value.getPtr()))
return abstract_b(true);
}
@@ -393,9 +471,10 @@ ASFUNCTIONBODY(XMLList,copy)
{
XMLList* th = obj->as<XMLList>();
XMLList *dest = Class<XMLList>::getInstanceS();
+ dest->targetobject = th->targetobject;
auto it=th->nodes.begin();
- for(; it!=th->nodes.end(); ++it)
- {
+ for(; it!=th->nodes.end(); ++it)
+ {
dest->nodes.push_back(_MR((*it)->copy()));
}
return dest;
@@ -435,11 +514,59 @@ ASFUNCTIONBODY(XMLList,attributes)
return res;
}
-ASFUNCTIONBODY(XMLList,normalize)
+ASFUNCTIONBODY(XMLList,comments)
{
- XMLList *th = obj->as<XMLList>();
+ XMLList* th=Class<XMLList>::cast(obj);
+
+ XMLList *res = Class<XMLList>::getInstanceS();
+ XML::XMLVector nodecomments;
auto it=th->nodes.begin();
- while (it!=th->nodes.end())
+ for(; it!=th->nodes.end(); ++it)
+ {
+ (*it)->getComments(nodecomments);
+ }
+ res->nodes.insert(res->nodes.end(), nodecomments.begin(), nodecomments.end());
+ return res;
+}
+ASFUNCTIONBODY(XMLList,processingInstructions)
+{
+ XMLList* th=Class<XMLList>::cast(obj);
+ tiny_string name;
+ ARG_UNPACK(name,"*");
+
+ XMLList *res = Class<XMLList>::getInstanceS();
+ XML::XMLVector nodeprocessingInstructions;
+ auto it=th->nodes.begin();
+ for(; it!=th->nodes.end(); ++it)
+ {
+ (*it)->getprocessingInstructions(nodeprocessingInstructions,name);
+ }
+ res->nodes.insert(res->nodes.end(), nodeprocessingInstructions.begin(), nodeprocessingInstructions.end());
+ return res;
+}
+ASFUNCTIONBODY(XMLList,_propertyIsEnumerable)
+{
+ XMLList* th=Class<XMLList>::cast(obj);
+ if (argslen == 1)
+ {
+ int32_t n = args[0]->toInt();
+ return abstract_b(n < (int32_t)th->nodes.size());
+
+ }
+ return abstract_b(false);
+}
+
+ASFUNCTIONBODY(XMLList,_normalize)
+{
+ XMLList *th = obj->as<XMLList>();
+ th->normalize();
+ th->incRef();
+ return th;
+}
+void XMLList::normalize()
+{
+ auto it=nodes.begin();
+ while (it!=nodes.end())
{
if ((*it)->getNodeKind() == XML_ELEMENT_NODE)
{
@@ -450,17 +577,17 @@ ASFUNCTIONBODY(XMLList,normalize)
{
if ((*it)->toString().empty())
{
- it = th->nodes.erase(it);
+ it = nodes.erase(it);
}
else
{
_R<XML> textnode = *it;
++it;
- while (it!=th->nodes.end() && (*it)->getNodeKind() == XML_TEXT_NODE)
+ while (it!=nodes.end() && (*it)->getNodeKind() == XML_TEXT_NODE)
{
textnode->addTextContent((*it)->toString());
- it = th->nodes.erase(it);
+ it = nodes.erase(it);
}
}
@@ -470,9 +597,51 @@ ASFUNCTIONBODY(XMLList,normalize)
++it;
}
}
+}
- th->incRef();
- return th;
+void XMLList::clear()
+{
+ nodes.clear();
+}
+void XMLList::getTargetVariables(const multiname& name,XML::XMLVector& retnodes)
+{
+ unsigned int index=0;
+ if(XML::isValidMultiname(name,index))
+ {
+ retnodes.push_back(nodes[index]);
+ }
+ else
+ {
+ tiny_string normalizedName=name.normalizedName();
+
+ //Only the first namespace is used, is this right?
+ tiny_string namespace_uri;
+ if(name.ns.size() > 0 && !name.ns[0].hasEmptyName())
+ {
+ nsNameAndKindImpl ns=name.ns[0].getImpl();
+ if (ns.kind==NAMESPACE)
+ namespace_uri=ns.name;
+ }
+
+ // namespace set by "default xml namespace = ..."
+ if(namespace_uri.empty())
+ namespace_uri=getVm()->getDefaultXMLNamespace();
+
+ for (uint32_t i = 0; i < nodes.size(); i++)
+ {
+ _R<XML> child= nodes[i];
+ bool nameMatches = (normalizedName=="" || normalizedName==child->nodename);
+ bool nsMatches = (namespace_uri=="" ||
+ (child->nodenamespace_uri == namespace_uri));
+
+ if(nameMatches && nsMatches)
+ {
+ retnodes.push_back(child);
+ }
+ if (child->childrenlist)
+ child->childrenlist->getTargetVariables(name,retnodes);
+ }
+ }
}
_NR<ASObject> XMLList::getVariableByMultiname(const multiname& name, GET_VARIABLE_OPTION opt)
@@ -493,14 +662,33 @@ _NR<ASObject> XMLList::getVariableByMultiname(const multiname& name, GET_VARIABL
return res;
}
+ if (name.isAttribute)
+ {
+ XML::XMLVector retnodes;
+ auto it=nodes.begin();
+ for(; it!=nodes.end(); ++it)
+ {
+ _NR<ASObject> o=(*it)->getVariableByMultiname(name,opt);
+ XMLList *x=dynamic_cast<XMLList *>(o.getPtr());
+ if(!x)
+ continue;
+
+ retnodes.insert(retnodes.end(), x->nodes.begin(), x->nodes.end());
+ }
+ if(retnodes.size()==0 && (opt & XML_STRICT)!=0)
+ return NullRef;
+
+ this->incRef();
+ return _MNR(Class<XMLList>::getInstanceS(retnodes,this,name));
+ }
unsigned int index=0;
- if(Array::isValidMultiname(name,index))
+ if(XML::isValidMultiname(name,index))
{
if(index<nodes.size())
return nodes[index];
else
- return NullRef;
+ return _MNR(getSys()->getUndefinedRef());
}
else
{
@@ -519,7 +707,8 @@ _NR<ASObject> XMLList::getVariableByMultiname(const multiname& name, GET_VARIABL
if(retnodes.size()==0 && (opt & XML_STRICT)!=0)
return NullRef;
- return _MNR(Class<XMLList>::getInstanceS(retnodes));
+ this->incRef();
+ return _MNR(Class<XMLList>::getInstanceS(retnodes,this,name));
}
}
@@ -528,16 +717,11 @@ bool XMLList::hasPropertyByMultiname(const multiname& name, bool considerDynamic
if(considerDynamic==false)
return ASObject::hasPropertyByMultiname(name, considerDynamic, considerPrototype);
- assert_and_throw(name.ns.size()>0);
- if(!name.ns[0].hasEmptyName())
- return ASObject::hasPropertyByMultiname(name, considerDynamic, considerPrototype);
-
unsigned int index=0;
- if(Array::isValidMultiname(name,index))
+ if(XML::isValidMultiname(name,index))
return index<nodes.size();
else
{
- XML::XMLVector retnodes;
auto it=nodes.begin();
for(; it!=nodes.end(); ++it)
{
@@ -554,23 +738,123 @@ void XMLList::setVariableByMultiname(const multiname& name, ASObject* o, CONST_A
{
assert_and_throw(implEnable);
unsigned int index=0;
- if(!Array::isValidMultiname(name,index))
- return ASObject::setVariableByMultiname(name,o,allowConst);
-
- XML* newNode=dynamic_cast<XML*>(o);
- if(newNode==NULL)
- return ASObject::setVariableByMultiname(name,o,allowConst);
+ XML::XMLVector retnodes;
+ XMLList* tmplist = targetobject;
+ multiname tmpprop = targetproperty;
+ if (targetobject)
+ {
+ while (tmplist->targetobject)
+ {
+ tmpprop = tmplist->targetproperty;
+ tmplist = tmplist->targetobject;
+ }
+ if (tmplist && !tmpprop.isEmpty())
+ {
+ tmplist->getTargetVariables(tmpprop,retnodes);
+ }
+ }
+ if(XML::isValidMultiname(name,index))
+ {
+ if (index >= nodes.size())
+ {
+ if (targetobject)
+ targetobject->appendSingleNode(o);
+ appendSingleNode(o);
+ }
+ else
+ {
+ replace(index, o,retnodes,allowConst);
+ }
+ }
+ else if (nodes.size() == 0)
+ {
+ if (tmplist)
+ {
+ if (!tmpprop.isEmpty())
+ {
+ XML* tmp = Class<XML>::getInstanceS();
+ tmp->nodetype = XML_ELEMENT_NODE;
+ tmp->nodename = targetproperty.normalizedName();
+ tmp->attributelist = _MR(Class<XMLList>::getInstanceS());
+ tmp->constructed = true;
+ tmp->setVariableByMultiname(name,o,allowConst);
+ tmp->incRef();
+ tiny_string tmpname = tmpprop.normalizedName();
+ if (retnodes.empty() && tmpname != "" && tmpname != "*")
+ {
+ XML* tmp2 = Class<XML>::getInstanceS();
+ tmp2->nodetype = XML_ELEMENT_NODE;
+ tmp2->nodename = tmpname;
+ tmp2->attributelist = _MR(Class<XMLList>::getInstanceS());
+ tmp2->constructed = true;
+ tmp2->setVariableByMultiname(targetproperty,tmp,allowConst);
+ tmp2->incRef();
+ tmplist->appendSingleNode(tmp2);
+ appendSingleNode(tmp2);
+ }
+ else
+ tmplist->setVariableByMultiname(tmpprop,tmp,allowConst);
+ }
+ else
+ {
+ tmplist->appendSingleNode(o);
+ appendSingleNode(o);
+ }
+ }
+ else
+ appendSingleNode(o);
+ }
+ else if (nodes.size() == 1)
+ {
+ nodes[0]->setVariableByMultiname(name, o, allowConst);
+ }
+ else
+ {
+ // do nothing, see ECMA-357, Section 9.2.1.2
+ }
+}
- //Nodes are always added at the end. The requested index are ignored. This is a tested behaviour.
- nodes.push_back(_MR(newNode));
+bool XMLList::deleteVariableByMultiname(const multiname& name)
+{
+ unsigned int index=0;
+ bool bdeleted = false;
+
+ if(XML::isValidMultiname(name,index))
+ {
+ _R<XML> node = nodes[index];
+ if (node->parentNode)
+ {
+ XMLList::XMLListVector::iterator it = node->parentNode->childrenlist->nodes.end();
+ while (it != node->parentNode->childrenlist->nodes.begin())
+ {
+ it--;
+ _R<XML> n = *it;
+ if (n.getPtr() == node.getPtr())
+ {
+ node->parentNode->childrenlist->nodes.erase(it);
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ for (XMLList::XMLListVector::iterator it = nodes.begin(); it != nodes.end(); it++)
+ {
+ _R<XML> node = *it;
+ if (node->deleteVariableByMultiname(name))
+ bdeleted = true;
+ }
+ }
+ return bdeleted;
}
-void XMLList::getDescendantsByQName(const tiny_string& name, const tiny_string& ns, XML::XMLVector& ret)
+void XMLList::getDescendantsByQName(const tiny_string& name, const tiny_string& ns, bool bIsAttribute, XML::XMLVector& ret)
{
auto it=nodes.begin();
for(; it!=nodes.end(); ++it)
{
- (*it)->getDescendantsByQName(name, ns, ret);
+ (*it)->getDescendantsByQName(name, ns, bIsAttribute, ret);
}
}
@@ -584,40 +868,50 @@ _NR<XML> XMLList::convertToXML() const
bool XMLList::hasSimpleContent() const
{
- if(nodes.size()==0)
- return true;
- else if(nodes.size()==1)
- return nodes[0]->hasSimpleContent();
- else
+ switch(nodes.size())
{
- auto it=nodes.begin();
- for(; it!=nodes.end(); ++it)
- {
- if((*it)->getNodeKind()==XML_ELEMENT_NODE)
- return false;
- }
+ case 0:
+ return true;
+ case 1:
+ return nodes[0]->hasSimpleContent();
+ }
+ auto it = nodes.begin();
+ while (it != nodes.end())
+ {
+ if ((*it)->nodetype == XML_ELEMENT_NODE)
+ return false;
+ it++;
}
-
return true;
}
bool XMLList::hasComplexContent() const
{
- if(nodes.size()==0)
- return false;
- else if(nodes.size()==1)
- return nodes[0]->hasComplexContent();
- else
+ return !hasSimpleContent();
+}
+
+void XMLList::appendSingleNode(ASObject *x)
+{
+ if (x->is<XML>())
{
- auto it=nodes.begin();
- for(; it!=nodes.end(); ++it)
+ x->incRef();
+ append(_MR(x->as<XML>()));
+ }
+ else if (x->is<XMLList>())
+ {
+ XMLList *list = x->as<XMLList>();
+ if (list->nodes.size() == 1)
{
- if((*it)->getNodeKind()==XML_ELEMENT_NODE)
- return true;
+ append(list->nodes[0]);
}
+ // do nothing, if length != 1. See ECMA-357, Section
+ // 9.2.1.2
+ }
+ else
+ {
+ tiny_string str = x->toString();
+ append(_MR(Class<XML>::getInstanceS(str)));
}
-
- return false;
}
void XMLList::append(_R<XML> x)
@@ -630,27 +924,118 @@ void XMLList::append(_R<XMLList> x)
nodes.insert(nodes.end(),x->nodes.begin(),x->nodes.end());
}
-tiny_string XMLList::toString_priv() const
+void XMLList::prepend(_R<XML> x)
+{
+ nodes.insert(nodes.begin(),x);
+}
+
+void XMLList::prepend(_R<XMLList> x)
+{
+ nodes.insert(nodes.begin(),x->nodes.begin(),x->nodes.end());
+}
+
+void XMLList::replace(unsigned int idx, ASObject *o, const XML::XMLVector &retnodes,CONST_ALLOWED_FLAG allowConst)
{
- if(hasSimpleContent())
+ if (idx >= nodes.size())
+ return;
+
+ if (nodes[idx]->getNodeKind() == XML_ATTRIBUTE_NODE || nodes[idx]->getNodeKind() == XML_TEXT_NODE)
{
- tiny_string ret;
- for(uint32_t i=0;i<nodes.size();i++)
+ if (targetobject)
+ targetobject->setVariableByMultiname(targetproperty,o,allowConst);
+ nodes[idx]->setTextContent(o->toString());
+ }
+ else if (o->is<XMLList>())
+ {
+ if (targetobject)
{
- xmlElementType kind=nodes[i]->getNodeKind();
- if(kind!=XML_COMMENT_NODE && kind!=XML_PI_NODE)
- ret+=nodes[i]->toString();
+ for (uint32_t i = 0; i < targetobject->nodes.size(); i++)
+ {
+ XML* n= targetobject->nodes[i].getPtr();
+ if (n == nodes[idx].getPtr())
+ {
+ multiname m(NULL);
+ m.name_type = multiname::NAME_INT;
+ m.name_i = i;
+ m.ns.push_back(nsNameAndKind("",NAMESPACE));
+ targetobject->setVariableByMultiname(m,o,allowConst);
+ break;
+ }
+ }
}
- return ret;
+ unsigned int k = 0;
+ vector<_R<XML>, reporter_allocator<_R<XML>>>::iterator it = nodes.begin();
+ while (k < idx && it!=nodes.end())
+ {
+ ++k;
+ ++it;
+ }
+
+ it = nodes.erase(it);
+
+ XMLList *toAdd = o->as<XMLList>();
+ nodes.insert(it, toAdd->nodes.begin(), toAdd->nodes.end());
+ }
+ else if (o->is<XML>())
+ {
+ if (retnodes.size() > idx)
+ {
+ multiname m(NULL);
+ m.name_type = multiname::NAME_INT;
+ m.name_i = idx;
+ m.ns.push_back(nsNameAndKind("",NAMESPACE));
+ targetobject->setVariableByMultiname(m,o,allowConst);
+ }
+ o->incRef();
+ nodes[idx] = _MR(o->as<XML>());
}
else
{
- xmlBufferPtr xmlBuffer=xmlBufferCreateSize(4096);
- toXMLString_priv(xmlBuffer);
- tiny_string ret((char*)xmlBuffer->content, true);
- xmlBufferFree(xmlBuffer);
+ if (nodes[idx]->nodetype == XML_TEXT_NODE)
+ nodes[idx]->nodevalue = o->toString();
+ else
+ {
+ nodes[idx]->childrenlist->clear();
+ _R<XML> tmp = _MR<XML>(Class<XML>::getInstanceS());
+ nodes[idx]->incRef();
+ tmp->parentNode = nodes[idx];
+ tmp->nodetype = XML_TEXT_NODE;
+ tmp->nodename = "text";
+ tmp->nodenamespace_uri = "";
+ tmp->nodenamespace_prefix = "";
+ tmp->nodevalue = o->toString();
+ tmp->constructed = true;
+ nodes[idx]->childrenlist->append(tmp);
+ }
+ }
+}
+
+tiny_string XMLList::toString_priv()
+{
+ if (hasSimpleContent())
+ {
+ tiny_string ret;
+ for(size_t i=0; i<nodes.size(); i++)
+ {
+ xmlElementType kind=nodes[i]->getNodeKind();
+ switch (kind)
+ {
+ case XML_COMMENT_NODE:
+ case XML_PI_NODE:
+ break;
+ case XML_ATTRIBUTE_NODE:
+ ret+=nodes[i]->toString_priv();
+ break;
+ default:
+ ret+=nodes[i]->toString_priv();
+ break;
+ }
+
+
+ }
return ret;
}
+ return toXMLString_internal();
}
tiny_string XMLList::toString()
@@ -673,24 +1058,28 @@ ASFUNCTIONBODY(XMLList,_toString)
return Class<ASString>::getInstanceS(th->toString_priv());
}
-void XMLList::toXMLString_priv(xmlBufferPtr buf) const
+tiny_string XMLList::toXMLString_internal(bool pretty)
{
- for(size_t i=0; i<nodes.size(); i++)
+ tiny_string res;
+ size_t len = nodes.size();
+ for(size_t i=0; i<len; i++)
{
- if(i>0)
- xmlBufferWriteChar(buf, "\n");
- nodes[i].getPtr()->toXMLString_priv(buf);
+ tiny_string tmp = nodes[i].getPtr()->toXMLString_internal(pretty);
+ if (tmp != "")
+ {
+ res += tmp;
+ if (pretty && i < len-1)
+ res += "\n";
+ }
}
+ return res;
}
ASFUNCTIONBODY(XMLList,toXMLString)
{
XMLList* th=Class<XMLList>::cast(obj);
assert_and_throw(argslen==0);
- xmlBufferPtr xmlBuffer=xmlBufferCreateSize(4096);
- th->toXMLString_priv(xmlBuffer);
- ASString* ret=Class<ASString>::getInstanceS((char*)xmlBuffer->content);
- xmlBufferFree(xmlBuffer);
+ ASString* ret=Class<ASString>::getInstanceS(th->toXMLString_internal());
return ret;
}
@@ -749,7 +1138,7 @@ void XMLList::appendNodesTo(XML *dest) const
for (it=nodes.begin(); it!=nodes.end(); ++it)
{
ASObject *arg0=it->getPtr();
- ASObject *ret=XML::appendChild(dest, &arg0, 1);
+ ASObject *ret=XML::_appendChild(dest, &arg0, 1);
if(ret)
ret->decRef();
}
diff --git a/src/scripting/toplevel/XMLList.h b/src/scripting/toplevel/XMLList.h
index e336061..e723a1f 100644
--- a/src/scripting/toplevel/XMLList.h
+++ b/src/scripting/toplevel/XMLList.h
@@ -28,12 +28,21 @@ namespace lightspark
{
class XMLList: public ASObject
{
+friend class XML;
+public:
+ typedef std::vector<_R<XML>, reporter_allocator<_R<XML>>> XMLListVector;
private:
- std::vector<_R<XML>, reporter_allocator<_R<XML>>> nodes;
+ XMLListVector nodes;
bool constructed;
- tiny_string toString_priv() const;
+ XMLList* targetobject;
+ multiname targetproperty;
+
+ tiny_string toString_priv();
void buildFromString(const std::string& str);
- void toXMLString_priv(xmlBufferPtr buf) const;
+ std::string extractXMLDeclaration(const std::string& xml, std::string& xmldecl_out);
+ void appendSingleNode(ASObject *x);
+ void replace(unsigned int i, ASObject *x, const XML::XMLVector& retnodes, CONST_ALLOWED_FLAG allowConst);
+ void getTargetVariables(const multiname& name, XML::XMLVector& retnodes);
public:
XMLList(Class_base* c);
/*
@@ -41,15 +50,16 @@ public:
*/
XMLList(Class_base* cb,bool c);
XMLList(Class_base* c,const XML::XMLVector& r);
+ XMLList(Class_base* c,const XML::XMLVector& r,XMLList* targetobject,const multiname& targetproperty);
XMLList(Class_base* c,const std::string& str);
void finalize();
- static void buildTraits(ASObject* o){};
+ static void buildTraits(ASObject* o){}
static void sinit(Class_base* c);
ASFUNCTION(_constructor);
ASFUNCTION(_getLength);
ASFUNCTION(attribute);
ASFUNCTION(attributes);
- ASFUNCTION(appendChild);
+ ASFUNCTION(_appendChild);
ASFUNCTION(child);
ASFUNCTION(children);
ASFUNCTION(childIndex);
@@ -68,7 +78,7 @@ public:
ASFUNCTION(_namespace);
ASFUNCTION(name);
ASFUNCTION(nodeKind);
- ASFUNCTION(normalize);
+ ASFUNCTION(_normalize);
ASFUNCTION(localName);
ASFUNCTION(inScopeNamespaces);
ASFUNCTION(addNamespace);
@@ -76,16 +86,28 @@ public:
ASFUNCTION(_setLocalName);
ASFUNCTION(_setName);
ASFUNCTION(_setNamespace);
+ ASFUNCTION(insertChildAfter);
+ ASFUNCTION(insertChildBefore);
+ ASFUNCTION(namespaceDeclarations);
+ ASFUNCTION(removeNamespace);
+ ASFUNCTION(comments);
+ ASFUNCTION(processingInstructions);
+ ASFUNCTION(_propertyIsEnumerable);
+ ASFUNCTION(_prependChild);
_NR<ASObject> getVariableByMultiname(const multiname& name, GET_VARIABLE_OPTION opt);
void setVariableByMultiname(const multiname& name, ASObject* o, CONST_ALLOWED_FLAG allowConst);
bool hasPropertyByMultiname(const multiname& name, bool considerDynamic, bool considerPrototype);
- void getDescendantsByQName(const tiny_string& name, const tiny_string& ns, XML::XMLVector& ret);
+ bool deleteVariableByMultiname(const multiname& name);
+ void getDescendantsByQName(const tiny_string& name, const tiny_string& ns, bool bIsAttribute, XML::XMLVector& ret);
_NR<XML> convertToXML() const;
bool hasSimpleContent() const;
bool hasComplexContent() const;
void append(_R<XML> x);
void append(_R<XMLList> x);
+ void prepend(_R<XML> x);
+ void prepend(_R<XMLList> x);
tiny_string toString();
+ tiny_string toXMLString_internal(bool pretty=true);
int32_t toInt();
bool isEqual(ASObject* r);
uint32_t nextNameIndex(uint32_t cur_index);
@@ -93,6 +115,9 @@ public:
_R<ASObject> nextValue(uint32_t index);
_R<XML> reduceToXML() const;
void appendNodesTo(XML *dest) const;
+ void normalize();
+ void clear();
+ XMLList* getTargetObject() { return targetobject; }
};
}
#endif /* SCRIPTING_TOPLEVEL_XMLLIST_H */
diff --git a/src/scripting/toplevel/toplevel.cpp b/src/scripting/toplevel/toplevel.cpp
index 95037b6..673a203 100644
--- a/src/scripting/toplevel/toplevel.cpp
+++ b/src/scripting/toplevel/toplevel.cpp
@@ -45,7 +45,6 @@
#include "parsing/amf3_generator.h"
#include "scripting/argconv.h"
#include "scripting/toplevel/Number.h"
-#include "scripting/toplevel/XML.h"
using namespace std;
using namespace lightspark;
@@ -86,9 +85,13 @@ bool Undefined::isEqual(ASObject* r)
case T_NUMBER:
case T_INTEGER:
case T_UINTEGER:
- case T_STRING:
case T_BOOLEAN:
return false;
+ case T_FUNCTION:
+ case T_STRING:
+ if (!r->isConstructed())
+ return true;
+ return false;
default:
return r->isEqual(this);
}
@@ -113,8 +116,7 @@ void Undefined::serialize(ByteArray* out, std::map<tiny_string, uint32_t>& strin
void Undefined::setVariableByMultiname(const multiname& name, ASObject* o, CONST_ALLOWED_FLAG allowConst)
{
- LOG(LOG_NOT_IMPLEMENTED, "Ignoring set on Undefined " << name);
- o->decRef();
+ throwError<TypeError>(kConvertUndefinedToObjectError);
}
IFunction::IFunction(Class_base* c):ASObject(c),length(0),inClass(NULL)
@@ -128,6 +130,18 @@ void IFunction::finalize()
closure_this.reset();
}
+void IFunction::sinit(Class_base* c)
+{
+ c->prototype->setVariableByQName("toString","",Class<IFunction>::getFunction(IFunction::_toString),DYNAMIC_TRAIT);
+
+ c->setDeclaredMethodByQName("call","",Class<IFunction>::getFunction(IFunction::_call),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("call",AS3,Class<IFunction>::getFunction(IFunction::_call),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("apply","",Class<IFunction>::getFunction(IFunction::apply),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("apply",AS3,Class<IFunction>::getFunction(IFunction::apply),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("length","",Class<IFunction>::getFunction(IFunction::_getter_length),GETTER_METHOD,true);
+ c->setDeclaredMethodByQName("toString","",Class<IFunction>::getFunction(IFunction::_toString),NORMAL_METHOD,false);
+}
+
ASFUNCTIONBODY_GETTER_SETTER(IFunction,prototype);
ASFUNCTIONBODY_GETTER(IFunction,length);
@@ -206,6 +220,15 @@ ASFUNCTIONBODY(IFunction,_toString)
return Class<ASString>::getInstanceS("function Function() {}");
}
+ASObject* Class<IFunction>::generator(ASObject* const* args, const unsigned int argslen)
+{
+ for(unsigned int i=0;i<argslen;i++)
+ args[i]->decRef();
+ if (argslen > 0)
+ throwError<EvalError>(kFunctionConstructorError);
+ return getNopFunction();
+}
+
ASObject *IFunction::describeType() const
{
xmlpp::DomParser p;
@@ -350,6 +373,8 @@ ASObject* SyntheticFunction::call(ASObject* obj, ASObject* const* args, uint32_t
cc.scope_stack=func_scope;
cc.initialScopeStack=func_scope.size();
cc.exec_pos=0;
+ if (getVm()->currentCallContext)
+ cc.defaultNamespaceUri = getVm()->currentCallContext->defaultNamespaceUri;
/* Set the current global object, each script in each DoABCTag has its own */
call_context* saved_cc = getVm()->currentCallContext;
@@ -530,6 +555,13 @@ ASObject* Function::call(ASObject* obj, ASObject* const* args, uint32_t num_args
ret=getSys()->getUndefinedRef();
return ret;
}
+bool Function::isEqual(ASObject* r)
+{
+ Function* f=dynamic_cast<Function*>(r);
+ if(f==NULL)
+ return false;
+ return (val==f->val) && (closure_this==f->closure_this);
+}
bool Null::isEqual(ASObject* r)
{
@@ -541,9 +573,13 @@ bool Null::isEqual(ASObject* r)
case T_INTEGER:
case T_UINTEGER:
case T_NUMBER:
- case T_STRING:
case T_BOOLEAN:
return false;
+ case T_FUNCTION:
+ case T_STRING:
+ if (!r->isConstructed())
+ return true;
+ return false;
default:
return r->isEqual(this);
}
@@ -658,7 +694,7 @@ Type* Type::getBuiltinType(const multiname* mn)
* by running ABCContext::exec() for all ABCContexts.
* Therefore, all classes are at least declared.
*/
-const Type* Type::getTypeFromMultiname(const multiname* mn, const ABCContext* context)
+const Type* Type::getTypeFromMultiname(const multiname* mn, ABCContext* context)
{
if(mn == 0) //multiname idx zero indicates any type
return Type::anyType;
@@ -671,17 +707,17 @@ const Type* Type::getTypeFromMultiname(const multiname* mn, const ABCContext* co
&& mn->ns.size() == 1 && mn->ns[0].hasEmptyName())
return Type::voidType;
- ASObject* typeObject;
+ ASObject* typeObject = NULL;
/*
- * During the newClass opcode, the class is added to context->classesBeingDefined.
+ * During the newClass opcode, the class is added to context->root->applicationDomain->classesBeingDefined.
* The class variable in the global scope is only set a bit later.
* When the class has to be resolved in between (for example, the
* class has traits of the class's type), then we'll find it in
* classesBeingDefined, but context->root->getVariableAndTargetByMultiname()
* would still return "Undefined".
*/
- auto i = context->classesBeingDefined.find(mn);
- if(i != context->classesBeingDefined.end())
+ auto i = context->root->applicationDomain->classesBeingDefined.find(mn);
+ if(i != context->root->applicationDomain->classesBeingDefined.end())
typeObject = i->second;
else
{
@@ -691,17 +727,11 @@ const Type* Type::getTypeFromMultiname(const multiname* mn, const ABCContext* co
if(!typeObject)
{
- //HACK: until we have implemented all flash classes, we need this hack
- LOG(LOG_NOT_IMPLEMENTED,"getTypeFromMultiname: could not find " << *mn << ", using AnyType");
- return Type::anyType;
- }
-
- if(!typeObject->is<Type>())
- {
- //It actually happens in the wild that the class for a member might be a private class
- //that is defined later in the same script. We have no way to solve the dependency, so return any
- LOG(LOG_NOT_IMPLEMENTED,"Not resolvable type " << *mn << ", using AnyType");
- return Type::anyType;
+ if (mn->ns.size() >= 1 && mn->ns[0].getImpl().name == "__AS3__.vec")
+ {
+ QName qname(getSys()->getStringFromUniqueId(mn->name_s_id),mn->ns[0].getImpl().name);
+ typeObject = Template<Vector>::getTemplateInstance(qname,context).getPtr();
+ }
}
return typeObject->as<Type>();
}
@@ -753,6 +783,23 @@ void Class_base::copyBorrowedTraitsFromSuper()
}
}
+void Class_base::initStandardProps()
+{
+ incRef();
+ constructorprop = _NR<ObjectConstructor>(new_objectConstructor(this,0));
+ constructorprop->incRef();
+ addConstructorGetter();
+
+ setDeclaredMethodByQName("toString","",Class<IFunction>::getFunction(Class_base::_toString),NORMAL_METHOD,false);
+ incRef();
+ prototype->setVariableByQName("constructor","",this,DYNAMIC_TRAIT);
+
+ if(super)
+ prototype->prevPrototype=super->prototype;
+ addPrototypeGetter();
+ addLengthGetter();
+}
+
ASObject* Class_base::coerce(ASObject* o) const
{
@@ -760,12 +807,15 @@ ASObject* Class_base::coerce(ASObject* o) const
return o;
if(o->is<Class_base>())
{ /* classes can be cast to the type 'Object' or 'Class' */
- if(this == Class<ASObject>::getClass()
+ if(this == Class<ASObject>::getClass()
|| (class_name.name=="Class" && class_name.ns==""))
- return o; /* 'this' is the type of a class */
- else
- throwError<TypeError>(kCheckTypeFailedError, o->getClassName(), getQualifiedClassName());
+ return o; /* 'this' is the type of a class */
+ else
+ throwError<TypeError>(kCheckTypeFailedError, o->getClassName(), getQualifiedClassName());
}
+ if (o->is<ObjectConstructor>())
+ return o;
+
//o->getClass() == NULL for primitive types
//those are handled in overloads Class<Number>::coerce etc.
if(!o->getClass() || !o->getClass()->isSubClass(this))
@@ -783,6 +833,11 @@ ASFUNCTIONBODY(Class_base,_toString)
return Class<ASString>::getInstanceS(ret);
}
+void Class_base::addConstructorGetter()
+{
+ setDeclaredMethodByQName("constructor","",Class<IFunction>::getFunction(_getter_constructorprop),GETTER_METHOD,false);
+}
+
void Class_base::addPrototypeGetter()
{
setDeclaredMethodByQName("prototype","",Class<IFunction>::getFunction(_getter_prototype),GETTER_METHOD,false);
@@ -799,6 +854,20 @@ Class_base::~Class_base()
LOG(LOG_ERROR,_("Class destroyed without cleanUp called"));
}
+ASObject* Class_base::_getter_constructorprop(ASObject* obj, ASObject* const* args, const unsigned int argslen)
+{
+ Class_base* th = NULL;
+ if(obj->is<Class_base>())
+ th = obj->as<Class_base>();
+ else
+ th = obj->getClass();
+ if(argslen != 0)
+ throw Class<ArgumentError>::getInstanceS("Arguments provided in getter");
+ ASObject* ret=th->constructorprop.getPtr();
+ ret->incRef();
+ return ret;
+}
+
ASObject* Class_base::_getter_prototype(ASObject* obj, ASObject* const* args, const unsigned int argslen)
{
if(!obj->is<Class_base>())
@@ -832,7 +901,7 @@ void Class_base::addImplementedInterface(Class_base* i)
tiny_string Class_base::toString()
{
- tiny_string ret="[Class ";
+ tiny_string ret="[class ";
ret+=class_name.name;
ret+="]";
return ret;
@@ -888,13 +957,16 @@ void Class_base::handleConstruction(ASObject* target, ASObject* const* args, uns
{
target->incRef();
ASObject* ret=constructor->call(target,args,argslen);
+ target->constructIndicator = true;
assert_and_throw(ret->is<Undefined>());
ret->decRef();
}
else
{
+ target->constructIndicator = true;
for(uint32_t i=0;i<argslen;i++)
args[i]->decRef();
+ //throwError<TypeError>(kConstructOfNonFunctionError);
}
}
@@ -990,25 +1062,40 @@ void Class_object::finalize()
Class_base::finalize();
}
-const std::vector<Class_base*>& Class_base::getInterfaces() const
+const std::vector<Class_base*>& Class_base::getInterfaces(bool *alldefined) const
{
+ if (alldefined)
+ *alldefined = true;
if(!interfaces.empty())
{
//Recursively get interfaces implemented by this interface
- for(unsigned int i=0;i<interfaces.size();i++)
+ std::vector<multiname>::iterator it = interfaces.begin();
+ while (it !=interfaces.end())
{
ASObject* target;
ASObject* interface_obj=this->context->root->applicationDomain->
- getVariableAndTargetByMultiname(interfaces[i], target);
- assert_and_throw(interface_obj && interface_obj->getObjectType()==T_CLASS);
- Class_base* inter=static_cast<Class_base*>(interface_obj);
-
- interfaces_added.push_back(inter);
- //Probe the interface for its interfaces
- inter->getInterfaces();
+ getVariableAndTargetByMultiname(*it, target);
+ if (interface_obj)
+ {
+ assert_and_throw(interface_obj->getObjectType()==T_CLASS);
+ Class_base* inter=static_cast<Class_base*>(interface_obj);
+ //Probe the interface for its interfaces
+ bool bAllDefinedSub;
+ inter->getInterfaces(&bAllDefinedSub);
+
+ if (bAllDefinedSub)
+ {
+ interfaces_added.push_back(inter);
+ interfaces.erase(it);
+ continue;
+ }
+ else if (alldefined)
+ *alldefined = false;
+ }
+ else if (alldefined)
+ *alldefined = false;
+ it++;
}
- //Clean the interface vector to save some space
- interfaces.clear();
}
return interfaces_added;
}
@@ -1043,6 +1130,11 @@ bool Class_base::isSubClass(const Class_base* cls, bool considerInterfaces) cons
if(cls==this || cls==Class<ASObject>::getClass())
return true;
+ // it seems that classes with the same name from different applicationDomains
+ // are treated as equal, so we test for same names
+ if (this->getQualifiedClassName() == cls->getQualifiedClassName())
+ return true;
+
//Now check the interfaces
if (considerInterfaces)
{
@@ -1146,7 +1238,7 @@ void Class_base::describeTraits(xmlpp::Element* root,
int kind=t.kind&0xf;
multiname* mname=context->getMultiname(t.name,NULL);
if (mname->name_type!=multiname::NAME_STRING ||
- (mname->ns.size()==1 && !mname->ns[0].hasEmptyName()) ||
+ (mname->ns.size()==1 && (!mname->ns[0].hasEmptyName() || mname->ns[0].getImpl().kind == PRIVATE_NAMESPACE)) ||
mname->ns.size() > 1)
continue;
@@ -1278,9 +1370,9 @@ void Class_base::initializeProtectedNamespace(const tiny_string& name, const nam
protected_ns=nsNameAndKind(name,baseNs->nsId,(NS_KIND)(int)ns.kind);
}
-const variable* Class_base::findBorrowedGettable(const multiname& name) const
+const variable* Class_base::findBorrowedGettable(const multiname& name,NS_KIND& nskind) const
{
- return ASObject::findGettableImpl(borrowedVariables,name);
+ return ASObject::findGettableImpl(borrowedVariables,name,nskind);
}
variable* Class_base::findBorrowedSettable(const multiname& name, bool* has_getter)
@@ -1288,9 +1380,25 @@ variable* Class_base::findBorrowedSettable(const multiname& name, bool* has_gett
return ASObject::findSettableImpl(borrowedVariables,name,has_getter);
}
+variable* Class_base::findSettableInPrototype(const multiname& name)
+{
+ Prototype* proto = prototype.getPtr();
+ while(proto)
+ {
+ variable *obj = proto->getObj()->findSettable(name);
+ if (obj)
+ return obj;
+
+ proto = proto->prevPrototype.getPtr();
+ }
+
+ return NULL;
+}
+
EARLY_BIND_STATUS Class_base::resolveMultinameStatically(const multiname& name) const
{
- if(findBorrowedGettable(name)!=NULL)
+ NS_KIND nskind;
+ if(findBorrowedGettable(name,nskind)!=NULL)
return BINDED;
else
return NOT_BINDED;
@@ -1306,14 +1414,19 @@ void ASQName::setByNode(xmlpp::Node* node)
local_name = node->get_name();
uri=node->get_namespace_uri();
}
+void ASQName::setByXML(XML* node)
+{
+ uri_is_null=false;
+ local_name = node->getName();
+ uri=node->getNamespaceURI();
+}
void ASQName::sinit(Class_base* c)
{
- c->setSuper(Class<ASObject>::getRef());
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED | CLASS_FINAL);
c->setDeclaredMethodByQName("uri","",Class<IFunction>::getFunction(_getURI),GETTER_METHOD,true);
c->setDeclaredMethodByQName("localName","",Class<IFunction>::getFunction(_getLocalName),GETTER_METHOD,true);
- c->prototype->setVariableByQName("toString",AS3,Class<IFunction>::getFunction(_toString),DYNAMIC_TRAIT);
+ c->prototype->setVariableByQName("toString","",Class<IFunction>::getFunction(_toString),DYNAMIC_TRAIT);
}
ASFUNCTIONBODY(ASQName,_constructor)
@@ -1404,9 +1517,7 @@ ASFUNCTIONBODY(ASQName,generator)
{
th->local_name="";
th->uri_is_null=false;
- th->uri="";
- // Should set th->uri to the default namespace
- LOG(LOG_NOT_IMPLEMENTED, "QName constructor not completely implemented");
+ th->uri=getVm()->getDefaultXMLNamespace();
return th;
}
if(argslen==1)
@@ -1448,9 +1559,7 @@ ASFUNCTIONBODY(ASQName,generator)
}
else
{
- // Should set th->uri to the default namespace
- LOG(LOG_NOT_IMPLEMENTED, "QName constructor not completely implemented");
- th->uri="";
+ th->uri=getVm()->getDefaultXMLNamespace();
}
}
else if(namespaceval->getObjectType()==T_NULL)
@@ -1517,14 +1626,14 @@ tiny_string ASQName::toString()
return s + local_name;
}
-Namespace::Namespace(Class_base* c):ASObject(c)
+Namespace::Namespace(Class_base* c):ASObject(c),nskind(NAMESPACE)
{
type=T_NAMESPACE;
prefix_is_undefined=false;
}
Namespace::Namespace(Class_base* c, const tiny_string& _uri, const tiny_string& _prefix)
- : ASObject(c),uri(_uri),prefix(_prefix)
+ : ASObject(c),nskind(NAMESPACE),uri(_uri),prefix(_prefix)
{
type=T_NAMESPACE;
prefix_is_undefined=false;
@@ -1532,11 +1641,10 @@ Namespace::Namespace(Class_base* c, const tiny_string& _uri, const tiny_string&
void Namespace::sinit(Class_base* c)
{
- c->setSuper(Class<ASObject>::getRef());
- c->setConstructor(Class<IFunction>::getFunction(_constructor));
- c->setDeclaredMethodByQName("uri","",Class<IFunction>::getFunction(_setURI),SETTER_METHOD,true);
+ CLASS_SETUP(c, ASObject, _constructor, CLASS_SEALED | CLASS_FINAL);
+ //c->setDeclaredMethodByQName("uri","",Class<IFunction>::getFunction(_setURI),SETTER_METHOD,true);
c->setDeclaredMethodByQName("uri","",Class<IFunction>::getFunction(_getURI),GETTER_METHOD,true);
- c->setDeclaredMethodByQName("prefix","",Class<IFunction>::getFunction(_setPrefix),SETTER_METHOD,true);
+ //c->setDeclaredMethodByQName("prefix","",Class<IFunction>::getFunction(_setPrefix),SETTER_METHOD,true);
c->setDeclaredMethodByQName("prefix","",Class<IFunction>::getFunction(_getPrefix),GETTER_METHOD,true);
c->setDeclaredMethodByQName("valueOf",AS3,Class<IFunction>::getFunction(_valueOf),NORMAL_METHOD,true);
c->prototype->setVariableByQName("toString","",Class<IFunction>::getFunction(_toString),DYNAMIC_TRAIT);
@@ -1720,20 +1828,20 @@ ASFUNCTIONBODY(Namespace,generator)
}
return th;
}
-
+/*
ASFUNCTIONBODY(Namespace,_setURI)
{
Namespace* th=static_cast<Namespace*>(obj);
th->uri=args[0]->toString();
return NULL;
}
-
+*/
ASFUNCTIONBODY(Namespace,_getURI)
{
Namespace* th=static_cast<Namespace*>(obj);
return Class<ASString>::getInstanceS(th->uri);
}
-
+/*
ASFUNCTIONBODY(Namespace,_setPrefix)
{
Namespace* th=static_cast<Namespace*>(obj);
@@ -1749,7 +1857,7 @@ ASFUNCTIONBODY(Namespace,_setPrefix)
}
return NULL;
}
-
+*/
ASFUNCTIONBODY(Namespace,_getPrefix)
{
Namespace* th=static_cast<Namespace*>(obj);
@@ -1809,7 +1917,10 @@ ASObject* Class<IFunction>::getInstance(bool construct, ASObject* const* args, c
{
if (argslen > 0)
throwError<EvalError>(kFunctionConstructorError);
- return getNopFunction();
+ ASObject* ret = getNopFunction();
+ if (construct)
+ ret->setConstructIndicator();
+ return ret;
}
Class<IFunction>* Class<IFunction>::getClass()
@@ -1831,6 +1942,7 @@ Class<IFunction>* Class<IFunction>::getClass()
ret->prototype = _MNR(new_functionPrototype(ret, ret->super->prototype));
ret->incRef();
ret->prototype->getObj()->setVariableByQName("constructor","",ret,DYNAMIC_TRAIT);
+ ret->prototype->getObj()->setConstructIndicator();
ret->incRef();
*retAddr = ret;
@@ -1838,15 +1950,14 @@ Class<IFunction>* Class<IFunction>::getClass()
//addPrototypeGetter and setDeclaredMethodByQName.
//Thus we make sure that everything is in order when getFunction() below is called
ret->addPrototypeGetter();
- //copy borrowed traits from ASObject by ourself
- ASObject::sinit(ret);
- ret->setDeclaredMethodByQName("call",AS3,Class<IFunction>::getFunction(IFunction::_call),NORMAL_METHOD,true);
- ret->setDeclaredMethodByQName("apply",AS3,Class<IFunction>::getFunction(IFunction::apply),NORMAL_METHOD,true);
+ IFunction::sinit(ret);
+ ret->constructorprop = _NR<ObjectConstructor>(new_objectConstructor(ret,ret->length));
+ ret->constructorprop->incRef();
+
+ ret->addConstructorGetter();
+
ret->setDeclaredMethodByQName("prototype","",Class<IFunction>::getFunction(IFunction::_getter_prototype),GETTER_METHOD,true);
ret->setDeclaredMethodByQName("prototype","",Class<IFunction>::getFunction(IFunction::_setter_prototype),SETTER_METHOD,true);
- ret->setDeclaredMethodByQName("length","",Class<IFunction>::getFunction(IFunction::_getter_length),GETTER_METHOD,true);
- ret->prototype->setVariableByQName("toString",AS3,Class<IFunction>::getFunction(IFunction::_toString),DYNAMIC_TRAIT);
- ret->setDeclaredMethodByQName("toString",AS3,Class<IFunction>::getFunction(Class_base::_toString),NORMAL_METHOD,false);
}
else
ret=static_cast<Class<IFunction>*>(*retAddr);
@@ -2243,8 +2354,15 @@ ASFUNCTIONBODY(lightspark,_isXMLName)
ObjectPrototype::ObjectPrototype(Class_base* c) : ASObject(c)
{
+ traitsInitialized = true;
+ constructIndicator = true;
+}
+bool ObjectPrototype::isEqual(ASObject* r)
+{
+ if (r->is<ObjectPrototype>())
+ return this->getClass() == r->getClass();
+ return ASObject::isEqual(r);
}
-
void ObjectPrototype::finalize()
{
ASObject::finalize();
@@ -2260,6 +2378,31 @@ _NR<ASObject> ObjectPrototype::getVariableByMultiname(const multiname& name, GET
return prevPrototype->getObj()->getVariableByMultiname(name, opt);
}
+
+ObjectConstructor::ObjectConstructor(Class_base* c,uint32_t length) : ASObject(c),_length(length)
+{
+ Class<ASObject>::getRef()->prototype->incRef();
+ this->prototype = Class<ASObject>::getRef()->prototype.getPtr();
+}
+
+_NR<ASObject> ObjectConstructor::getVariableByMultiname(const multiname& name, GET_VARIABLE_OPTION opt)
+{
+ if (name.normalizedName() == "prototype")
+ {
+ prototype->getObj()->incRef();
+ return _NR<ASObject>(prototype->getObj());
+ }
+ if (name.normalizedName() == "length")
+ {
+ return _NR<ASObject>(abstract_d(_length));
+ }
+ return getClass()->getVariableByMultiname(name, opt);
+}
+bool ObjectConstructor::isEqual(ASObject* r)
+{
+ return this == r || getClass() == r;
+}
+
FunctionPrototype::FunctionPrototype(Class_base* c, _NR<Prototype> p) : Function(c, ASNop)
{
prevPrototype=p;
diff --git a/src/scripting/toplevel/toplevel.h b/src/scripting/toplevel/toplevel.h
index 500f85a..3d75de4 100644
--- a/src/scripting/toplevel/toplevel.h
+++ b/src/scripting/toplevel/toplevel.h
@@ -29,7 +29,7 @@
#include "scripting/abcutils.h"
#include "scripting/toplevel/Boolean.h"
#include "scripting/toplevel/Error.h"
-//#include "scripting/toplevel/XML.h"
+#include "scripting/toplevel/XML.h"
#include "memory_support.h"
#include <libxml++/parsers/domparser.h>
#include <boost/intrusive/list.hpp>
@@ -45,7 +45,7 @@ class ASString;
class method_info;
struct call_context;
struct traits_info;
-class namespace_info;
+struct namespace_info;
class Any;
class Void;
class Class_object;
@@ -74,7 +74,7 @@ public:
* then an exception is thrown.
* The caller does not own the object returned.
*/
- static const Type* getTypeFromMultiname(const multiname* mn, const ABCContext* context);
+ static const Type* getTypeFromMultiname(const multiname* mn, ABCContext* context);
/*
* Checks if the type is already in sys->classes
*/
@@ -136,6 +136,7 @@ public:
};
class Prototype;
+class ObjectConstructor;
class Class_base: public ASObject, public Type
{
@@ -158,9 +159,11 @@ private:
protected:
void copyBorrowedTraitsFromSuper();
ASFUNCTION(_toString);
+ void initStandardProps();
public:
variables_map borrowedVariables;
ASPROPERTY_GETTER(_NR<Prototype>,prototype);
+ ASPROPERTY_GETTER(_NR<ObjectConstructor>,constructorprop);
_NR<Class_base> super;
//We need to know what is the context we are referring to
ABCContext* context;
@@ -175,11 +178,13 @@ private:
//TODO: move in Class_inherit
bool use_protected:1;
public:
+ void addConstructorGetter();
void addPrototypeGetter();
void addLengthGetter();
void setupDeclaredTraits(ASObject *target);
void handleConstruction(ASObject* target, ASObject* const* args, unsigned int argslen, bool buildAndLink);
void setConstructor(IFunction* c);
+ bool hasConstructor() { return constructor != NULL; }
Class_base(const QName& name, MemoryAccount* m);
//Special constructor for Class_object
Class_base(const Class_object*);
@@ -189,7 +194,7 @@ public:
void addImplementedInterface(const multiname& i);
void addImplementedInterface(Class_base* i);
virtual void buildInstanceTraits(ASObject* o) const=0;
- const std::vector<Class_base*>& getInterfaces() const;
+ const std::vector<Class_base*>& getInterfaces(bool *alldefined = NULL) const;
virtual void linkInterface(Class_base* c) const;
/*
* Returns true when 'this' is a subclass of 'cls',
@@ -198,7 +203,7 @@ public:
*/
bool isSubClass(const Class_base* cls, bool considerInterfaces=true) const;
tiny_string getQualifiedClassName() const;
- tiny_string getName() const { return class_name.name; }
+ tiny_string getName() const { return (class_name.ns.empty() ? class_name.name : class_name.ns +"$"+ class_name.name); }
tiny_string toString();
virtual ASObject* generator(ASObject* const* args, const unsigned int argslen);
ASObject *describeType() const;
@@ -220,8 +225,9 @@ public:
super = super_;
copyBorrowedTraitsFromSuper();
}
- const variable* findBorrowedGettable(const multiname& name) const DLL_LOCAL;
+ const variable* findBorrowedGettable(const multiname& name, NS_KIND &nskind) const DLL_LOCAL;
variable* findBorrowedSettable(const multiname& name, bool* has_getter=NULL) DLL_LOCAL;
+ variable* findSettableInPrototype(const multiname& name) DLL_LOCAL;
EARLY_BIND_STATUS resolveMultinameStatically(const multiname& name) const;
const multiname* resolveSlotTypeName(uint32_t slotId) const { /*TODO: implement*/ return NULL; }
};
@@ -232,7 +238,7 @@ private:
QName template_name;
public:
Template_base(QName name);
- virtual Class_base* applyType(const std::vector<Type*>& t)=0;
+ virtual Class_base* applyType(const std::vector<const Type*>& t)=0;
};
class Class_object: public Class_base
@@ -247,7 +253,7 @@ private:
}
void buildInstanceTraits(ASObject* o) const
{
- throw RunTimeException("Class_object::buildInstanceTraits");
+// throw RunTimeException("Class_object::buildInstanceTraits");
}
void finalize();
public:
@@ -284,8 +290,25 @@ public:
void decRef() { ASObject::decRef(); }
ASObject* getObj() { return this; }
_NR<ASObject> getVariableByMultiname(const multiname& name, GET_VARIABLE_OPTION opt=NONE);
+ bool isEqual(ASObject* r);
};
+/* Special object used as constructor property for classes
+ * It has its own prototype object, but everything else is forwarded to the class object
+ */
+class ObjectConstructor: public ASObject
+{
+ Prototype* prototype;
+ uint32_t _length;
+public:
+ ObjectConstructor(Class_base* c,uint32_t length);
+ void incRef() { getClass()->incRef(); }
+ void decRef() { getClass()->decRef(); }
+ _NR<ASObject> getVariableByMultiname(const multiname& name, GET_VARIABLE_OPTION opt=NONE);
+ bool isEqual(ASObject* r);
+};
+
+
/* Special object returned when new func() syntax is used.
* This object looks for properties on the prototype object that is passed in the constructor
*/
@@ -311,6 +334,8 @@ protected:
IFunction(Class_base *c);
virtual IFunction* clone()=0;
_NR<ASObject> closure_this;
+
+ static void sinit(Class_base* c);
public:
/* If this is a method, inClass is the class this is defined in.
* If this is a function, inClass == NULL
@@ -319,6 +344,7 @@ public:
/* returns whether this is this a method of a function */
bool isMethod() const { return inClass != NULL; }
bool isBound() const { return closure_this; }
+ bool isConstructed() const { return constructIndicator; }
void finalize();
ASFUNCTION(apply);
ASFUNCTION(_call);
@@ -348,6 +374,7 @@ public:
ret->setClass(getClass());
}
ret->closure_this=c;
+ ret->constructIndicator = true;
//std::cout << "Binding " << ret << std::endl;
return ret;
}
@@ -365,6 +392,8 @@ public:
* Implements the IFunction interface for functions implemented
* in c-code.
*/
+class FunctionPrototype;
+
class Function : public IFunction
{
friend class Class<IFunction>;
@@ -381,13 +410,7 @@ protected:
method_info* getMethodInfo() const { return NULL; }
public:
ASObject* call(ASObject* obj, ASObject* const* args, uint32_t num_args);
- bool isEqual(ASObject* r)
- {
- Function* f=dynamic_cast<Function*>(r);
- if(f==NULL)
- return false;
- return (val==f->val) && (closure_this==f->closure_this);
- }
+ bool isEqual(ASObject* r);
};
/* Special object used as prototype for the Function class
@@ -469,6 +492,7 @@ public:
{
Class<IFunction>* c=Class<IFunction>::getClass();
Function* ret=new (c->memoryAccount) Function(c, v);
+ ret->constructIndicator = true;
return ret;
}
static Function* getFunction(Function::as_function v, int len)
@@ -476,18 +500,21 @@ public:
Class<IFunction>* c=Class<IFunction>::getClass();
Function* ret=new (c->memoryAccount) Function(c, v);
ret->length = len;
+ ret->constructIndicator = true;
return ret;
}
static SyntheticFunction* getSyntheticFunction(method_info* m)
{
Class<IFunction>* c=Class<IFunction>::getClass();
SyntheticFunction* ret=new (c->memoryAccount) SyntheticFunction(c, m);
+ ret->constructIndicator = true;
c->handleConstruction(ret,NULL,0,true);
return ret;
}
void buildInstanceTraits(ASObject* o) const
{
}
+ virtual ASObject* generator(ASObject* const* args, const unsigned int argslen);
};
class Undefined : public ASObject
@@ -525,7 +552,7 @@ public:
class ASQName: public ASObject
{
-friend class multiname;
+friend struct multiname;
friend class Namespace;
private:
bool uri_is_null;
@@ -534,6 +561,7 @@ private:
public:
ASQName(Class_base* c);
void setByNode(xmlpp::Node* node);
+ void setByXML(XML* node);
static void sinit(Class_base*);
ASFUNCTION(_constructor);
ASFUNCTION(generator);
@@ -551,6 +579,7 @@ class Namespace: public ASObject
friend class ASQName;
friend class ABCContext;
private:
+ NS_KIND nskind;
bool prefix_is_undefined;
tiny_string uri;
tiny_string prefix;
@@ -562,9 +591,10 @@ public:
ASFUNCTION(_constructor);
ASFUNCTION(generator);
ASFUNCTION(_getURI);
- ASFUNCTION(_setURI);
+ // according to ECMA-357 and tamarin tests uri/prefix properties are readonly
+ //ASFUNCTION(_setURI);
ASFUNCTION(_getPrefix);
- ASFUNCTION(_setPrefix);
+ //ASFUNCTION(_setPrefix);
ASFUNCTION(_toString);
ASFUNCTION(_valueOf);
ASFUNCTION(_ECMA_valueOf);
diff --git a/src/swf.cpp b/src/swf.cpp
index 008fdaf..e1504bc 100644
--- a/src/swf.cpp
+++ b/src/swf.cpp
@@ -52,22 +52,22 @@ extern "C" {
using namespace std;
using namespace lightspark;
-static GStaticPrivate tls_system = G_STATIC_PRIVATE_INIT;
+DEFINE_AND_INITIALIZE_TLS(tls_system);
SystemState* lightspark::getSys()
{
- SystemState* ret = (SystemState*)g_static_private_get(&tls_system);
+ SystemState* ret = (SystemState*)tls_get(&tls_system);
return ret;
}
void lightspark::setTLSSys(SystemState* sys)
{
- g_static_private_set(&tls_system,sys,NULL);
+ tls_set(&tls_system,sys);
}
-static GStaticPrivate parse_thread_tls = G_STATIC_PRIVATE_INIT; /* TLS */
+DEFINE_AND_INITIALIZE_TLS(parse_thread_tls);
ParseThread* lightspark::getParseThread()
{
- ParseThread* pt = (ParseThread*)g_static_private_get(&parse_thread_tls);
+ ParseThread* pt = (ParseThread*)tls_get(&parse_thread_tls);
assert(pt);
return pt;
}
@@ -145,6 +145,7 @@ RootMovieClip* RootMovieClip::getInstance(_NR<LoaderInfo> li, _R<ApplicationDoma
{
Class_base* movieClipClass = Class<MovieClip>::getClass();
RootMovieClip* ret=new (movieClipClass->memoryAccount) RootMovieClip(li, appDomain, secDomain, movieClipClass);
+ ret->constructIndicator = true;
return ret;
}
@@ -1271,7 +1272,7 @@ void ParseThread::parseSWFHeader(RootMovieClip *root, UI8 ver)
void ParseThread::execute()
{
- g_static_private_set(&parse_thread_tls,this,NULL);
+ tls_set(&parse_thread_tls,this);
try
{
UI8 Signature[4];
@@ -1315,6 +1316,14 @@ void ParseThread::execute()
void ParseThread::parseSWF(UI8 ver)
{
+ if (loader && !loader->allowLoadingSWF())
+ {
+ _NR<LoaderInfo> li=loader->getContentLoaderInfo();
+ getVm()->addEvent(li,_MR(Class<SecurityErrorEvent>::getInstanceS(
+ "Cannot import a SWF file when LoaderContext.allowCodeImport is false."))); // 3226
+ return;
+ }
+
objectSpinlock.lock();
RootMovieClip* root=NULL;
if(parsedObject.isNull())
@@ -1333,10 +1342,15 @@ void ParseThread::parseSWF(UI8 ver)
}
objectSpinlock.unlock();
- std::queue<const ControlTag*> symbolClassTags;
+ std::queue<const ControlTag*> queuedTags;
try
{
parseSWFHeader(root, ver);
+ if (loader)
+ {
+ _NR<LoaderInfo> li=loader->getContentLoaderInfo();
+ li->swfVersion = root->version;
+ }
if(root->version < 9)
{
LOG(LOG_INFO,"SWF version " << root->version << " is not handled by lightspark, falling back to gnash (if available)");
@@ -1359,7 +1373,10 @@ void ParseThread::parseSWF(UI8 ver)
{
getSys()->needsAVM2(fat->ActionScript3);
if(!fat->ActionScript3)
+ {
+ delete fat;
return; /* no more parsing necessary, handled by fallback */
+ }
if(fat->UseNetwork
&& getSys()->securityManager->getSandboxType() == SecurityManager::LOCAL_WITH_FILE)
{
@@ -1378,14 +1395,14 @@ void ParseThread::parseSWF(UI8 ver)
{
case END_TAG:
{
- // The whole frame has been parsed, now execute all queued SymbolClass tags,
+ // The whole frame has been parsed, now execute all queued tags,
// in the order in which they appeared in the file.
- while(!symbolClassTags.empty())
+ while(!queuedTags.empty())
{
- const ControlTag* t=symbolClassTags.front();
+ const ControlTag* t=queuedTags.front();
t->execute(root);
delete t;
- symbolClassTags.pop();
+ queuedTags.pop();
}
if(!empty)
@@ -1411,12 +1428,12 @@ void ParseThread::parseSWF(UI8 ver)
case SHOW_TAG:
// The whole frame has been parsed, now execute all queued SymbolClass tags,
// in the order in which they appeared in the file.
- while(!symbolClassTags.empty())
+ while(!queuedTags.empty())
{
- const ControlTag* t=symbolClassTags.front();
+ const ControlTag* t=queuedTags.front();
t->execute(root);
delete t;
- symbolClassTags.pop();
+ queuedTags.pop();
}
root->commitFrame(true);
@@ -1424,13 +1441,14 @@ void ParseThread::parseSWF(UI8 ver)
delete tag;
break;
case SYMBOL_CLASS_TAG:
+ case ACTION_TAG:
{
- // Add symbol class tags to the queue, to be executed when the rest of the
+ // Add symbol class tags or action to the queue, to be executed when the rest of the
// frame has been parsed. This is to handle invalid SWF files that define ID's
// used in the SymbolClass tag only after the tag, which would otherwise result
// in "undefined dictionary ID" errors.
const ControlTag* stag = static_cast<const ControlTag*>(tag);
- symbolClassTags.push(stag);
+ queuedTags.push(stag);
break;
}
case CONTROL_TAG:
@@ -1932,6 +1950,14 @@ void SystemState::openPageInBrowser(const tiny_string& url, const tiny_string& w
engineData->openPageInBrowser(url, window);
}
+void SystemState::showMouseCursor(bool visible)
+{
+ if (visible)
+ EngineData::runInGtkThread(sigc::mem_fun(engineData, &EngineData::showMouseCursor));
+ else
+ EngineData::runInGtkThread(sigc::mem_fun(engineData, &EngineData::hideMouseCursor));
+}
+
/* This is run in vm's thread context */
void RootMovieClip::initFrame()
{
diff --git a/src/swf.h b/src/swf.h
index 419204a..a778a1c 100644
--- a/src/swf.h
+++ b/src/swf.h
@@ -30,6 +30,7 @@
#include "swftypes.h"
#include "scripting/flash/display/flashdisplay.h"
#include "scripting/flash/net/flashnet.h"
+#include "scripting/flash/utils/IntervalManager.h"
#include "timer.h"
#include "memory_support.h"
#include "platforms/engineutils.h"
@@ -429,6 +430,8 @@ public:
//Opening web pages
void openPageInBrowser(const tiny_string& url, const tiny_string& window);
+
+ void showMouseCursor(bool visible);
};
class ParseThread: public IThreadJob
diff --git a/src/swftypes.cpp b/src/swftypes.cpp
index 1ec1807..f0bd3c1 100644
--- a/src/swftypes.cpp
+++ b/src/swftypes.cpp
@@ -43,7 +43,7 @@ multiname::multiname(MemoryAccount* m):name_o(NULL),ns(reporter_allocator<nsName
tiny_string multiname::qualifiedString() const
{
- assert_and_throw(ns.size()==1);
+ assert_and_throw(ns.size()>=1);
assert_and_throw(name_type==NAME_STRING);
const tiny_string nsName=ns[0].getImpl().name;
const tiny_string& name=getSys()->getStringFromUniqueId(name_s_id);
@@ -162,6 +162,7 @@ bool multiname::toUInt(uint32_t& index, bool acceptStringFractions) const
if(str.empty())
return false;
index=0;
+ uint64_t parsed = 0;
for(auto i=str.begin(); i!=str.end(); ++i)
{
if (*i == '.' && acceptStringFractions)
@@ -175,14 +176,21 @@ bool multiname::toUInt(uint32_t& index, bool acceptStringFractions) const
for (; i!=str.end(); ++i)
if (*i != '0')
return false;
- return true;
+ break;
}
else if(!i.isdigit())
return false;
- index*=10;
- index+=i.digit_value();
+ parsed*=10;
+ parsed+=i.digit_value();
+ if (parsed > UINT32_MAX)
+ break;
}
+
+ if (parsed > UINT32_MAX)
+ return false;
+
+ index = (uint32_t)parsed;
break;
}
//This is already an int, so its good enough
@@ -192,7 +200,7 @@ bool multiname::toUInt(uint32_t& index, bool acceptStringFractions) const
index=name_i;
break;
case multiname::NAME_NUMBER:
- if(!Number::isInteger(name_d) || name_d < 0)
+ if(!Number::isInteger(name_d) || name_d < 0 || name_d > UINT32_MAX)
return false;
index=name_d;
break;
@@ -515,10 +523,14 @@ std::istream& lightspark::operator>>(std::istream& s, FILLSTYLEARRAY& v)
assert(v.version!=0xff);
UI8 FillStyleCount;
s >> FillStyleCount;
+ int fsc = FillStyleCount;
if(FillStyleCount==0xff)
- LOG(LOG_ERROR,_("Fill array extended not supported"));
-
- for(int i=0;i<FillStyleCount;i++)
+ {
+ UI16_SWF ExtendedFillStyleCount;
+ s >> ExtendedFillStyleCount;
+ fsc = ExtendedFillStyleCount;
+ }
+ for(int i=0;i<fsc;i++)
{
FILLSTYLE t(v.version);
s >> t;
@@ -806,7 +818,7 @@ std::istream& lightspark::operator>>(std::istream& s, FILLSTYLE& v)
else
{
LOG(LOG_ERROR,_("Not supported fill style ") << (int)v.FillStyleType);
- throw ParseException("Not supported fill style");
+ throw ParseException("Not supported fill style");
}
return s;
}
@@ -1315,7 +1327,9 @@ std::istream& lightspark::operator>>(std::istream& s, CLIPACTIONS& v)
ASObject* lightspark::abstract_d(number_t i)
{
- Number* ret=Class<Number>::getInstanceS(i);
+ Number* ret=Class<Number>::getInstanceS();
+ // we have to set the value seperately, because for i = NaN, getInstanceS will overwrite the value
+ ret->val = i;
return ret;
}
@@ -1342,7 +1356,7 @@ void lightspark::stringToQName(const tiny_string& tmp, tiny_string& name, tiny_s
assert_and_throw(collon != tmp.raw_buf() && *(collon-1) == ':');
uint32_t collon_offset = collon-tmp.raw_buf();
ns = tmp.substr_bytes(0,collon_offset-1);
- name = tmp.substr_bytes(collon_offset+1,tmp.numChars()-collon_offset-1);
+ name = tmp.substr_bytes(collon_offset+1,tmp.numBytes()-collon_offset-1);
return;
}
// No namespace, look for a package name
@@ -1351,7 +1365,7 @@ void lightspark::stringToQName(const tiny_string& tmp, tiny_string& name, tiny_s
{
uint32_t dot_offset = dot-tmp.raw_buf();
ns = tmp.substr_bytes(0,dot_offset);
- name = tmp.substr_bytes(dot_offset+1,tmp.numChars()-dot_offset-1);
+ name = tmp.substr_bytes(dot_offset+1,tmp.numBytes()-dot_offset-1);
return;
}
//No namespace or package in the string
@@ -1398,6 +1412,18 @@ FILLSTYLE::~FILLSTYLE()
{
}
+FILLSTYLE& FILLSTYLE::operator=(FILLSTYLE r)
+{
+ std::swap(Matrix, r.Matrix);
+ std::swap(Gradient, r.Gradient);
+ std::swap(FocalGradient, r.FocalGradient);
+ std::swap(bitmap, r.bitmap);
+ std::swap(Color, r.Color);
+ std::swap(FillStyleType, r.FillStyleType);
+ std::swap(version, r.version);
+ return *this;
+}
+
nsNameAndKind::nsNameAndKind(const tiny_string& _name, NS_KIND _kind)
{
nsNameAndKindImpl tmp(_name, _kind);
@@ -1504,3 +1530,26 @@ tiny_string RGB::toString() const
return ss.str();
}
+
+std::istream& lightspark::operator>>(std::istream& stream, SOUNDINFO& v)
+{
+ BitStream bs(stream);
+ UB(2,bs); // reserved
+ v.SyncStop = UB(1,bs);
+ v.SyncNoMultiple = UB(1,bs);
+ v.HasEnvelope = UB(1,bs);
+ v.HasLoops = UB(1,bs);
+ v.HasOutPoint = UB(1,bs);
+ v.HasInPoint = UB(1,bs);
+ if (v.HasInPoint)
+ stream >> v.InPoint;
+ if (v.HasOutPoint)
+ stream >> v.OutPoint;
+ if (v.HasLoops)
+ stream >> v.LoopCount;
+ if (v.HasEnvelope)
+ stream >> v.EnvPoints;
+ // TODO: EnvelopeRecords
+ return stream;
+}
+
diff --git a/src/swftypes.h b/src/swftypes.h
index 4022ec9..b477e09 100644
--- a/src/swftypes.h
+++ b/src/swftypes.h
@@ -83,7 +83,7 @@ typedef double number_t;
class ASObject;
class ABCContext;
-class namespace_info;
+struct namespace_info;
struct multiname;
class QName
@@ -376,6 +376,7 @@ struct multiname: public memory_reporter
void resetNameIfObject();
bool isQName() const { return ns.size() == 1; }
bool toUInt(uint32_t& out, bool acceptStringFractions=false) const;
+ bool isEmpty() const { return name_type == NAME_OBJECT && name_o == NULL;}
};
class FLOAT
@@ -885,6 +886,7 @@ class FILLSTYLE
public:
FILLSTYLE(uint8_t v);
FILLSTYLE(const FILLSTYLE& r);
+ FILLSTYLE& operator=(FILLSTYLE r);
virtual ~FILLSTYLE();
MATRIX Matrix;
GRADIENT Gradient;
@@ -924,10 +926,10 @@ public:
class LINESTYLE2
{
public:
- LINESTYLE2(uint8_t v):FillType(v),version(v){}
+ LINESTYLE2(uint8_t v):HasFillFlag(false),FillType(v),version(v){}
UB StartCapStyle;
UB JointStyle;
- UB HasFillFlag;
+ bool HasFillFlag;
UB NoHScaleFlag;
UB NoVScaleFlag;
UB PixelHintingFlag;
@@ -1295,6 +1297,21 @@ public:
CLIPEVENTFLAGS AllEventFlags;
};
+class SOUNDINFO
+{
+public:
+ UB SyncStop;
+ UB SyncNoMultiple;
+ UB HasEnvelope;
+ UB HasLoops;
+ UB HasOutPoint;
+ UB HasInPoint;
+ UI32_SWF InPoint;
+ UI32_SWF OutPoint;
+ UI16_SWF LoopCount;
+ UI8 EnvPoints;
+};
+
class RunState
{
public:
@@ -1359,7 +1376,7 @@ std::istream& operator>>(std::istream& stream, GRADIENTGLOWFILTER& v);
std::istream& operator>>(std::istream& stream, CONVOLUTIONFILTER& v);
std::istream& operator>>(std::istream& stream, COLORMATRIXFILTER& v);
std::istream& operator>>(std::istream& stream, GRADIENTBEVELFILTER& v);
-
+std::istream& operator>>(std::istream& stream, SOUNDINFO& v);
};
#endif /* SWFTYPES_H */
diff --git a/src/threading.cpp b/src/threading.cpp
index 26666a8..3e6c31a 100644
--- a/src/threading.cpp
+++ b/src/threading.cpp
@@ -26,6 +26,33 @@
using namespace lightspark;
+#if GLIB_CHECK_VERSION(2, 31, 0)
+
+void lightspark::tls_set(GPrivate *key, gpointer value)
+{
+ g_private_set(key, value);
+}
+
+gpointer lightspark::tls_get(GPrivate *key)
+{
+ return g_private_get(key);
+}
+
+#else
+
+void lightspark::tls_set(GStaticPrivate *key, gpointer value)
+{
+ g_static_private_set(key, value, NULL);
+}
+
+gpointer lightspark::tls_get(GStaticPrivate *key)
+{
+ return g_static_private_get(key);
+}
+
+#endif
+
+
Semaphore::Semaphore(uint32_t init):value(init)
{
}
diff --git a/src/threading.h b/src/threading.h
index eef5a2e..e6604cf 100644
--- a/src/threading.h
+++ b/src/threading.h
@@ -55,6 +55,16 @@ typedef Mutex::Lock Locker;
typedef Mutex Spinlock;
typedef Mutex::Lock SpinlockLocker;
+#if GLIB_CHECK_VERSION(2, 31, 0)
+#define DEFINE_AND_INITIALIZE_TLS(name) static GPrivate (name)
+void tls_set(GPrivate *key, gpointer value);
+gpointer tls_get(GPrivate *key);
+#else
+#define DEFINE_AND_INITIALIZE_TLS(name) static GStaticPrivate (name) = G_STATIC_PRIVATE_INIT
+void tls_set(GStaticPrivate *key, gpointer value);
+gpointer tls_get(GStaticPrivate *key);
+#endif
+
class DLL_PUBLIC Semaphore
{
private:
diff --git a/src/tiny_string.cpp b/src/tiny_string.cpp
index 8257cae..9fec690 100644
--- a/src/tiny_string.cpp
+++ b/src/tiny_string.cpp
@@ -42,6 +42,78 @@ tiny_string::tiny_string(std::istream& in, int len):buf(_buf_static),stringSize(
buf[len]='\0';
}
+tiny_string::tiny_string(const char* s,bool copy):_buf_static(),buf(_buf_static),type(READONLY)
+{
+ if(copy)
+ makePrivateCopy(s);
+ else
+ {
+ stringSize=strlen(s)+1;
+ buf=(char*)s; //This is an unsafe conversion, we have to take care of the RO data
+ }
+}
+
+tiny_string::tiny_string(const tiny_string& r):_buf_static(),buf(_buf_static),stringSize(r.stringSize),type(STATIC)
+{
+ //Fast path for static read-only strings
+ if(r.type==READONLY)
+ {
+ type=READONLY;
+ buf=r.buf;
+ return;
+ }
+ if(stringSize > STATIC_SIZE)
+ createBuffer(stringSize);
+ memcpy(buf,r.buf,stringSize);
+}
+
+tiny_string::tiny_string(const std::string& r):_buf_static(),buf(_buf_static),stringSize(r.size()+1),type(STATIC)
+{
+ if(stringSize > STATIC_SIZE)
+ createBuffer(stringSize);
+ memcpy(buf,r.c_str(),stringSize);
+}
+
+tiny_string::~tiny_string()
+{
+ resetToStatic();
+}
+
+tiny_string& tiny_string::operator=(const tiny_string& s)
+{
+ resetToStatic();
+ stringSize=s.stringSize;
+ //Fast path for static read-only strings
+ if(s.type==READONLY)
+ {
+ type=READONLY;
+ buf=s.buf;
+ }
+ else
+ {
+ if(stringSize > STATIC_SIZE)
+ createBuffer(stringSize);
+ memcpy(buf,s.buf,stringSize);
+ }
+ return *this;
+}
+
+tiny_string& tiny_string::operator=(const std::string& s)
+{
+ resetToStatic();
+ stringSize=s.size()+1;
+ if(stringSize > STATIC_SIZE)
+ createBuffer(stringSize);
+ memcpy(buf,s.c_str(),stringSize);
+ return *this;
+}
+
+tiny_string& tiny_string::operator=(const char* s)
+{
+ makePrivateCopy(s);
+ return *this;
+}
+
tiny_string& tiny_string::operator=(const Glib::ustring& r)
{
resetToStatic();
@@ -123,6 +195,17 @@ tiny_string& tiny_string::operator+=(const tiny_string& r)
return *this;
}
+tiny_string& tiny_string::operator+=(const std::string& s)
+{
+ //TODO: optimize
+ return *this += tiny_string(s);
+}
+
+tiny_string& tiny_string::operator+=(uint32_t c)
+{
+ return (*this += tiny_string::fromChar(c));
+}
+
const tiny_string tiny_string::operator+(const tiny_string& r) const
{
tiny_string ret(*this);
@@ -130,6 +213,218 @@ const tiny_string tiny_string::operator+(const tiny_string& r) const
return ret;
}
+const tiny_string tiny_string::operator+(const char* s) const
+{
+ return *this + tiny_string(s);
+}
+
+const tiny_string tiny_string::operator+(const std::string& r) const
+{
+ return *this + tiny_string(r);
+}
+
+bool tiny_string::operator<(const tiny_string& r) const
+{
+ //don't check trailing \0
+ return memcmp(buf,r.buf,std::min(stringSize,r.stringSize))<0;
+}
+
+bool tiny_string::operator>(const tiny_string& r) const
+{
+ //don't check trailing \0
+ return memcmp(buf,r.buf,std::min(stringSize,r.stringSize))>0;
+}
+
+bool tiny_string::operator==(const tiny_string& r) const
+{
+ //The length is checked as an optimization before checking the contents
+ if(stringSize != r.stringSize)
+ return false;
+ //don't check trailing \0
+ return memcmp(buf,r.buf,stringSize-1)==0;
+}
+
+bool tiny_string::operator==(const std::string& r) const
+{
+ //The length is checked as an optimization before checking the contents
+ if(stringSize != r.size()+1)
+ return false;
+ //don't check trailing \0
+ return memcmp(buf,r.c_str(),stringSize-1)==0;
+}
+
+bool tiny_string::operator!=(const std::string& r) const
+{
+ if(stringSize != r.size()+1)
+ return true;
+ //don't check trailing \0
+ return memcmp(buf,r.c_str(),stringSize-1)!=0;
+}
+
+bool tiny_string::operator!=(const tiny_string& r) const
+{
+ return !(*this==r);
+}
+
+bool tiny_string::operator==(const char* r) const
+{
+ return strcmp(buf,r)==0;
+}
+
+bool tiny_string::operator==(const xmlChar* r) const
+{
+ return strcmp(buf,reinterpret_cast<const char*>(r))==0;
+}
+
+bool tiny_string::operator!=(const char* r) const
+{
+ return !(*this==r);
+}
+
+const char* tiny_string::raw_buf() const
+{
+ return buf;
+}
+
+bool tiny_string::empty() const
+{
+ return stringSize == 1;
+}
+
+/* returns the length in bytes, not counting the trailing \0 */
+uint32_t tiny_string::numBytes() const
+{
+ return stringSize-1;
+}
+
+/* returns the length in utf-8 characters, not counting the trailing \0 */
+uint32_t tiny_string::numChars() const
+{
+ //we cannot use g_utf8_strlen, as we may have '\0' inside our string
+ uint32_t len = 0;
+ char* end = buf+numBytes();
+ char* p = buf;
+ while(p < end)
+ {
+ p = g_utf8_next_char(p);
+ ++len;
+ }
+ return len;
+}
+
+char* tiny_string::strchr(char c) const
+{
+ //TODO: does this handle '\0' in middle of buf gracefully?
+ return g_utf8_strchr(buf, numBytes(), c);
+}
+
+char* tiny_string::strchrr(char c) const
+{
+ //TODO: does this handle '\0' in middle of buf gracefully?
+ return g_utf8_strrchr(buf, numBytes(), c);
+}
+
+tiny_string::operator std::string() const
+{
+ return std::string(buf,stringSize-1);
+}
+
+bool tiny_string::startsWith(const char* o) const
+{
+ return strncmp(buf,o,strlen(o)) == 0;
+}
+bool tiny_string::endsWith(const char* o) const
+{
+ size_t olen = strlen(o);
+ return (numBytes() >= olen) &&
+ (strncmp(buf+numBytes()-olen,o,olen) == 0);
+}
+
+/* idx is an index of utf-8 characters */
+uint32_t tiny_string::charAt(uint32_t idx) const
+{
+ return g_utf8_get_char(g_utf8_offset_to_pointer(buf,idx));
+}
+
+/* start is an index of characters.
+ * returns index of character */
+uint32_t tiny_string::find(const tiny_string& needle, uint32_t start) const
+{
+ //TODO: omit copy into std::string
+ size_t bytestart = g_utf8_offset_to_pointer(buf,start) - buf;
+ size_t bytepos = std::string(*this).find(needle.raw_buf(),bytestart,needle.numBytes());
+ if(bytepos == std::string::npos)
+ return npos;
+ else
+ return g_utf8_pointer_to_offset(buf,buf+bytepos);
+}
+
+uint32_t tiny_string::rfind(const tiny_string& needle, uint32_t start) const
+{
+ //TODO: omit copy into std::string
+ size_t bytestart;
+ if(start == npos)
+ bytestart = std::string::npos;
+ else
+ bytestart = g_utf8_offset_to_pointer(buf,start) - buf;
+
+ size_t bytepos = std::string(*this).rfind(needle.raw_buf(),bytestart,needle.numBytes());
+ if(bytepos == std::string::npos)
+ return npos;
+ else
+ return g_utf8_pointer_to_offset(buf,buf+bytepos);
+}
+
+void tiny_string::makePrivateCopy(const char* s)
+{
+ resetToStatic();
+ stringSize=strlen(s)+1;
+ if(stringSize > STATIC_SIZE)
+ createBuffer(stringSize);
+ strcpy(buf,s);
+}
+
+void tiny_string::createBuffer(uint32_t s)
+{
+ type=DYNAMIC;
+ reportMemoryChange(s);
+ buf=new char[s];
+}
+
+void tiny_string::resizeBuffer(uint32_t s)
+{
+ assert(type==DYNAMIC);
+ char* oldBuf=buf;
+ reportMemoryChange(s-stringSize);
+ buf=new char[s];
+ assert(s >= stringSize);
+ memcpy(buf,oldBuf,stringSize);
+ delete[] oldBuf;
+}
+
+void tiny_string::resetToStatic()
+{
+ if(type==DYNAMIC)
+ {
+ reportMemoryChange(-stringSize);
+ delete[] buf;
+ }
+ stringSize=1;
+ _buf_static[0] = '\0';
+ buf=_buf_static;
+ type=STATIC;
+}
+
+tiny_string tiny_string::fromChar(uint32_t c)
+{
+ tiny_string ret;
+ ret.buf = ret._buf_static;
+ ret.type = STATIC;
+ ret.stringSize = g_unichar_to_utf8(c,ret.buf) + 1;
+ ret.buf[ret.stringSize-1] = '\0';
+ return ret;
+}
+
tiny_string& tiny_string::replace(uint32_t pos1, uint32_t n1, const tiny_string& o )
{
assert(pos1 <= numChars());
@@ -202,6 +497,109 @@ std::list<tiny_string> tiny_string::split(uint32_t delimiter) const
return res;
}
+tiny_string tiny_string::lowercase() const
+{
+ // have to loop manually, because g_utf8_strdown doesn't
+ // handle nul-chars
+ tiny_string ret;
+ uint32_t allocated = 2*numBytes()+7;
+ ret.createBuffer(allocated);
+ char *p = ret.buf;
+ uint32_t len = 0;
+ for (CharIterator it=begin(); it!=end(); it++)
+ {
+ assert(pend-p >= 6);
+ gunichar c = g_unichar_tolower(*it);
+ gint n = g_unichar_to_utf8(c, p);
+ p += n;
+ len += n;
+ }
+ *p = '\0';
+ ret.stringSize = len+1;
+ return ret;
+}
+
+tiny_string tiny_string::uppercase() const
+{
+ // have to loop manually, because g_utf8_strup doesn't
+ // handle nul-chars
+ tiny_string ret;
+ uint32_t allocated = 2*numBytes()+7;
+ ret.createBuffer(allocated);
+ char *p = ret.buf;
+ uint32_t len = 0;
+ for (CharIterator it=begin(); it!=end(); it++)
+ {
+ assert(pend-p >= 6);
+ gunichar c = g_unichar_toupper(*it);
+ gint n = g_unichar_to_utf8(c, p);
+ p += n;
+ len += n;
+ }
+ *p = '\0';
+ ret.stringSize = len+1;
+ return ret;
+}
+
+/* like strcasecmp(s1.raw_buf(),s2.raw_buf()) but for unicode
+ * TODO: slow! */
+int tiny_string::strcasecmp(tiny_string& s2) const
+{
+ char* str1 = g_utf8_casefold(this->raw_buf(),this->numBytes());
+ char* str2 = g_utf8_casefold(s2.raw_buf(),s2.numBytes());
+ int ret = g_utf8_collate(str1,str2);
+ g_free(str1);
+ g_free(str2);
+ return ret;
+}
+
+uint32_t tiny_string::bytePosToIndex(uint32_t bytepos) const
+{
+ if (bytepos >= numBytes())
+ return numChars();
+
+ return g_utf8_pointer_to_offset(raw_buf(), raw_buf() + bytepos);
+}
+
+CharIterator tiny_string::begin()
+{
+ return CharIterator(buf);
+}
+
+CharIterator tiny_string::begin() const
+{
+ return CharIterator(buf);
+}
+
+CharIterator tiny_string::end()
+{
+ //points to the trailing '\0' byte
+ return CharIterator(buf+numBytes());
+}
+
+CharIterator tiny_string::end() const
+{
+ //points to the trailing '\0' byte
+ return CharIterator(buf+numBytes());
+}
+
+int tiny_string::compare(const tiny_string& r) const
+{
+ int l = std::min(stringSize,r.stringSize);
+ int res = 0;
+ for(int i=0;i < l-1;i++)
+ {
+ res = (int)buf[i] - (int)r.buf[i];
+ if (res != 0)
+ return res;
+ }
+ if (stringSize > r.stringSize)
+ res = 1;
+ else if (stringSize < r.stringSize)
+ res = -1;
+ return res;
+}
+
#ifdef MEMORY_USAGE_PROFILING
void tiny_string::reportMemoryChange(int32_t change) const
{
diff --git a/src/tiny_string.h b/src/tiny_string.h
index 8c05750..a8f18a7 100644
--- a/src/tiny_string.h
+++ b/src/tiny_string.h
@@ -56,8 +56,8 @@ public:
CharIterator operator++(int) // postfix
{
CharIterator result = *this;
- ++(*this);
- return result;
+ ++(*this);
+ return result;
}
bool operator==(const CharIterator& o) const
{
@@ -83,7 +83,7 @@ public:
* The string can contain '\0's, so don't use raw_buf().
* Use len() to determine actual size.
*/
-class tiny_string
+class DLL_PUBLIC tiny_string
{
friend std::ostream& operator<<(std::ostream& s, const tiny_string& r);
private:
@@ -105,224 +105,52 @@ private:
void reportMemoryChange(int32_t change) const {}
#endif
//TODO: use static buffer again if reassigning to short string
- void makePrivateCopy(const char* s)
- {
- resetToStatic();
- stringSize=strlen(s)+1;
- if(stringSize > STATIC_SIZE)
- createBuffer(stringSize);
- strcpy(buf,s);
- }
- void createBuffer(uint32_t s)
- {
- type=DYNAMIC;
- reportMemoryChange(s);
- buf=new char[s];
- }
- void resizeBuffer(uint32_t s)
- {
- assert(type==DYNAMIC);
- char* oldBuf=buf;
- reportMemoryChange(s-stringSize);
- buf=new char[s];
- assert(s >= stringSize);
- memcpy(buf,oldBuf,stringSize);
- delete[] oldBuf;
- }
- void resetToStatic()
- {
- if(type==DYNAMIC)
- {
- reportMemoryChange(-stringSize);
- delete[] buf;
- }
- stringSize=1;
- _buf_static[0] = '\0';
- buf=_buf_static;
- type=STATIC;
- }
+ void makePrivateCopy(const char* s);
+ void createBuffer(uint32_t s);
+ void resizeBuffer(uint32_t s);
+ void resetToStatic();
public:
static const uint32_t npos = (uint32_t)(-1);
tiny_string():_buf_static(),buf(_buf_static),stringSize(1),type(STATIC){buf[0]=0;}
/* construct from utf character */
- static tiny_string fromChar(uint32_t c)
- {
- tiny_string ret;
- ret.buf = ret._buf_static;
- ret.type = STATIC;
- ret.stringSize = g_unichar_to_utf8(c,ret.buf) + 1;
- ret.buf[ret.stringSize-1] = '\0';
- return ret;
- }
- tiny_string(const char* s,bool copy=false):_buf_static(),buf(_buf_static),type(READONLY)
- {
- if(copy)
- makePrivateCopy(s);
- else
- {
- stringSize=strlen(s)+1;
- buf=(char*)s; //This is an unsafe conversion, we have to take care of the RO data
- }
- }
- tiny_string(const tiny_string& r):_buf_static(),buf(_buf_static),stringSize(r.stringSize),type(STATIC)
- {
- //Fast path for static read-only strings
- if(r.type==READONLY)
- {
- type=READONLY;
- buf=r.buf;
- return;
- }
- if(stringSize > STATIC_SIZE)
- createBuffer(stringSize);
- memcpy(buf,r.buf,stringSize);
- }
- tiny_string(const std::string& r):_buf_static(),buf(_buf_static),stringSize(r.size()+1),type(STATIC)
- {
- if(stringSize > STATIC_SIZE)
- createBuffer(stringSize);
- memcpy(buf,r.c_str(),stringSize);
- }
+ static tiny_string fromChar(uint32_t c);
+ tiny_string(const char* s,bool copy=false);
+ tiny_string(const tiny_string& r);
+ tiny_string(const std::string& r);
tiny_string(const Glib::ustring& r);
tiny_string(std::istream& in, int len);
- ~tiny_string()
- {
- resetToStatic();
- }
- tiny_string& operator=(const tiny_string& s)
- {
- resetToStatic();
- stringSize=s.stringSize;
- //Fast path for static read-only strings
- if(s.type==READONLY)
- {
- type=READONLY;
- buf=s.buf;
- }
- else
- {
- if(stringSize > STATIC_SIZE)
- createBuffer(stringSize);
- memcpy(buf,s.buf,stringSize);
- }
- return *this;
- }
- tiny_string& operator=(const std::string& s)
- {
- resetToStatic();
- stringSize=s.size()+1;
- if(stringSize > STATIC_SIZE)
- createBuffer(stringSize);
- memcpy(buf,s.c_str(),stringSize);
- return *this;
- }
- tiny_string& operator=(const char* s)
- {
- makePrivateCopy(s);
- return *this;
- }
+ ~tiny_string();
+ tiny_string& operator=(const tiny_string& s);
+ tiny_string& operator=(const std::string& s);
+ tiny_string& operator=(const char* s);
tiny_string& operator=(const Glib::ustring& s);
tiny_string& operator+=(const char* s);
tiny_string& operator+=(const tiny_string& r);
- tiny_string& operator+=(const std::string& s)
- {
- //TODO: optimize
- return *this += tiny_string(s);
- }
+ tiny_string& operator+=(const std::string& s);
tiny_string& operator+=(const Glib::ustring& s);
- tiny_string& operator+=(uint32_t c)
- {
- return (*this += tiny_string::fromChar(c));
- }
+ tiny_string& operator+=(uint32_t c);
const tiny_string operator+(const tiny_string& r) const;
- const tiny_string operator+(const char* s) const
- {
- return *this + tiny_string(s);
- }
- const tiny_string operator+(const std::string& r) const
- {
- return *this + tiny_string(r);
- }
+ const tiny_string operator+(const char* s) const;
+ const tiny_string operator+(const std::string& r) const;
const tiny_string operator+(const Glib::ustring& r) const;
- bool operator<(const tiny_string& r) const
- {
- //don't check trailing \0
- return memcmp(buf,r.buf,std::min(stringSize,r.stringSize))<0;
- }
- bool operator>(const tiny_string& r) const
- {
- //don't check trailing \0
- return memcmp(buf,r.buf,std::min(stringSize,r.stringSize))>0;
- }
- bool operator==(const tiny_string& r) const
- {
- //The length is checked as an optimization before checking the contents
- if(stringSize != r.stringSize)
- return false;
- //don't check trailing \0
- return memcmp(buf,r.buf,stringSize-1)==0;
- }
- bool operator==(const std::string& r) const
- {
- //The length is checked as an optimization before checking the contents
- if(stringSize != r.size()+1)
- return false;
- //don't check trailing \0
- return memcmp(buf,r.c_str(),stringSize-1)==0;
- }
- bool operator!=(const std::string& r) const
- {
- if(stringSize != r.size()+1)
- return true;
- //don't check trailing \0
- return memcmp(buf,r.c_str(),stringSize-1)!=0;
- }
- bool operator!=(const tiny_string& r) const
- {
- return !(*this==r);
- }
- bool operator==(const char* r) const
- {
- return strcmp(buf,r)==0;
- }
- bool operator==(const xmlChar* r) const
- {
- return strcmp(buf,reinterpret_cast<const char*>(r))==0;
- }
- bool operator!=(const char* r) const
- {
- return !(*this==r);
- }
+ bool operator<(const tiny_string& r) const;
+ bool operator>(const tiny_string& r) const;
+ bool operator==(const tiny_string& r) const;
+ bool operator==(const std::string& r) const;
+ bool operator!=(const std::string& r) const;
+ bool operator!=(const tiny_string& r) const;
+ bool operator==(const char* r) const;
+ bool operator==(const xmlChar* r) const;
+ bool operator!=(const char* r) const;
bool operator==(const Glib::ustring&) const;
bool operator!=(const Glib::ustring&) const;
- const char* raw_buf() const
- {
- return buf;
- }
- bool empty() const
- {
- return stringSize == 1;
- }
+ const char* raw_buf() const;
+ bool empty() const;
/* returns the length in bytes, not counting the trailing \0 */
- uint32_t numBytes() const
- {
- return stringSize-1;
- }
+ uint32_t numBytes() const;
/* returns the length in utf-8 characters, not counting the trailing \0 */
- uint32_t numChars() const
- {
- //we cannot use g_utf8_strlen, as we may have '\0' inside our string
- uint32_t len = 0;
- char* end = buf+numBytes();
- char* p = buf;
- while(p < end)
- {
- p = g_utf8_next_char(p);
- ++len;
- }
- return len;
- }
+ uint32_t numChars() const;
/* start and len are indices of utf8-characters */
tiny_string substr(uint32_t start, uint32_t len) const;
tiny_string substr(uint32_t start, const CharIterator& end) const;
@@ -330,113 +158,34 @@ public:
tiny_string substr_bytes(uint32_t start, uint32_t len) const;
/* finds the first occurence of char in the utf-8 string
* Return NULL if not found, else ptr to beginning of first occurence of c */
- char* strchr(char c) const
- {
- //TODO: does this handle '\0' in middle of buf gracefully?
- return g_utf8_strchr(buf, numBytes(), c);
- }
- char* strchrr(char c) const
- {
- //TODO: does this handle '\0' in middle of buf gracefully?
- return g_utf8_strrchr(buf, numBytes(), c);
- }
- /*explicit*/ operator std::string() const
- {
- return std::string(buf,stringSize-1);
- }
+ char* strchr(char c) const;
+ char* strchrr(char c) const;
+ /*explicit*/ operator std::string() const;
operator Glib::ustring() const;
- bool startsWith(const char* o) const
- {
- return strncmp(buf,o,strlen(o)) == 0;
- }
- bool endsWith(const char* o) const
- {
- size_t olen = strlen(o);
- return (numBytes() >= olen) &&
- (strncmp(buf+numBytes()-olen,o,olen) == 0);
- }
+ bool startsWith(const char* o) const;
+ bool endsWith(const char* o) const;
/* idx is an index of utf-8 characters */
- uint32_t charAt(uint32_t idx) const
- {
- return g_utf8_get_char(g_utf8_offset_to_pointer(buf,idx));
- }
+ uint32_t charAt(uint32_t idx) const;
/* start is an index of characters.
* returns index of character */
- uint32_t find(const tiny_string& needle, uint32_t start = 0) const
- {
- //TODO: omit copy into std::string
- size_t bytestart = g_utf8_offset_to_pointer(buf,start) - buf;
- size_t bytepos = std::string(*this).find(needle.raw_buf(),bytestart,needle.numBytes());
- if(bytepos == std::string::npos)
- return npos;
- else
- return g_utf8_pointer_to_offset(buf,buf+bytepos);
- }
- uint32_t rfind(const tiny_string& needle, uint32_t start = npos) const
- {
- //TODO: omit copy into std::string
- size_t bytestart;
- if(start == npos)
- bytestart = std::string::npos;
- else
- bytestart = g_utf8_offset_to_pointer(buf,start) - buf;
-
- size_t bytepos = std::string(*this).rfind(needle.raw_buf(),bytestart,needle.numBytes());
- if(bytepos == std::string::npos)
- return npos;
- else
- return g_utf8_pointer_to_offset(buf,buf+bytepos);
- }
+ uint32_t find(const tiny_string& needle, uint32_t start = 0) const;
+ uint32_t rfind(const tiny_string& needle, uint32_t start = npos) const;
tiny_string& replace(uint32_t pos1, uint32_t n1, const tiny_string& o);
tiny_string& replace_bytes(uint32_t bytestart, uint32_t bytenum, const tiny_string& o);
- tiny_string lowercase() const
- {
- //TODO: omit copy, handle \0 in string
- char *strdown = g_utf8_strdown(buf,numBytes());
- tiny_string ret(strdown,/*copy:*/true);
- g_free(strdown);
- return ret;
- }
- tiny_string uppercase() const
- {
- //TODO: omit copy, handle \0 in string
- char *strup = g_utf8_strup(buf,numBytes());
- tiny_string ret(strup,/*copy:*/true);
- g_free(strup);
- return ret;
- }
- /* like strcasecmp(s1.raw_buf(),s2.raw_buf()) but for unicode
- * TODO: slow! */
- int strcasecmp(tiny_string& s2) const
- {
- char* str1 = g_utf8_casefold(this->raw_buf(),this->numBytes());
- char* str2 = g_utf8_casefold(s2.raw_buf(),s2.numBytes());
- int ret = g_utf8_collate(str1,str2);
- g_free(str1);
- g_free(str2);
- return ret;
- }
+ tiny_string lowercase() const;
+ tiny_string uppercase() const;
+ /* like strcasecmp(s1.raw_buf(),s2.raw_buf()) but for unicode */
+ int strcasecmp(tiny_string& s2) const;
/* split string at each occurrence of delimiter character */
std::list<tiny_string> split(uint32_t delimiter) const;
+ /* Convert from byte offset to UTF-8 character index */
+ uint32_t bytePosToIndex(uint32_t bytepos) const;
/* iterate over utf8 characters */
- CharIterator begin()
- {
- return CharIterator(buf);
- }
- CharIterator begin() const
- {
- return CharIterator(buf);
- }
- CharIterator end()
- {
- //points to the trailing '\0' byte
- return CharIterator(buf+numBytes());
- }
- CharIterator end() const
- {
- //points to the trailing '\0' byte
- return CharIterator(buf+numBytes());
- }
+ CharIterator begin();
+ CharIterator begin() const;
+ CharIterator end();
+ CharIterator end() const;
+ int compare(const tiny_string& r) const;
};
};
diff --git a/tests/encodeURI_test.mxml b/tests/encodeURI_test.mxml
index e00f7e3..d84daa7 100644
--- a/tests/encodeURI_test.mxml
+++ b/tests/encodeURI_test.mxml
@@ -14,15 +14,82 @@
var encodedStr:String = "0189ABYZabyz;/?:@&=+$,#-_.!~*'()%20%7B%7D&";
var lowerEncodedStr:String = "0189ABYZabyz;/?:@&=+$,#-_.!~*'()%20%7b%7d&";
Tests.assertEquals(encodedStr, encodeURI(decodedStr), "encodeURI(): standard encodeURI");
+ Tests.assertEquals("a%C3%A4o%C3%B6", encodeURI("aäoö"), "encodeURI(): UTF-8 string");
Tests.assertEquals(decodedStr, decodeURI(encodedStr), "deocdeURI(): standard decodeURI");
Tests.assertEquals(decodedStr, decodeURI(lowerEncodedStr), "decodeURI(): decode lowercase encoded string");
+ Tests.assertEquals("ABC %3B%2F%3F%3A%40%26%3D%2B%24%2C%23 DEF", decodeURI("ABC%20%3B%2F%3F%3A%40%26%3D%2B%24%2C%23%20DEF"), "decodeURI(): reserved characters are not decoded");
+ Tests.assertEquals("aäoö", decodeURI("a%C3%A4o%C3%B6"), "decodeURI(): UTF-8 string");
+
+ var actual:String = "no exception thrown";
+ try {
+ decodeURI("%3X");
+ } catch (e:URIError) {
+ actual="URIError";
+ } catch (e:Error) {
+ actual = "wrong Error";
+ }
+ Tests.assertEquals("URIError", actual, "decodeURI(): invalid percent encoding");
+
+ actual = "no exception thrown";
+ try {
+ decodeURI("%C0%80");
+ } catch (e:URIError) {
+ actual="URIError";
+ } catch (e:Error) {
+ actual = "wrong Error";
+ }
+ Tests.assertEquals("URIError", actual, "decodeURI(): invalid UTF-8 sequence");
+
+ actual = "no exception thrown";
+ try {
+ decodeURI("%C3xyz");
+ } catch (e:URIError) {
+ actual="URIError";
+ } catch (e:Error) {
+ actual = "wrong Error";
+ }
+ Tests.assertEquals("URIError", actual, "decodeURI(): truncated UTF-8 sequence");
decodedStr = "0189ABYZabyz;/?:@&=+$,#-_.!~*'() {}&";
encodedStr = "0189ABYZabyz%3B%2F%3F%3A%40%26%3D%2B%24%2C%23-_.!~*'()%20%7B%7D%26";
lowerEncodedStr = "0189ABYZabyz%3b%2f%3f%3a%40%26%3d%2b%24%2c%23-_.!~*'()%20%7b%7d%26";
Tests.assertEquals(encodedStr, encodeURIComponent(decodedStr), "encodeURIComponent(): standard encodeURIComponent");
+ Tests.assertEquals("a%C3%A4o%C3%B6", encodeURIComponent("aäoö"), "encodeURIComponent(): UTF-8 string");
Tests.assertEquals(decodedStr, decodeURIComponent(encodedStr), "deocdeURIComponent(): standard decodeURIComponent");
Tests.assertEquals(decodedStr, decodeURIComponent(lowerEncodedStr), "decodeURIComponent(): decode lowercase encoded string");
+ Tests.assertEquals("aäoö", decodeURIComponent("a%C3%A4o%C3%B6"), "decodeURIComponent(): UTF-8 string");
+
+ actual = "no exception thrown";
+ try {
+ decodeURIComponent("%3X");
+ } catch (e:URIError) {
+ actual="URIError";
+ } catch (e:Error) {
+ actual = "wrong Error";
+ }
+ Tests.assertEquals("URIError", actual, "decodeURIComponent(): invalid percent encoding");
+
+ actual = "no exception thrown";
+ try {
+ decodeURIComponent("%C0%80");
+ } catch (e:URIError) {
+ actual="URIError";
+ } catch (e:Error) {
+ actual = "wrong Error";
+ }
+ Tests.assertEquals("URIError", actual, "decodeURIComponent(): invalid UTF-8 sequence");
+
+ actual = "no exception thrown";
+ try {
+ decodeURIComponent("%C3xyz");
+ } catch (e:URIError) {
+ actual="URIError";
+ } catch (e:Error) {
+ actual = "wrong Error";
+ }
+ Tests.assertEquals("URIError", actual, "decodeURIComponent(): truncated UTF-8 sequence");
+
+
Tests.report(visual, this.name);
}
]]>
diff --git a/tests/make-tamarin b/tests/make-tamarin
index 3e5ff89..7c73243 100755
--- a/tests/make-tamarin
+++ b/tests/make-tamarin
@@ -5,6 +5,7 @@ echo "or ./make-tamarin ecma3/Boolean"
TAMARIN=${TAMARIN:-tamarin}
ASC=${ASC:-`pwd`/asc.jar}
+AVM=${AVM:-${TAMARIN}/objdir/shell/avmshell}
if [[ ! -d $TAMARIN ]]; then
echo "Directory tamarin not found, please run"
echo "hg clone http://hg.mozilla.org/tamarin-redux tamarin"
@@ -23,15 +24,111 @@ if [[ `java -jar $ASC | sed -n -e 's/version [^ ]* build \(.*\)/\1/p'` -lt 18513
exit 1
fi
-CUR=`pwd`
-
-#cd $TAMARIN/test/acceptance && \
-#rm -f ats_temp.abc ats_temp.as shell.as && \
-#echo "override| -optimize -in $CUR/tamarin-lightspark.as -AS3 -swf 200,200 -in ./ats_temp.as" > dir.asc_args && \
-#./runtests.py --asc $ASC --builtinabc ../../core/builtin.abc --shellabc ../../shell/shell_toplevel.abc --ats --atsdir $CUR/tamarin-SWF || exit 1
-(cd $TAMARIN/test/acceptance && \
-rm -f ats_temp.abc ats_temp.as shell.as && \
-grep USES_SWFVERSION . -R --files-with-matches | xargs --no-run-if-empty rm && \
-echo "override| -optimize -in $CUR/tamarin-lightspark.as -AS3 -swf 200,200 -in ./ats_temp.as" > dir.asc_args && \
-./runtests.py --asc $ASC --builtinabc ../../generated/builtin.abc --shellabc ../../generated/shell_toplevel.abc --ats --atsdir $CUR/tamarin-SWF $1) \
-|| echo "Compiling tests failed. Make sure you have the latest tamarin-redux and asc.jar from http://hg.mozilla.org/tamarin-redux and ftp://ftp.mozilla.org/pub/js/tamarin/builds/asc/latest/asc.jar, respectively."
+export CUR=`pwd`
+
+printCompileErrorAndExit()
+{
+ echo "Compiling tests failed. Make sure you have the latest tamarin-redux and asc.jar from http://hg.mozilla.org/tamarin-redux and ftp://ftp.mozilla.org/pub/js/tamarin/builds/asc/latest/asc.jar, respectively."
+ exit 1;
+}
+
+# compile tests from Tamarin before commit 7555
+makeTamarin1()
+{
+ (cd $TAMARIN/test/acceptance && \
+ rm -f ats_temp.abc ats_temp.as shell.as && \
+ grep USES_SWFVERSION . -R --files-with-matches | xargs --no-run-if-empty rm && \
+ echo "override| -optimize -in $CUR/tamarin-lightspark.as -AS3 -swf 200,200 -in ./ats_temp.as" > dir.asc_args && \
+ ./runtests.py --asc $ASC --builtinabc ../../generated/builtin.abc --shellabc ../../generated/shell_toplevel.abc --ats --atsdir $CUR/tamarin-SWF $1) \
+ || printCompileErrorAndExit;
+}
+
+# compile tests from Tamarin commit 7555 and later
+makeTamarin2()
+{
+ if [[ ! -f $AVM ]]; then
+ echo "Set shell variable AVM to point to avmshell executable"
+ exit 1
+ fi
+
+ java -jar $ASC -import $TAMARIN/generated/builtin.abc quit.as
+
+ cd $TAMARIN/test/acceptance
+ compiled=$(./runtests.py --asc $ASC --avm $AVM --builtinabc ../../generated/builtin.abc --shellabc ../../generated/shell_toplevel.abc --rebuildtests $1)
+ if [[ $? -ne 0 ]]; then
+ printCompileErrorAndExit;
+ fi
+
+ # The first sed selects lines starting with "compiling" unless the
+ # following lines starts with "Excluding".
+ #
+ # The second sed filters out some strange cases (TODO: check
+ # these!).
+ echo "$compiled" | \
+ sed -n '/^compiling/{N; /\nExcluding/ b excluded; P; D; b; :excluded d}' | \
+ sed -n '/ascompiling\|mmgc\/outofmemory\.as\|mmgc\/memlimit\.as\|bug_515935.as\|abc_$/!p' | \
+ sed -e 's/compiling \(.*\)/\1/' \
+ -e 's/\(.*\.\)[a-z]\+$/\1abc/' | \
+ xargs -L 1 bash -c 'linkTamarinTest $0'
+ cd -
+}
+
+# Sort classes in $TEST_SUPPORT in dependecy order: put interface
+# classes first and sort other classes alphabetically.
+function sortSupportClasses() {
+ local interfaces=$(echo "$TEST_SUPPORT" | tr " " "\n" | grep Interface)
+ local classes=$(echo "$TEST_SUPPORT" | tr " " "\n" | grep -v Interface | sort)
+ TEST_SUPPORT=$(echo "$interfaces $classes" | tr "\n" " ")
+}
+
+# Create a .swf for a Tamarin test case by figuring out which .abc
+# files belong to the test case and merging them.
+# Input: the name of test case's main .abc or .abs file
+function linkTamarinTest() {
+ shouldExcludeTest "$1"
+ local exclude_test=$?
+
+ if [[ -f "$1" && "$exclude_test" -eq 0 ]]; then
+ echo "Linking $1"
+
+ mkdir -p $CUR/tamarin-SWF/$(dirname $1)
+ OUTPUT_SWF="$CUR/tamarin-SWF/${1/%ab[cs]/swf}"
+
+ COMMON="Assert.abc Utils.abc"
+ ABS_SUPPORT=$(if [[ -f ${1/%abc/abs} ]]; then echo abcasm/abs_helper.abc; fi)
+ TEST_SUPPORT=$(if [[ -d ${1/%.abc/} ]]; then echo $(ls ${1/%.abc/}/*.abc 2> /dev/null); fi)
+ sortSupportClasses
+ ABC_FILES="$COMMON $TEST_SUPPORT $ABS_SUPPORT $1 $CUR/quit.abc"
+
+ $CUR/../tools/mergeABCtoSWF $ABC_FILES -o $OUTPUT_SWF
+ elif [[ "$exclude_test" -ne 0 ]]; then
+ echo "Excluding $1"
+ fi
+}
+
+# Exclude testcases that need imports from shell_toplevel (avmplus,
+# avmshell packages) until versioned identifiers are supported.
+function shouldExcludeTest() {
+ local asfile=${1/ab[cs]/as}
+ grep --quiet --no-messages "import avmplus\|import avmshell" "$asfile"
+ if [[ $? -eq 0 ]]; then
+ return 1
+ else
+ return 0
+ fi
+}
+
+export -f linkTamarinTest sortSupportClasses shouldExcludeTest
+
+if [[ "x$1" = "x" ]]; then
+ rm -rf tamarin-SWF/*
+fi
+
+# Tamarin testing framework changed in commit 7555 in a way that is
+# incompatible with previous version of this script. Use Assert.as, a
+# file introduced in that commit, to detect the new test setup.
+if [[ -f $TAMARIN/test/acceptance/Assert.as ]]; then
+ makeTamarin2;
+else
+ makeTamarin1;
+fi
diff --git a/tests/methodNamespace_test.mxml b/tests/methodNamespace_test.mxml
new file mode 100644
index 0000000..141714d
--- /dev/null
+++ b/tests/methodNamespace_test.mxml
@@ -0,0 +1,141 @@
+<?xml version="1.0"?>
+<mx:Application name="lightspark_methodNamespace_test"
+ xmlns:mx="http://www.adobe.com/2006/mxml"
+ layout="absolute"
+ applicationComplete="appComplete();"
+ backgroundColor="white">
+
+<mx:Script>
+ <![CDATA[
+ import Tests;
+ private function appComplete():void
+ {
+ namespace as3_ns = "http://adobe.com/AS3/2006/builtin";
+ namespace public_ns = "";
+
+ testMethods(Object.prototype, "Object prototype",
+ [["toString", public_ns, "exists"],
+ ["toString", as3_ns, "ReferenceError"]]);
+
+ testMethods(new Object(), "Object instance",
+ [["toString", public_ns, "exists"],
+ ["toString", as3_ns, "ReferenceError"]]);
+
+ testMethods(String.prototype, "String prototype",
+ [["toString", public_ns, "exists"],
+ ["toString", as3_ns, "ReferenceError"],
+ ["split", public_ns, "exists"],
+ ["split", as3_ns, "ReferenceError"]]);
+
+ testMethods(new String(""), "String instance",
+ [["toString", public_ns, "exists"],
+ ["toString", as3_ns, "exists"],
+ ["split", public_ns, "exists"],
+ ["split", as3_ns, "exists"]]);
+
+ testMethods(Number.prototype, "Number prototype",
+ [["toString", public_ns, "exists"],
+ ["toString", as3_ns, "ReferenceError"]]);
+
+ testMethods(new Number(0), "Number instance",
+ [["toString", public_ns, "exists"],
+ ["toString", as3_ns, "exists"]]);
+
+ testMethods(Boolean.prototype, "Boolean prototype",
+ [["toString", public_ns, "exists"],
+ ["toString", as3_ns, "ReferenceError"]]);
+
+ testMethods(new Boolean(), "Boolean instance",
+ [["toString", public_ns, "exists"],
+ ["toString", as3_ns, "exists"]]);
+
+ testMethods(Function.prototype, "Function prototype",
+ [["toString", public_ns, "exists"],
+ ["toString", as3_ns, "ReferenceError"],
+ ["call", public_ns, "exists"],
+ ["call", as3_ns, "exists"]]);
+
+ testMethods(function():void {}, "function instance",
+ [["toString", public_ns, "exists"],
+ ["toString", as3_ns, "ReferenceError"],
+ ["call", public_ns, "exists"],
+ ["call", as3_ns, "exists"]]);
+
+ testMethods(Math, "Math",
+ [["toString", public_ns, "exists"],
+ ["toString", as3_ns, "ReferenceError"]]);
+
+ testMethods(Error, "Error",
+ [["toString", public_ns, "exists"],
+ ["toString", as3_ns, "ReferenceError"]]);
+
+ testMethods(new Error(), "Error instance",
+ [["toString", public_ns, "exists"],
+ ["toString", as3_ns, "ReferenceError"]]);
+
+ testMethods(Date, "Date",
+ [["toString", public_ns, "exists"],
+ ["toString", as3_ns, "ReferenceError"]]);
+
+ testMethods(new Date(), "Date",
+ [["toString", public_ns, "exists"],
+ ["toString", as3_ns, "exists"]]);
+
+ testMethods(RegExp.prototype, "RegExp prototype",
+ [["toString", public_ns, "exists"],
+ ["toString", as3_ns, "ReferenceError"],
+ ["exec", public_ns, "exists"],
+ ["exec", as3_ns, "exists"]]);
+
+ testMethods(new RegExp(), "RegExp instance",
+ [["toString", public_ns, "exists"],
+ ["toString", as3_ns, "ReferenceError"],
+ ["exec", public_ns, "exists"],
+ ["exec", as3_ns, "exists"]]);
+
+ testMethods(Vector.prototype, "Vector prototype",
+ [["toString", public_ns, "exists"],
+ ["toString", as3_ns, "ReferenceError"],
+ ["every", public_ns, "undefined"],
+ ["every", as3_ns, "ReferenceError"]]);
+
+ testMethods(new Vector.<int>(), "Vector instance",
+ [["toString", public_ns, "exists"],
+ ["toString", as3_ns, "exists"],
+ ["every", public_ns, "exists"],
+ ["every", as3_ns, "exists"]]);
+
+ Tests.report(visual, this.name);
+ }
+
+ private function testMethods(obj:*, testName:String, methodsAndExpectedResults:Array):void {
+ for (var i:int=0; i<methodsAndExpectedResults.length; i++) {
+ var method:String = methodsAndExpectedResults[i][0];
+ var ns:Namespace = methodsAndExpectedResults[i][1];
+ var expected:String = methodsAndExpectedResults[i][2];
+ var s:String = checkMethodExists(obj, ns, method);
+ var name:String = ns.toString() + "::" + method + " on " + testName;
+ Tests.assertEquals(expected, s, name);
+ }
+ }
+
+ private function checkMethodExists(obj:*, ns:Namespace, method:String):String {
+ var result:String = "exists";
+ try {
+ var f:* = obj.ns::[method];
+ if (f == undefined) {
+ result = "undefined";
+ }
+ } catch(e:ReferenceError) {
+ result = "ReferenceError";
+ } catch(e:Error) {
+ result = e.toString();
+ }
+ return result;
+ }
+ ]]>
+</mx:Script>
+
+<mx:UIComponent id="visual" />
+
+</mx:Application>
diff --git a/tests/quit.as b/tests/quit.as
new file mode 100644
index 0000000..368487a
--- /dev/null
+++ b/tests/quit.as
@@ -0,0 +1,2 @@
+namespace flashsystemns = "flash.system";
+flashsystemns::fscommand("quit");
diff --git a/tests/tests b/tests/tests
index e57dccd..e89bbc5 100755
--- a/tests/tests
+++ b/tests/tests
@@ -33,6 +33,56 @@ BLACKLIST=0;
JUNITFILE=""
NOXVFB=0;
+# Convert output from local and pre-7555 commit Tamarin testcases to JUnit XML
+function writeJUnit1() {
+ tcnum=0
+ #Find all lines that start with '. [' or 'F [' or 'A ..F.. ['
+ tcnum=$(echo "$1" | sed -n -e "/^\(A \)\?[F\.]\+ \[.*/p" \
+ | { while read L
+ do
+ tcnum=`expr $tcnum + 1`
+ #Escape <>& and remove non-printable characters
+ xml_l=`echo -e "$L" | sed -e 's/[^[:print:]]//g' -e 's/\&/\&/g' -e 's/</\</g' -e 's/>/\>/g'`
+ #Check if L starts with an 'F' or with 'A ...F'
+ if echo -e "$L" | grep -e "^\(A \.*\)\?F" > /dev/null ; then
+ echo "<testcase classname=\"$2\" name=\"${3}_tc${tcnum}\"><failure type=\"testfailure\">$xml_l</failure></testcase>" >> "$JUNITFILE"
+ else
+ echo "<testcase classname=\"$2\" name=\"${3}_tc${tcnum}\"/>" >> "$JUNITFILE"
+ fi
+ done
+ echo $tcnum
+ })
+
+ if [[ "$tcnum" != "$4" ]]; then
+ echo -e "\nError parsing test output of $test: Not enough testcases seen"
+ exit 1
+ fi
+}
+
+# Convert output from post-7555 commit Tamarin to JUnit XML
+function writeJUnit2() {
+ tcnum=0
+ tcnum=$(echo "$1" | grep 'PASSED!\|FAILED!' \
+ | { while read L
+ do
+ tcnum=`expr $tcnum + 1`
+ #Escape <>& and remove non-printable characters
+ xml_l=`echo -e "$L" | sed -e 's/[^[:print:]]//g' -e 's/\&/\&/g' -e 's/</\</g' -e 's/>/\>/g'`
+ if echo "$L" | grep 'FAILED!' > /dev/null ; then
+ echo "<testcase classname=\"$2\" name=\"${3}_tc${tcnum}\"><failure type=\"testfailure\">$xml_l</failure></testcase>" >> "$JUNITFILE"
+ else
+ echo "<testcase classname=\"$2\" name=\"${3}_tc${tcnum}\"/>" >> "$JUNITFILE"
+ fi
+ done
+ echo $tcnum
+ })
+
+ if [[ "$tcnum" != "$4" ]]; then
+ echo -e "\nError parsing test output of $test: Not enough testcases seen"
+ exit 1
+ fi
+}
+
if ! `which timeout > /dev/null`; then
echo "Warning: 'timeout' command not found"
TIMEOUTCMD=""
@@ -182,7 +232,7 @@ if [ $COMPILE -eq 1 ]; then
echo -e "\n" 1>&2;
fi
-FAILURECOUNT=0; SUCCESSCOUNT=0; TESTCOUNT=0;
+FAILURECOUNT=0; SUCCESSCOUNT=0; TESTCOUNT=0; EXITEDCOUNT=0; ALLSUCCESSCOUNT=0; NOSUMMARYCOUNT=0;
#Colors used for colorization
CLEAR='\\\e[0m';
@@ -283,15 +333,21 @@ for test in $TESTS; do
fi
fi
if [[ -n "$JUNITFILE" ]]; then
- echo "<testcase classname=\"$testclass\" name=\"$testname\"><failure type=\"exitvalue\">Exit Value $ev</failure></testcase>" >> "$JUNITFILE"
+ if [[ "$ev" = "124" ]]; then
+ echo "<testcase classname=\"$testclass\" name=\"$testname\"><failure type=\"timeout\">Timeout</failure></testcase>" >> "$JUNITFILE"
+ else
+ echo "<testcase classname=\"$testclass\" name=\"$testname\"><failure type=\"exitvalue\">Exit Value $ev</failure></testcase>" >> "$JUNITFILE"
+ fi
fi
FAILURECOUNT=`expr $FAILURECOUNT + 1`;
FAILED_TESTS="$FAILED_TESTS $test"
+ EXITEDCOUNT=`expr $EXITEDCOUNT + 1`
continue
fi
#Remove the RANDR error when running under xvfb, convert control characters to something like \303
lines=`sed -e '/Xlib: extension "RANDR" missing on display.*/d' -e 's/[[:cntrl:]]//' $LOGFILE`
if [ "`echo $lines | grep '==Failures'`" != "" ]; then
+ # local tests and Tamarin before commit 7555
THISFAILEDCOUNT=`echo "$lines" | sed -n -e 's/.*=Failures (\(.*\)\/.*)=.*/\1/p'`
THISNUMTESTS=`echo "$lines" | sed -n -e 's/.*=Failures (.*\/\(.*\))=.*/\1/p'`
THISSUCCESSCOUNT=`expr $THISNUMTESTS - $THISFAILEDCOUNT`
@@ -299,9 +355,22 @@ for test in $TESTS; do
SUCCESSCOUNT=`expr $SUCCESSCOUNT + $THISSUCCESSCOUNT`;
FAILED_TESTS="$FAILED_TESTS $test"
elif [ "`echo $lines | grep '==No failures'`" != "" ]; then
+ # local tests and Tamarin before commit 7555
THISSUCCESSCOUNT=`echo "$lines" | sed -n -e 's/.*=No failures (\(.*\))=.*/\1/p'`
THISNUMTESTS="$THISSUCCESSCOUNT"
SUCCESSCOUNT=`expr $SUCCESSCOUNT + $THISSUCCESSCOUNT`;
+ ALLSUCCESSCOUNT=`expr $ALLSUCCESSCOUNT + 1`
+ elif [ "`echo $lines | grep 'PASSED!\|FAILED!'`" != "" ]; then
+ # Tamarin commit 7555 and later
+ THISSUCCESSCOUNT=`echo "$lines" | grep -c 'PASSED!'`
+ THISFAILEDCOUNT=`echo "$lines" | grep -c 'FAILED!'`
+ THISNUMTESTS=`expr $THISSUCCESSCOUNT + $THISFAILEDCOUNT`
+ FAILURECOUNT=`expr $FAILURECOUNT + $THISFAILEDCOUNT`;
+ SUCCESSCOUNT=`expr $SUCCESSCOUNT + $THISSUCCESSCOUNT`;
+ FAILED_TESTS="$FAILED_TESTS $test"
+ if [ $THISFAILEDCOUNT -eq 0 ]; then
+ ALLSUCCESSCOUNT=`expr $ALLSUCCESSCOUNT + 1`
+ fi
else
if [ $COLORS -eq 1 ]; then
echo -e "\\e[0;31m$test printed no test summary!\\e[0m"
@@ -313,31 +382,15 @@ for test in $TESTS; do
fi
FAILURECOUNT=`expr $FAILURECOUNT + 1`;
FAILED_TESTS="$FAILED_TESTS $test"
+ NOSUMMARYCOUNT=`expr $NOSUMMARYCOUNT + 1`
continue
fi
if [[ -n "$JUNITFILE" ]]; then
- #For xml output
- tcnum=0
- #Find all lines that start with '. [' or 'F [' or 'A ..F.. ['
- tcnum=$(echo "$lines" | sed -n -e "/^\(A \)\?[F\.]\+ \[.*/p" \
- | { while read L
- do
- tcnum=`expr $tcnum + 1`
- #Escape <>& and remove non-printable characters
- xml_l=`echo -e "$L" | sed -e 's/[^[:print:]]//g' -e 's/\&/\&/g' -e 's/</\</g' -e 's/>/\>/g'`
- #Check if L starts with an 'F' or with 'A ...F'
- if echo -e "$L" | grep -e "^\(A \.*\)\?F" > /dev/null ; then
- echo "<testcase classname=\"$testclass\" name=\"${testname}_tc${tcnum}\"><failure type=\"testfailure\">$xml_l</failure></testcase>" >> "$JUNITFILE"
- else
- echo "<testcase classname=\"$testclass\" name=\"${testname}_tc${tcnum}\"/>" >> "$JUNITFILE"
- fi
- done
- echo $tcnum
- })
- if [[ "$tcnum" != "$THISNUMTESTS" ]]; then
- echo -e "\nError parsing test output of $test: Not enough testcases seen"
- exit 1
+ if [[ "`echo $lines | grep '==Failures\|==No failures'`" != "" ]]; then
+ writeJUnit1 "$lines" "$testclass" "$testname" "$THISNUMTESTS"
+ else
+ writeJUnit2 "$lines" "$testclass" "$testname" "$THISNUMTESTS"
fi
fi
@@ -399,7 +452,13 @@ if [ $PROPRIETARY -eq 0 ]; then
fi
if [ $COLORS -eq 1 ]; then
- echo -e "Tests run: $TESTCOUNT, \e[1;32m$SUCCESSCOUNT successful\e[0m and \e[1;31m$FAILURECOUNT failed\e[0m" 1>&2
+ echo -e "\e[1;36mTEST SUMMARY:" 1>&2
+ echo -e "$TESTCOUNT tests\e[0m were run, of which \e[1;32m`expr $TESTCOUNT - $EXITEDCOUNT` finished\e[0m and \e[1;31m$EXITEDCOUNT exited prematurely\e[0m." 1>&2
+ echo -e "\e[1;36m`expr $SUCCESSCOUNT + $FAILURECOUNT` single test cases\e[0m were performed: \e[1;32m$SUCCESSCOUNT were successful\e[0m and \e[1;31m$FAILURECOUNT failed\e[0m (\e[1;36m`expr $SUCCESSCOUNT \* 100 / \( $SUCCESSCOUNT + $FAILURECOUNT \)`% success rate\e[0m)." 1>&2
+ echo -e "\e[1;32m$ALLSUCCESSCOUNT tests passed every single test case\e[0m, while \e[1;31m$NOSUMMARYCOUNT didn't print a test summary\e[0m." 1>&2
else
- echo -e "Tests run: $TESTCOUNT, $SUCCESSCOUNT successful and $FAILURECOUNT failed" 1>&2
+ echo -e "TEST SUMMARY:" 1>&2
+ echo -e "$TESTCOUNT tests were run, of which `expr $TESTCOUNT - $EXITEDCOUNT` finished and $EXITEDCOUNT exited prematurely." 1>&2
+ echo -e "`expr $SUCCESSCOUNT + $FAILURECOUNT` single test cases were performed: $SUCCESSCOUNT were successful and $FAILURECOUNT failed (`expr $SUCCESSCOUNT \* 100 / \( $SUCCESSCOUNT + $FAILURECOUNT \)`% success rate)." 1>&2
+ echo -e "$ALLSUCCESSCOUNT tests passed every single test case, while $NOSUMMARYCOUNT didn't print a test summary." 1>&2
fi
diff --git a/tools/langref_parser b/tools/langref_parser
index 88849c9..5d470cd 100755
--- a/tools/langref_parser
+++ b/tools/langref_parser
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/python2
#This greps the source for SET_NAMESPACE, REGISTER_CLASS_NAME2,
#sinit definition and the following ->set{Getter,Setter,Method}ByQName calls
@@ -21,7 +21,7 @@ if len(sys.argv) < 2:
print("Call by langref_parser langref-directory")
print("If you do not have a langref directory,")
print("please download http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/standalone.zip")
- print("and unpack it.")
+ print("and unpack it.")
exit(1)
langref = sys.argv[1]
@@ -71,10 +71,11 @@ for dirpath, dirnames, filenames in os.walk(langref):
if m:
if dirpath==langref:
curClass = m.group(1)
+ isConst = False
else:
curClass = dirpath.replace("langref/","").replace("/",".") +"."+ m.group(1)
- dclasses.add(curClass)
- isConst = False
+ dclasses.add(curClass)
+ isConst = False
break
m = regconst.search(line)
if m:
@@ -84,7 +85,7 @@ for dirpath, dirnames, filenames in os.walk(langref):
#there may be another match on this line
m = regproperty.search(line)
if m:
- name = m.group(1)
+ name = m.group(1).replace("#","").replace("(","").replace(")","")
isOverride = m.group(2) != None
isStatic = m.group(3) != None
isReadOnly = m.group(4) != None
@@ -94,7 +95,7 @@ for dirpath, dirnames, filenames in os.walk(langref):
continue
m = regmethod.search(line)
if m:
- name = m.group(1)
+ name = m.group(1).replace("#","").replace("(","").replace(")","")
dmethods.add((curClass,name))
line = line[m.end():]
continue
diff --git a/tools/mergeABCtoSWF b/tools/mergeABCtoSWF
new file mode 100755
index 0000000..9e2b5be
--- /dev/null
+++ b/tools/mergeABCtoSWF
@@ -0,0 +1,134 @@
+#!/usr/bin/python
+
+# Copyright (C) 2013 Antti Ajanki (antti.ajanki at iki.fi)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# This script merges one or more ABC files into a simple SWF wrapper.
+#
+# Usage: mergeABCtoSWF abcFile1 [abcFile2 ...] [-o outputSWFFile]
+#
+# The ABC files should be in dependency order, files that provide
+# functions should be listed before files that use those functions.
+
+import struct
+import sys
+import os.path
+from optparse import OptionParser
+
+class SWFFile:
+ TAG_END = 0
+ TAG_SHOW_FRAME = 1
+ TAG_FILE_ATTRIBUTES = 69
+ TAG_DOABC = 82
+
+ ATTR_HAS_AS3 = 8
+
+ # RECT 8000x6000
+ DEFAULT_RECT = '\x78\x00\x03\xe8\x00\x00\x0b\xb8\x00'
+
+ def __init__(self, filename):
+ self.file = open(filename, 'wb')
+ self.writeSWFHeader()
+
+ def writeSWFHeader(self):
+ self.file.write('FWS')
+ # version
+ self.file.write(chr(9))
+ # length, will be set in finalize
+ self.file.write('\0'*4)
+ # rect size in twips
+ self.file.write(self.DEFAULT_RECT)
+ # framerate
+ self.writeUI16(20 << 8)
+ # frame count
+ self.writeUI16(1)
+ self.addFileAttributesTag()
+
+ def finalize(self):
+ self.addShowFrameTag()
+ self.addEndTag()
+ self.updateSize()
+ self.file.close()
+ self.file = None
+
+ def addFileAttributesTag(self):
+ body = chr(self.ATTR_HAS_AS3) + '\0'*3
+ self.writeTag(self.TAG_FILE_ATTRIBUTES, body)
+
+ def addABCBlock(self, abc):
+ body = '\0'*4 # flags
+ body += '\0' # name
+ body += abc
+ self.writeTag(self.TAG_DOABC, body)
+
+ def addShowFrameTag(self):
+ self.writeTag(self.TAG_SHOW_FRAME, '')
+
+ def addEndTag(self):
+ self.file.write('\0\0')
+
+ def writeTag(self, tagType, body):
+ #print 'tag %d at %d length %s' % (tagType, self.file.tell(), len(body))
+ self.writeTagHeader(tagType, len(body))
+ self.file.write(body)
+
+ def writeTagHeader(self, tagType, tagLength):
+ assert (tagType & 0x3FF) == tagType
+ if tagLength >= 0x3F:
+ self.writeUI16((tagType << 6) | 0x3F)
+ self.writeSI32(tagLength)
+ else:
+ self.writeUI16((tagType << 6) | tagLength)
+
+ def updateSize(self):
+ size = self.file.tell()
+ self.file.seek(4, 0)
+ self.writeSI32(size)
+ self.file.seek(0, 2)
+
+ def writeUI16(self, value):
+ self.file.write(struct.pack('<H', value))
+
+ def writeSI32(self, value):
+ self.file.write(struct.pack('<i', value))
+
+
+def parseParameters():
+ usage = 'usage: %prog abcFile1 [abcFile2 ...] [-o outputSWFFile]'
+ parser = OptionParser(usage=usage)
+ parser.add_option('-o', dest='output',
+ help='Name of the output SWF file')
+ (options, abcFiles) = parser.parse_args()
+
+ if not abcFiles:
+ print 'ABC filenames required'
+ sys.exit(1)
+
+ if options.output:
+ SWF = options.output
+ else:
+ SWF = os.path.splitext(abcFiles[-1])[0] + '.swf'
+
+ return (abcFiles, SWF)
+
+def main():
+ abcfiles, swfFileName = parseParameters()
+ swf = SWFFile(swfFileName)
+ for abc in abcfiles:
+ swf.addABCBlock(open(abc).read())
+ swf.finalize()
+
+if __name__ == '__main__':
+ main()
diff --git a/tools/pygil b/tools/pygil
index c6c0cd5..02e3662 100755
--- a/tools/pygil
+++ b/tools/pygil
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/python2
#This greps the source for SET_NAMESPACE, REGISTER_CLASS_NAME2,
#sinit definition and the following ->set{Getter,Setter,Method}ByQName calls
@@ -13,9 +13,10 @@ import pickle
#These regexp are used for finding important pieces in the source
sinit = re.compile('.*void\s*(\w*)::sinit\(.*')
-rconstructor = re.compile('[^/]*->setConstructor\(NULL|Class<IFunction>::getFunction\([^)]*\)\).*')
+rconstructor = re.compile('[^/]*ASFUNCTIONBODY\([^,]*, *\_constructor\)')
#looks like builtin->registerBuiltin("Capabilities","flash.system",Class<Capabilities>::getRef());
rclass = re.compile('.*builtin->registerBuiltin\( *"([^"]*)", *"([^"]*)", *Class<([^>]*)>::getRef\(\)\)')
+rtemplateclass = re.compile('.*builtin->registerBuiltin\( *"([^"]*)", *"([^"]*)", *_MR\(Template<([^>]*)>::getTemplate\(\)\)\)')
rinterfaceclass = re.compile('.*builtin->registerBuiltin\( *"([^"]*)", *"([^"]*)", *InterfaceClass<([^>]*)>::getRef\(\)\)')
#looks like builtin->registerBuiltin("Socket","flash.net",Class<ASObject>::getStubClass(QName("Socket","flash.net")));
rstupclass = re.compile('.*builtin->registerBuiltin\( *"([^"]*)", *"([^"]*)", *Class<ASObject>::getStubClass\(QName.*')
@@ -27,7 +28,8 @@ rget2 = re.compile('.*REGISTER_GETTER\([^,]*, *(.*)\)')
rset2 = re.compile('.*REGISTER_SETTER\([^,]*, *(.*)\)')
rgetset2 = re.compile('.*REGISTER_GETTER_SETTER\([^,]*, *(.*)\)')
#Constant names do not contain lower-case letters
-rconst = re.compile('[^/]*->setVariableByQName\("([A-Z_]*)",.*_TRAIT');
+rconst = re.compile('[^/]*->setVariableByQName\("([A-Z_0-9]*)",.*_TRAIT');
+rcomment = re.compile('[ \t]*/')
def getFullname(cls,name):
if cls != "":
@@ -54,10 +56,15 @@ curClass = ""
f = open('../src/scripting/abc.cpp','r')
for line in f.read().replace("\n","").replace("\t"," ").split(";"):
m = rclass.match(line)
- if m:
+ if m:
fullname = getFullname(m.group(2),m.group(1))
internalToExternal[m.group(3)] = fullname
classes.add(fullname)
+ m = rtemplateclass.match(line)
+ if m:
+ fullname = getFullname("",m.group(1))
+ internalToExternal[m.group(3)] = fullname
+ classes.add(fullname)
m = rinterfaceclass.match(line)
if m:
fullname = getFullname(m.group(2),m.group(1))
@@ -81,7 +88,14 @@ p1 = Popen(["find", "..", "-name",'*.cpp'], stdout=PIPE)
p2 = Popen(["xargs","cat"], stdin=p1.stdout, stdout=PIPE);
p1.stdout.close()
-for line in p2.communicate()[0].split(";"):
+ptmp =""
+for line in p2.communicate()[0].split("\n"):
+ m = rcomment.match(line)
+ if m:
+ continue
+ ptmp = ptmp + line
+
+for line in ptmp.split(";"):
line = line.replace("\n","").rstrip().rstrip();
m = sinit.match(line)
if m:
--
Alioth's hooks/post-receive on /srv/git.debian.org/git/pkg-flash/lightspark.git
More information about the pkg-flash-devel
mailing list