Package macromedia.abc

Source Code of macromedia.abc.AbcData$Method

/*
*
*  Licensed to the Apache Software Foundation (ASF) under one or more
*  contributor license agreements.  See the NOTICE file distributed with
*  this work for additional information regarding copyright ownership.
*  The ASF licenses this file to You 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.
*
*/
package macromedia.abc;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import macromedia.asc.embedding.avmplus.ActionBlockConstants;
import macromedia.asc.parser.MetaDataEvaluator;
import macromedia.asc.parser.MetaDataNode;
import macromedia.asc.semantics.MetaData;
import macromedia.asc.semantics.Value;
import macromedia.asc.util.Decimal128;

@SuppressWarnings("nls")
public class AbcData implements java.io.Externalizable
  /**
   * Attempt to read the cache from the persistent store when set.
   */
  static boolean readCache = true;
 
  /**
   * Attempt to write the cache to persistent store when set.
   */
  static boolean saveCache = true;
 
  /**
   * Object used to serialize access to the cache.
   */
  static final Object serializationLock = new Object();
 
  public static boolean contains(String src_name)
  {
    return getCache().cache.containsKey(src_name);
  }
 
  public static AbcData getCacheEntry(String src_name)
  {
    return getCache().get(src_name);
  }
 
  public void finish()
  {
    if ( !( dirty && saveCache) )
    {
      getCache().remove(this);
    }
  }

  private boolean dirty = false;
  private String scriptName;
   
  private static AbcDataCache instance;
 
  /**
   * @return the singleton instance of the cache.
   */
  private static AbcDataCache getCache()
  {
    synchronized(serializationLock)
    {
      if ( null == instance )
        deserializeCache (new File("/tmp/AbcDataCache.ser"));
      return instance;
    }
  }
 
  /**
   * Deserialize the AbcDataCache if feasible.
   * @param input - the File that holds the serialized cache.
   * @post The instance field holds a deserialized or new cache.
   * @throws nothing -- errors dealt with here.
   */
  private static void deserializeCache(File input)
  {
    {
      if ( null == instance && readCache && input.canRead() )
      {
        try
        {
          ObjectInputStream objIn = new ObjectInputStream(new FileInputStream(input));
          instance = (AbcDataCache)objIn.readObject();
          objIn.close();
         
          instance.file = input;
        }
        catch ( java.io.InvalidClassException incompatible_serialized_class )
        {
          //  Previously serialized class can't be deserialized,
            //  start a new cache.
        }
        catch ( Exception ex)
        {
          // TODO: Better reporting.
          ex.printStackTrace();
        }
      }
     
      if ( null == instance )
        instance = new AbcDataCache(input);
    }
  }
 
  public static void preload()
  {
    new Thread() {
      @Override
            public void run() {
        getCache();
      }
    }.start();
  }

  private static class AbcDataCache implements java.io.Externalizable
 
    private Map<String, AbcData> cache;
    private boolean dirty;
   
    private File file;
   
    AbcDataCache(File f)
    {
      cache = new HashMap<String,AbcData>();
      file  = f;
      dirty = false;
     
      if ( saveCache )
      {
        Runtime.getRuntime().addShutdownHook(
          new Thread() {
            @Override
            public void run()
            {
              // TODO: This shutdown hook should be a last resort!
              AbcData.instance.flush();
            }
          }
        );
      }
    }
   
   
    public void flush()
    {
      if ( this.dirty )
      {
        try
        {
          ObjectOutputStream objOut = new ObjectOutputStream(new FileOutputStream(this.file));
          objOut.writeObject(this);
          objOut.close();
          this.dirty = false;
          System.out.println("Serialized AbcDataCache to " + this.file.getCanonicalPath()); //$NON-NLS-1$
        }
        catch ( Exception ex)
        {
          // Better logging would be nice, but a shutdown
            // hook can't depend on any facilities but the
            // most basic.
          ex.printStackTrace();
        }
      }
    }
   
    /**
     * Retrieve or create cached AbcData for a script.
     * @param script_name - the script name.
     * @return the script's AbcData entry.
     * @post this.dirty set if the AbcData was created.
     */
    AbcData get(String script_name)
    {
      if ( !cache.containsKey(script_name) )
      {
        setDirty();
        cache.put(script_name, new AbcData(script_name));
        cache.get(script_name).dirty  = true;
      }
     
      return cache.get(script_name);
    }
   
    /**
     * Set the cache's dirty bit.
     * @param is_dirty
     * @post static maps cleared.
     */
    private void setDirty()
    {
      this.dirty = true;
    }
   
    void remove(AbcData data)
    {
      if ( !(dirty && saveCache) )
      {
        cache.remove(data.scriptName);
      }
       
    }


    @SuppressWarnings("unchecked")
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
    {
      cache = (Map<String,AbcData>)in.readObject();
      dirty = false;
      file = new File(in.readObject().toString());
    }


    public void writeExternal(ObjectOutput out) throws IOException
    {
      out.writeObject(cache);
      out.writeObject(file.getCanonicalPath());
    }
  }

  /*
   *   Housekeeping functions
   */
  public AbcData(String script_name)
  {
    this.scriptName = script_name;
    //  see deserialization code,
    //  which resets the dirty bit.
    this.dirty = true;
  }

  public boolean isBuilding()
  {
    return this.dirty;
  }
 
  /*
   * Traits
   */
  public class Trait implements java.io.Externalizable
  {
    int nameIndex;
        int kind;
        int [] data;
        int[] metadata;
       
       
    public Trait(int name_index, int kind, int[] data)
    {
      this.nameIndex = name_index;
      this.kind = kind;
      this.data = data;
    }
   
    public void addMetadata(int[] metadata)
    {
      this.metadata = metadata;
    }
   
    public int getNameIndex() {
      return this.nameIndex;
    }
   
    public int getAttrs()
    {
      return kind >> 4;
    }
   
    public int getTag()
    {
      return kind & 0xf;
    }
   
    public boolean hasMetadata() {
      return ( getAttrs() & ActionBlockConstants.TRAIT_FLAG_metadata) != 0;
    }
   
    public boolean isConstTrait() {
      return (getTag() == ActionBlockConstants.TRAIT_Const);
    }
   
    public int[] getMetadata()
    {
      return this.metadata;
    }
   
    public int getSlotId() {
      assert(getTag() == ActionBlockConstants.TRAIT_Var || getTag() == ActionBlockConstants.TRAIT_Const || getTag() == ActionBlockConstants.TRAIT_Class);
      return data[0];
    }
   
    public int getTypeName() {
      assert(getTag() == ActionBlockConstants.TRAIT_Var || getTag() == ActionBlockConstants.TRAIT_Const);
      return data[1];
    }
   
    public int getValueIndex() {
      assert(getTag() == ActionBlockConstants.TRAIT_Var || getTag() == ActionBlockConstants.TRAIT_Const);
      return data[2];
    }
   
    public int getValueKind() {
      assert(getTag() == ActionBlockConstants.TRAIT_Var || getTag() == ActionBlockConstants.TRAIT_Const);
      return data[3];
    }
   
    public int getDispId() {
      assert(getTag() == ActionBlockConstants.TRAIT_Method || getTag() == ActionBlockConstants.TRAIT_Getter || getTag() == ActionBlockConstants.TRAIT_Setter);
      return data[0];
    }
   
    public int getMethodId() {
      assert(getTag() == ActionBlockConstants.TRAIT_Method || getTag() == ActionBlockConstants.TRAIT_Getter || getTag() == ActionBlockConstants.TRAIT_Setter);
      return data[1];
    }
   
    public int getClassId() {
      assert(getTag() == ActionBlockConstants.TRAIT_Class);
      return data[1];
    }

    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
    {
      nameIndex = in.readInt();
          kind = in.readByte();
          data = (int[]) in.readObject();
          metadata = (int[]) in.readObject();
    }

    public void writeExternal(ObjectOutput out) throws IOException
    {
      out.writeInt(nameIndex);
      out.writeByte(kind);
      out.writeObject(data);
      out.writeObject(metadata);
    }
  }
 
  /*
   * NameData is an unstructured view of deserialized name data.
   */
  public class NameData implements java.io.Externalizable
    {
    int kind = 0;
       
        int[] params;
       
        NameData(int kind, int[] params)
        {
          this.kind = kind;
          this.params = params;
        }
       
        public int getKind()
        {
          return this.kind;
        }
       
       
        public int[] getParams()
        {
          return this.params;
        }

    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
    {
      kind = in.readByte();
      params = (int[])in.readObject();
    }

    public void writeExternal(ObjectOutput out) throws IOException
    {
      out.writeByte(kind);
      out.writeObject(params);
    }
   
    Set<Integer> getVersions()
    {
      Namespace ns = null;
     
      // If the name's a multiname, get the first namespace
      // since they all share the same base URI.
      if ( ActionBlockConstants.CONSTANT_Multiname == kind || ActionBlockConstants.CONSTANT_MultinameA == kind )
      {
        int[] nss = AbcData.this.namespaceSets[this.params[1]].namespaceIds;
        ns = (nss.length > 0)? namespaces[nss[0]]: null;
      }
      else
        ns = namespaces[params[0]];
     
      switch ( kind )
        {
            case ActionBlockConstants.CONSTANT_Qname:
            case ActionBlockConstants.CONSTANT_QnameA:
                ns = namespaces[params[0]];
                break;
            case ActionBlockConstants.CONSTANT_Multiname:
            case ActionBlockConstants.CONSTANT_MultinameA:
              int[] nss = AbcData.this.namespaceSets[this.params[1]].namespaceIds;
        ns = (nss.length > 0)? namespaces[nss[0]]: null;
                break;
            default:
              ns = null;
            }
   
      if ( ns != null )
      {
        String uri = strings[ns.nameOffset];
        return getVersion(uri);
      }
      return null;
    }
   
    Set<Integer> getVersion(String uri)
      {
      if (uri.length() == 0)
        return null;
     
      int last = uri.codePointAt(uri.length()-1);
      if(last >= 0xE000 && last <= 0xF000)
      {
        Set<Integer> result = new TreeSet<Integer>();
        result.add(last-0xE000);
        return result;
      }

      return null;
    }
    }
   
    /**
     * Names defined in this script.
     */
    private NameData[] nameData;
   
    /**
     * Temporary holder for names read from abc files.
     * Types are:
     * QName: namespace id,name id
     * Typename: QName reference (base), type parameter list of QName references
     * Multiname: name, namespaceset id
     */
    public class BinaryMN
    {
        public int kind = 0;           // MultiName type
        public int nameID = 0;         // name CPool string index (not used for CONSTANT_Typename)
        public int nsID = 0;           // namespace or namespaceset id
        public boolean nsIsSet = false;
       
        public int baseMN;             // CONSTANT_Typename: base name CPool MN index (e.g. 'Vector'
        public int[] params;           // CONSTANT_TypeName: parameter type CPool MN index (e.g. Vector<'int'>)
       
        public Set<Integer> versions;  // optional: supports version gather
       
        /**
         * Construct a non-parameterized name.
         * @param name_index
         * @param name_space
         * @param ns_is_set
         * @param versions
         */
        BinaryMN(int kind, int name_index, int name_space, boolean ns_is_set, Set<Integer>versions)
        {
            this.kind = kind;
            this.nameID = name_index;
            this.nsID = name_space;
            this.nsIsSet = ns_is_set;
            this.versions = versions;
        }
       
        /**
         * Construct a parameterized name.
         */
        BinaryMN(int kind, int base_name, int[] plist)
        {
            this.kind = kind;
            this.baseMN = base_name;
            this.params = plist;
        }
       
    }
   
    private transient BinaryMN[] binaryMultinames;
   
    public BinaryMN getName(int idx)
    {
        if ( null == this.binaryMultinames[idx] )
        {
            NameData nd = this.nameData[idx];
            int name_index = 0;
            int name_space = 0;
            boolean ns_is_set = false;
           
            switch ( nd.kind )
            {
            case ActionBlockConstants.CONSTANT_Qname:
            case ActionBlockConstants.CONSTANT_QnameA:
                name_space = nd.params[0];
                name_index = nd.params[1];
                ns_is_set  = false;
                this.binaryMultinames[idx] = new BinaryMN(nd.kind, name_index, name_space, ns_is_set, nd.getVersions());
                break;
            case ActionBlockConstants.CONSTANT_TypeName:
                name_index = nd.params[0];
                int count = nd.params.length - 2;
                assert( count == nd.params[1]);
                int[] plist = new int[count];
                for( int i = 0; i < count; ++i )
                    plist[i] = nd.params[i+2];
                this.binaryMultinames[idx] = new BinaryMN(nd.kind, name_index, plist);
                break;
            case ActionBlockConstants.CONSTANT_Multiname:
            case ActionBlockConstants.CONSTANT_MultinameA:
                    name_index = nd.params[0];
                    name_space = nd.params[1];
                    ns_is_set  = true;
                    this.binaryMultinames[idx] = new BinaryMN(nd.kind, name_index, name_space, ns_is_set, nd.getVersions());
                break;
            default:
                throw new IllegalArgumentException("Unexpected multiname type: " + nd.kind); //$NON-NLS-1$
            }
        }
       
        return this.binaryMultinames[idx];

    }
   
    AbcParser parser;
    public void setParser(AbcParser parser)
    {
      this.parser = parser;
    }
   
 
  /*
   * Namespace is an ABC-centric view of a namespace.
   */
  public class Namespace implements java.io.Externalizable
  {
 
    int nameOffset;
    public byte nsKind;
   
    Namespace(int name_offset, int ns_kind)
    {
      this.nameOffset = name_offset;
      this.nsKind = (byte)ns_kind;
    }
   
    public String getName()
    {
      assert(nameOffset < strings.length);
      return strings[nameOffset];
    }

    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
    {
      nameOffset = in.readInt();
      nsKind = in.readByte();
    }

    public void writeExternal(ObjectOutput out) throws IOException
    {
      out.writeInt(nameOffset);
      out.writeByte(nsKind);
    }
  }
 
  Namespace[] namespaces;
 
  public Namespace getNamespace(int i)
  {
    return this.namespaces[i];
  }
 
  /*
   * Namespace sets
   */
  public class NamespaceSet implements java.io.Externalizable
  {
    int[] namespaceIds;
   
    NamespaceSet(int[] nss_ids)
    {
      this.namespaceIds = nss_ids;
    }

    public int[] getNamespaceIds()
    {
      return this.namespaceIds;
    }

    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
    {
      namespaceIds = (int[])in.readObject();
    }

    public void writeExternal(ObjectOutput out) throws IOException
    {
      out.writeObject(namespaceIds);
    }
  }
 
  NamespaceSet[] namespaceSets;
 
  public void addNamespaceSet(int nss_id, int[] namespaces)
  {
    if ( !isBuilding() )
      return;
 
    assert(this.namespaceSets != null && nss_id < this.namespaceSets.length && null == this.namespaceSets[nss_id]);
    NamespaceSet nss = new NamespaceSet(namespaces);
    this.namespaceSets[nss_id] = nss;
  }
 
  public NamespaceSet getNamespaceSet(int id)
  {
    assert(id < this.namespaceSets.length);
    return this.namespaceSets[id];
  }

  /*
   * Strings
   */
  String[] strings;
 
  public String getString(int i)
  {
    return this.strings[i];
  }
   
  /*
   * Ints
   */
  int[] ints;
 
  public int getInt(int i)
  {
    return this.ints[i];
  }
 
  /*
   * Uints
   */
  long[] uints;
 
  public long getUint(int i)
  {
    return uints[i];
  }
 
  /*
   * Doubles
   */
  double[] doubles;
 
  public double getDouble(int i)
  {
    return doubles[i];
  }
 
  /*
   * Decimals
   */
  private Decimal128[] decimals;
 
  public Decimal128 getDecimal(int i)
  {
      return decimals[i];
  }
 
  /*
   *  Methods
   */
  public class Method  implements java.io.Externalizable
  {
    private int returnType;
    int[] paramTypes;
    private int nameIndex;
    int flags;
    int[] optionalParamTypes;
    int[] optionalParamKinds;
    int[] paramNames;
   
    public Method(int return_type, int[] param_types,
      int name_index, int flags, int[] optional_param_types,
      int[] optional_param_kinds, int[] param_names)
    {
      this.returnType = return_type;
      this.paramTypes = param_types;
      this.nameIndex = name_index;
      this.flags = flags;
      this.optionalParamTypes = optional_param_types;
      this.optionalParamKinds = optional_param_kinds;
      this.paramNames = param_names;
    }


    public int getReturnType() {
      return returnType;
    }
    public int[] getParamTypes() {
      return this.paramTypes;
    }
    public int getNameIndex() {
      return nameIndex;
    }
    public int getFlags() {
      return this.flags;
    }
    public int[] getOptionalParamTypes() {
      return optionalParamTypes;
    }
    public int[] getOptionalParamKinds() {
      return optionalParamKinds;
    }
    public String[] getParamNames() {
      String[] result = new String[paramNames.length];
     
      for ( int i = 0; i < paramNames.length; i++ )
        result[i] = strings[paramNames[i]];
      return result;
    }
   
    public boolean getNeedsRest() {
      return (flags & ActionBlockConstants.METHOD_Needrest) != 0 || (flags & ActionBlockConstants.METHOD_IgnoreRest) != 0;
    }
        public boolean getHasOptional() {
          return (flags & ActionBlockConstants.METHOD_HasOptional) != 0;
        }
        public boolean getHasParamNames() {
          return (flags & ActionBlockConstants.METHOD_HasParamNames) != 0;
        }


    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
    {
      returnType = in.readInt();
      paramTypes = (int[])in.readObject();
      nameIndex = in.readInt();
      flags = in.readInt();
      optionalParamTypes = (int[])in.readObject();
      optionalParamKinds = (int[])in.readObject();
      paramNames = (int[])in.readObject();
    }


    public void writeExternal(ObjectOutput out) throws IOException
    {
      out.writeInt(returnType);
      out.writeObject(paramTypes);
      out.writeInt(nameIndex);
      out.writeInt(flags);
      out.writeObject(optionalParamTypes);
      out.writeObject(optionalParamKinds);
      out.writeObject(paramNames);
    }
  }
 
  private Method[] methods;
 
  public Method getMethod(int index)
  {
    assert(index >= 0 && index < this.methods.length);
    return this.methods[index];
  }

  /*
   *  Metadata
   */
  public class Metadata implements java.io.Externalizable
  {
    int nameIndex;
    int[] keys;
    int[] values;
   
    Metadata(int name_index, int[] keys, int[] values)
    {
      this.nameIndex = name_index;
      this.keys = keys;
      this.values = values;
      assert(keys.length == values.length);
    }
   
    public int getDataCount() {
      return keys.length;
    }
   
    public String getName()
    {
      return getString(this.nameIndex);
    }
   
    public String getKey(int idx)
    {
      assert(idx >= 0 && idx < keys.length);
      return getString(keys[idx]);
    }
   
    public String getValue(int idx)
    {
      assert(idx >= 0 && idx < values.length);
      return getString(values[idx]);
    }

    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
    {
      nameIndex = in.readInt();
      keys = (int[]) in.readObject();
      values = (int[]) in.readObject();
    }

    public void writeExternal(ObjectOutput out) throws IOException
    {
      out.writeInt(nameIndex);
      out.writeObject(keys);
      out.writeObject(values);
    }
   
  }
 
  private Metadata[] raw_metadata;
  private transient MetaData[] semantic_metadata;
 
  public MetaData getMetadata(int idx, MetaDataNode metaNode )
  {
      if ( null == this.semantic_metadata[idx] )
      {
          Metadata m = this.raw_metadata[idx];
          metaNode.setId(m.getName());

            int[] keys = m.keys;
            int[] raw_values = m.values;
           
            Value[] vals = new Value[keys.length];
            for(int i = 0; i < keys.length; ++i )
            {
                String value = strings[raw_values[i]];
                vals[i] = ( keys[i] == 0 )
                    ? new MetaDataEvaluator.KeylessValue(value)
                    : new MetaDataEvaluator.KeyValuePair( strings[keys[i]], value);
            }
           
            metaNode.setValues(vals);
           semantic_metadata[idx] = metaNode.getMetadata();
      }
    return this.semantic_metadata[idx];
  }
 
 
  /*
   * InstanceInfo
   */
  public class InstanceInfo implements java.io.Externalizable
  {
    int nameIndex;
    int superIndex;
    int flags;
    int protectedNs;
    int[] interfaces;
    int initIndex;
    Trait[] iTraits;
   
    InstanceInfo(int nameIndex, int superIndex, int flags, int protected_ns, int[] interfaces, int init_index, Trait[] itraits)
    {
      this.nameIndex = nameIndex;
      this.superIndex = superIndex;
      this.flags = flags;
      this.protectedNs = protected_ns;
      this.interfaces = interfaces;
      this.initIndex = init_index;
      this.iTraits = itraits;
    }

    public int getInstanceNameID() {
      return nameIndex;
    }
   
    public int getSuperID() {
      return superIndex;
    }
   
    public int getFlags() {
      return flags;
    }
   
    public int getProtectedNs() {
      return protectedNs;
    }
   
    public int[] getInterfaces() {
      return interfaces;
    }
   
    public int getInitIndex() {
      return initIndex;
    }
   
    public Trait[] getITraits() {
      return iTraits;
    }

    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
    {
      nameIndex = in.readInt();
      superIndex  = in.readInt();
      flags  = in.readInt();
      protectedNs  = in.readInt();
      interfaces = (int[]) in.readObject();
      initIndex = in.readInt();
      iTraits = (Trait[])in.readObject();
    }

    public void writeExternal(ObjectOutput out) throws IOException
    {
       out.writeInt(nameIndex);
       out.writeInt(superIndex);
       out.writeInt(flags);
       out.writeInt(protectedNs);
       out.writeObject(interfaces);
       out.writeInt(initIndex);
       out.writeObject(iTraits);
    }
  }
 
  private InstanceInfo[] instanceInfos;
 
  public InstanceInfo getInstanceInfo(int i)
  {
    return this.instanceInfos[i];
  }
 
  /*
   * ClassInfo
   */
  public class ClassInfo implements java.io.Externalizable
  {
    int clinitIndex;
    Trait[] cTraits;
   
    ClassInfo(int clinit_index, Trait[] ctraits)
    {
      this.clinitIndex = clinit_index;
      this.cTraits = ctraits;
    }
   
    public int getClinitIndex() {
      return clinitIndex;
    }
   
    public Trait[] getCTraits() {
      return cTraits;
    }

    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
    {
      clinitIndex = in.readInt();
      cTraits = (Trait[]) in.readObject();
    }

    public void writeExternal(ObjectOutput out) throws IOException
    {
      out.writeInt(clinitIndex);
      out.writeObject(cTraits);
    }
  }
 
  private ClassInfo[] classInfos;
 
  public int getClassInfoSize() {
    return this.classInfos.length;
  }
 
  public ClassInfo getClassInfo(int idx)
  {
    assert(this.classInfos != null && idx >= 0 && idx <= this.classInfos.length);
    return this.classInfos[idx];
  }
 
  /*
   * ScriptInfo
   */
  public class ScriptInfo implements java.io.Externalizable
  {
    int initIndex;
    Trait[] scriptTraits;
   
    ScriptInfo(int init_index, Trait[] script_traits)
    {
      this.initIndex = init_index;
      this.scriptTraits = script_traits;
    }
   
    public int getInitIndex() {
      return this.initIndex;
    }
   
    public Trait[] getScriptTraits() {
      return this.scriptTraits;
    }

    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
    {
      initIndex = in.readInt();
      scriptTraits = (Trait[]) in.readObject();
    }

    public void writeExternal(ObjectOutput out) throws IOException
    {
      out.writeInt(initIndex);
      out.writeObject(scriptTraits);
    }
  }
 
  ScriptInfo[] scriptInfos;
 
  public int getScriptInfoSize()
  {
    return this.scriptInfos.length;
  }
 
  public ScriptInfo getScriptInfo(int idx)
  {
    assert(this.scriptInfos != null && idx >= && idx < this.scriptInfos.length);
    return this.scriptInfos[idx];
  }

  /**
   *   Serialize the AbcData to an ObjectOutput stream.
   */
  public void writeExternal(ObjectOutput out) throws IOException
  {
    out.writeObject(classInfos);
    out.writeObject(doubles);
    out.writeObject(instanceInfos);
    out.writeObject(ints);
    out.writeObject(raw_metadata);
    out.writeObject(methods);
    out.writeObject(namespaces);
    out.writeObject(namespaceSets);
    out.writeObject(nameData);
    out.writeObject(scriptInfos);
    out.writeObject(scriptName);
    out.writeObject(strings);
    out.writeObject(uints);
  }
 
  /**
   * Deserialize the AbcData.
   */
  public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
  {
    classInfos = (ClassInfo[])in.readObject();
    doubles = (double[]) in.readObject();
    instanceInfos = (InstanceInfo[])in.readObject();
    ints = (int[])in.readObject();
    raw_metadata = (Metadata[])in.readObject();
    semantic_metadata = new MetaData[raw_metadata.length];
    methods = (Method[]) in.readObject();
    namespaces = (Namespace[]) in.readObject();
    namespaceSets = (NamespaceSet[])in.readObject();
    nameData = (NameData[])in.readObject();
    scriptInfos = (ScriptInfo[])in.readObject();
    scriptName = (String)in.readObject();
    strings = (String[])in.readObject();
    uints = (long[]) in.readObject();
   
    dirty = false;
  }
 
  public void readAbc(byte[] raw_abc)
  {
      if (!this.isBuilding() )
          return;

      readAbc(new BytecodeBuffer(raw_abc));
  }
    
  public void readAbc(BytecodeBuffer buf)
  {
      if (!this.isBuilding() )
            return;
     
        int minor_version = buf.readU16();
        /*int major_version =*/ buf.readU16();

        // Scan the bytecode for the stuff we care about
        scanCpool(buf, minor_version >= ActionBlockConstants.MINORwithDECIMAL);
        scanMethods(buf);
        scanMetadata(buf);
        scanClasses(buf);
        scanScripts(buf);
  }

  void scanCpool(BytecodeBuffer buf, boolean hasDecimal)
    {
        int size;
       
        size = buf.readU32();  
        this.ints = new int[size];
        for (int i = 1; i < size; i++)
        {
            this.ints[i] = buf.readU32();
        }
       
        size = buf.readU32();
        this.uints = new long[size];
        for (int i = 1; i < size; i++)
        {
            this.uints[i] = buf.readU32() & 0xFFFFFFFFL;
        }
       
        size = buf.readU32();
        this.doubles = new double[size];
        for (int i = 1; i < size; i++)
        {
            this.doubles[i] = buf.readDouble();
        }
       
        if (hasDecimal)
        {
            size = buf.readU32();
            this.decimals = new Decimal128[size];

            for (int i = 1; i < size; i++)
            {
               byte[] rep = buf.readBytes(16);
               decimals[i] = new Decimal128(rep);
            }
        }

        size = buf.readU32();
        this.strings = new String[size];
        this.strings[0] = "".intern();
        for (int i = 1; i < size; i++)
        {
            int length = buf.readU32();
            this.strings[i] = buf.readString(length).intern();
            buf.skip(length);   //  readString() doesn't reset pos pointer.
        }
       
        size = buf.readU32();
        this.namespaces = new Namespace[size];
        for (int i = 1; i < size; i++)
        {
            int ns_kind = buf.readU8(); // kind byte
            int name_offset = buf.readU32();
            this.namespaces[i] = new Namespace(name_offset, ns_kind);
        }
       
        size = buf.readU32();
        this.namespaceSets = new NamespaceSet[size];
        for (int i = 1; i < size; i++)
        {
            int count = buf.readU32(); // count
            int[] ns_ids = new int[count];
            for(int q =0; q < count; ++q)
            {
                ns_ids[q] = buf.readU32();
            }
            this.namespaceSets[i] = new NamespaceSet(ns_ids);
        }
       
        size = buf.readU32();
        this.nameData = new NameData[size];
        this.binaryMultinames = new BinaryMN[size];
             
        for (int i = 1; i < size; i++)
        {
            int kind = buf.readU8();
            switch (kind)
            {
                case ActionBlockConstants.CONSTANT_Qname:
                case ActionBlockConstants.CONSTANT_QnameA:
                    this.nameData[i] = new NameData(kind, new int[] {buf.readU32(), buf.readU32()});
                    break;
                case ActionBlockConstants.CONSTANT_RTQname:
                case ActionBlockConstants.CONSTANT_RTQnameA:
                    this.nameData[i] = new NameData(kind, new int[] {buf.readU32()});
                    break;
                case ActionBlockConstants.CONSTANT_Multiname:
                case ActionBlockConstants.CONSTANT_MultinameA:
                    this.nameData[i] = new NameData(kind, new int[] {buf.readU32(), buf.readU32()} );
                    break;
                case ActionBlockConstants.CONSTANT_MultinameL:
                case ActionBlockConstants.CONSTANT_MultinameLA:
                    this.nameData[i] = new NameData(kind, new int[] {buf.readU32()});
                    break;
                case ActionBlockConstants.CONSTANT_TypeName:
                    int name_index = buf.readU32(); // name index
                    int count = buf.readU32(); // param count;
                    int[] entries = new int[count+2];
                    entries[0] = name_index;
                    entries[1] = count;
                    for ( int k = 0; k < count; k++)
                        entries[k+2] = buf.readU32();
                    this.nameData[i] = new NameData(kind, entries);
                    break;
                case ActionBlockConstants.CONSTANT_RTQnameL:
                case ActionBlockConstants.CONSTANT_RTQnameLA:
                    this.nameData[i] = new NameData(kind, null);
                    break;
                default:
                    throw new RuntimeException("bad multiname type: " + kind);

            }
        }
    }

    void scanMethods(BytecodeBuffer buf)
    {
        int methodEntries = buf.readU32();
        this.methods = new Method[methodEntries];
       
        for (int i = 0; i < methodEntries; i++)
        {
            int param_count = buf.readU32();
            int return_type = buf.readU32();
            int[] param_types = new int[param_count];
            for ( int j = 0; j < param_count; j++ )
                param_types[j] = buf.readU32();
            int name_index = buf.readU32();
            int flags = buf.readU8();  
           
            int optional_param_count = ((flags & ActionBlockConstants.METHOD_HasOptional) != 0)? buf.readU32(): 0;
            int[] optional_param_types = new int[optional_param_count];
            int[] optional_param_kinds = new int[optional_param_count];
           
            for( int q = 0; q < optional_param_count; ++q )
            {
                optional_param_types[q] = buf.readU32();
                optional_param_kinds[q] = buf.readU8();
            }

            int param_name_count = ((flags & ActionBlockConstants.METHOD_HasParamNames)!=0) ? param_count : 0;
            int[] param_names = new int[param_name_count];
            for( int q = 0; q < param_name_count; ++q )
            {
                param_names[q] = buf.readU32();
            }
           
            this.methods[i] = new Method(return_type, param_types, name_index, flags, optional_param_types, optional_param_kinds, param_names);
        }
    }

    void scanMetadata(BytecodeBuffer buf)
    {
        int metadataEntries = buf.readU32();
       
        this.raw_metadata = new Metadata[metadataEntries];
        this.semantic_metadata = new MetaData[metadataEntries];
       
        for (int i = 0; i < metadataEntries; i++)
        {
            int name_index  = buf.readU32();
            int value_count = buf.readU32(); //returnType
           
            int[] keys   = new int[value_count];
            int[] values = new int[value_count];
           
            for ( int j = 0; j < value_count; j++ )
            {
                keys[j] = buf.readU32();
            }
            for(int j = 0; j < value_count; j++ )
            {
                values[j] = buf.readU32();
            }
           
            this.raw_metadata[i] = new Metadata( name_index, keys, values );
        }
    }

    void scanClasses(BytecodeBuffer buf)
    {
        int classEntries = buf.readU32();

        this.classInfos = new ClassInfo[classEntries];
        this.instanceInfos = new InstanceInfo[classEntries];
       
        // InstanceInfos
        for(int i = 0; i < classEntries; ++i)
        {
            int name_index = buf.readU32();
            int super_index = buf.readU32(); //super_index
            int flags = buf.readU8();
            int protected_ns = 0;
            if ((flags & ActionBlockConstants.CLASS_FLAG_protected) != 0)
            {
                protected_ns = buf.readU32();
            }
              
            int interface_count = buf.readU32();
            int[] interfaces = new int[interface_count];
            for ( int j = 0; j < interface_count; j++ )
                interfaces[j] = buf.readU32();
            int init_index = buf.readU32();
            AbcData.Trait[] itraits = scanTraits(buf);
           
            this.instanceInfos[i] = new InstanceInfo(name_index, super_index, flags, protected_ns, interfaces, init_index, itraits);
        }

        // ClassInfos
        for(int i = 0; i < classEntries; ++i)
        {
            int clinit_index = buf.readU32();
            AbcData.Trait[] ctraits = scanTraits(buf);
           
            this.classInfos[i] = new ClassInfo(clinit_index, ctraits);
        }

    }

    void scanScripts(BytecodeBuffer buf)
    {
        int script_count = buf.readU32();
        this.scriptInfos = new ScriptInfo[script_count];
        for(int i = 0 ; i < script_count; ++i )
        {
            this.scriptInfos[i] = new ScriptInfo(buf.readU32(), scanTraits(buf));
        }
    }

    /**
     * Read traits from the bytecode into AbcData cache form
     * @return the deserialized traits.
     */
    AbcData.Trait[] scanTraits(BytecodeBuffer buf)
    {
        int count = buf.readU32();
       
        AbcData.Trait[] result = new AbcData.Trait[count];

        for (int i = 0; i < count; i++)
        {
            int name_index = buf.readU32();
            int kind = buf.readU8();
            int tag = kind & 0x0f;
           
            AbcData.Trait new_trait = null;
           
            switch (tag)
            {
            case ActionBlockConstants.TRAIT_Var:
            case ActionBlockConstants.TRAIT_Const:
            {
                int slot_id = buf.readU32();
                int trait_type = buf.readU32();
                int value_index = buf.readU32();
                int value_kind = 0;
                if( value_index > 0 )
                    value_kind = buf.readU8();
           
                new_trait = this.new Trait(name_index, kind, new int[] { slot_id, trait_type, value_index, value_kind});
                break;
            }
            case ActionBlockConstants.TRAIT_Method:
            case ActionBlockConstants.TRAIT_Getter:
            case ActionBlockConstants.TRAIT_Setter:
            {
                int disp_id = buf.readU32();
                int method = buf.readU32();
                new_trait = this.new Trait(name_index, kind, new int[] {disp_id, method} );
                break;
            }
            case ActionBlockConstants.TRAIT_Class:
            case ActionBlockConstants.TRAIT_Function:
            {
                int slot_id  = buf.readU32();
                int class_id = buf.readU32();
                new_trait = this.new Trait(name_index, kind, new int[] { slot_id, class_id } );
                break;
            }
            default:
                break;
                //throw new DecoderException("Invalid trait kind: " + kind);
            }
           
            assert(new_trait != null);
            result[i] = new_trait;
           
            if( new_trait.hasMetadata() )
            {
                int metadata_count = buf.readU32();
                int[] metadata = new int[metadata_count];
                for ( int j = 0; j < metadata_count; j++)
                    metadata[j] = buf.readU32();
                new_trait.addMetadata(metadata);
            }
        }
       
        return result;
    }

 
 
}
TOP

Related Classes of macromedia.abc.AbcData$Method

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.