flash.swf.SwfDecoder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of swfutils Show documentation
Show all versions of swfutils Show documentation
The Apache Royale Compiler SWF Utility classes
The newest version!
/*
*
* 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 flash.swf;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.BufferedInputStream;
import java.io.UTFDataFormatException;
/**
* A decoder for a whole SWF.
*/
public final class SwfDecoder extends BufferedInputStream
{
private int offset;
private int bitBuf;
private int bitPos;
int swfVersion;
/**
* create a decoder that reads directly from this byte array
* @param b
* @param swfVersion
*/
public SwfDecoder(byte[] b, int swfVersion)
{
this((InputStream)null, swfVersion);
buf = b;
count = b.length;
pos = 0;
}
/**
* create a buffering decoder that reads from this unbuffered
* input stream. Since SwfDecoder is a BufferedInputStream,
* it is not necessary to provide a BufferedInputStream for good
* performance.
* @param in
* @param swfVersion
*/
public SwfDecoder(InputStream in, int swfVersion)
{
super(in);
this.swfVersion = swfVersion;
}
public SwfDecoder(InputStream in, int swfVersion, int offset)
{
this(in, swfVersion);
this.offset = offset;
}
public void readFully(byte[] b) throws IOException
{
int remain = b.length;
int off = 0;
int count;
while (remain > 0)
{
count = read(b, off, remain);
if (count > 0)
{
off += count;
remain -= count;
}
else
{
throw new SwfFormatException("couldn't read " + remain);
}
}
}
public int read() throws IOException
{
offset++;
return super.read();
}
public int read(byte b[], int off, int len)
throws IOException
{
int n = super.read(b,off,len);
offset += n;
return n;
}
public synchronized long skip(long len) throws IOException
{
long n = super.skip(len);
offset += n;
return n;
}
public float readFixed8() throws IOException
{
int val = readUI16();
// FIXME: this doesn't consider sign of original 8.8 value
return (float)(val / 256.0);
}
public int readUI8() throws IOException
{
if (pos= 2)
{
i = buf[pos] & 0xFF | (buf[pos + 1] & 0xFF) << 8;
pos += 2;
offset += 2;
}
else if (in != null)
{
i = super.read() | super.read()<<8;
offset += 2;
}
else
{
return -1;
}
return i;
}
public long readUI32() throws IOException
{
long i = readSI32() & 0xFFFFFFFFL;
return i;
}
public int readSI32() throws IOException
{
syncBits();
int i;
if (count - pos >= 4)
{
i = buf[pos] & 0xFF | (buf[pos + 1] & 0xFF) << 8 | (buf[pos + 2] & 0xFF) << 16 | buf[pos + 3] << 24;
offset += 4;
pos += 4;
}
else if (in != null)
{
i = super.read() | super.read() << 8 | super.read() << 16 | super.read() << 24;
offset += 4;
}
else
{
i = -1;
}
return i;
}
public long read64() throws IOException
{
return (readUI32() & 0xFFFFFFFFL) | (readUI32() << 32);
}
public boolean readBit() throws IOException
{
return readUBits(1) != 0;
}
public int readUBits(int numBits) throws IOException
{
if (numBits == 0)
{
return 0;
}
int bitsLeft = numBits;
int result = 0;
if (bitPos == 0) //no value in the buffer - read a byte
{
bitBuf = readUI8();
bitPos = 8;
}
while (true)
{
int shift = bitsLeft - bitPos;
if (shift > 0)
{
// Consume the entire buffer
result |= bitBuf << shift;
bitsLeft -= bitPos;
// Get the next byte from the input stream
bitBuf = readUI8();
bitPos = 8;
}
else
{
// Consume a portion of the buffer
result |= bitBuf >> -shift;
bitPos -= bitsLeft;
bitBuf &= 0xff >> (8 - bitPos); // mask off the consumed bits
// if (print) System.out.println(" read"+numBits+" " + result);
return result;
}
}
}
public int readSBits(int numBits) throws IOException
{
if (numBits > 32)
{
throw new SwfFormatException("Number of bits > 32");
}
int num = readUBits(numBits);
int shift = 32-numBits;
// sign extension
num = (num << shift) >> shift;
return num;
}
public int readSI16() throws IOException
{
return (short)readUI16();
}
public float readFloat() throws IOException
{
int bits = readSI32();
return Float.intBitsToFloat( bits );
}
private final ByteArrayOutputStream out = new ByteArrayOutputStream(256)
{
public byte[] toByteArray()
{
// don't bother copying the array
return buf;
}
};
public String readLengthString() throws IOException
{
int length = readUI8();
byte[] b = new byte[length];
readFully(b);
// [paul] Flash Authoring and the player null terminate the
// string, so ignore the last byte when constructing the String.
if (swfVersion >= 6)
{
return new String(b, 0, length - 1, "UTF8").intern();
}
else
{
// use platform encoding
return new String(b, 0, length - 1).intern();
}
}
public String readString() throws IOException
{
if (swfVersion >= 6)
{
return readUTF().intern();
}
else
{
int ch;
while ((ch = readUI8()) > 0)
{
out.write(ch);
}
// use platform encoding
String s = new String(out.toByteArray(), 0, out.size());
out.reset();
return s.intern();
}
}
private String readUTF() throws IOException
{
StringBuilder b = new StringBuilder();
int c, c2, c3;
while ((c = readUI8()) > 0)
{
switch (c >> 4)
{
case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
/* 0xxxxxxx*/
b.append((char) c);
break;
case 12: case 13:
/* 110x xxxx 10xx xxxx*/
c2 = readUI8();
if (c2 <= 0 || (c2 & 0xC0) != 0x80)
throw new UTFDataFormatException();
b.append((char) ((c & 0x1F) << 6 | c2 & 0x3F));
break;
case 14:
/* 1110 xxxx 10xx xxxx 10xx xxxx */
c2 = readUI8();
c3 = readUI8();
if (c2 <= 0 || c3 <= 0 || ((c2 & 0xC0) != 0x80) || ((c3 & 0xC0) != 0x80))
throw new UTFDataFormatException();
b.append((char) ((c & 0x0F) << 12 | (c2 & 0x3F) << 6 | c3 & 0x3F));
break;
default:
/* 10xx xxxx, 1111 xxxx */
throw new UTFDataFormatException();
}
}
return b.toString();
}
public void syncBits()
{
bitPos = 0;
}
public int getOffset()
{
return offset;
}
private int markOffset;
public void mark(int readlimit)
{
markOffset = offset;
super.mark(readlimit);
}
public void reset() throws IOException
{
offset = markOffset;
super.reset();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy