Files
jpexs-decompiler/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFOutputStream.java
Jindra Petřík 04922aaf69 Separated FFDec core library and the rest (GUI).
FFDec Library is now LGPLv3, others stay GPLv3.
Version changed to 3.0.0 for FFDec, 1.0.0 for FFDec Library.
2014-08-24 17:55:42 +02:00

1758 lines
57 KiB
Java

/*
* Copyright (C) 2010-2014 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;
import com.jpexs.decompiler.flash.tags.DefineBitsLosslessTag;
import com.jpexs.decompiler.flash.tags.Tag;
import com.jpexs.decompiler.flash.types.ALPHABITMAPDATA;
import com.jpexs.decompiler.flash.types.ARGB;
import com.jpexs.decompiler.flash.types.BITMAPDATA;
import com.jpexs.decompiler.flash.types.BUTTONCONDACTION;
import com.jpexs.decompiler.flash.types.BUTTONRECORD;
import com.jpexs.decompiler.flash.types.CLIPACTIONRECORD;
import com.jpexs.decompiler.flash.types.CLIPACTIONS;
import com.jpexs.decompiler.flash.types.CLIPEVENTFLAGS;
import com.jpexs.decompiler.flash.types.CXFORM;
import com.jpexs.decompiler.flash.types.CXFORMWITHALPHA;
import com.jpexs.decompiler.flash.types.FILLSTYLE;
import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY;
import com.jpexs.decompiler.flash.types.FOCALGRADIENT;
import com.jpexs.decompiler.flash.types.GLYPHENTRY;
import com.jpexs.decompiler.flash.types.GRADIENT;
import com.jpexs.decompiler.flash.types.GRADRECORD;
import com.jpexs.decompiler.flash.types.KERNINGRECORD;
import com.jpexs.decompiler.flash.types.LANGCODE;
import com.jpexs.decompiler.flash.types.LINESTYLE;
import com.jpexs.decompiler.flash.types.LINESTYLE2;
import com.jpexs.decompiler.flash.types.LINESTYLEARRAY;
import com.jpexs.decompiler.flash.types.MATRIX;
import com.jpexs.decompiler.flash.types.MORPHFILLSTYLE;
import com.jpexs.decompiler.flash.types.MORPHFILLSTYLEARRAY;
import com.jpexs.decompiler.flash.types.MORPHFOCALGRADIENT;
import com.jpexs.decompiler.flash.types.MORPHGRADIENT;
import com.jpexs.decompiler.flash.types.MORPHGRADRECORD;
import com.jpexs.decompiler.flash.types.MORPHLINESTYLE;
import com.jpexs.decompiler.flash.types.MORPHLINESTYLE2;
import com.jpexs.decompiler.flash.types.MORPHLINESTYLEARRAY;
import com.jpexs.decompiler.flash.types.PIX15;
import com.jpexs.decompiler.flash.types.PIX24;
import com.jpexs.decompiler.flash.types.RECT;
import com.jpexs.decompiler.flash.types.RGB;
import com.jpexs.decompiler.flash.types.RGBA;
import com.jpexs.decompiler.flash.types.SHAPE;
import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE;
import com.jpexs.decompiler.flash.types.SOUNDENVELOPE;
import com.jpexs.decompiler.flash.types.SOUNDINFO;
import com.jpexs.decompiler.flash.types.TEXTRECORD;
import com.jpexs.decompiler.flash.types.ZONEDATA;
import com.jpexs.decompiler.flash.types.ZONERECORD;
import com.jpexs.decompiler.flash.types.filters.BEVELFILTER;
import com.jpexs.decompiler.flash.types.filters.BLURFILTER;
import com.jpexs.decompiler.flash.types.filters.COLORMATRIXFILTER;
import com.jpexs.decompiler.flash.types.filters.CONVOLUTIONFILTER;
import com.jpexs.decompiler.flash.types.filters.DROPSHADOWFILTER;
import com.jpexs.decompiler.flash.types.filters.FILTER;
import com.jpexs.decompiler.flash.types.filters.GLOWFILTER;
import com.jpexs.decompiler.flash.types.filters.GRADIENTBEVELFILTER;
import com.jpexs.decompiler.flash.types.filters.GRADIENTGLOWFILTER;
import com.jpexs.decompiler.flash.types.shaperecords.CurvedEdgeRecord;
import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord;
import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD;
import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord;
import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord;
import com.jpexs.helpers.utf8.Utf8Helper;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;
/**
* Class for writing data into SWF file
*
* @author JPEXS
*/
public class SWFOutputStream extends OutputStream {
private final OutputStream os;
private final int version;
private long pos = 0;
private int bitPos = 0;
private int tempByte = 0;
public long getPos() {
return pos;
}
/**
* Constructor
*
* @param os OutputStream for writing data
* @param version Version of SWF
*/
public SWFOutputStream(OutputStream os, int version) {
this.version = version;
this.os = os;
}
/**
* Writes byte to the stream
*
* @param b byte to write
* @throws IOException
*/
@Override
public void write(int b) throws IOException {
alignByte();
os.write(b);
pos++;
}
@Override
public void write(byte[] b) throws IOException {
alignByte();
os.write(b);
pos += b.length;
}
private void alignByte() throws IOException {
if (bitPos > 0) {
bitPos = 0;
write(tempByte);
tempByte = 0;
}
}
/**
* Writes UI8 (Unsigned 8bit integer) value to the stream
*
* @param val UI8 value to write
* @throws IOException
*/
public void writeUI8(int val) throws IOException {
write(val);
}
/**
* Writes String value to the stream
*
* @param value String value
* @throws IOException
*/
public void writeString(String value) throws IOException {
write(Utf8Helper.getBytes(value));
write(0);
}
/**
* Writes UI32 (Unsigned 32bit integer) value to the stream
*
* @param value UI32 value
* @throws IOException
*/
public void writeUI32(long value) throws IOException {
write((int) (value & 0xff));
write((int) ((value >> 8) & 0xff));
write((int) ((value >> 16) & 0xff));
write((int) ((value >> 24) & 0xff));
}
/**
* Writes UI16 (Unsigned 16bit integer) value to the stream
*
* @param value UI16 value
* @throws IOException
*/
public void writeUI16(int value) throws IOException {
write((int) (value & 0xff));
write((int) ((value >> 8) & 0xff));
}
/**
* Writes SI32 (Signed 32bit integer) value to the stream
*
* @param value SI32 value
* @throws IOException
*/
public void writeSI32(long value) throws IOException {
writeUI32(value);
}
/**
* Writes SI16 (Signed 16bit integer) value to the stream
*
* @param value SI16 value
* @throws IOException
*/
public void writeSI16(int value) throws IOException {
writeUI16(value);
}
/**
* Writes SI8 (Signed 8bit integer) value to the stream
*
* @param value SI8 value
* @throws IOException
*/
public void writeSI8(int value) throws IOException {
writeUI8(value);
}
/**
* Writes FIXED (Fixed point 16.16) value to the stream
*
* @param value FIXED value
* @throws IOException
*/
public void writeFIXED(double value) throws IOException {
long valueLong = (long) (value * (1 << 16));
int beforePoint = (int) valueLong >> 16;
int afterPoint = (int) valueLong % (1 << 16);
writeUI16(afterPoint);
writeUI16(beforePoint);
}
/**
* Writes FIXED8 (Fixed point 8.8) value to the stream
*
* @param value FIXED8 value
* @throws IOException
*/
public void writeFIXED8(float value) throws IOException {
int beforePoint = (int) getIntPart(value);
int afterPoint = (int) getIntPart((value + (value < 0 ? beforePoint : -beforePoint)) * 256);
writeUI8(afterPoint);
writeUI8(beforePoint);
}
private void writeLong(long value) throws IOException {
byte[] writeBuffer = new byte[8];
writeBuffer[3] = (byte) (value >>> 56);
writeBuffer[2] = (byte) (value >>> 48);
writeBuffer[1] = (byte) (value >>> 40);
writeBuffer[0] = (byte) (value >>> 32);
writeBuffer[7] = (byte) (value >>> 24);
writeBuffer[6] = (byte) (value >>> 16);
writeBuffer[5] = (byte) (value >>> 8);
writeBuffer[4] = (byte) (value);
write(writeBuffer);
}
/**
* Writes DOUBLE (double precision floating point value) value to the stream
*
* @param value DOUBLE value
* @throws IOException
*/
public void writeDOUBLE(double value) throws IOException {
writeLong(Double.doubleToLongBits(value));
}
/**
* Writes FLOAT (single precision floating point value) value to the stream
*
* @param value FLOAT value
* @throws IOException
*/
public void writeFLOAT(float value) throws IOException {
writeUI32(Float.floatToIntBits(value));
}
/**
* Writes FLOAT16 (16bit floating point value) value to the stream
*
* @param value FLOAT16 value
* @throws IOException
*/
public void writeFLOAT16(float value) throws IOException {
int bits = Float.floatToRawIntBits(value);
int sign = bits >> 31;
int exponent = (bits >> 22) & 0xff;
int mantisa = bits & 0x3FFFFF;
mantisa >>= 13;
writeUI16((sign << 15) + (exponent << 10) + mantisa);
}
/**
* Writes EncodedU32 (Encoded unsigned 32bit value) value to the stream
*
* @param value U32 value
* @throws IOException
*/
public void writeEncodedU32(long value) throws IOException {
boolean loop = true;
value &= 0xFFFFFFFF;
do {
int ret = (int) (value & 0x7F);
if (value < 0x80) {
loop = false;
}
if (value > 0x7F) {
ret += 0x80;
}
write(ret);
value >>= 7;
} while (loop);
}
/**
* Flushes data to underlying stream
*
* @throws IOException
*/
@Override
public void flush() throws IOException {
if (bitPos > 0) {
bitPos = 0;
write(tempByte);
tempByte = 0;
}
os.flush();
}
/**
* Closes the stream
*
* @throws IOException
*/
@Override
public void close() throws IOException {
flush();
os.close();
}
/**
* Writes UB[nBits] (Unsigned-bit value) value to the stream
*
* @param nBits Number of bits which represent value
* @param value Unsigned value to write
* @throws IOException
*/
public void writeUB(int nBits, long value) throws IOException {
for (int bit = 0; bit < nBits; bit++) {
int nb = (int) ((value >> (nBits - 1 - bit)) & 1);
tempByte += nb * (1 << (7 - bitPos));
bitPos++;
if (bitPos == 8) {
bitPos = 0;
write(tempByte);
tempByte = 0;
}
}
}
/**
* Writes SB[nBits] (Signed-bit value) value to the stream
*
* @param nBits Number of bits which represent value
* @param value Signed value to write
* @throws IOException
*/
public void writeSB(int nBits, long value) throws IOException {
writeUB(nBits, value);
}
/**
* Writes FB[nBits] (Signed fixed-point bit value) value to the stream
*
* @param nBits Number of bits which represent value
* @param value Double value to write
* @throws IOException
*/
public void writeFB(int nBits, double value) throws IOException {
if (nBits == 0) {
return;
}
long longVal = (long) (value * (1 << 16));
writeSB(nBits, longVal);
}
/**
* Writes RECT value to the stream
*
* @param value RECT value
* @throws IOException
*/
public void writeRECT(RECT value) throws IOException {
int nBits = 0;
int xMin = truncateTo31Bit(value.Xmin);
int xMax = truncateTo31Bit(value.Xmax);
int yMin = truncateTo31Bit(value.Ymin);
int yMax = truncateTo31Bit(value.Ymax);
nBits = enlargeBitCountS(nBits, xMin);
nBits = enlargeBitCountS(nBits, xMax);
nBits = enlargeBitCountS(nBits, yMin);
nBits = enlargeBitCountS(nBits, yMax);
writeUB(5, nBits);
writeSB(nBits, xMin);
writeSB(nBits, xMax);
writeSB(nBits, yMin);
writeSB(nBits, yMax);
alignByte();
}
private int truncateTo31Bit(int value) {
if (value > 0x3fffffff) {
value = 0x3fffffff;
}
if (value < -0x3fffffff) {
value = -0x3fffffff;
}
return value;
}
/**
* Writes list of Tag values to the stream
*
* @param tags List of tag values
* @throws IOException
*/
public void writeTags(List<Tag> tags) throws IOException {
for (Tag tag : tags) {
tag.writeTag(this);
}
}
/**
* Calculates number of bits needed for representing unsigned value
*
* @param value Unsigned value
* @return Number of bits
*/
public static int getNeededBitsU(int value) {
value = Math.abs(value);
long x = 1;
int nBits;
for (nBits = 1; nBits <= 64; nBits++) {
x <<= 1;
if (x > value) {
break;
}
}
return nBits;
}
/**
* Calculates number of bits needed for representing signed value
*
* @param v Signed value
* @return Number of bits
*/
public static int getNeededBitsS(int v) {
int counter = 32;
int mask = 0x80000000;
final int val = (v < 0) ? -v : v;
while (((val & mask) == 0) && (counter > 0)) {
mask >>>= 1;
counter -= 1;
}
return counter + 1;
}
/**
* Calculates number of bits needed for representing signed values
*
* @param first First Signed value
* @param params Next Signed values
* @return Number of bits
*/
public static int getNeededBitsS(int first, int... params) {
int nBits = 0;
nBits = enlargeBitCountS(nBits, first);
for (int i = 0; i < params.length; i++) {
nBits = enlargeBitCountS(nBits, params[i]);
}
return nBits;
}
public static int getNeededBitsU(int first, int... params) {
int nBits = 0;
nBits = enlargeBitCountU(nBits, first);
for (int i = 0; i < params.length; i++) {
nBits = enlargeBitCountU(nBits, params[i]);
}
return nBits;
}
private static long getIntPart(double value) {
if (value < 0) {
return (long) Math.ceil(value);
}
return (long) Math.floor(value);
}
public static int unsignedSize(final int value) {
final int val = (value < 0) ? -value - 1 : value;
int counter = 32;
int mask = 0x80000000;
while (((val & mask) == 0) && (counter > 0)) {
mask >>>= 1;
counter -= 1;
}
return counter;
}
/**
* Calculates number of bits needed for representing fixed-point value
*
* @param value Fixed-point value
* @return Number of bits
*/
public static int getNeededBitsF(float value) {
//0.26213074 16bits
//0.5 17bits
//1.3476715 18bits
int k = (int) value;
return getNeededBitsS(k) + 16;
}
public static int enlargeBitCountS(int currentBitCount, int value) {
int neededNew = getNeededBitsS(value);
if (neededNew > currentBitCount) {
return neededNew;
}
return currentBitCount;
}
public static int enlargeBitCountU(int currentBitCount, int value) {
int neededNew = getNeededBitsU(value);
if (neededNew > currentBitCount) {
return neededNew;
}
return currentBitCount;
}
/**
* Writes MATRIX value to the stream
*
* @param value MATRIX value
* @throws IOException
*/
public void writeMatrix(MATRIX value) throws IOException {
writeUB(1, value.hasScale ? 1 : 0);
if (value.hasScale) {
int nBits = 0;
nBits = enlargeBitCountS(nBits, value.scaleX);
nBits = enlargeBitCountS(nBits, value.scaleY);
writeUB(5, nBits);
writeSB(nBits, value.scaleX);
writeSB(nBits, value.scaleY);
}
writeUB(1, value.hasRotate ? 1 : 0);
if (value.hasRotate) {
int nBits = 0;
nBits = enlargeBitCountS(nBits, value.rotateSkew0);
nBits = enlargeBitCountS(nBits, value.rotateSkew1);
writeUB(5, nBits);
writeSB(nBits, value.rotateSkew0);
writeSB(nBits, value.rotateSkew1);
}
int NTranslateBits = 0;
NTranslateBits = enlargeBitCountS(NTranslateBits, value.translateX);
NTranslateBits = enlargeBitCountS(NTranslateBits, value.translateY);
writeUB(5, NTranslateBits);
writeSB(NTranslateBits, value.translateX);
writeSB(NTranslateBits, value.translateY);
alignByte();
}
/**
* Writes CXFORM value to the stream
*
* @param value CXFORM value
* @throws IOException
*/
public void writeCXFORM(CXFORM value) throws IOException {
writeUB(1, value.hasAddTerms ? 1 : 0);
writeUB(1, value.hasMultTerms ? 1 : 0);
int Nbits = 1;
if (value.hasMultTerms) {
Nbits = enlargeBitCountS(Nbits, value.redMultTerm);
Nbits = enlargeBitCountS(Nbits, value.greenMultTerm);
Nbits = enlargeBitCountS(Nbits, value.blueMultTerm);
}
if (value.hasAddTerms) {
Nbits = enlargeBitCountS(Nbits, value.redAddTerm);
Nbits = enlargeBitCountS(Nbits, value.greenAddTerm);
Nbits = enlargeBitCountS(Nbits, value.blueAddTerm);
}
writeUB(4, Nbits);
if (value.hasMultTerms) {
writeSB(Nbits, value.redMultTerm);
writeSB(Nbits, value.greenMultTerm);
writeSB(Nbits, value.blueMultTerm);
}
if (value.hasAddTerms) {
writeSB(Nbits, value.redAddTerm);
writeSB(Nbits, value.greenAddTerm);
writeSB(Nbits, value.blueAddTerm);
}
alignByte();
}
/**
* Writes CXFORMWITHALPHA value to the stream
*
* @param value CXFORMWITHALPHA value
* @throws IOException
*/
public void writeCXFORMWITHALPHA(CXFORMWITHALPHA value) throws IOException {
writeUB(1, value.hasAddTerms ? 1 : 0);
writeUB(1, value.hasMultTerms ? 1 : 0);
int Nbits = 1;
if (value.hasMultTerms) {
Nbits = enlargeBitCountS(Nbits, value.redMultTerm);
Nbits = enlargeBitCountS(Nbits, value.greenMultTerm);
Nbits = enlargeBitCountS(Nbits, value.blueMultTerm);
Nbits = enlargeBitCountS(Nbits, value.alphaMultTerm);
}
if (value.hasAddTerms) {
Nbits = enlargeBitCountS(Nbits, value.redAddTerm);
Nbits = enlargeBitCountS(Nbits, value.greenAddTerm);
Nbits = enlargeBitCountS(Nbits, value.blueAddTerm);
Nbits = enlargeBitCountS(Nbits, value.alphaAddTerm);
}
writeUB(4, Nbits);
if (value.hasMultTerms) {
writeSB(Nbits, value.redMultTerm);
writeSB(Nbits, value.greenMultTerm);
writeSB(Nbits, value.blueMultTerm);
writeSB(Nbits, value.alphaMultTerm);
}
if (value.hasAddTerms) {
writeSB(Nbits, value.redAddTerm);
writeSB(Nbits, value.greenAddTerm);
writeSB(Nbits, value.blueAddTerm);
writeSB(Nbits, value.alphaAddTerm);
}
alignByte();
}
/**
* Writes CLIPEVENTFLAGS value to the stream
*
* @param value CLIPEVENTFLAGS value
* @throws IOException
*/
public void writeCLIPEVENTFLAGS(CLIPEVENTFLAGS value) throws IOException {
writeUB(1, value.clipEventKeyUp ? 1 : 0);
writeUB(1, value.clipEventKeyDown ? 1 : 0);
writeUB(1, value.clipEventMouseUp ? 1 : 0);
writeUB(1, value.clipEventMouseDown ? 1 : 0);
writeUB(1, value.clipEventMouseMove ? 1 : 0);
writeUB(1, value.clipEventUnload ? 1 : 0);
writeUB(1, value.clipEventEnterFrame ? 1 : 0);
writeUB(1, value.clipEventLoad ? 1 : 0);
writeUB(1, value.clipEventDragOver ? 1 : 0);
writeUB(1, value.clipEventRollOut ? 1 : 0);
writeUB(1, value.clipEventRollOver ? 1 : 0);
writeUB(1, value.clipEventReleaseOutside ? 1 : 0);
writeUB(1, value.clipEventRelease ? 1 : 0);
writeUB(1, value.clipEventPress ? 1 : 0);
writeUB(1, value.clipEventInitialize ? 1 : 0);
writeUB(1, value.clipEventData ? 1 : 0);
if (version >= 6) {
writeUB(5, value.reserved);
writeUB(1, value.clipEventConstruct ? 1 : 0);
writeUB(1, value.clipEventKeyPress ? 1 : 0);
writeUB(1, value.clipEventDragOut ? 1 : 0);
writeUB(8, value.reserved2);
}
}
/**
* Writes CLIPACTIONRECORD value to the stream
*
* @param value CLIPACTIONRECORD value
* @throws IOException
*/
public void writeCLIPACTIONRECORD(CLIPACTIONRECORD value) throws IOException {
writeCLIPEVENTFLAGS(value.eventFlags);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (SWFOutputStream sos = new SWFOutputStream(baos, version)) {
if (value.eventFlags.clipEventKeyPress) {
sos.writeUI8(value.keyCode);
}
sos.write(value.actionBytes.getRangeData());
}
byte[] data = baos.toByteArray();
writeUI32(data.length); //actionRecordSize
write(data);
}
/**
* Writes CLIPACTIONS value to the stream
*
* @param value CLIPACTIONS value
* @throws IOException
*/
public void writeCLIPACTIONS(CLIPACTIONS value) throws IOException {
writeUI16(value.reserved);
writeCLIPEVENTFLAGS(value.allEventFlags);
for (CLIPACTIONRECORD car : value.clipActionRecords) {
writeCLIPACTIONRECORD(car);
}
if (version <= 5) {
writeUI16(0);
} else {
writeUI32(0);
}
}
/**
* Writes COLORMATRIXFILTER value to the stream
*
* @param value COLORMATRIXFILTER value
* @throws IOException
*/
public void writeCOLORMATRIXFILTER(COLORMATRIXFILTER value) throws IOException {
for (int i = 0; i < 20; i++) {
writeFLOAT(value.matrix[i]);
}
}
/**
* Writes RGBA value to the stream
*
* @param value RGBA value
* @throws IOException
*/
public void writeRGBA(RGBA value) throws IOException {
writeUI8(value.red);
writeUI8(value.green);
writeUI8(value.blue);
writeUI8(value.alpha);
}
/**
* Writes ARGB value to the stream
*
* @param value ARGB value
* @throws IOException
*/
public void writeARGB(ARGB value) throws IOException {
writeUI8(value.alpha);
writeUI8(value.red);
writeUI8(value.green);
writeUI8(value.blue);
}
/**
* Writes RGB value to the stream
*
* @param value RGB value
* @throws IOException
*/
public void writeRGB(RGB value) throws IOException {
writeUI8(value.red);
writeUI8(value.green);
writeUI8(value.blue);
}
/**
* Writes CONVOLUTIONFILTER value to the stream
*
* @param value CONVOLUTIONFILTER value
* @throws IOException
*/
public void writeCONVOLUTIONFILTER(CONVOLUTIONFILTER value) throws IOException {
writeUI8(value.matrixX);
writeUI8(value.matrixY);
writeFLOAT(value.divisor);
writeFLOAT(value.bias);
for (int x = 0; x < value.matrixX; x++) {
for (int y = 0; y < value.matrixY; y++) {
writeFLOAT(value.matrix[x][y]);
}
}
writeRGBA(value.defaultColor);
writeUB(6, value.reserved);
writeUB(1, value.clamp ? 1 : 0);
writeUB(1, value.preserveAlpha ? 1 : 0);
}
/**
* Writes BLURFILTER value to the stream
*
* @param value BLURFILTER value
* @throws IOException
*/
public void writeBLURFILTER(BLURFILTER value) throws IOException {
writeFIXED(value.blurX);
writeFIXED(value.blurY);
writeUB(5, value.passes);
writeUB(3, value.reserved);
}
/**
* Writes DROPSHADOWFILTER value to the stream
*
* @param value DROPSHADOWFILTER value
* @throws IOException
*/
public void writeDROPSHADOWFILTER(DROPSHADOWFILTER value) throws IOException {
writeRGBA(value.dropShadowColor);
writeFIXED(value.blurX);
writeFIXED(value.blurY);
writeFIXED(value.angle);
writeFIXED(value.distance);
writeFIXED8(value.strength);
writeUB(1, value.innerShadow ? 1 : 0);
writeUB(1, value.knockout ? 1 : 0);
writeUB(1, value.compositeSource ? 1 : 0);
writeUB(5, value.passes);
}
/**
* Writes GLOWFILTER value to the stream
*
* @param value GLOWFILTER value
* @throws IOException
*/
public void writeGLOWFILTER(GLOWFILTER value) throws IOException {
writeRGBA(value.glowColor);
writeFIXED(value.blurX);
writeFIXED(value.blurY);
writeFIXED8(value.strength);
writeUB(1, value.innerGlow ? 1 : 0);
writeUB(1, value.knockout ? 1 : 0);
writeUB(1, value.compositeSource ? 1 : 0);
writeUB(5, value.passes);
}
/**
* Writes BEVELFILTER value to the stream
*
* @param value BEVELFILTER value
* @throws IOException
*/
public void writeBEVELFILTER(BEVELFILTER value) throws IOException {
writeRGBA(value.highlightColor);
writeRGBA(value.shadowColor);
writeFIXED(value.blurX);
writeFIXED(value.blurY);
writeFIXED(value.angle);
writeFIXED(value.distance);
writeFIXED8(value.strength);
writeUB(1, value.innerShadow ? 1 : 0);
writeUB(1, value.knockout ? 1 : 0);
writeUB(1, value.compositeSource ? 1 : 0);
writeUB(1, value.onTop ? 1 : 0);
writeUB(4, value.passes);
}
/**
* Writes GRADIENTGLOWFILTER value to the stream
*
* @param value GRADIENTGLOWFILTER value
* @throws IOException
*/
public void writeGRADIENTGLOWFILTER(GRADIENTGLOWFILTER value) throws IOException {
writeUI8(value.gradientColors.length);
for (int i = 0; i < value.gradientColors.length; i++) {
writeRGBA(value.gradientColors[i]);
}
for (int i = 0; i < value.gradientColors.length; i++) {
writeUI8(value.gradientRatio[i]);
}
writeFIXED(value.blurX);
writeFIXED(value.blurY);
writeFIXED(value.angle);
writeFIXED(value.distance);
writeFIXED8(value.strength);
writeUB(1, value.innerShadow ? 1 : 0);
writeUB(1, value.knockout ? 1 : 0);
writeUB(1, value.compositeSource ? 1 : 0);
writeUB(1, value.onTop ? 1 : 0);
writeUB(4, value.passes);
}
/**
* Writes GRADIENTBEVELFILTER value to the stream
*
* @param value GRADIENTBEVELFILTER value
* @throws IOException
*/
public void writeGRADIENTBEVELFILTER(GRADIENTBEVELFILTER value) throws IOException {
writeUI8(value.gradientColors.length);
for (int i = 0; i < value.gradientColors.length; i++) {
writeRGBA(value.gradientColors[i]);
}
for (int i = 0; i < value.gradientColors.length; i++) {
writeUI8(value.gradientRatio[i]);
}
writeFIXED(value.blurX);
writeFIXED(value.blurY);
writeFIXED(value.angle);
writeFIXED(value.distance);
writeFIXED8(value.strength);
writeUB(1, value.innerShadow ? 1 : 0);
writeUB(1, value.knockout ? 1 : 0);
writeUB(1, value.compositeSource ? 1 : 0);
writeUB(1, value.onTop ? 1 : 0);
writeUB(4, value.passes);
}
/**
* Writes list of FILTER values to the stream
*
* @param list List of FILTER values
* @throws IOException
*/
public void writeFILTERLIST(List<FILTER> list) throws IOException {
writeUI8(list.size());
for (int i = 0; i < list.size(); i++) {
writeFILTER(list.get(i));
}
}
/**
* Writes FILTER value to the stream
*
* @param value FILTER value
* @throws IOException
*/
public void writeFILTER(FILTER value) throws IOException {
writeUI8(value.id);
if (value instanceof DROPSHADOWFILTER) {
writeDROPSHADOWFILTER((DROPSHADOWFILTER) value);
}
if (value instanceof BLURFILTER) {
writeBLURFILTER((BLURFILTER) value);
}
if (value instanceof GLOWFILTER) {
writeGLOWFILTER((GLOWFILTER) value);
}
if (value instanceof BEVELFILTER) {
writeBEVELFILTER((BEVELFILTER) value);
}
if (value instanceof GRADIENTGLOWFILTER) {
writeGRADIENTGLOWFILTER((GRADIENTGLOWFILTER) value);
}
if (value instanceof CONVOLUTIONFILTER) {
writeCONVOLUTIONFILTER((CONVOLUTIONFILTER) value);
}
if (value instanceof COLORMATRIXFILTER) {
writeCOLORMATRIXFILTER((COLORMATRIXFILTER) value);
}
if (value instanceof GRADIENTBEVELFILTER) {
writeGRADIENTBEVELFILTER((GRADIENTBEVELFILTER) value);
}
}
/**
* Writes list of BUTTONRECORD values to the stream
*
* @param list List of BUTTONRECORD values
* @param inDefineButton2 Whether write inside of DefineButton2Tag or not
* @throws IOException
*/
public void writeBUTTONRECORDList(List<BUTTONRECORD> list, boolean inDefineButton2) throws IOException {
for (BUTTONRECORD brec : list) {
writeBUTTONRECORD(brec, inDefineButton2);
}
writeUI8(0);
}
/**
* Writes BUTTONRECORD value to the stream
*
* @param value BUTTONRECORD value
* @param inDefineButton2 Whether write inside of DefineButton2Tag or not
* @throws IOException
*/
public void writeBUTTONRECORD(BUTTONRECORD value, boolean inDefineButton2) throws IOException {
writeUB(2, value.reserved);
writeUB(1, value.buttonHasBlendMode ? 1 : 0);
writeUB(1, value.buttonHasFilterList ? 1 : 0);
writeUB(1, value.buttonStateHitTest ? 1 : 0);
writeUB(1, value.buttonStateDown ? 1 : 0);
writeUB(1, value.buttonStateOver ? 1 : 0);
writeUB(1, value.buttonStateUp ? 1 : 0);
writeUI16(value.characterId);
writeUI16(value.placeDepth);
writeMatrix(value.placeMatrix);
if (inDefineButton2) {
writeCXFORMWITHALPHA(value.colorTransform);
if (value.buttonHasFilterList) {
writeFILTERLIST(value.filterList);
}
if (value.buttonHasBlendMode) {
writeUI8(value.blendMode);
}
}
}
/**
* Writes list of BUTTONCONDACTION values to the stream
*
* @param list List of BUTTONCONDACTION values
* @throws IOException
*/
public void writeBUTTONCONDACTIONList(List<BUTTONCONDACTION> list) throws IOException {
for (int i = 0; i < list.size(); i++) {
writeBUTTONCONDACTION(list.get(i), i == list.size() - 1);
}
}
/**
* Writes BUTTONCONDACTION value to the stream
*
* @param value BUTTONCONDACTION value
* @param isLast True if it is last on the list
* @throws IOException
*/
public void writeBUTTONCONDACTION(BUTTONCONDACTION value, boolean isLast) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (SWFOutputStream sos = new SWFOutputStream(baos, version)) {
sos.writeUB(1, value.condIdleToOverDown ? 1 : 0);
sos.writeUB(1, value.condOutDownToIdle ? 1 : 0);
sos.writeUB(1, value.condOutDownToOverDown ? 1 : 0);
sos.writeUB(1, value.condOverDownToOutDown ? 1 : 0);
sos.writeUB(1, value.condOverDownToOverUp ? 1 : 0);
sos.writeUB(1, value.condOverUpToOverDown ? 1 : 0);
sos.writeUB(1, value.condOverUpToIddle ? 1 : 0);
sos.writeUB(1, value.condIdleToOverUp ? 1 : 0);
sos.writeUB(7, value.condKeyPress);
sos.writeUB(1, value.condOverDownToIdle ? 1 : 0);
sos.write(value.actionBytes.getRangeData());
}
byte[] data = baos.toByteArray();
if (isLast) {
writeUI16(0);
} else {
writeUI16(data.length + 2);
}
write(data);
}
/**
* Writes FILLSTYLE value to the stream
*
* @param value FILLSTYLE value
* @param shapeNum 1 in DefineShape, 2 in DefineShape2,...
* @throws IOException
*/
public void writeFILLSTYLE(FILLSTYLE value, int shapeNum) throws IOException {
writeUI8(value.fillStyleType);
if (value.fillStyleType == FILLSTYLE.SOLID) {
if (shapeNum >= 3) {
writeRGBA((RGBA) value.color);
} else if (shapeNum == 1 || shapeNum == 2) {
writeRGB(value.color);
}
}
if ((value.fillStyleType == FILLSTYLE.LINEAR_GRADIENT)
|| (value.fillStyleType == FILLSTYLE.RADIAL_GRADIENT)
|| (value.fillStyleType == FILLSTYLE.FOCAL_RADIAL_GRADIENT)) {
writeMatrix(value.gradientMatrix);
}
if ((value.fillStyleType == FILLSTYLE.LINEAR_GRADIENT)
|| (value.fillStyleType == FILLSTYLE.RADIAL_GRADIENT)) {
writeGRADIENT(value.gradient, shapeNum);
}
if (value.fillStyleType == FILLSTYLE.FOCAL_RADIAL_GRADIENT) {
writeFOCALGRADIENT((FOCALGRADIENT) value.gradient, shapeNum);
}
if ((value.fillStyleType == FILLSTYLE.REPEATING_BITMAP)
|| (value.fillStyleType == FILLSTYLE.CLIPPED_BITMAP)
|| (value.fillStyleType == FILLSTYLE.NON_SMOOTHED_REPEATING_BITMAP)
|| (value.fillStyleType == FILLSTYLE.NON_SMOOTHED_CLIPPED_BITMAP)) {
writeUI16(value.bitmapId);
writeMatrix(value.bitmapMatrix);
}
}
/**
* Writes FILLSTYLEARRAY value to the stream
*
* @param value FILLSTYLEARRAY value
* @param shapeNum 1 in DefineShape, 2 in DefineShape2,...
* @throws IOException
*/
public void writeFILLSTYLEARRAY(FILLSTYLEARRAY value, int shapeNum) throws IOException {
int fillStyleCount = value.fillStyles.length;
if (shapeNum == 2 || shapeNum == 3) {
if (fillStyleCount >= 0xff) {
writeUI8(0xff);
writeUI16(fillStyleCount);
} else {
writeUI8(fillStyleCount);
}
} else {
writeUI8(fillStyleCount);
}
for (int i = 0; i < value.fillStyles.length; i++) {
writeFILLSTYLE(value.fillStyles[i], shapeNum);
}
}
/**
* Writes FOCALGRADIENT value to the stream
*
* @param value FILLSTYLEARRAY value
* @param shapeNum 1 in DefineShape, 2 in DefineShape2,...
* @throws IOException
*/
public void writeFOCALGRADIENT(FOCALGRADIENT value, int shapeNum) throws IOException {
writeUB(2, value.spreadMode);
writeUB(2, value.interpolationMode);
writeUB(4, value.gradientRecords.length);
for (int i = 0; i < value.gradientRecords.length; i++) {
writeGRADRECORD(value.gradientRecords[i], shapeNum);
}
writeFIXED8(value.focalPoint);
}
/**
* Writes GRADIENT value to the stream
*
* @param value GRADIENT value
* @param shapeNum 1 in DefineShape, 2 in DefineShape2,...
* @throws IOException
*/
public void writeGRADIENT(GRADIENT value, int shapeNum) throws IOException {
writeUB(2, value.spreadMode);
writeUB(2, value.interpolationMode);
writeUB(4, value.gradientRecords.length);
for (int i = 0; i < value.gradientRecords.length; i++) {
writeGRADRECORD(value.gradientRecords[i], shapeNum);
}
}
/**
* Writes GRADRECORD value to the stream
*
* @param value GRADRECORD value
* @param shapeNum 1 in DefineShape, 2 in DefineShape2,...
* @throws IOException
*/
public void writeGRADRECORD(GRADRECORD value, int shapeNum) throws IOException {
writeUI8(value.ratio);
if (shapeNum == 1 || shapeNum == 2) {
writeRGB(value.color);
} else if (shapeNum == 3) {
writeRGBA((RGBA) value.color);
}
}
/**
* Writes LINESTYLE value to the stream
*
* @param value LINESTYLE value
* @param shapeNum 1 in DefineShape, 2 in DefineShape2,...
* @throws IOException
*/
public void writeLINESTYLE(LINESTYLE value, int shapeNum) throws IOException {
writeUI16(value.width);
if (shapeNum == 1 || shapeNum == 2) {
writeRGB(value.color);
} else if (shapeNum == 3) {
writeRGBA((RGBA) value.color);
}
}
/**
* Writes LINESTYLE2 value to the stream
*
* @param value LINESTYLE2 value
* @param shapeNum 1 in DefineShape, 2 in DefineShape2,...
* @throws IOException
*/
public void writeLINESTYLE2(LINESTYLE2 value, int shapeNum) throws IOException {
writeUI16(value.width);
writeUB(2, value.startCapStyle);
writeUB(2, value.joinStyle);
writeUB(1, value.hasFillFlag ? 1 : 0);
writeUB(1, value.noHScaleFlag ? 1 : 0);
writeUB(1, value.noVScaleFlag ? 1 : 0);
writeUB(1, value.pixelHintingFlag ? 1 : 0);
writeUB(5, value.reserved);
writeUB(1, value.noClose ? 1 : 0);
writeUB(2, value.endCapStyle);
if (value.joinStyle == LINESTYLE2.MITER_JOIN) {
writeUI16(value.miterLimitFactor);
}
if (!value.hasFillFlag) {
writeRGBA((RGBA) value.color);
} else {
writeFILLSTYLE(value.fillType, shapeNum);
}
}
/**
* Writes LINESTYLEARRAY value to the stream
*
* @param value FILLSTYLEARRAY value
* @param shapeNum 1 in DefineShape, 2 in DefineShape2,...
* @throws IOException
*/
public void writeLINESTYLEARRAY(LINESTYLEARRAY value, int shapeNum) throws IOException {
int lineStyleCount;
if (shapeNum == 1 || shapeNum == 2 || shapeNum == 3) {
lineStyleCount = value.lineStyles.length;
if (lineStyleCount >= 0xff) {
writeUI8(0xff);
writeUI16(lineStyleCount);
} else {
writeUI8(lineStyleCount);
}
for (int i = 0; i < lineStyleCount; i++) {
writeLINESTYLE(value.lineStyles[i], shapeNum);
}
} else if (shapeNum == 4) {
lineStyleCount = value.lineStyles.length;
if (lineStyleCount >= 0xff) {
writeUI8(0xff);
writeUI16(lineStyleCount);
} else {
writeUI8(lineStyleCount);
}
for (int i = 0; i < lineStyleCount; i++) {
writeLINESTYLE2((LINESTYLE2) value.lineStyles[i], shapeNum);
}
}
}
/**
* Writes SHAPE value to the stream
*
* @param value SHAPE value
* @param shapeNum 1 in DefineShape, 2 in DefineShape2,...
* @throws IOException
*/
public void writeSHAPE(SHAPE value, int shapeNum) throws IOException {
writeUB(4, value.numFillBits);
writeUB(4, value.numLineBits);
writeSHAPERECORDS(value.shapeRecords, value.numFillBits, value.numLineBits, shapeNum);
}
/**
* Writes SHAPEWITHSTYLE value to the stream
*
* @param value SHAPEWITHSTYLE value
* @param shapeNum 1 in DefineShape, 2 in DefineShape2,...
* @throws IOException
*/
public void writeSHAPEWITHSTYLE(SHAPEWITHSTYLE value, int shapeNum) throws IOException {
writeFILLSTYLEARRAY(value.fillStyles, shapeNum);
writeLINESTYLEARRAY(value.lineStyles, shapeNum);
writeUB(4, value.numFillBits);
writeUB(4, value.numLineBits);
writeSHAPERECORDS(value.shapeRecords, value.numFillBits, value.numLineBits, shapeNum);
}
/**
* Writes SHAPERECORDs value to the stream
*
* @param value SHAPERECORDS value
* @param fillBits
* @param lineBits
* @param shapeNum 1 in DefineShape, 2 in DefineShape2,...
* @throws IOException
*/
private void writeSHAPERECORDS(List<SHAPERECORD> value, int fillBits, int lineBits, int shapeNum) throws IOException {
for (SHAPERECORD sh : value) {
if (sh instanceof CurvedEdgeRecord) {
CurvedEdgeRecord cer = (CurvedEdgeRecord) sh;
writeUB(1, 1); //typeFlag
writeUB(1, 0);//curvedEdge
writeUB(4, cer.numBits);
writeUB(cer.numBits + 2, cer.controlDeltaX);
writeUB(cer.numBits + 2, cer.controlDeltaY);
writeUB(cer.numBits + 2, cer.anchorDeltaX);
writeUB(cer.numBits + 2, cer.anchorDeltaY);
} else if (sh instanceof StraightEdgeRecord) {
StraightEdgeRecord ser = (StraightEdgeRecord) sh;
writeUB(1, 1); //typeFlag
writeUB(1, 1);//straightEdge
writeUB(4, ser.numBits);
writeUB(1, ser.generalLineFlag ? 1 : 0);
if (!ser.generalLineFlag) {
writeUB(1, ser.vertLineFlag ? 1 : 0);
}
if (ser.generalLineFlag || (!ser.vertLineFlag)) {
writeSB(ser.numBits + 2, ser.deltaX);
}
if (ser.generalLineFlag || ser.vertLineFlag) {
writeSB(ser.numBits + 2, ser.deltaY);
}
} else if (sh instanceof StyleChangeRecord) {
StyleChangeRecord scr = (StyleChangeRecord) sh;
writeUB(1, 0); //typeFlag
writeUB(1, scr.stateNewStyles ? 1 : 0);
writeUB(1, scr.stateLineStyle ? 1 : 0);
writeUB(1, scr.stateFillStyle1 ? 1 : 0);
writeUB(1, scr.stateFillStyle0 ? 1 : 0);
writeUB(1, scr.stateMoveTo ? 1 : 0);
if (scr.stateMoveTo) {
writeUB(5, scr.moveBits);
writeUB(scr.moveBits, scr.moveDeltaX);
writeUB(scr.moveBits, scr.moveDeltaY);
}
if (scr.stateFillStyle0) {
writeUB(fillBits, scr.fillStyle0);
}
if (scr.stateFillStyle1) {
writeUB(fillBits, scr.fillStyle1);
}
if (scr.stateLineStyle) {
writeUB(lineBits, scr.lineStyle);
}
if (scr.stateNewStyles) {
writeFILLSTYLEARRAY(scr.fillStyles, shapeNum);
writeLINESTYLEARRAY(scr.lineStyles, shapeNum);
writeUB(4, scr.numFillBits);
writeUB(4, scr.numLineBits);
}
} else if (sh instanceof EndShapeRecord) {
writeUB(1, 0); //typeFlag
writeUB(5, 0); //end of shape flag
}
}
alignByte();
}
/**
* Writes SOUNDINFO value to the stream
*
* @param value SOUNDINFO value
* @throws IOException
*/
public void writeSOUNDINFO(SOUNDINFO value) throws IOException {
writeUB(2, value.reserved);
writeUB(1, value.syncStop ? 1 : 0);
writeUB(1, value.syncNoMultiple ? 1 : 0);
writeUB(1, value.hasEnvelope ? 1 : 0);
writeUB(1, value.hasLoops ? 1 : 0);
writeUB(1, value.hasOutPoint ? 1 : 0);
writeUB(1, value.hasInPoint ? 1 : 0);
if (value.hasInPoint) {
writeUI32(value.inPoint);
}
if (value.hasOutPoint) {
writeUI32(value.outPoint);
}
if (value.hasLoops) {
writeUI16(value.loopCount);
}
if (value.hasEnvelope) {
writeUI8(value.envelopeRecords.length);
for (SOUNDENVELOPE env : value.envelopeRecords) {
writeSOUNDENVELOPE(env);
}
}
}
/**
* Writes SOUNDENVELOPE value to the stream
*
* @param value SOUNDENVELOPE value
* @throws IOException
*/
public void writeSOUNDENVELOPE(SOUNDENVELOPE value) throws IOException {
writeUI32(value.pos44);
writeUI16(value.leftLevel);
writeUI16(value.rightLevel);
}
/**
* Writes TEXTRECORD value to the stream
*
* @param value TEXTRECORD value
* @param inDefineText2
* @param glyphBits
* @param advanceBits
* @throws IOException
*/
public void writeTEXTRECORD(TEXTRECORD value, boolean inDefineText2, int glyphBits, int advanceBits) throws IOException {
writeUB(1, 1);
writeUB(3, 0);
writeUB(1, value.styleFlagsHasFont ? 1 : 0);
writeUB(1, value.styleFlagsHasColor ? 1 : 0);
writeUB(1, value.styleFlagsHasYOffset ? 1 : 0);
writeUB(1, value.styleFlagsHasXOffset ? 1 : 0);
if (value.styleFlagsHasFont) {
writeUI16(value.fontId);
}
if (value.styleFlagsHasColor) {
if (inDefineText2) {
writeRGBA(value.textColorA);
} else {
writeRGB(value.textColor);
}
}
if (value.styleFlagsHasXOffset) {
writeSI16(value.xOffset);
}
if (value.styleFlagsHasYOffset) {
writeSI16(value.yOffset);
}
if (value.styleFlagsHasFont) {
writeUI16(value.textHeight);
}
writeUI8(value.glyphEntries.length);
for (GLYPHENTRY ge : value.glyphEntries) {
writeGLYPHENTRY(ge, glyphBits, advanceBits);
}
alignByte();
}
/**
* Writes GLYPHENTRY value to the stream
*
* @param value GLYPHENTRY value
* @param glyphBits
* @param advanceBits
* @throws IOException
*/
public void writeGLYPHENTRY(GLYPHENTRY value, int glyphBits, int advanceBits) throws IOException {
writeUB(glyphBits, value.glyphIndex);
writeSB(advanceBits, value.glyphAdvance);
}
/**
* Writes MORPHFILLSTYLE value to the stream
*
* @param value MORPHFILLSTYLE value
* @param shapeNum 1 in DefineMorphShape, 2 in DefineMorphShape2,...
* @throws IOException
*/
public void writeMORPHFILLSTYLE(MORPHFILLSTYLE value, int shapeNum) throws IOException {
writeUI8(value.fillStyleType);
if (value.fillStyleType == MORPHFILLSTYLE.SOLID) {
writeRGBA(value.startColor);
writeRGBA(value.endColor);
}
if ((value.fillStyleType == MORPHFILLSTYLE.LINEAR_GRADIENT)
|| (value.fillStyleType == MORPHFILLSTYLE.RADIAL_GRADIENT)) {
writeMatrix(value.startGradientMatrix);
writeMatrix(value.endGradientMatrix);
}
if ((value.fillStyleType == MORPHFILLSTYLE.LINEAR_GRADIENT)
|| (value.fillStyleType == MORPHFILLSTYLE.RADIAL_GRADIENT)) {
writeMORPHGRADIENT(value.gradient, shapeNum);
}
if ((value.fillStyleType == MORPHFILLSTYLE.REPEATING_BITMAP)
|| (value.fillStyleType == MORPHFILLSTYLE.CLIPPED_BITMAP)
|| (value.fillStyleType == MORPHFILLSTYLE.NON_SMOOTHED_REPEATING_BITMAP)
|| (value.fillStyleType == MORPHFILLSTYLE.NON_SMOOTHED_CLIPPED_BITMAP)) {
writeUI16(value.bitmapId);
writeMatrix(value.startBitmapMatrix);
writeMatrix(value.endBitmapMatrix);
}
}
/**
* WritesMORPH FILLSTYLEARRAY value to the stream
*
* @param value MORPHFILLSTYLEARRAY value
* @param morphShapeNum 1 on DefineMorphShape, 2 on DefineMorphShape
* @throws IOException
*/
public void writeMORPHFILLSTYLEARRAY(MORPHFILLSTYLEARRAY value, int morphShapeNum) throws IOException {
int fillStyleCount = value.fillStyles.length;
if (fillStyleCount >= 0xff) {
writeUI8(0xff);
writeUI16(fillStyleCount);
} else {
writeUI8(fillStyleCount);
}
for (int i = 0; i < value.fillStyles.length; i++) {
writeMORPHFILLSTYLE(value.fillStyles[i], morphShapeNum);
}
}
/**
* Writes MORPHGRADIENT value to the stream
*
* @param value MORPHGRADIENT value
* @param shapeNum 1 in DefineMorphShape, 2 in DefineMorphShape2,...
* @throws IOException
*/
public void writeMORPHGRADIENT(MORPHGRADIENT value, int shapeNum) throws IOException {
//Despite of documentation (UI8 1-8), there are two fields
// spreadMode and interPolationMode which are same as in GRADIENT
writeUB(2, value.spreadMode);
writeUB(2, value.interPolationMode);
writeUB(4, value.gradientRecords.length);
for (int i = 0; i < value.gradientRecords.length; i++) {
writeMORPHGRADRECORD(value.gradientRecords[i]);
}
}
/**
* Writes MORPHFOCALGRADIENT value to the stream
*
* Undocumented feature
*
* @param value MORPHGRADIENT value
* @param shapeNum 1 in DefineMorphShape, 2 in DefineMorphShape2,...
* @throws IOException
*/
public void writeMORPHFOCALGRADIENT(MORPHFOCALGRADIENT value, int shapeNum) throws IOException {
writeUB(2, value.spreadMode);
writeUB(2, value.interPolationMode);
writeUB(4, value.gradientRecords.length);
for (int i = 0; i < value.gradientRecords.length; i++) {
writeMORPHGRADRECORD(value.gradientRecords[i]);
}
writeFIXED8(value.startFocalPoint);
writeFIXED8(value.endFocalPoint);
}
/**
* Writes MORPHGRADRECORD value to the stream
*
* @param value MORPHGRADRECORD value
* @throws IOException
*/
public void writeMORPHGRADRECORD(MORPHGRADRECORD value) throws IOException {
writeUI8(value.startRatio);
writeRGBA(value.startColor);
writeUI8(value.endRatio);
writeRGBA(value.endColor);
}
/**
* Writes MORPHLINESTYLE value to the stream
*
* @param value LINESTYLE value
* @param shapeNum 1 in DefineMorphShape, 2 in DefineMorphShape2,...
* @throws IOException
*/
public void writeMORPHLINESTYLE(MORPHLINESTYLE value, int shapeNum) throws IOException {
writeUI16(value.startWidth);
writeUI16(value.endWidth);
writeRGBA(value.startColor);
writeRGBA(value.endColor);
}
/**
* Writes MORPHLINESTYLE2 value to the stream
*
* @param value MORPHLINESTYLE2 value
* @param shapeNum 1 in DefineMorphShape, 2 in DefineMorphShape2,...
* @throws IOException
*/
public void writeMORPHLINESTYLE2(MORPHLINESTYLE2 value, int shapeNum) throws IOException {
writeUI16(value.startWidth);
writeUI16(value.endWidth);
writeUB(2, value.startCapStyle);
writeUB(2, value.joinStyle);
writeUB(1, value.hasFillFlag ? 1 : 0);
writeUB(1, value.noHScaleFlag ? 1 : 0);
writeUB(1, value.noVScaleFlag ? 1 : 0);
writeUB(1, value.pixelHintingFlag ? 1 : 0);
writeUB(5, value.reserved);
writeUB(1, value.noClose ? 1 : 0);
writeUB(2, value.endCapStyle);
if (value.joinStyle == LINESTYLE2.MITER_JOIN) {
writeUI16(value.miterLimitFactor);
}
if (!value.hasFillFlag) {
writeRGBA(value.startColor);
writeRGBA(value.endColor);
} else {
writeMORPHFILLSTYLE(value.fillType, shapeNum);
}
}
/**
* Writes MORPHLINESTYLEARRAY value to the stream
*
* @param value MORPHFILLSTYLEARRAY value
* @param morphShapeNum 1 in DefineMorphShape, 2 in DefineMorphShape2,...
* @throws IOException
*/
public void writeMORPHLINESTYLEARRAY(MORPHLINESTYLEARRAY value, int morphShapeNum) throws IOException {
int lineStyleCount;
if (morphShapeNum == 1) {
lineStyleCount = value.lineStyles.length;
if (lineStyleCount >= 0xff) {
writeUI8(0xff);
writeUI16(lineStyleCount);
} else {
writeUI8(lineStyleCount);
}
for (int i = 0; i < lineStyleCount; i++) {
writeMORPHLINESTYLE(value.lineStyles[i], morphShapeNum);
}
} else if (morphShapeNum == 2) {
lineStyleCount = value.lineStyles2.length;
if (lineStyleCount >= 0xff) {
writeUI8(0xff);
writeUI16(lineStyleCount);
} else {
writeUI8(lineStyleCount);
}
for (int i = 0; i < lineStyleCount; i++) {
writeMORPHLINESTYLE2(value.lineStyles2[i], morphShapeNum);
}
}
}
/**
* Writes KERNINGRECORD value to the stream
*
* @param value KERNINGRECORD value
* @param fontFlagsWideCodes
* @throws IOException
*/
public void writeKERNINGRECORD(KERNINGRECORD value, boolean fontFlagsWideCodes) throws IOException {
if (fontFlagsWideCodes) {
writeUI16(value.fontKerningCode1);
writeUI16(value.fontKerningCode2);
} else {
writeUI8(value.fontKerningCode1);
writeUI8(value.fontKerningCode2);
}
writeSI16(value.fontKerningAdjustment);
}
/**
* Writes LANGCODE value to the stream
*
* @param value LANGCODE value
* @throws IOException
*/
public void writeLANGCODE(LANGCODE value) throws IOException {
writeUI8(value.languageCode);
}
/**
* Writes ZONERECORD value to the stream
*
* @param value ZONERECORD value
* @throws IOException
*/
public void writeZONERECORD(ZONERECORD value) throws IOException {
writeUI8(value.zonedata.length);
for (int i = 0; i < value.zonedata.length; i++) {
writeZONEDATA(value.zonedata[i]);
}
writeUB(6, 0);
writeUB(1, value.zoneMaskY ? 1 : 0);
writeUB(1, value.zoneMaskX ? 1 : 0);
}
/**
* Writes ZONEDATA value to the stream
*
* @param value ZONEDATA value
* @throws IOException
*/
public void writeZONEDATA(ZONEDATA value) throws IOException {
writeUI16(value.alignmentCoordinate);
writeUI16(value.range);
}
public void writeBytesZlib(byte[] data) throws IOException {
DeflaterOutputStream deflater = new DeflaterOutputStream(this, new Deflater(9));
deflater.write(data);
deflater.finish();
}
/**
* Reads one BITMAPDATA value from the stream
*
* @param value
* @param bitmapFormat
* @param bitmapWidth
* @param bitmapHeight
* @throws IOException
*/
public void writeBITMAPDATA(BITMAPDATA value, int bitmapFormat, int bitmapWidth, int bitmapHeight) throws IOException {
int dataLen = 0;
int pos = 0;
for (int y = 0; y < bitmapHeight; y++) {
int x = 0;
for (; x < bitmapWidth; x++) {
if (bitmapFormat == DefineBitsLosslessTag.FORMAT_15BIT_RGB) {
dataLen += 2;
writePIX15(value.bitmapPixelDataPix15[pos]);
}
if (bitmapFormat == DefineBitsLosslessTag.FORMAT_24BIT_RGB) {
dataLen += 4;
writePIX24(value.bitmapPixelDataPix24[pos]);
}
pos++;
}
while ((dataLen % 4) != 0) {
dataLen++;
writeUI8(0);
}
}
}
/**
* Reads one ALPHABITMAPDATA value from the stream
*
* @param value
* @param bitmapFormat
* @param bitmapWidth
* @param bitmapHeight
* @throws IOException
*/
public void writeALPHABITMAPDATA(ALPHABITMAPDATA value, int bitmapFormat, int bitmapWidth, int bitmapHeight) throws IOException {
int pos = 0;
for (int y = 0; y < bitmapHeight; y++) {
for (int x = 0; x < bitmapWidth; x++) {
writeARGB(value.bitmapPixelData[pos]);
pos++;
}
}
}
/**
* Writes PIX24 value to the stream
*
* @param value PIX24 value
* @throws IOException
*/
public void writePIX24(PIX24 value) throws IOException {
writeUI8(value.reserved);
writeUI8(value.red);
writeUI8(value.green);
writeUI8(value.blue);
}
/**
* Writes PIX15 value to the stream
*
* @param value PIX15 value
* @throws IOException
*/
public void writePIX15(PIX15 value) throws IOException {
writeUB(1, 0);
writeUB(5, value.red);
writeUB(5, value.green);
writeUB(5, value.blue);
}
}