blob: b51f051cf478d769e968397391a9090ede457ff3 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009 IBM Corporation and Others
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Shin SAITO - initial API and implementation
*******************************************************************************/
package org.eclipse.actf.model.internal.flash.proxy;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Logger;
import java.util.zip.InflaterInputStream;
class SwfStageResizer {
private static final Logger LOGGER = Logger.getLogger(SwfStageResizer.class
.getName());
private static final int COMPRESSED_FLAG = 0x43; // 'C'
private int bitBuf = 0;
private int bitPos = 0;
private int byteCount = 0;
private byte[] buf2 = new byte[17];
private ByteArrayOutputStream bo;
private InputStream bi;
static public byte[] resize(byte[] swf, int w, int h) {
return new SwfStageResizer().doResize(swf, w, h);
}
public byte[] doResize(byte[] swf, int w, int h) {
try {
LOGGER
.info("Resizing SWF to " + (w / 20) + "x" + (h / 20) + " pixels..."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
bo = new ByteArrayOutputStream();
bi = new ByteArrayInputStream(swf);
int data;
byte[] buf;
data = bi.read();
bo.write('F');
boolean isCompressed = (data == COMPRESSED_FLAG);
LOGGER.fine("compressed? = " + isCompressed); //$NON-NLS-1$
bo.write(bi.read());
bo.write(bi.read());
data = bi.read();
bo.write(data);
int swfVersion = data & 0xFF;
LOGGER.fine("SWF version = " + swfVersion); //$NON-NLS-1$
buf = new byte[4];
bi.read(buf);
int length = buf[0] & 0xFF | (buf[1] & 0xFF) << 8
| (buf[2] & 0xFF) << 16 | buf[3] << 24;
LOGGER.fine("length = " + length); //$NON-NLS-1$
bo.write(buf); // writes overwritten data
if (isCompressed) {
bi = new InflaterInputStream(bi);
}
int[] size = readFrameSize();
LOGGER
.fine("original frame size (in twips) = " + size[0] + "x" + size[1]); //$NON-NLS-1$ //$NON-NLS-2$
writeFrameSize(w, h);
data = bi.read();
int rate = (data & 0xff) << 8;
bo.write(data);
data = bi.read();
rate |= data & 0xff;
bo.write(data);
LOGGER.fine("framerate = " + rate); //$NON-NLS-1$
data = bi.read();
int framecount = data & 0xff;
bo.write(data);
data = bi.read();
framecount |= (data & 0xff) << 8;
bo.write(data);
LOGGER.fine("framecount = " + framecount); //$NON-NLS-1$
// header finished
// main body. consumes tags
while ((data = bi.read()) >= 0) {
bo.write(data);
}
// modify file size field
byte[] array = bo.toByteArray();
int fileSize = array.length;
LOGGER
.info("Modifying file size field from " + length + " to " + fileSize); //$NON-NLS-1$ //$NON-NLS-2$
for (int i = 4; i <= 7; i++) {
array[i] = (byte) (fileSize & 0xFF);
fileSize = fileSize >> 8;
}
LOGGER.fine("done"); //$NON-NLS-1$
return array;
} catch (IOException e) {
e.printStackTrace();
return new byte[0];
}
}
private int[] readFrameSize() throws IOException {
int[] size = new int[2];
int nBits = readUBits(5);
LOGGER.fine("frame size X min = " + Integer.toString(readSBits(nBits))); //$NON-NLS-1$
size[0] = readSBits(nBits);
LOGGER.fine("frame size X max (twips) = " + Integer.toString(size[0])); //$NON-NLS-1$
LOGGER.fine("frame size Y min = " + Integer.toString(readSBits(nBits))); //$NON-NLS-1$
size[1] = readSBits(nBits);
LOGGER.fine("frame size Y max (twips) = " + Integer.toString(size[1])); //$NON-NLS-1$
return size;
}
private int readSBits(int numBits) throws IOException {
if (numBits > 32) {
throw new IOException("Number of bits > 32"); //$NON-NLS-1$
}
int num = readUBits(numBits);
int shift = 32 - numBits;
// sign extension
num = (num << shift) >> shift;
return num;
}
private int readUBits(int numBits) throws IOException {
if (numBits == 0) {
return 0;
}
int bitsLeft = numBits;
int result = 0;
byte[] buf;
if (bitPos == 0) // no value in the buffer - read a byte
{
buf = new byte[1];
bi.read(buf);
buf2[byteCount] = buf[0];
byteCount++;
bitBuf = buf[0] & 0xFF;
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
buf = new byte[1];
bi.read(buf);
buf2[byteCount] = buf[0];
byteCount++;
bitBuf = buf[0] & 0xFF;
bitPos = 8;
} else {
// Consume a portion of the buffer
result |= bitBuf >> -shift;
bitPos -= bitsLeft;
bitBuf &= 0xff >> (8 - bitPos); // mask off the consumed bits
return result;
}
}
}
private void writeFrameSize(int w, int h) throws IOException {
int dw = numDigit(w) + 1;
int dh = numDigit(h) + 1;
LOGGER.fine("required number of digits = " + dw + ", " + dh); //$NON-NLS-1$ //$NON-NLS-2$
int d = Math.max(dw, dh);
BitBuffer bb = new BitBuffer();
bb.append(d, 5);
bb.append(0, d);
bb.append(w, d);
bb.append(0, d);
bb.append(h, d);
bo.write(bb.toByteArray());
}
private int numDigit(int v) {
if (v < 0) {
return -1;
} else {
int d = 0;
while (v > 0) {
v = v >> 1;
d++;
}
return d;
}
}
}