diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..53e7ee8
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,12 @@
+Native/BytecodeEditor/Release
+Native/BytecodeEditor/Debug
+Native/BytecodeEditor/AdobeAIRSDK
+Native/BytecodeEditor/.vs
+Native/BytecodeEditor/.vscode
+Native/BytecodeEditor/BytecodeEditor.vcxproj.filters
+Native/BytecodeEditor/BytecodeEditor.vcxproj.user
+*.swc
+*.swf
+*.dll
+AS3/bin
+AS3/obj
diff --git a/ANEBytecodeEditor.ane b/ANEBytecodeEditor.ane
new file mode 100644
index 0000000..e719347
Binary files /dev/null and b/ANEBytecodeEditor.ane differ
diff --git a/AS3/ANEBytecodeEditorSWC.as3proj b/AS3/ANEBytecodeEditorSWC.as3proj
new file mode 100644
index 0000000..2da0727
--- /dev/null
+++ b/AS3/ANEBytecodeEditorSWC.as3proj
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ "$(BaseDir)\Tools\swcbuild\swcbuild.exe" "$(ProjectPath)" "-compiler=$(CompilerPath)" "-debug=$(BuildConfig)" "-library=C:\Program Files (x86)\FlashDevelop\Library" -asdoc=true -keep-asdoc=false
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/AS3/src/com/cff/anebe/AssemblyDoneEvent.as b/AS3/src/com/cff/anebe/AssemblyDoneEvent.as
new file mode 100644
index 0000000..b1722f4
--- /dev/null
+++ b/AS3/src/com/cff/anebe/AssemblyDoneEvent.as
@@ -0,0 +1,32 @@
+package com.cff.anebe
+{
+ import flash.events.Event;
+ import flash.utils.ByteArray;
+
+ /**
+ * ...
+ * @author Chris
+ */
+ public class AssemblyDoneEvent extends Event
+ {
+ public var assembled:ByteArray;
+
+ public function AssemblyDoneEvent(assembled:ByteArray, bubbles:Boolean=false, cancelable:Boolean=false)
+ {
+ super(Events.ASSEMBLY_DONE, bubbles, cancelable);
+ this.assembled = assembled;
+ }
+
+ public override function clone():Event
+ {
+ return new AssemblyDoneEvent(assembled, bubbles, cancelable);
+ }
+
+ public override function toString():String
+ {
+ return formatToString("AssemblyDoneEvent", "type", "bubbles", "cancelable", "eventPhase");
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/AS3/src/com/cff/anebe/BytecodeEditor.as b/AS3/src/com/cff/anebe/BytecodeEditor.as
new file mode 100644
index 0000000..bea49b3
--- /dev/null
+++ b/AS3/src/com/cff/anebe/BytecodeEditor.as
@@ -0,0 +1,367 @@
+package com.cff.anebe
+{
+ import flash.events.EventDispatcher;
+ import flash.events.StatusEvent;
+ import flash.external.ExtensionContext;
+ import flash.utils.ByteArray;
+ import flash.utils.CompressionAlgorithm;
+ /**
+ * ...
+ * @author Chris
+ */
+ public class BytecodeEditor extends EventDispatcher
+ {
+ private var extContext:ExtensionContext;
+
+ public function BytecodeEditor()
+ {
+ extContext = ExtensionContext.createExtensionContext("com.cff.anebe.ANEBytecodeEditor", "");
+ extContext.addEventListener(StatusEvent.STATUS, this.onStatusEvent);
+ }
+
+ // Disassembles SWF into a map of file name to file contents
+ public function Disassemble(swf:ByteArray):Object
+ {
+ swf.position = 0;
+ var decompressor:ByteArray = new ByteArray();
+ switch (swf.readUTFBytes(1))
+ {
+ case "F":
+ swf.position = 0;
+ break;
+ case "C":
+ swf.position = 8;
+ swf.readBytes(decompressor);
+ swf.position = 8;
+ decompressor.uncompress(CompressionAlgorithm.ZLIB);
+ swf.writeBytes(decompressor);
+ swf.position = 0;
+ swf.writeUTFBytes("F");
+ swf.position = 0;
+ decompressor = null;
+ break;
+ case "Z":
+ swf.position = 8;
+ swf.readBytes(decompressor, 8);
+ swf.position = 8;
+ decompressor.uncompress(CompressionAlgorithm.LZMA);
+ swf.writeBytes(decompressor);
+ swf.position = 0;
+ swf.writeUTFBytes("F");
+ swf.position = 0;
+ decompressor = null;
+ break;
+ default:
+ throw new Error("Unrecognized compression scheme for SWF");
+ }
+
+ var ret:Object = extContext.call("SetCurrentSWF", swf);
+
+ if (ret == null)
+ {
+ throw new Error("Unknown error occurred while setting SWF");
+ }
+ else if (ret is String)
+ {
+ throw new Error(ret);
+ }
+ else // returned Boolean
+ {
+ if (!(ret as Boolean))
+ {
+ throw new Error("SetCurrentSWF returned false somehow");
+ }
+ else
+ {
+ ret = extContext.call("Disassemble");
+
+ if (ret == null)
+ {
+ throw new Error("Unknown error occurred");
+ }
+ else if (ret is String)
+ {
+ throw new Error(ret);
+ }
+ else
+ {
+ return ret;
+ }
+ }
+ }
+ }
+
+ // Assembles an SWF from a map of file name to file contents. If replaceSWF is unspecified, and Disassemble was called, uses
+ // the last SWF's data for the rest of the SWF.
+ public function Assemble(strings:Object, replaceSWF:ByteArray = null):ByteArray
+ {
+ if (replaceSWF != null)
+ {
+ replaceSWF.position = 0;
+ var decompressor:ByteArray = new ByteArray();
+ switch (replaceSWF.readUTFBytes(1))
+ {
+ case "F":
+ replaceSWF.position = 0;
+ break;
+ case "C":
+ replaceSWF.position = 8;
+ replaceSWF.readBytes(decompressor);
+ replaceSWF.position = 8;
+ decompressor.uncompress(CompressionAlgorithm.ZLIB);
+ replaceSWF.writeBytes(decompressor);
+ replaceSWF.position = 0;
+ replaceSWF.writeUTFBytes("F");
+ replaceSWF.position = 0;
+ decompressor = null;
+ break;
+ case "Z":
+ replaceSWF.position = 8;
+ replaceSWF.readBytes(decompressor, 8);
+ replaceSWF.position = 8;
+ decompressor.uncompress(CompressionAlgorithm.LZMA);
+ replaceSWF.writeBytes(decompressor);
+ replaceSWF.position = 0;
+ replaceSWF.writeUTFBytes("F");
+ replaceSWF.position = 0;
+ decompressor = null;
+ break;
+ default:
+ throw new Error("Unrecognized compression scheme for SWF");
+ }
+
+ var ret:Object = extContext.call("SetCurrentSWF", replaceSWF);
+
+ if (ret == null)
+ {
+ throw new Error("Unknown error occurred while setting SWF");
+ }
+ else if (ret is String)
+ {
+ throw new Error(ret);
+ }
+ else // returned Boolean
+ {
+ if (!(ret as Boolean))
+ {
+ throw new Error("SetCurrentSWF returned false somehow");
+ }
+ }
+ }
+
+ var vec:Vector. = new [];
+ for (var str:String in strings)
+ {
+ vec[vec.length] = str;
+ }
+
+ ret = extContext.call("Assemble", strings, vec);
+
+ if (ret == null)
+ {
+ throw new Error("Unknown error occurred");
+ }
+ else if (ret is String)
+ {
+ throw new Error(ret);
+ }
+ else // byte array was returned
+ {
+ return ret as ByteArray;
+ }
+ }
+
+ // Disassembles SWF into a map of file name to file contents, asynchronously
+ public function DisassembleAsync(swf:ByteArray):void
+ {
+ swf.position = 0;
+ var decompressor:ByteArray = new ByteArray();
+ switch (swf.readUTFBytes(1))
+ {
+ case "F":
+ swf.position = 0;
+ break;
+ case "C":
+ swf.position = 8;
+ swf.readBytes(decompressor);
+ swf.position = 8;
+ decompressor.uncompress(CompressionAlgorithm.ZLIB);
+ swf.writeBytes(decompressor);
+ swf.position = 0;
+ swf.writeUTFBytes("F");
+ swf.position = 0;
+ decompressor = null;
+ break;
+ case "Z":
+ swf.position = 8;
+ swf.readBytes(decompressor, 8);
+ swf.position = 8;
+ decompressor.uncompress(CompressionAlgorithm.LZMA);
+ swf.writeBytes(decompressor);
+ swf.position = 0;
+ swf.writeUTFBytes("F");
+ swf.position = 0;
+ decompressor = null;
+ break;
+ default:
+ throw new Error("Unrecognized compression scheme for SWF");
+ }
+
+ var ret:Object = extContext.call("SetCurrentSWF", swf);
+
+ if (ret == null)
+ {
+ throw new Error("Unknown error occurred while setting SWF");
+ }
+ else if (ret is String)
+ {
+ throw new Error(ret);
+ }
+ else // returned Boolean
+ {
+ if (!(ret as Boolean))
+ {
+ throw new Error("SetCurrentSWF returned false somehow");
+ }
+ else
+ {
+ ret = extContext.call("DisassembleAsync");
+
+ if (ret == null)
+ {
+ throw new Error("Unknown error occurred during DisassembleAsync");
+ }
+ else if (ret is String)
+ {
+ throw new Error(ret);
+ }
+ else // Returned Boolean
+ {
+ if (!(ret as Boolean))
+ {
+ throw new Error("DisassembleAsync returned false somehow");
+ }
+ }
+ }
+ }
+ }
+
+ // Assembles an SWF from a map of file name to file contents, asynchronously. If replaceSWF is unspecified, and Disassemble was called, uses
+ // the last SWF's data for the rest of the SWF.
+ public function AssembleAsync(strings:Object, replaceSWF:ByteArray = null):void
+ {
+ if (replaceSWF != null)
+ {
+ replaceSWF.position = 0;
+ var decompressor:ByteArray = new ByteArray();
+ switch (replaceSWF.readUTFBytes(1))
+ {
+ case "F":
+ replaceSWF.position = 0;
+ break;
+ case "C":
+ replaceSWF.position = 8;
+ replaceSWF.readBytes(decompressor);
+ replaceSWF.position = 8;
+ decompressor.uncompress(CompressionAlgorithm.ZLIB);
+ replaceSWF.writeBytes(decompressor);
+ replaceSWF.position = 0;
+ replaceSWF.writeUTFBytes("F");
+ replaceSWF.position = 0;
+ decompressor = null;
+ break;
+ case "Z":
+ replaceSWF.position = 8;
+ replaceSWF.readBytes(decompressor, 8);
+ replaceSWF.position = 8;
+ decompressor.uncompress(CompressionAlgorithm.LZMA);
+ replaceSWF.writeBytes(decompressor);
+ replaceSWF.position = 0;
+ replaceSWF.writeUTFBytes("F");
+ replaceSWF.position = 0;
+ decompressor = null;
+ break;
+ default:
+ throw new Error("Unrecognized compression scheme for SWF");
+ }
+
+ var ret:Object = extContext.call("SetCurrentSWF", replaceSWF);
+
+ if (ret == null)
+ {
+ throw new Error("Unknown error occurred while setting SWF");
+ }
+ else if (ret is String)
+ {
+ throw new Error(ret);
+ }
+ else // returned Boolean
+ {
+ if (!(ret as Boolean))
+ {
+ throw new Error("SetCurrentSWF returned false somehow");
+ }
+ }
+ }
+
+ var vec:Vector. = new [];
+ for (var str:String in strings)
+ {
+ vec[vec.length] = str;
+ }
+
+ ret = extContext.call("AssembleAsync", strings, vec);
+
+ if (ret == null)
+ {
+ throw new Error("Unknown error occurred");
+ }
+ else if (ret is String)
+ {
+ throw new Error(ret);
+ }
+ else // returned Boolean
+ {
+ if (!(ret as Boolean))
+ {
+ throw new Error("AssembleAsync returned false somehow");
+ }
+ }
+ }
+
+ public function Cleanup():void
+ {
+ extContext.call("Cleanup");
+ }
+
+ private function onStatusEvent(e:StatusEvent):void
+ {
+ if (e.level == "ERROR")
+ {
+ var error:Object = extContext.call("AsyncTaskResult");
+ if (error is String)
+ {
+ throw new Error(error);
+ }
+ else
+ {
+ throw new Error("Unknown error occurred while performing an ANEByteCodeEditor async task");
+ }
+ }
+ else
+ {
+ var data:Object = extContext.call("AsyncTaskResult");
+
+ if (data is ByteArray)
+ {
+ this.dispatchEvent(new AssemblyDoneEvent(data as ByteArray));
+ }
+ else
+ {
+ this.dispatchEvent(new DisassemblyDoneEvent(data));
+ }
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/AS3/src/com/cff/anebe/DisassemblyDoneEvent.as b/AS3/src/com/cff/anebe/DisassemblyDoneEvent.as
new file mode 100644
index 0000000..3c8d627
--- /dev/null
+++ b/AS3/src/com/cff/anebe/DisassemblyDoneEvent.as
@@ -0,0 +1,31 @@
+package com.cff.anebe
+{
+ import flash.events.Event;
+
+ /**
+ * ...
+ * @author Chris
+ */
+ public class DisassemblyDoneEvent extends Event
+ {
+ public var strings:Object;
+ public function DisassemblyDoneEvent(strings:Object, bubbles:Boolean=false, cancelable:Boolean=false)
+ {
+ super(Events.DISASSEMBLY_DONE, bubbles, cancelable);
+
+ this.strings = strings;
+ }
+
+ public override function clone():Event
+ {
+ return new DisassemblyDoneEvent(strings, bubbles, cancelable);
+ }
+
+ public override function toString():String
+ {
+ return formatToString("DisassemblyDoneEvent", "type", "bubbles", "cancelable", "eventPhase");
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/AS3/src/com/cff/anebe/Events.as b/AS3/src/com/cff/anebe/Events.as
new file mode 100644
index 0000000..d3fa439
--- /dev/null
+++ b/AS3/src/com/cff/anebe/Events.as
@@ -0,0 +1,13 @@
+package com.cff.anebe
+{
+ /**
+ * ...
+ * @author Chris
+ */
+ public final class Events
+ {
+ public static const ASSEMBLY_DONE:String = "ASSEMBLY_DONE";
+ public static const DISASSEMBLY_DONE:String = "DISASSEMBLY_DONE";
+ }
+
+}
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..4619efa
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2020 Chris Feger
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/Native/BytecodeEditor/BytecodeEditor.sln b/Native/BytecodeEditor/BytecodeEditor.sln
new file mode 100644
index 0000000..a443173
--- /dev/null
+++ b/Native/BytecodeEditor/BytecodeEditor.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BytecodeEditor", "BytecodeEditor.vcxproj", "{76827AD2-1616-45C5-8FE5-58E26AF91B3D}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {76827AD2-1616-45C5-8FE5-58E26AF91B3D}.Debug|Win32.ActiveCfg = Debug|Win32
+ {76827AD2-1616-45C5-8FE5-58E26AF91B3D}.Debug|Win32.Build.0 = Debug|Win32
+ {76827AD2-1616-45C5-8FE5-58E26AF91B3D}.Release|Win32.ActiveCfg = Release|Win32
+ {76827AD2-1616-45C5-8FE5-58E26AF91B3D}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/Native/BytecodeEditor/BytecodeEditor.vcxproj b/Native/BytecodeEditor/BytecodeEditor.vcxproj
new file mode 100644
index 0000000..5f9fa71
--- /dev/null
+++ b/Native/BytecodeEditor/BytecodeEditor.vcxproj
@@ -0,0 +1,171 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+
+ {76827AD2-1616-45C5-8FE5-58E26AF91B3D}
+ Win32Proj
+ FRESteamWorks
+ BytecodeEditor
+ 10.0
+
+
+
+ DynamicLibrary
+ true
+ Unicode
+ v143
+
+
+ DynamicLibrary
+ false
+ true
+ Unicode
+ v143
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(SolutionDir)$(Configuration)\
+ AllRules.ruleset
+
+
+ false
+ $(SolutionDir)$(Configuration)\
+
+
+
+
+
+ Level3
+ Disabled
+ USE_BREAKPAD_HANDLER;VERSION_SAFE_STEAM_API_INTERFACES;WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ $(SolutionDir)\AdobeAIRSDK\include;$(SolutionDir)SteamSDK\public;$(ProjectDir)\include;%(AdditionalIncludeDirectories)
+ MultiThreadedDebug
+ 4068
+
+
+ Windows
+ true
+ $(SolutionDir)AdobeAIRSDK\lib\win;$(SolutionDir)SteamSDK\redistributable_bin;%(AdditionalLibraryDirectories)
+ steam_api.lib;FlashRuntimeExtensions.lib;%(AdditionalDependencies)
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ USE_BREAKPAD_HANDLER;VERSION_SAFE_STEAM_API_INTERFACES;WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ $(SolutionDir)\AdobeAIRSDK\include;$(ProjectDir)\include;%(AdditionalIncludeDirectories)
+ MultiThreaded
+ 4068
+
+
+ Windows
+ true
+ true
+ true
+ $(SolutionDir)AdobeAIRSDK\lib\win;%(AdditionalLibraryDirectories)
+ FlashRuntimeExtensions.lib;%(AdditionalDependencies)
+
+
+ true
+
+
+
+
+
+
+
+
+ stdcpp20
+
+
+ stdcpp20
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Native/BytecodeEditor/include/ABC/ABCFile.hpp b/Native/BytecodeEditor/include/ABC/ABCFile.hpp
new file mode 100644
index 0000000..8d2d688
--- /dev/null
+++ b/Native/BytecodeEditor/include/ABC/ABCFile.hpp
@@ -0,0 +1,57 @@
+#pragma once
+
+#include "ABC/Class.hpp"
+#include "ABC/Instance.hpp"
+#include "ABC/Metadata.hpp"
+#include "ABC/MethodBody.hpp"
+#include "ABC/MethodInfo.hpp"
+#include "ABC/Multiname.hpp"
+#include "ABC/Namespace.hpp"
+#include "ABC/Script.hpp"
+#include
+#include
+
+namespace ABC
+{
+ struct ABCFile
+ {
+ uint16_t minorVersion, majorVersion;
+ std::vector ints;
+ std::vector uints;
+ std::vector doubles;
+ std::vector strings;
+ std::vector namespaces;
+ std::vector> namespaceSets;
+ std::vector multinames;
+
+ std::vector methods;
+ std::vector metadata;
+ std::vector instances;
+ std::vector classes;
+ std::vector