@awayfl/avm1
Version:
Virtual machine for executing AS1 and AS2 code
244 lines (243 loc) • 9.71 kB
JavaScript
/**
* Copyright 2014 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { alCoerceString, alToString } from './runtime';
import { installBuiltins } from './natives';
import { Debug, release, assert } from '@awayfl/swf-loader';
import { AVM1Key } from './lib/AVM1Key';
import { AVM1Mouse } from './lib/AVM1Mouse';
import { AVM1Stage } from './lib/AVM1Stage';
import { AVM1MovieClip } from './lib/AVM1MovieClip';
import { getAVM1Object } from './lib/AVM1Utils';
import { AssetLibrary } from '@awayjs/core';
var AVM1ActionsData = /** @class */ (function () {
function AVM1ActionsData(bytes, id, parent, encryptedData) {
if (parent === void 0) { parent = null; }
this.bytes = bytes;
this.id = id;
this.parent = parent;
this.encryptedData = encryptedData;
this.debugPath = this.id;
this.ir = null;
this.compiled = null;
}
return AVM1ActionsData;
}());
export { AVM1ActionsData };
var ActionsDataFactory = /** @class */ (function () {
function ActionsDataFactory() {
this._cache = new WeakMap();
}
ActionsDataFactory.prototype.createActionsData = function (actionData, id, parent) {
if (parent === void 0) { parent = null; }
var isArray = (actionData instanceof Uint8Array);
var bytes = isArray ? actionData : actionData.actionsData;
var encryptedData = isArray ? undefined : actionData.encryptedData;
var actionsData = this._cache.get(bytes);
if (!actionsData) {
actionsData = new AVM1ActionsData(bytes, id, parent, encryptedData);
this._cache.set(bytes, actionsData);
}
release || assert(actionsData.bytes === actionData && actionsData.id === id && actionsData.parent === parent);
return actionsData;
};
return ActionsDataFactory;
}());
export { ActionsDataFactory };
var AVM1Context = /** @class */ (function () {
function AVM1Context(swfVersion) {
this.eventObservers = {};
this.assets = {};
this.awayAssets = {};
this.assetsSymbols = [];
this.assetsClasses = [];
this.staticStates = new WeakMap();
this.swfVersion = swfVersion;
this.globals = null;
this.actionsDataFactory = new ActionsDataFactory();
if (swfVersion > 6) {
this.isPropertyCaseSensitive = true;
this.normalizeName = this.normalizeNameCaseSensitive;
}
else {
this.isPropertyCaseSensitive = false;
this._nameCache = Object.create(null);
this.normalizeName = this.normalizeNameCaseInsensitive;
}
this.builtins = {};
installBuiltins(this);
}
AVM1Context.prototype.resolveTarget = function (target) { };
AVM1Context.prototype.resolveRoot = function () { };
AVM1Context.prototype.checkTimeout = function () { };
AVM1Context.prototype.executeActions = function (actionsData, scopeObj) { };
AVM1Context.prototype.executeFunction = function (fn, thisArg, args) { };
AVM1Context.prototype.normalizeNameCaseSensitive = function (name) {
switch (typeof name) {
case 'number':
case 'string':
return name;
default:
return alToString(this, name);
}
};
AVM1Context.prototype.normalizeNameCaseInsensitive = function (name) {
switch (typeof name) {
case 'number':
return name.toString();
case 'string':
break;
default:
name = alToString(this, name);
}
var normalizedName = this._nameCache[name];
if (normalizedName) {
return normalizedName;
}
normalizedName = name.toLowerCase();
this._nameCache[name] = normalizedName;
return normalizedName;
};
AVM1Context.prototype._getEventPropertyObservers = function (propertyName, create) {
if (!this.isPropertyCaseSensitive) {
propertyName = propertyName.toLowerCase();
}
var observers = this.eventObservers[propertyName];
if (observers) {
return observers;
}
if (create) {
observers = [];
this.eventObservers[propertyName] = observers;
return observers;
}
return null;
};
AVM1Context.prototype.registerEventPropertyObserver = function (propertyName, observer) {
var observers = this._getEventPropertyObservers(propertyName, true);
observers.push(observer);
};
AVM1Context.prototype.unregisterEventPropertyObserver = function (propertyName, observer) {
var observers = this._getEventPropertyObservers(propertyName, false);
if (!observers) {
return;
}
var j = observers.indexOf(observer);
if (j < 0) {
return;
}
observers.splice(j, 1);
};
AVM1Context.prototype.broadcastEventPropertyChange = function (propertyName) {
var observers = this._getEventPropertyObservers(propertyName, false);
if (!observers) {
return;
}
observers.forEach(function (observer) { return observer.onEventPropertyModified(propertyName); });
};
AVM1Context.prototype.addAsset = function (className, symbolId, symbolProps) {
//console.log("addAsset", className, symbolId, symbolProps);
release || Debug.assert(typeof className === 'string' && !isNaN(symbolId));
this.assets[className.toLowerCase()] = symbolId;
this.assetsSymbols[symbolId] = symbolProps;
//80pro: directly store assets in dictionary
this.awayAssets[className.toLowerCase()] = symbolProps;
};
AVM1Context.prototype.registerClass = function (className, theClass) {
className = alCoerceString(this, className);
if (className === null) {
this.utils.warn('Cannot register class for symbol: className is missing');
return;
}
var myAsset = AssetLibrary.getAsset(className, AVM1MovieClip.currentMCAssetNameSpace);
if (!myAsset || !myAsset.adaptee) {
console.warn('can not find symbol to register class ' + className);
return;
}
//console.log("register", myAsset.adaptee.name, myAsset.adaptee.id);
myAsset.adaptee.avm1Symbol = theClass;
/*
var symbolId = this.assets[className.toLowerCase()];
if (symbolId === undefined) {
this.utils.warn('Cannot register ' + className + ' class for symbol');
return;
}
this.assetsClasses[symbolId] = theClass;*/
};
AVM1Context.prototype.getSymbolClass = function (symbolId) {
return this.assetsClasses[symbolId] || null;
};
AVM1Context.prototype.getAsset = function (className) {
className = alCoerceString(this, className);
if (className === null) {
return undefined;
}
var symbolId = this.assets[className.toLowerCase()];
if (symbolId === undefined) {
return undefined;
}
var symbol = this.awayAssets[className.toLowerCase()];
if (!symbol) {
console.log('error in getAsset. not implemented to grab assets from loaderInfo');
/*symbol = this.loaderInfo.getSymbolById(symbolId);
if (!symbol) {
Debug.warning("Symbol " + symbolId + " is not defined.");
return undefined;
}
this.assetsSymbols[symbolId] = symbol;*/
}
return {
symbolId: symbolId,
symbolProps: symbol
};
};
AVM1Context.prototype.reset = function () {
this.eventObservers = Object.create(null);
this.assets = {};
this.assetsSymbols = [];
this.assetsClasses = [];
this.awayAssets = {};
this.staticStates = new WeakMap();
AVM1Stage.bindStage(this, this.globals.Stage, null, null, null);
};
AVM1Context.prototype.setStage = function (avmStage, avm1Handler, htmlElement) {
AVM1Key.bindStage(this, this.globals.Key, avmStage, htmlElement);
AVM1Mouse.bindStage(this, this.globals.Mouse, avmStage, htmlElement);
AVM1Stage.bindStage(this, this.globals.Stage, avmStage, avm1Handler, htmlElement);
};
AVM1Context.prototype.getStaticState = function (cls) {
var state = this.staticStates.get(cls);
if (!state) {
state = Object.create(null);
var initStatic = cls.alInitStatic;
if (initStatic) {
initStatic.call(state, this);
}
this.staticStates.set(cls, state);
}
return state;
};
AVM1Context.prototype.resolveLevel = function (level) {
release || Debug.assert(typeof level === 'number');
var as3Root = this.globals._getRootForLevel(level);
if (!as3Root) {
this.utils.warn('Unable to resolve level ' + level + ' root');
return undefined;
}
return getAVM1Object(as3Root, this);
};
return AVM1Context;
}());
export { AVM1Context };