package com.intellij.flex.uiDesigner.abc; import com.intellij.flex.uiDesigner.io.IOUtil; import com.intellij.openapi.vfs.VirtualFile; import gnu.trove.TIntArrayList; import java.awt.*; import java.io.*; abstract class MovieTranscoder extends SwfTranscoder { private static byte[] SPRITE_SYMBOL_OWN_CLASS_ABC; private static byte[] MOVIE_CLIP_SYMBOL_OWN_CLASS_ABC; private static final byte[] ROOT_SWF_CLASS_NAME = "flash.display.Sprite".getBytes(); private static final byte[] SYMBOL_OWN_CLASS_NAME = "_SymbolOwnClass".getBytes(); protected static final int SYMBOL_CLASS_TAG_LENGTH = 2 /* NumSymbols */ + symbolClassEntryLength(ROOT_SWF_CLASS_NAME) + symbolClassEntryLength(SYMBOL_OWN_CLASS_NAME); protected static final int SYMBOL_CLASS_TAG_FULL_LENGTH = recordHeaderLength(SYMBOL_CLASS_TAG_LENGTH) + SYMBOL_CLASS_TAG_LENGTH; private int bitPos; private int bitBuf; protected Rectangle bounds; protected DataOutputStream out; protected byte[] data; private static int symbolClassEntryLength(byte[] name) { return 2 /* 16-bit character tag ID */ + name.length + 1 /* terminator, 0 */; } protected static int recordHeaderLength(int length) { return length < 63 ? 2 : 6; } public void transcode(VirtualFile in, File out) throws IOException { transcode(in.getInputStream(), in.getLength(), out, true); } @SuppressWarnings("IOResourceOpenedButNotSafelyClosed") protected void transcode(InputStream inputStream, long inputLength, File outFile, boolean writeBounds) throws IOException { out = new DataOutputStream(new BufferedOutputStream(readSourceAndCreateFileOut(inputStream, inputLength, outFile))); data = buffer.array(); try { transcode(writeBounds); } finally { out.close(); out = null; } } protected abstract void transcode(boolean writeBounds) throws IOException; protected void syncBits() { bitPos = 0; } protected void writeSymbolClass(int spriteId) throws IOException { buffer.position(0); encodeTagHeader(TagTypes.SymbolClass, SYMBOL_CLASS_TAG_LENGTH); buffer.putShort((short)2); buffer.putShort((short)0); buffer.put(ROOT_SWF_CLASS_NAME); buffer.put((byte)0); buffer.putShort((short)spriteId); buffer.put(SYMBOL_OWN_CLASS_NAME); buffer.put((byte)0); out.write(data, 0, buffer.position()); } protected static byte[] getSymbolOwnClassAbc(short frameCount) throws IOException { if (frameCount > 1) { if (MOVIE_CLIP_SYMBOL_OWN_CLASS_ABC == null) { MOVIE_CLIP_SYMBOL_OWN_CLASS_ABC = IOUtil.getResourceBytes("MSymbolOwnClass.abc"); MOVIE_CLIP_SYMBOL_OWN_CLASS_ABC[21] = '_'; // replace M => _ } return MOVIE_CLIP_SYMBOL_OWN_CLASS_ABC; } else { if (SPRITE_SYMBOL_OWN_CLASS_ABC == null) { SPRITE_SYMBOL_OWN_CLASS_ABC = IOUtil.getResourceBytes("SSymbolOwnClass.abc"); SPRITE_SYMBOL_OWN_CLASS_ABC[21] = '_'; // replace S => _ } return SPRITE_SYMBOL_OWN_CLASS_ABC; } } protected void writeMovieBounds() throws IOException { out.writeInt(bounds.x); out.writeInt(bounds.y); out.writeInt(bounds.width); out.writeInt(bounds.height); } protected void writeSparseBytes(TIntArrayList positions, final int start, final int end) throws IOException { final int maxI = positions.size() - 1; int prevOffset = start; int i = 0; while (i < maxI) { out.write(data, prevOffset, positions.getQuick(i++) - prevOffset); prevOffset = positions.getQuick(i++); } out.write(data, prevOffset, end - prevOffset); } protected void decodeRect() throws IOException { syncBits(); bounds = new Rectangle(); final int nBits = readUBits(5); bounds.x = readSBits(nBits); bounds.width = readSBits(nBits) - bounds.x; bounds.y = readSBits(nBits); final int i = readSBits(nBits); bounds.height = i - bounds.y; } protected int readSBits(int numBits) throws IOException { if (numBits > 32) { throw new IOException("Number of bits > 32"); } int num = readUBits(numBits); int shift = 32 - numBits; // sign extension return (num << shift) >> shift; } protected int readUBits(final int numBits) throws IOException { if (numBits == 0) { return 0; } int bitsLeft = numBits; int result = 0; //no value in the buffer - read a byte if (bitPos == 0) { bitBuf = readUI8(); bitPos = 8; } while (true) { final 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 return result; } } } }