/* * Copyright (C) 2010-2013 JPEXS * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package com.jpexs.decompiler.flash.abc; import com.jpexs.decompiler.flash.abc.types.*; import com.jpexs.decompiler.flash.abc.types.traits.*; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; public class ABCInputStream extends InputStream { private static final int CLASS_PROTECTED_NS = 8; private static final int ATTR_METADATA = 4; private InputStream is; private long bytesRead = 0; private ByteArrayOutputStream bufferOs = null; public static boolean DEBUG_READ = false; public void startBuffer() { bufferOs = new ByteArrayOutputStream(); } public byte[] stopBuffer() { if (bufferOs == null) { return new byte[0]; } byte ret[] = bufferOs.toByteArray(); bufferOs = null; return ret; } public ABCInputStream(InputStream is) { this.is = is; } @Override public int read() throws IOException { bytesRead++; int i = is.read(); if (DEBUG_READ) { System.out.println("Read:0x" + Integer.toHexString(i)); } if (bufferOs != null) { if (i != -1) { bufferOs.write(i); } } return i; } @Override public int read(byte[] b) throws IOException { int currBytesRead = is.read(b); bytesRead += currBytesRead; if (DEBUG_READ) { StringBuilder sb = new StringBuilder("Read["); sb.append(currBytesRead); sb.append('/'); sb.append(b.length); sb.append("]: "); for (int jj = 0; jj < currBytesRead; jj++) { sb.append("0x"); sb.append(Integer.toHexString(b[jj])); sb.append(' '); } System.out.println(sb.toString()); } if (bufferOs != null) { if (currBytesRead > 0) { bufferOs.write(b, 0, currBytesRead); } } return currBytesRead; } ; public int readU8() throws IOException { return read(); } public int readU32() throws IOException { int i; int ret = 0; int bytePos = 0; int byteCount = 0; boolean nextByte; do { i = read(); nextByte = (i >> 7) == 1; i = i & 0x7f; ret = ret + (i << bytePos); byteCount++; bytePos += 7; } while (nextByte); return ret; } public int readU30() throws IOException { return readU32(); } public int readS24() throws IOException { int ret = (read()) + (read() << 8) + (read() << 16); if ((ret >> 23) == 1) { ret = ret | 0xff000000; } return ret; } public int readU16() throws IOException { return (read()) + (read() << 8); } public long readS32() throws IOException { int i; long ret = 0; int bytePos = 0; int byteCount = 0; boolean nextByte; do { i = read(); nextByte = (i >> 7) == 1; i = i & 0x7f; ret = ret + (i << bytePos); byteCount++; bytePos += 7; if (bytePos == 35) { if ((ret >> 31) == 1) { ret = -(ret & 0x7fffffff); } break; } } while (nextByte); return ret; } @Override public int available() throws IOException { return is.available(); } public final long readLong() throws IOException { byte readBuffer[] = safeRead(8); return (((long) readBuffer[7] << 56) + ((long) (readBuffer[6] & 255) << 48) + ((long) (readBuffer[5] & 255) << 40) + ((long) (readBuffer[4] & 255) << 32) + ((long) (readBuffer[3] & 255) << 24) + ((readBuffer[2] & 255) << 16) + ((readBuffer[1] & 255) << 8) + ((readBuffer[0] & 255))); } public double readDouble() throws IOException { long el = readLong(); double ret = Double.longBitsToDouble(el); return ret; } private byte[] safeRead(int count) throws IOException { byte ret[] = new byte[count]; for (int i = 0; i < count; i++) { ret[i] = (byte) read(); } return ret; } public Namespace readNamespace() throws IOException { int kind = read(); int name_index = 0; for (int k = 0; k < Namespace.nameSpaceKinds.length; k++) { if (Namespace.nameSpaceKinds[k] == kind) { name_index = readU30(); break; } } return new Namespace(kind, name_index); } public Multiname readMultiname() throws IOException { int kind = readU8(); int namespace_index = -1; int name_index = -1; int namespace_set_index = -1; int qname_index = -1; List params = new ArrayList<>(); if ((kind == 7) || (kind == 0xd)) { // CONSTANT_QName and CONSTANT_QNameA. namespace_index = readU30(); name_index = readU30(); } else if ((kind == 0xf) || (kind == 0x10)) { //CONSTANT_RTQName and CONSTANT_RTQNameA name_index = readU30(); } else if ((kind == 0x11) || (kind == 0x12))//kind==0x11,0x12 nothing CONSTANT_RTQNameL and CONSTANT_RTQNameLA. { } else if ((kind == 9) || (kind == 0xe)) { // CONSTANT_Multiname and CONSTANT_MultinameA. name_index = readU30(); namespace_set_index = readU30(); } else if ((kind == 0x1B) || (kind == 0x1C)) { //CONSTANT_MultinameL and CONSTANT_MultinameLA namespace_set_index = readU30(); } else if (kind == 0x1D) { //Constant_TypeName qname_index = readU30(); //Multiname index!!! int paramsLength = readU30(); for (int i = 0; i < paramsLength; i++) { params.add(readU30()); //multiname indices! } } else { System.err.println("Unknown kind of Multiname:0x" + Integer.toHexString(kind)); System.exit(1); } return new Multiname(kind, name_index, namespace_index, namespace_set_index, qname_index, params); } public MethodInfo readMethodInfo() throws IOException { int param_count = readU30(); int ret_type = readU30(); int param_types[] = new int[param_count]; for (int i = 0; i < param_count; i++) { param_types[i] = readU30(); } int name_index = readU30(); int flags = read(); //// 1=need_arguments, 2=need_activation, 4=need_rest 8=has_optional (16=ignore_rest, 32=explicit,) 64=setsdxns, 128=has_paramnames ValueKind optional[] = new ValueKind[0]; if ((flags & 8) == 8) { //if has_optional int optional_count = readU30(); optional = new ValueKind[optional_count]; for (int i = 0; i < optional_count; i++) { optional[i] = new ValueKind(readU30(), read()); } } int param_names[] = new int[param_count]; if ((flags & 128) == 128) { //if has_paramnames for (int i = 0; i < param_count; i++) { param_names[i] = readU30(); } } return new MethodInfo(param_types, ret_type, name_index, flags, optional, param_names); } public Trait readTrait() throws IOException { long pos = getPosition(); startBuffer(); int name_index = readU30(); int kind = read(); int kindType = 0xf & kind; int kindFlags = kind >> 4; Trait trait; switch (kindType) { case 0: //slot case 6: //const TraitSlotConst t1 = new TraitSlotConst(); t1.slot_id = readU30(); t1.type_index = readU30(); t1.value_index = readU30(); if (t1.value_index != 0) { t1.value_kind = read(); } trait = t1; break; case 1: //method case 2: //getter case 3: //setter TraitMethodGetterSetter t2 = new TraitMethodGetterSetter(); t2.disp_id = readU30(); t2.method_info = readU30(); trait = t2; break; case 4: //class TraitClass t3 = new TraitClass(); t3.slot_id = readU30(); t3.class_info = readU30(); trait = t3; break; case 5: //function TraitFunction t4 = new TraitFunction(); t4.slot_index = readU30(); t4.method_info = readU30(); trait = t4; break; default: throw new IOException("Unknown trait kind:" + kind); } trait.fileOffset = pos; trait.kindType = kindType; trait.kindFlags = kindFlags; trait.name_index = name_index; if ((kindFlags & ATTR_METADATA) != 0) { int metadata_count = readU30(); trait.metadata = new int[metadata_count]; for (int i = 0; i < metadata_count; i++) { trait.metadata[i] = readU30(); } } trait.bytes = stopBuffer(); return trait; } public Traits readTraits() throws IOException { int count = readU30(); Traits traits = new Traits(); traits.traits = new Trait[count]; for (int i = 0; i < count; i++) { traits.traits[i] = readTrait(); } return traits; } public byte[] readBytes(int count) throws IOException { byte ret[] = new byte[count]; for (int i = 0; i < count; i++) { ret[i] = (byte) read(); } return ret; } public Decimal readDecimal() throws IOException { byte data[] = readBytes(16); return new Decimal(data); } public InstanceInfo readInstanceInfo() throws IOException { InstanceInfo ret = new InstanceInfo(); ret.name_index = readU30(); ret.super_index = readU30(); ret.flags = read(); if ((ret.flags & CLASS_PROTECTED_NS) != 0) { ret.protectedNS = readU30(); } int interfaces_count = readU30(); ret.interfaces = new int[interfaces_count]; for (int i = 0; i < interfaces_count; i++) { ret.interfaces[i] = readU30(); } ret.iinit_index = readU30(); ret.instance_traits = readTraits(); return ret; } public String readString() throws IOException { int length = readU30(); byte b[] = safeRead(length); String r = new String(b, "UTF-8"); return r; } /*public void markStart(){ bytesRead=0; }*/ public long getPosition() { return bytesRead; } }