1 /* -*- mode: java; tab-width: 4; insert-tabs-mode: nil; indent-tabs-mode: nil -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is [Open Source Virtual Machine.].
17 * The Initial Developer of the Original Code is
18 * Adobe System Incorporated.
19 * Portions created by the Initial Developer are Copyright (C) 2004-2006
20 * the Initial Developer. All Rights Reserved.
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 use default namespace Abc,
44 // Construct an ABCFile instance from a bytestream representing an abc block.
45 function parseAbcFile(b : ABCByteStream) : ABCFile {
49 if (magic != (46<<16|16))
50 throw new Error("not an abc file. magic=" + magic.toString(16));
52 var abc : ABCFile = new ABCFile();
54 abc.constants = parseCpool(b);
60 for(i = 0; i < n; i++) {
61 abc.addMethod(parseMethodInfo(b));
66 for(i = 0; i < n; i++) {
67 abc.addMetadata(parseMetadata(b));
72 for(i = 0; i < n; i++) {
73 abc.addInstance(parseInstanceInfo(b));
77 for(i = 0; i < n; i++) {
78 abc.addClass(parseClassInfo(b));
83 for(i = 0; i < n; i++) {
84 abc.addScript(parseScriptInfo(b));
89 for(i = 0; i < n; i++) {
90 abc.addMethodBody(parseMethodBody(b));
96 function parseCpool(b : ABCByteStream) : ABCConstantPool {
100 var pool : ABCConstantPool = new ABCConstantPool;
104 for (i=1; i < n; i++)
105 pool.int32(b.readS32());
109 for (i=1; i < n; i++)
110 pool.uint32(b.readU32());
115 for (i=1; i < n; i++)
116 pool.float64(b.readDouble());
120 for (i=1; i < n; i++)
121 pool.stringUtf8(b.readUTFBytes(b.readU32()));
125 for (i=1; i < n; i++)
127 var nskind = b.readByte();
128 var uri = b.readU32();
129 pool.namespace(nskind, uri);
134 for (i=1; i < n; i++)
136 var count:int = b.readU30();
138 for (j=0; j < count; j++)
139 nsset[j] = b.readU30();
140 pool.namespaceset(nsset);
145 for (i=1; i < n; i++) {
146 var kind = b.readByte();
149 case CONSTANT_QNameA:
150 pool.QName(b.readU30(), b.readU30(), kind==CONSTANT_QNameA);
153 case CONSTANT_RTQName:
154 case CONSTANT_RTQNameA:
155 pool.RTQName(b.readU30(), kind==CONSTANT_RTQNameA);
158 case CONSTANT_RTQNameL:
159 case CONSTANT_RTQNameLA:
160 pool.RTQNameL(kind==CONSTANT_RTQNameLA);
164 case CONSTANT_Multiname:
165 case CONSTANT_MultinameA:
166 var name = b.readU30();
167 pool.Multiname(b.readU30(), name, kind==CONSTANT_MultinameA);
170 case CONSTANT_MultinameL:
171 case CONSTANT_MultinameLA:
172 pool.MultinameL(b.readU30(), kind==CONSTANT_MultinameLA);
180 function parseMethodInfo(b : ABCByteStream) : ABCMethodInfo {
182 var paramcount = b.readU32();
183 var returntype = b.readU32();
185 for(let i = 0; i < paramcount; ++i) {
186 params[i] = b.readU32();
189 var name = b.readU32();
190 var flags = b.readByte();
192 var optionalcount = 0;
193 var optionals = null;
194 if( flags & METHOD_HasOptional ) {
195 optionalcount = b.readU32();
197 for(let i = 0; i < optionalcount; ++i ) {
198 optionals[i] = { val:b.readU32(), kind:b.readByte() };
202 var paramnames = null;
203 if( flags & METHOD_HasParamNames ) {
205 for(let i = 0; i < paramcount; ++i)
206 paramnames[i] = b.readU32();
209 return new ABCMethodInfo(name, params, returntype, flags, optionals, paramnames);
212 function parseMetadataInfo(b : ABCByteStream) : ABCMetadataInfo {
213 var name = b.readU32();
214 var itemcount = b.readU32();
217 for( let i = 0; i < itemcount; i++ ) {
218 let key = b.readU32();
219 let value = b.readU32();
220 items[i] = { key:key, value:value };
223 return new ABCMetadataInfo(name, items);
226 function parseInstanceInfo(b : ABCByteStream) : ABCInstanceInfo {
227 var name = b.readU32();
228 var superclass = b.readU32();
229 var flags = b.readByte();
232 protectedNS = b.readU32();
234 var interfacecount = b.readU32();
236 for(let i = 0; i < interfacecount; ++i) {
237 interfaces[i] = b.readU32();
239 var iinit = b.readU32();
241 var instance_info = new ABCInstanceInfo(name, superclass, flags, protectedNS, interfaces);
243 instance_info.setIInit(iinit);
245 parseTraits(instance_info, b);
247 return instance_info;
250 function parseClassInfo(b : ABCByteStream) : ABCClassInfo {
251 var cinit = b.readU32();
253 var class_info = new ABCClassInfo();
254 class_info.setCInit(cinit);
256 parseTraits(class_info, b);
261 function parseScriptInfo(b : ABCByteStream) : ABCScriptInfo {
263 var script = new ABCScriptInfo(b.readU32());
264 parseTraits(script, b);
268 function parseMethodBody(b : ABCByteStream) : ABCMethodBodyInfo {
269 var mb:ABCMethodBodyInfo = new ABCMethodBodyInfo(b.readU32());
271 mb.setMaxStack(b.readU32());
272 mb.setLocalCount(b.readU32());
273 mb.setInitScopeDepth(b.readU32());
274 mb.setMaxScopeDepth(b.readU32());
276 let code_len = b.readU32();
277 let code = new ABCByteStream;
279 for(let i = 0; i < code_len; ++i) {
280 code.uint8(b.readByte());
283 var excount = b.readU32();
284 for( let i = 0; i < excount; ++i ) {
285 mb.addException(parseException(b));
293 function parseException(b : ABCByteStream) : ABCException {
294 var start = b.readU32();
295 var end = b.readU32();
296 var target = b.readU32();
297 var typename = b.readU32();
298 var name = b.readU32();
300 // WTF is wrong with this????
302 ex = new ABCException(start, end, target, typename, name);
306 function parseTraits(target, b : ABCByteStream) {
307 var traitcount = b.readU32();
308 for(let i =0 ; i < traitcount; ++i) {
309 target.addTrait(parseTrait(b));
313 function parseTrait(b : ABCByteStream) { //: ABCTrait should be ABCTrait once inheritance is supported
315 var name = b.readU32();
317 var tag = b.readByte();
318 var kind = tag & 0x0F;
319 var attrs = (tag>>4) & 0x0F;
326 let slotid = b.readU32();
327 let typename = b.readU32();
328 let value = b.readU32();
332 trait = new ABCSlotTrait(name, attrs, kind==TRAIT_Const, slotid, typename, value, kind);
337 let dispid = b.readU32();
338 let methinfo = b.readU32();
339 trait = new ABCOtherTrait(name, attrs, kind, dispid, methinfo);
342 let slotid = b.readU32();
343 let classinfo = b.readU32();
344 trait = new ABCOtherTrait(name, attrs, kind, slotid, classinfo);
346 case TRAIT_Function: // TODO:
352 if( attrs & ATTR_Metadata ) {
353 let metadatacount = b.readU32();
354 for(let i = 0; i < metadatacount; ++i) {
355 trait.addMetadata(b.readU32());
362 // This is a helper for parsing the ABCConstantPool from its
363 // bytes and storing the resulting values in arrays. This allows
364 // easy access to the values referenced in the pools.
366 public class ABCConstantPoolParser {
367 // the pools themselves are public for people who need the
369 public var int_pool, uint_pool, double_pool;
370 public var utf8_pool, namespace_pool, namespaceset_pool, name_pool;
372 public function ABCConstantPoolParser(pool: ABCConstantPool) {
373 // load the constants from an existing abc object
374 // setup our arrays, reserving element 0 which remains undefined
375 int_pool = new Array(1);
376 uint_pool = new Array(1);
377 double_pool = new Array(1);
378 utf8_pool = new Array(1);
379 namespace_pool = new Array(1);
380 namespaceset_pool = new Array(1);
381 name_pool = new Array(1);
383 // and read the bytes from the streams.
384 intPool(pool.int_bytes);
385 uintPool(pool.uint_bytes);
386 doublePool(pool.double_bytes);
387 utf8Pool(pool.utf8_bytes);
388 namespacePool(pool.namespace_bytes);
389 namespacesetPool(pool.namespaceset_bytes);
390 namePool(pool.multiname_bytes);
393 // We also provide a couple of helper functions take an index/ices
394 // and indirects through the various pools returning the value.
395 public function getInt(offset: uint) : int {
396 return int_pool[offset];
398 public function getUint(offset: uint) : uint {
399 return uint_pool[offset];
401 public function getDouble(offset: uint) : double {
402 return double_pool[offset];
404 public function getUtf8(offset: uint) : string {
405 return utf8_pool[offset];
407 public function getNamespace(offset: uint) {
408 // returns [kind:uint, value:string]
409 var entry = namespace_pool[offset]
410 return [entry.kind, getUtf8(entry.utf8)]
412 public function getConstantName(offset: uint) {
413 // returns [namespace:string, name:string]
414 var entry = name_pool[offset]
415 Util::assert(entry.kind == CONSTANT_QName); // not a constant string.
416 var [ns_kind, ns_name] = getNamespace(entry.ns)
417 return [ns_name, getUtf8(entry.utf8)]
419 public function getConstantNameType(offset: uint) {
420 var entry = name_pool[offset]
421 Util::assert(entry.kind == CONSTANT_QName); // not a constant string.
422 var [ns_kind, ns_name] = getNamespace(entry.ns)
427 // ******************************************************
428 // Loading/parsing of the pools
429 // prepare a pool's stream for re-reading
430 function preparePool (nd) : uint
432 var orig = nd.position;
438 // load the various pools
439 function intPool (nd) : void {
440 var orig = preparePool(nd);
441 while (nd.bytesAvailable)
442 int_pool.push(nd.readS32());
446 function uintPool (nd) : void {
447 var orig = preparePool(nd);
448 while (nd.bytesAvailable)
449 uint_pool.push(nd.readU32());
453 function doublePool (nd) : void {
454 var orig = preparePool(nd);nd.position;
455 while (nd.bytesAvailable)
456 double_pool.push(nd.readDouble());
460 function utf8Pool (nd) : void {
461 var orig = preparePool(nd);
462 while (nd.bytesAvailable) {
463 var len = nd.readU32();
464 utf8_pool.push(nd.readUTFBytes(len));
469 function namespacePool (nd) : void {
470 var orig = preparePool(nd);
471 while(nd.bytesAvailable)
472 namespace_pool.push( {kind: nd.readByte(), utf8: nd.readU32()} )
476 function namespacesetPool (nd) : void {
477 var orig = preparePool(nd);
478 while(nd.bytesAvailable) {
479 // read a const - each one is variable length.
480 var len = nd.readU32();
481 var new_val = new Array(len);
482 for (var i = 0 ; i < len; ++i)
483 new_val[i] = nd.readU32();
485 namespaceset_pool.push(new_val);
490 function namePool (nd) : void {
491 var orig = preparePool(nd);
492 while(nd.bytesAvailable) {
494 var kind = nd.readByte();
495 var new_val = {kind: kind}
499 new_val.ns = nd.readU32(); // ns offset
500 new_val.utf8 = nd.readU32(); // utf8 index
502 case CONSTANT_RTQName:
503 new_val.utf8 = nd.readU32(); // utf8 index.
505 case CONSTANT_RTQNameL:
507 case CONSTANT_Multiname:
508 new_val.utf8 = nd.readU32(); // utf8 offset
509 new_val.nsset = nd.readU32(); // nsset offset
511 case CONSTANT_MultinameL:
512 new_val.nss = nd.readU32() // nss
514 case CONSTANT_QNameA:
515 case CONSTANT_RTQNameA:
516 case CONSTANT_RTQNameLA:
517 case CONSTANT_MultinameA:
518 case CONSTANT_MultinameLA:
520 // we must fail here - we don't know how many bytes to
521 // read, screwing up attempts to parse ones which follow
522 throw("Unsupported Name constant");
524 name_pool.push(new_val);