~ \ blog \ Compilation d'AS3 en AS3

Compilation d'AS3 en AS3

Tags :

J’ai découvert il y a quelques temps deja, un petit framework contenant une partie du code de tamarin, dans ces premiers commits, et qui permet donc de compiler de l’AS3 avec le Flash Player, moyennant quelques adaptations d’écritures, et quelques issues à connaitre.

L’idée, c’est que l’application cliente ne dispose que des interfaces des classes, pour qu’en cas de décompilation, les classes critiques ne puissent être obtenues.

Applications

Imaginons, un serveur socket, binaire ou xml, qui discute avec son application cliente, elle reçoit en AMF3 ou sous forme Hexa, un String compréssé, modifié, et crypté. On reçoit ce String, on le décompresse, on le décrypte, etc, et on en arrive à la compilation proprement dite.

On peut aussi imaginer tout un tas d’autre cas d’utilisations :

Il faut savoir que sur le framework en question, les seuls trucs utiles à garder, c’est :

Le Compileur en AS3 pur, d’une il marche pas, de deux, il est lent, et de trois, il est tellement mal écrit, qu’il y a 3000 warnings et aucun typage, en gardant que les classes et packages nommés plus haut, il ne devrait plus y avoir de soucis.

Utilisation

Donc la création et la compilation d’une classe au runtime est assez facile, au niveau de la syntaxe, la seule chose qui change, c’est les import :

/*
import flash.utils;
devient :
*/
namespace utils = "flash.utils"; 
use namespace utils;

Prenons une classe toute simple :

namespace event = "flash.events"; 
use namespace event;
public class MyClass extends EventDispatcher
{
	private static var ID : int = 0;
	
	private var _label : String;
	private var _id : int;
	
	public function MyClass ()
	{
		_id = ID;
		ID++;
	}
	
	public function get id () : int
	{
		return _id;
	}
	
	public function set label (value:String) : void
	{
		if (_label != value)
		{
			_label = value;
			dispatchEvent(new Event('labelChanged'));
		}
	}
	
	public function get label () : String
	{
		return _label;
	}
}

Imaginons que le code précédent est stocké dans une variable maClass sous forme de String :

var c : CompiledESC = new CompiledESC ();
var classDump : ByteArray = c.eval(maClass);
var swf : ByteArray = ByteLoader.wrapInSWF([classDump]);
/* ici vous pouvez au choix, loader votre classe dans le LoaderContext qui vont convient : */
var l : Loader = new Loader ();
var lc : LoaderContext = new LoaderContext (false,ApplicationDomain.currentDomain,null);
l.contentLoaderInfo.addEventListener(Event.COMPLETE,onLoaderComplete,false,0,true);
l.loadBytes(swf,lc);
/* et plus loin, dans votre */
private function onLoaderComplete (e:Event) : void
{
	if (ApplicationDomain.currentDomain.hasDefinition('MyClass'))
	{
		var c : Class = ApplicationDomain.currentDomain.getDefinition('MyClass') as Class;
		var instance : * = new c ();
		trace (instance.id);
	}
}

Les quelques problèmes rencontrés, en vrac :

Sinon, ça marche plutôt bien, et ça permet de faire des choses assez sympas :), en esperant que Flash 10 ne casse pas tout :)

Discussion

kabnot, 2008/06/17 22:57:

Salut Niko,

Quand tu dis que le compilateur en AS3 pur ne marche pas, tu as été obligé de faire des adaptations ?

Ou est-ce que simplement avec les morceaux de code présents ici on peut compiler sans rien toucher ? Autre point, j’imagine qu’avec le code actuel on ne peut compiler des classes que une à une. Y a t-il un moyen d’avoir une compilation sur un ensemble de définitions de classe dépendantes les unes des autres ?

 
Nicolas Coevoet, 2008/06/17 23:09:

Quand je dis que le compilateur en AS3 pur ne marche pas, c’est que les quelques tests que j’ai efféctué avec n’était pas concluant, alors qu’avec la version Tamarin, ça compile vite et bien.

Avec le code tel que donné là, ça compile sans soucis.

Tu dois pouvoir compiler plusieurs classes à la fois, même si elles sont dépendantes, cependant, il faut s’assurer que l’ordre de compilation est respecté, donc par ordre de dépendances, ensuite tu n’as qu’à ajouter l’ensemble des différentes classes précompilés, évaluées, de cette maniere là :

var classDump : ByteArray = c.eval(maClass);
var classDump2 : ByteArray = c.eval(maClass2);
var swf : ByteArray = ByteLoader.wrapInSWF([classDump,classDump2]);

Aprés il faut bien entendu tester tout cela en mode debug, car la compilation est tout de même particuliere :)

 
kabnot, 2008/06/17 23:16:

Merci pour ces précisions. Je crois que je vais vite trouver une application à ce compiler dans le cadre de mon travail sur la synthèse sonore. Ca m’ouvre des portes pour le portage visant le Flash Player 9, puisqu’à ce jour, les techniques connues nécessitent de compiler des swf :)

 
War, 2009/07/25 04:38:

Je viens de faire un test avec les derniers *.abc de tamarin

j’ai pus constater qu’un trace de this fonctionne.

Pour flash10, ca tourne avec ( en ayant compilé en flash 9 )

je rajouterais, que ces fichiers une fois sauvegardé on du mal a être décompilé (”file corrupted”)

A noter en plus, j’ai du modifier l’égèrement compile esc pour qu’il attende d’avoir correctement loadé avant de définir “done”

/

private function loadESC():void {

		var a:* = [
			new debug_abc as ByteArray,
			new util_abc as ByteArray,
			new util_tamarin_abc as ByteArray,
			new bytes_tamarin_abc as ByteArray,
			new util_tamarin_abc as ByteArray,
			new lex_char_abc as ByteArray,
			new lex_scan_abc as ByteArray,
			new lex_token_abc as ByteArray,
			new ast_abc as ByteArray,
			new parse_abc as ByteArray,
			new asm_abc as ByteArray,
			new abc_abc as ByteArray,
			new emit_abc as ByteArray,
			new cogen_abc as ByteArray,
			new cogen_stmt_abc as ByteArray,
			new cogen_expr_abc as ByteArray,
			new esc_core_abc as ByteArray,
			new eval_support_abc as ByteArray,
			new esc_env_abc as ByteArray,
		]
		a= ByteLoader.loadBytes(a, true);
		var c:LoaderContext = null;
		c = new LoaderContext(false, ApplicationDomain.currentDomain, null);
		var l:Loader = new Loader();
		l.contentLoaderInfo.addEventListener(Event.COMPLETE, bytesComplete);

		l.loadBytes(a, c);
	}
	private function bytesComplete(event:Event):void{
		done = true;
	}