/*
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
*/
package com.jpexs.decompiler.flash.types.gfx;
import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.dumpview.DumpInfo;
import com.jpexs.helpers.MemoryInputStream;
import com.jpexs.helpers.utf8.Utf8Helper;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
/**
*
* @author JPEXS
*/
public class GFxInputStream {
private final MemoryInputStream is;
private static final int MaxUInt7 = (1 << 7) - 1;
public DumpInfo dumpInfo;
public GFxInputStream(MemoryInputStream is) {
this.is = is;
}
public DumpInfo newDumpLevel(String name, String type) {
if (dumpInfo != null) {
long startByte = is.getPos();
DumpInfo di = new DumpInfo(name, type, null, startByte, 0, 0, 0);
di.parent = dumpInfo;
dumpInfo.getChildInfos().add(di);
dumpInfo = di;
}
return dumpInfo;
}
public void endDumpLevel() {
endDumpLevel(null);
}
public void endDumpLevel(Object value) {
if (dumpInfo != null) {
dumpInfo.lengthBytes = is.getPos() - dumpInfo.startByte;
dumpInfo.previewValue = value;
dumpInfo = dumpInfo.parent;
}
}
public int available() throws IOException {
return is.available();
}
public void setPos(long pos) throws IOException {
is.seek(pos);
}
public long getPos() {
return is.getPos();
}
private int read() throws IOException {
return is.read();
}
public int readUI8(String name) throws IOException {
newDumpLevel(name, "UI8");
int ret = read();
endDumpLevel(ret);
return ret;
}
public int readUI16(String name) throws IOException {
newDumpLevel(name, "UI8");
int ret = read() + (read() << 8);
endDumpLevel(ret);
return ret;
}
/**
* Reads one SI16 (Signed 16bit integer) value from the stream
*
* @param name
* @return SI16 value
* @throws IOException
*/
public int readSI16(String name) throws IOException {
newDumpLevel(name, "SI16");
int uval = read() + (read() << 8);
if (uval >= 0x8000) {
uval = -(((~uval) & 0xffff) + 1);
}
endDumpLevel(uval);
return uval;
}
private long readUI32Internal() throws IOException {
long ret = (read() + (read() << 8) + (read() << 16) + (read() << 24)) & 0xffffffff;
return ret;
}
public long readUI32(String name) throws IOException {
newDumpLevel(name, "UI32");
long ret = readUI32Internal();
endDumpLevel(ret);
return ret;
}
public long readUI30(String name) throws IOException {
newDumpLevel(name, "UI30");
long v;
int tb = read();
long t = tb;
switch (tb & 3) {
case 0:
v = t >> 2;
endDumpLevel(v);
return v;
case 1:
t >>= 2;
v = t | (read() << 6);
endDumpLevel(v);
return v;
case 2:
t >>= 2;
t |= (read() << 6);
v = t | (read() << 14);
endDumpLevel(v);
return v;
}
t >>= 2;
t |= (read() << 6);
t |= (read() << 14);
v = t | (read() << 22);
endDumpLevel(v);
return v;
}
public float readFLOAT(String name) throws IOException {
newDumpLevel(name, "UI32");
int val = (int) readUI32Internal();
float ret = Float.intBitsToFloat(val);
endDumpLevel(ret);
return ret;
}
public int readSI8(String name) throws IOException {
newDumpLevel(name, "SI8");
int uval = readSI8Internal();
endDumpLevel(uval);
return uval;
}
private int readSI8Internal() throws IOException {
int uval = read();
if (uval >= 0x80) {
uval = -(((~uval) & 0xff) + 1);
}
return uval;
}
public int readSI15(String name) throws IOException {
newDumpLevel(name, "SI15");
int t = readSI8Internal();
int v;
if ((t & 1) == 0) {
v = t >> 1;
endDumpLevel(v);
return v;
}
t = ((t >> 1) & MaxUInt7);
v = (t | (readSI8Internal() << 7));
endDumpLevel(v);
return v;
}
public int readUI15(String name) throws IOException {
newDumpLevel(name, "UI15");
int t = read();
int v;
if ((t & 1) == 0) {
v = t >> 1;
endDumpLevel(v);
return v;
}
t = (t >> 1);
v = (t | (read() << 7));
endDumpLevel(v);
return v;
}
/**
* Reads bytes from the stream
*
* @param count Number of bytes to read
* @param name
* @return Array of read bytes
* @throws IOException
*/
public byte[] readBytes(long count, String name) throws IOException {
if (count <= 0) {
return SWFInputStream.BYTE_ARRAY_EMPTY;
}
newDumpLevel(name, "bytes");
byte[] ret = new byte[(int) count];
for (int i = 0; i < count; i++) {
ret[i] = (byte) read();
}
endDumpLevel();
return ret;
}
void read(byte[] bytes) throws IOException {
is.read(bytes);
}
/**
* Reads one string value from the stream
*
* @param name
* @return String value
* @throws IOException
*/
public String readString(String name) throws IOException {
newDumpLevel(name, "string");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int r;
while (true) {
r = read();
if (r == 0) {
String res = new String(baos.toByteArray(), Utf8Helper.charset);
endDumpLevel(res);
return res;
}
baos.write(r);
}
}
}