diff --git a/src/com/jpexs/decompiler/flash/SWFInputStream.java b/src/com/jpexs/decompiler/flash/SWFInputStream.java
index 6e2d173cc..495b963cf 100644
--- a/src/com/jpexs/decompiler/flash/SWFInputStream.java
+++ b/src/com/jpexs/decompiler/flash/SWFInputStream.java
@@ -1,3275 +1,3276 @@
-/*
- * Copyright (C) 2010-2014 JPEXS
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package com.jpexs.decompiler.flash;
-
-import com.jpexs.decompiler.flash.action.Action;
-import com.jpexs.decompiler.flash.action.model.ConstantPool;
-import com.jpexs.decompiler.flash.action.special.ActionEnd;
-import com.jpexs.decompiler.flash.action.special.ActionNop;
-import com.jpexs.decompiler.flash.action.swf3.ActionGetURL;
-import com.jpexs.decompiler.flash.action.swf3.ActionGoToLabel;
-import com.jpexs.decompiler.flash.action.swf3.ActionGotoFrame;
-import com.jpexs.decompiler.flash.action.swf3.ActionNextFrame;
-import com.jpexs.decompiler.flash.action.swf3.ActionPlay;
-import com.jpexs.decompiler.flash.action.swf3.ActionPrevFrame;
-import com.jpexs.decompiler.flash.action.swf3.ActionSetTarget;
-import com.jpexs.decompiler.flash.action.swf3.ActionStop;
-import com.jpexs.decompiler.flash.action.swf3.ActionStopSounds;
-import com.jpexs.decompiler.flash.action.swf3.ActionToggleQuality;
-import com.jpexs.decompiler.flash.action.swf3.ActionWaitForFrame;
-import com.jpexs.decompiler.flash.action.swf4.ActionAdd;
-import com.jpexs.decompiler.flash.action.swf4.ActionAnd;
-import com.jpexs.decompiler.flash.action.swf4.ActionAsciiToChar;
-import com.jpexs.decompiler.flash.action.swf4.ActionCall;
-import com.jpexs.decompiler.flash.action.swf4.ActionCharToAscii;
-import com.jpexs.decompiler.flash.action.swf4.ActionCloneSprite;
-import com.jpexs.decompiler.flash.action.swf4.ActionDivide;
-import com.jpexs.decompiler.flash.action.swf4.ActionEndDrag;
-import com.jpexs.decompiler.flash.action.swf4.ActionEquals;
-import com.jpexs.decompiler.flash.action.swf4.ActionGetProperty;
-import com.jpexs.decompiler.flash.action.swf4.ActionGetTime;
-import com.jpexs.decompiler.flash.action.swf4.ActionGetURL2;
-import com.jpexs.decompiler.flash.action.swf4.ActionGetVariable;
-import com.jpexs.decompiler.flash.action.swf4.ActionGotoFrame2;
-import com.jpexs.decompiler.flash.action.swf4.ActionIf;
-import com.jpexs.decompiler.flash.action.swf4.ActionJump;
-import com.jpexs.decompiler.flash.action.swf4.ActionLess;
-import com.jpexs.decompiler.flash.action.swf4.ActionMBAsciiToChar;
-import com.jpexs.decompiler.flash.action.swf4.ActionMBCharToAscii;
-import com.jpexs.decompiler.flash.action.swf4.ActionMBStringExtract;
-import com.jpexs.decompiler.flash.action.swf4.ActionMBStringLength;
-import com.jpexs.decompiler.flash.action.swf4.ActionMultiply;
-import com.jpexs.decompiler.flash.action.swf4.ActionNot;
-import com.jpexs.decompiler.flash.action.swf4.ActionOr;
-import com.jpexs.decompiler.flash.action.swf4.ActionPop;
-import com.jpexs.decompiler.flash.action.swf4.ActionPush;
-import com.jpexs.decompiler.flash.action.swf4.ActionRandomNumber;
-import com.jpexs.decompiler.flash.action.swf4.ActionRemoveSprite;
-import com.jpexs.decompiler.flash.action.swf4.ActionSetProperty;
-import com.jpexs.decompiler.flash.action.swf4.ActionSetTarget2;
-import com.jpexs.decompiler.flash.action.swf4.ActionSetVariable;
-import com.jpexs.decompiler.flash.action.swf4.ActionStartDrag;
-import com.jpexs.decompiler.flash.action.swf4.ActionStringAdd;
-import com.jpexs.decompiler.flash.action.swf4.ActionStringEquals;
-import com.jpexs.decompiler.flash.action.swf4.ActionStringExtract;
-import com.jpexs.decompiler.flash.action.swf4.ActionStringLength;
-import com.jpexs.decompiler.flash.action.swf4.ActionStringLess;
-import com.jpexs.decompiler.flash.action.swf4.ActionSubtract;
-import com.jpexs.decompiler.flash.action.swf4.ActionToInteger;
-import com.jpexs.decompiler.flash.action.swf4.ActionTrace;
-import com.jpexs.decompiler.flash.action.swf4.ActionWaitForFrame2;
-import com.jpexs.decompiler.flash.action.swf5.ActionAdd2;
-import com.jpexs.decompiler.flash.action.swf5.ActionBitAnd;
-import com.jpexs.decompiler.flash.action.swf5.ActionBitLShift;
-import com.jpexs.decompiler.flash.action.swf5.ActionBitOr;
-import com.jpexs.decompiler.flash.action.swf5.ActionBitRShift;
-import com.jpexs.decompiler.flash.action.swf5.ActionBitURShift;
-import com.jpexs.decompiler.flash.action.swf5.ActionBitXor;
-import com.jpexs.decompiler.flash.action.swf5.ActionCallFunction;
-import com.jpexs.decompiler.flash.action.swf5.ActionCallMethod;
-import com.jpexs.decompiler.flash.action.swf5.ActionConstantPool;
-import com.jpexs.decompiler.flash.action.swf5.ActionDecrement;
-import com.jpexs.decompiler.flash.action.swf5.ActionDefineFunction;
-import com.jpexs.decompiler.flash.action.swf5.ActionDefineLocal;
-import com.jpexs.decompiler.flash.action.swf5.ActionDefineLocal2;
-import com.jpexs.decompiler.flash.action.swf5.ActionDelete;
-import com.jpexs.decompiler.flash.action.swf5.ActionDelete2;
-import com.jpexs.decompiler.flash.action.swf5.ActionEnumerate;
-import com.jpexs.decompiler.flash.action.swf5.ActionEquals2;
-import com.jpexs.decompiler.flash.action.swf5.ActionGetMember;
-import com.jpexs.decompiler.flash.action.swf5.ActionIncrement;
-import com.jpexs.decompiler.flash.action.swf5.ActionInitArray;
-import com.jpexs.decompiler.flash.action.swf5.ActionInitObject;
-import com.jpexs.decompiler.flash.action.swf5.ActionLess2;
-import com.jpexs.decompiler.flash.action.swf5.ActionModulo;
-import com.jpexs.decompiler.flash.action.swf5.ActionNewMethod;
-import com.jpexs.decompiler.flash.action.swf5.ActionNewObject;
-import com.jpexs.decompiler.flash.action.swf5.ActionPushDuplicate;
-import com.jpexs.decompiler.flash.action.swf5.ActionReturn;
-import com.jpexs.decompiler.flash.action.swf5.ActionSetMember;
-import com.jpexs.decompiler.flash.action.swf5.ActionStackSwap;
-import com.jpexs.decompiler.flash.action.swf5.ActionStoreRegister;
-import com.jpexs.decompiler.flash.action.swf5.ActionTargetPath;
-import com.jpexs.decompiler.flash.action.swf5.ActionToNumber;
-import com.jpexs.decompiler.flash.action.swf5.ActionToString;
-import com.jpexs.decompiler.flash.action.swf5.ActionTypeOf;
-import com.jpexs.decompiler.flash.action.swf5.ActionWith;
-import com.jpexs.decompiler.flash.action.swf6.ActionEnumerate2;
-import com.jpexs.decompiler.flash.action.swf6.ActionGreater;
-import com.jpexs.decompiler.flash.action.swf6.ActionInstanceOf;
-import com.jpexs.decompiler.flash.action.swf6.ActionStrictEquals;
-import com.jpexs.decompiler.flash.action.swf6.ActionStringGreater;
-import com.jpexs.decompiler.flash.action.swf7.ActionCastOp;
-import com.jpexs.decompiler.flash.action.swf7.ActionDefineFunction2;
-import com.jpexs.decompiler.flash.action.swf7.ActionExtends;
-import com.jpexs.decompiler.flash.action.swf7.ActionImplementsOp;
-import com.jpexs.decompiler.flash.action.swf7.ActionThrow;
-import com.jpexs.decompiler.flash.action.swf7.ActionTry;
-import com.jpexs.decompiler.flash.configuration.Configuration;
-import com.jpexs.decompiler.flash.dumpview.DumpInfo;
-import com.jpexs.decompiler.flash.tags.CSMTextSettingsTag;
-import com.jpexs.decompiler.flash.tags.DebugIDTag;
-import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag;
-import com.jpexs.decompiler.flash.tags.DefineBitsJPEG2Tag;
-import com.jpexs.decompiler.flash.tags.DefineBitsJPEG3Tag;
-import com.jpexs.decompiler.flash.tags.DefineBitsJPEG4Tag;
-import com.jpexs.decompiler.flash.tags.DefineBitsLossless2Tag;
-import com.jpexs.decompiler.flash.tags.DefineBitsLosslessTag;
-import com.jpexs.decompiler.flash.tags.DefineBitsTag;
-import com.jpexs.decompiler.flash.tags.DefineButton2Tag;
-import com.jpexs.decompiler.flash.tags.DefineButtonCxformTag;
-import com.jpexs.decompiler.flash.tags.DefineButtonSoundTag;
-import com.jpexs.decompiler.flash.tags.DefineButtonTag;
-import com.jpexs.decompiler.flash.tags.DefineEditTextTag;
-import com.jpexs.decompiler.flash.tags.DefineFont2Tag;
-import com.jpexs.decompiler.flash.tags.DefineFont3Tag;
-import com.jpexs.decompiler.flash.tags.DefineFont4Tag;
-import com.jpexs.decompiler.flash.tags.DefineFontAlignZonesTag;
-import com.jpexs.decompiler.flash.tags.DefineFontInfo2Tag;
-import com.jpexs.decompiler.flash.tags.DefineFontInfoTag;
-import com.jpexs.decompiler.flash.tags.DefineFontNameTag;
-import com.jpexs.decompiler.flash.tags.DefineFontTag;
-import com.jpexs.decompiler.flash.tags.DefineMorphShape2Tag;
-import com.jpexs.decompiler.flash.tags.DefineMorphShapeTag;
-import com.jpexs.decompiler.flash.tags.DefineScalingGridTag;
-import com.jpexs.decompiler.flash.tags.DefineSceneAndFrameLabelDataTag;
-import com.jpexs.decompiler.flash.tags.DefineShape2Tag;
-import com.jpexs.decompiler.flash.tags.DefineShape3Tag;
-import com.jpexs.decompiler.flash.tags.DefineShape4Tag;
-import com.jpexs.decompiler.flash.tags.DefineShapeTag;
-import com.jpexs.decompiler.flash.tags.DefineSoundTag;
-import com.jpexs.decompiler.flash.tags.DefineSpriteTag;
-import com.jpexs.decompiler.flash.tags.DefineText2Tag;
-import com.jpexs.decompiler.flash.tags.DefineTextTag;
-import com.jpexs.decompiler.flash.tags.DefineVideoStreamTag;
-import com.jpexs.decompiler.flash.tags.DoABCDefineTag;
-import com.jpexs.decompiler.flash.tags.DoABCTag;
-import com.jpexs.decompiler.flash.tags.DoActionTag;
-import com.jpexs.decompiler.flash.tags.DoInitActionTag;
-import com.jpexs.decompiler.flash.tags.EnableDebugger2Tag;
-import com.jpexs.decompiler.flash.tags.EnableDebuggerTag;
-import com.jpexs.decompiler.flash.tags.EnableTelemetryTag;
-import com.jpexs.decompiler.flash.tags.EndTag;
-import com.jpexs.decompiler.flash.tags.ExportAssetsTag;
-import com.jpexs.decompiler.flash.tags.FileAttributesTag;
-import com.jpexs.decompiler.flash.tags.FrameLabelTag;
-import com.jpexs.decompiler.flash.tags.ImportAssets2Tag;
-import com.jpexs.decompiler.flash.tags.ImportAssetsTag;
-import com.jpexs.decompiler.flash.tags.JPEGTablesTag;
-import com.jpexs.decompiler.flash.tags.MetadataTag;
-import com.jpexs.decompiler.flash.tags.PlaceObject2Tag;
-import com.jpexs.decompiler.flash.tags.PlaceObject3Tag;
-import com.jpexs.decompiler.flash.tags.PlaceObject4Tag;
-import com.jpexs.decompiler.flash.tags.PlaceObjectTag;
-import com.jpexs.decompiler.flash.tags.ProductInfoTag;
-import com.jpexs.decompiler.flash.tags.ProtectTag;
-import com.jpexs.decompiler.flash.tags.RemoveObject2Tag;
-import com.jpexs.decompiler.flash.tags.RemoveObjectTag;
-import com.jpexs.decompiler.flash.tags.ScriptLimitsTag;
-import com.jpexs.decompiler.flash.tags.SetBackgroundColorTag;
-import com.jpexs.decompiler.flash.tags.SetTabIndexTag;
-import com.jpexs.decompiler.flash.tags.ShowFrameTag;
-import com.jpexs.decompiler.flash.tags.SoundStreamBlockTag;
-import com.jpexs.decompiler.flash.tags.SoundStreamHead2Tag;
-import com.jpexs.decompiler.flash.tags.SoundStreamHeadTag;
-import com.jpexs.decompiler.flash.tags.StartSound2Tag;
-import com.jpexs.decompiler.flash.tags.StartSoundTag;
-import com.jpexs.decompiler.flash.tags.SymbolClassTag;
-import com.jpexs.decompiler.flash.tags.Tag;
-import com.jpexs.decompiler.flash.tags.TagStub;
-import com.jpexs.decompiler.flash.tags.UnknownTag;
-import com.jpexs.decompiler.flash.tags.VideoFrameTag;
-import com.jpexs.decompiler.flash.tags.gfx.DefineCompactedFont;
-import com.jpexs.decompiler.flash.tags.gfx.DefineExternalGradient;
-import com.jpexs.decompiler.flash.tags.gfx.DefineExternalImage;
-import com.jpexs.decompiler.flash.tags.gfx.DefineExternalImage2;
-import com.jpexs.decompiler.flash.tags.gfx.DefineExternalSound;
-import com.jpexs.decompiler.flash.tags.gfx.DefineExternalStreamSound;
-import com.jpexs.decompiler.flash.tags.gfx.DefineGradientMap;
-import com.jpexs.decompiler.flash.tags.gfx.DefineSubImage;
-import com.jpexs.decompiler.flash.tags.gfx.ExporterInfoTag;
-import com.jpexs.decompiler.flash.tags.gfx.FontTextureInfo;
-import com.jpexs.decompiler.flash.timeline.Timelined;
-import com.jpexs.decompiler.flash.types.ALPHABITMAPDATA;
-import com.jpexs.decompiler.flash.types.ALPHACOLORMAPDATA;
-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.COLORMAPDATA;
-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.ByteArrayRange;
-import com.jpexs.helpers.Helper;
-import com.jpexs.helpers.MemoryInputStream;
-import com.jpexs.helpers.ProgressListener;
-import com.jpexs.helpers.utf8.Utf8Helper;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.EOFException;
-import java.io.IOException;
-import java.io.PrintStream;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-import java.util.zip.InflaterInputStream;
-
-/**
- * Class for reading data from SWF file
- *
- * @author JPEXS
- */
-public class SWFInputStream implements AutoCloseable {
-
- private MemoryInputStream is;
- private long startingPos;
- private static final Logger logger = Logger.getLogger(SWFInputStream.class.getName());
- private final List listeners = new ArrayList<>();
- private long percentMax;
- private SWF swf;
- public DumpInfo dumpInfo;
-
- public void addPercentListener(ProgressListener listener) {
- listeners.add(listener);
- }
-
- public void removePercentListener(ProgressListener listener) {
- int index = listeners.indexOf(listener);
- if (index > -1) {
- listeners.remove(index);
- }
- }
-
- private void informListeners() {
- if (listeners.size() > 0 && percentMax > 0) {
- int percent = (int) (getPos() * 100 / percentMax);
- if (lastPercent != percent) {
- for (ProgressListener pl : listeners) {
- pl.progress(percent);
- }
- lastPercent = percent;
- }
- }
- }
-
- public void setPercentMax(long percentMax) {
- this.percentMax = percentMax;
- }
-
- /**
- * Constructor
- *
- * @param swf SWF to read
- * @param data SWF data
- * @param startingPos
- * @param limit
- * @throws java.io.IOException
- */
- public SWFInputStream(SWF swf, byte[] data, long startingPos, int limit) throws IOException {
- this.swf = swf;
- this.startingPos = startingPos;
- is = new MemoryInputStream(data, 0, limit);
- }
-
- /**
- * Constructor
- *
- * @param swf SWF to read
- * @param data SWF data
- * @throws java.io.IOException
- */
- public SWFInputStream(SWF swf, byte[] data) throws IOException {
- this(swf, data, 0L, data.length);
- }
-
- public SWF getSwf() {
- return swf;
- }
-
- /**
- * Gets position in bytes in the stream
- *
- * @return Number of bytes
- */
- public long getPos() {
- return startingPos + is.getPos();
- }
-
- /**
- * Sets position in bytes in the stream
- *
- * @param pos Number of bytes
- * @throws java.io.IOException
- */
- public void seek(long pos) throws IOException {
- is.seek(pos - startingPos);
- }
-
- private void newDumpLevel(String name, String type) {
- if (dumpInfo != null) {
- long startByte = is.getPos();
- if (bitPos > 0) {
- startByte--;
- }
- DumpInfo di = new DumpInfo(name, type, null, startByte, bitPos, 0, 0);
- di.parent = dumpInfo;
- dumpInfo.getChildInfos().add(di);
- dumpInfo = di;
- }
- }
-
- private void endDumpLevel() {
- endDumpLevel(null);
- }
-
- private void endDumpLevel(Object value) {
- if (dumpInfo != null) {
- if (dumpInfo.startBit == 0 && bitPos == 0) {
- dumpInfo.lengthBytes = is.getPos() - dumpInfo.startByte;
- } else {
- dumpInfo.lengthBits = (int) ((is.getPos() - dumpInfo.startByte - 1) * 8 - dumpInfo.startBit + (bitPos == 0 ? 8 : bitPos));
- }
- dumpInfo.previewValue = value;
- dumpInfo = dumpInfo.parent;
- }
- }
-
- /**
- * Reads one byte from the stream
- *
- * @return byte
- * @throws IOException
- */
- private int readEx() throws IOException {
- bitPos = 0;
- return readNoBitReset();
- }
-
- private void alignByte() {
- bitPos = 0;
- }
-
- private int lastPercent = -1;
-
- private int readNoBitReset() throws IOException, EndOfStreamException {
- informListeners();
- int r = is.read();
- if (r == -1) {
- throw new EndOfStreamException();
- }
- return r;
- }
-
- /**
- * Reads one UI8 (Unsigned 8bit integer) value from the stream
- *
- * @param name
- * @return UI8 value or -1 on error
- * @throws IOException
- */
- public int readUI8(String name) throws IOException {
- newDumpLevel(name, "UI8");
- int ret = readEx();
- endDumpLevel(ret);
- return ret;
- }
-
- /**
- * 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 = readEx();
- if (r == 0) {
- endDumpLevel();
- return new String(baos.toByteArray(), Utf8Helper.charset);
- }
- baos.write(r);
- }
- }
-
- /**
- * Reads one UI32 (Unsigned 32bit integer) value from the stream
- *
- * @param name
- * @return UI32 value
- * @throws IOException
- */
- public long readUI32(String name) throws IOException {
- newDumpLevel(name, "UI32");
- long ret = readUI32Internal();
- endDumpLevel(ret);
- return ret;
- }
-
- /**
- * Reads one UI32 (Unsigned 32bit integer) value from the stream
- *
- * @return UI32 value
- * @throws IOException
- */
- private long readUI32Internal() throws IOException {
- return (readEx() + (readEx() << 8) + (readEx() << 16) + (readEx() << 24)) & 0xffffffff;
- }
-
- /**
- * Reads one UI16 (Unsigned 16bit integer) value from the stream
- *
- * @param name
- * @return UI16 value
- * @throws IOException
- */
- public int readUI16(String name) throws IOException {
- newDumpLevel(name, "UI16");
- int ret = readUI16Internal();
- endDumpLevel(ret);
- return ret;
- }
-
- /**
- * Reads one UI16 (Unsigned 16bit integer) value from the stream
- *
- * @return UI16 value
- * @throws IOException
- */
- private int readUI16Internal() throws IOException {
- return readEx() + (readEx() << 8);
- }
-
- public int readUI24(String name) throws IOException {
- newDumpLevel(name, "UI24");
- int ret = readEx() + (readEx() << 8) + (readEx() << 16);
- endDumpLevel(ret);
- return ret;
- }
-
- /**
- * Reads one SI32 (Signed 32bit integer) value from the stream
- *
- * @param name
- * @return SI32 value
- * @throws IOException
- */
- public long readSI32(String name) throws IOException {
- newDumpLevel(name, "SI32");
- long uval = readEx() + (readEx() << 8) + (readEx() << 16) + (readEx() << 24);
- if (uval >= 0x80000000) {
- uval = -(((~uval) & 0xffffffff) + 1);
- }
- endDumpLevel(uval);
- return uval;
- }
-
- /**
- * 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 = readEx() + (readEx() << 8);
- if (uval >= 0x8000) {
- uval = -(((~uval) & 0xffff) + 1);
- }
- endDumpLevel(uval);
- return uval;
- }
-
- /**
- * Reads one SI8 (Signed 8bit integer) value from the stream
- *
- * @param name
- * @return SI8 value
- * @throws IOException
- */
- public int readSI8(String name) throws IOException {
- newDumpLevel(name, "SI8");
- int uval = readEx();
- if (uval >= 0x80) {
- uval = -(((~uval) & 0xff) + 1);
- }
- endDumpLevel(uval);
- return uval;
- }
-
- /**
- * Reads one FIXED (Fixed point 16.16) value from the stream
- *
- * @param name
- * @return FIXED value
- * @throws IOException
- */
- public double readFIXED(String name) throws IOException {
- newDumpLevel(name, "FIXED");
- int afterPoint = readUI16Internal();
- int beforePoint = readUI16Internal();
- double ret = ((double) ((beforePoint << 16) + afterPoint)) / 65536;
- endDumpLevel(ret);
- return ret;
- }
-
- /**
- * Reads one FIXED8 (Fixed point 8.8) value from the stream
- *
- * @param name
- * @return FIXED8 value
- * @throws IOException
- */
- public float readFIXED8(String name) throws IOException {
- newDumpLevel(name, "FIXED8");
- int afterPoint = readEx();
- int beforePoint = readEx();
- float ret = beforePoint + (((float) afterPoint) / 256);
- endDumpLevel(ret);
- return ret;
- }
-
- private long readLong() throws IOException {
- byte[] readBuffer = readBytesInternalEx(8);
- return (((long) readBuffer[3] << 56)
- + ((long) (readBuffer[2] & 255) << 48)
- + ((long) (readBuffer[1] & 255) << 40)
- + ((long) (readBuffer[0] & 255) << 32)
- + ((long) (readBuffer[7] & 255) << 24)
- + ((readBuffer[6] & 255) << 16)
- + ((readBuffer[5] & 255) << 8)
- + ((readBuffer[4] & 255)));
- }
-
- /**
- * Reads one DOUBLE (double precision floating point value) value from the
- * stream
- *
- * @param name
- * @return DOUBLE value
- * @throws IOException
- */
- public double readDOUBLE(String name) throws IOException {
- newDumpLevel(name, "DOUBLE");
- long el = readLong();
- double ret = Double.longBitsToDouble(el);
- endDumpLevel(ret);
- return ret;
- }
-
- /**
- * Reads one FLOAT (single precision floating point value) value from the
- * stream
- *
- * @param name
- * @return FLOAT value
- * @throws IOException
- */
- public float readFLOAT(String name) throws IOException {
- newDumpLevel(name, "FLOAT");
- int val = (int) readUI32Internal();
- float ret = Float.intBitsToFloat(val);
- endDumpLevel(ret);
- /*int sign = val >> 31;
- int mantisa = val & 0x3FFFFF;
- int exp = (val >> 22) & 0xFF;
- float ret =(sign == 1 ? -1 : 1) * (float) Math.pow(2, exp)* (1+((mantisa)/ (float)(1<<23)));*/
- return ret;
- }
-
- /**
- * Reads one FLOAT16 (16bit floating point value) value from the stream
- *
- * @param name
- * @return FLOAT16 value
- * @throws IOException
- */
- public float readFLOAT16(String name) throws IOException {
- newDumpLevel(name, "FLOAT16");
- int val = readUI16Internal();
- int sign = val >> 15;
- int mantisa = val & 0x3FF;
- int exp = (val >> 10) & 0x1F;
- float ret = (sign == 1 ? -1 : 1) * (float) Math.pow(2, exp) * (1 + ((mantisa) / (float) (1 << 10)));
- endDumpLevel(ret);
- return ret;
- }
-
- /**
- * Reads bytes from the stream
- *
- * @param count Number of bytes to read
- * @param name
- * @return Array of read bytes
- * @throws IOException
- */
- public byte[] readBytesEx(long count, String name) throws IOException {
- if (count <= 0) {
- return new byte[0];
- }
- newDumpLevel(name, "bytes");
- byte[] ret = readBytesInternalEx(count);
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads bytes from the stream
- *
- * @param count Number of bytes to read
- * @return Array of read bytes
- * @throws IOException
- */
- private byte[] readBytesInternalEx(long count) throws IOException {
- if (count <= 0) {
- return new byte[0];
- }
-
- informListeners();
- bitPos = 0;
- byte[] ret = new byte[(int) count];
- if (is.read(ret) != count) {
- throw new EndOfStreamException();
- }
-
- return ret;
- }
-
- /**
- * Skip bytes from the stream
- *
- * @param count Number of bytes to skip
- * @throws IOException
- */
- public void skipBytes(int count) throws IOException {
- try {
- bitPos = 0;
- for (int i = 0; i < count; i++) {
- readNoBitReset();
- }
- } catch (EOFException | EndOfStreamException ex) {
- logger.log(Level.SEVERE, null, ex);
- }
- }
-
- /**
- * Reads bytes from the stream
- *
- * @param count Number of bytes to read
- * @param name
- * @return Array of read bytes
- * @throws IOException
- */
- public byte[] readBytes(int count, String name) throws IOException {
- if (count <= 0) {
- return new byte[0];
- }
- newDumpLevel(name, "bytes");
- byte[] ret = new byte[count];
- int i = 0;
- try {
- for (i = 0; i < count; i++) {
- ret[i] = (byte) readEx();
- }
- } catch (EOFException | EndOfStreamException ex) {
- ret = Arrays.copyOf(ret, i); // truncate array
- logger.log(Level.SEVERE, null, ex);
- }
- endDumpLevel();
- return ret;
- }
-
- public byte[] readBytesZlib(long count, String name) throws IOException {
- newDumpLevel(name, "bytesZlib");
- byte[] data = readBytesInternalEx(count);
- endDumpLevel();
- InflaterInputStream dis = new InflaterInputStream(new ByteArrayInputStream(data));
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- byte[] buf = new byte[4096];
- int c = 0;
- while ((c = dis.read(buf)) > 0) {
- baos.write(buf, 0, c);
- }
- return baos.toByteArray();
- }
-
- /**
- * Reads one EncodedU32 (Encoded unsigned 32bit value) value from the stream
- *
- * @param name
- * @return U32 value
- * @throws IOException
- */
- public long readEncodedU32(String name) throws IOException {
- newDumpLevel(name, "encodedU32");
- int result = readEx();
- if ((result & 0x00000080) == 0) {
- endDumpLevel(result);
- return result;
- }
- result = (result & 0x0000007f) | (readEx()) << 7;
- if ((result & 0x00004000) == 0) {
- endDumpLevel(result);
- return result;
- }
- result = (result & 0x00003fff) | (readEx()) << 14;
- if ((result & 0x00200000) == 0) {
- endDumpLevel(result);
- return result;
- }
- result = (result & 0x001fffff) | (readEx()) << 21;
- if ((result & 0x10000000) == 0) {
- endDumpLevel(result);
- return result;
- }
- result = (result & 0x0fffffff) | (readEx()) << 28;
- endDumpLevel(result);
- return result;
- }
- private int bitPos = 0;
- private int tempByte = 0;
-
- /**
- * Reads UB[nBits] (Unsigned-bit value) value from the stream
- *
- * @param nBits Number of bits which represent value
- * @param name
- * @return Unsigned value
- * @throws IOException
- */
- public long readUB(int nBits, String name) throws IOException {
- if (nBits == 0) {
- return 0;
- }
- newDumpLevel(name, "UB");
- long ret = readUBInternal(nBits);
- endDumpLevel(ret);
- return ret;
- }
-
- /**
- * Reads UB[nBits] (Unsigned-bit value) value from the stream
- *
- * @param nBits Number of bits which represent value
- * @return Unsigned value
- * @throws IOException
- */
- private long readUBInternal(int nBits) throws IOException {
- if (nBits == 0) {
- return 0;
- }
- long ret = 0;
- if (bitPos == 0) {
- tempByte = readNoBitReset();
- }
- for (int bit = 0; bit < nBits; bit++) {
- int nb = (tempByte >> (7 - bitPos)) & 1;
- ret += (nb << (nBits - 1 - bit));
- bitPos++;
- if (bitPos == 8) {
- bitPos = 0;
- if (bit != nBits - 1) {
- tempByte = readNoBitReset();
- }
- }
- }
- return ret;
- }
-
- /**
- * Reads SB[nBits] (Signed-bit value) value from the stream
- *
- * @param nBits Number of bits which represent value
- * @param name
- * @return Signed value
- * @throws IOException
- */
- public long readSB(int nBits, String name) throws IOException {
- newDumpLevel(name, "SB");
- long ret = readSBInternal(nBits);
- endDumpLevel(ret);
- return ret;
- }
-
- /**
- * Reads SB[nBits] (Signed-bit value) value from the stream
- *
- * @param nBits Number of bits which represent value
- * @return Signed value
- * @throws IOException
- */
- private long readSBInternal(int nBits) throws IOException {
- int uval = (int) readUBInternal(nBits);
-
- int shift = 32 - nBits;
- // sign extension
- uval = (uval << shift) >> shift;
- return uval;
- }
-
- /**
- * Reads FB[nBits] (Signed fixed-point bit value) value from the stream
- *
- * @param nBits Number of bits which represent value
- * @param name
- * @return Fixed-point value
- * @throws IOException
- */
- public float readFB(int nBits, String name) throws IOException {
- if (nBits == 0) {
- return 0;
- }
- newDumpLevel(name, "FB");
- float val = readSBInternal(nBits);
- float ret = val / 0x10000;
- endDumpLevel(ret);
- return ret;
- }
-
- /**
- * Reads one RECT value from the stream
- *
- * @param name
- * @return RECT value
- * @throws IOException
- */
- public RECT readRECT(String name) throws IOException {
- RECT ret = new RECT();
- newDumpLevel(name, "RECT");
- int NBits = (int) readUB(5, "NBits");
- ret.Xmin = (int) readSB(NBits, "Xmin");
- ret.Xmax = (int) readSB(NBits, "Xmax");
- ret.Ymin = (int) readSB(NBits, "Ymin");
- ret.Ymax = (int) readSB(NBits, "Ymax");
- ret.nbits = NBits;
- alignByte();
- endDumpLevel();
- return ret;
- }
-
- private static void dumpTag(PrintStream out, int version, Tag tag, int level) {
- StringBuilder sb = new StringBuilder();
- sb.append(Helper.formatHex((int) tag.getPos(), 8));
- sb.append(": ");
- sb.append(Helper.indent(level, "", " "));
- sb.append(Helper.format(tag.toString(), 25 - 2 * level));
- sb.append(" tagId=");
- sb.append(Helper.formatInt(tag.getId(), 3));
- sb.append(" len=");
- sb.append(Helper.formatInt(tag.getOriginalDataLength(), 8));
- sb.append(" ");
- sb.append(Helper.bytesToHexString(64, tag.getData(), 0));
- out.println(sb.toString());
-// out.println(Utils.formatHex((int)tag.getPos(), 8) + ": " + Utils.indent(level, "") + Utils.format(tag.toString(), 25 - 2*level) + " tagId="+tag.getId()+" len="+tag.getOrigDataLength()+": "+Utils.bytesToHexString(64, tag.getData(version), 0));
- if (tag.hasSubTags()) {
- for (Tag subTag : tag.getSubTags()) {
- dumpTag(out, version, subTag, level + 1);
- }
- }
- }
-
- @Override
- public void close() {
- }
-
- private class TagResolutionTask implements Callable {
-
- private final Tag tag;
- private final DumpInfo dumpInfo;
- private final int level;
- private final boolean parallel;
- private final boolean skipUnusualTags;
- private final boolean gfx;
-
- public TagResolutionTask(Tag tag, DumpInfo dumpInfo, int level, boolean parallel, boolean skipUnusualTags, boolean gfx) {
- this.tag = tag;
- this.dumpInfo = dumpInfo;
- this.level = level;
- this.parallel = parallel;
- this.skipUnusualTags = skipUnusualTags;
- this.gfx = gfx;
- }
-
- @Override
- public Tag call() throws Exception {
- try {
- Tag t = resolveTag(tag, level, parallel, skipUnusualTags, gfx);
- if (dumpInfo!= null && t != null) {
- dumpInfo.name = t.getName();
- }
- return t;
- } catch (EndOfStreamException ex) {
- logger.log(Level.SEVERE, null, ex);
- return tag;
- }
- }
- }
-
- /**
- * Reads list of tags from the stream. Reading ends with End tag(=0) or end
- * of the stream. Optionally can skip AS1/2 tags when file is AS3
- *
- * @param timelined
- * @param level
- * @param parallel
- * @param skipUnusualTags
- * @param parseTags
- * @param gfx
- * @return List of tags
- * @throws IOException
- * @throws java.lang.InterruptedException
- */
- public List readTagList(Timelined timelined, int level, boolean parallel, boolean skipUnusualTags, boolean parseTags, boolean gfx) throws IOException, InterruptedException {
- ExecutorService executor = null;
- List> futureResults = new ArrayList<>();
- if (parallel) {
- executor = Executors.newFixedThreadPool(Configuration.parallelThreadCount.get());
- futureResults = new ArrayList<>();
- }
- List tags = new ArrayList<>();
- Tag tag;
- boolean isAS3 = false;
- while (true) {
- long pos = getPos();
- newDumpLevel(null, "TAG");
- try {
- tag = readTag(level, pos, parseTags && !parallel, parallel, skipUnusualTags, gfx);
- } catch (EOFException | EndOfStreamException ex) {
- tag = null;
- }
- DumpInfo di = dumpInfo;
- if (di != null && tag != null) {
- di.name = tag.getName();
- }
- endDumpLevel(tag == null ? null : tag.getId());
- if (tag == null) {
- break;
- }
-
- tag.setTimelined(timelined);
- if (!parallel) {
- tags.add(tag);
- }
- if (Configuration.dumpTags.get() && level == 0) {
- dumpTag(System.out, swf.version, tag, level);
- }
-
- boolean doParse;
- if (!skipUnusualTags) {
- doParse = true;
- } else {
- switch (tag.getId()) {
- case FileAttributesTag.ID: //FileAttributes
- tag = resolveTag(tag, level, parallel, skipUnusualTags, gfx);
- FileAttributesTag fileAttributes = (FileAttributesTag) tag;
- if (fileAttributes.actionScript3) {
- isAS3 = true;
- }
- doParse = true;
- break;
- case DoActionTag.ID:
- case DoInitActionTag.ID:
- if (isAS3) {
- doParse = false;
- } else {
- doParse = true;
- }
- break;
- case ShowFrameTag.ID:
- case PlaceObjectTag.ID:
- case PlaceObject2Tag.ID:
- case RemoveObjectTag.ID:
- case RemoveObject2Tag.ID:
- case PlaceObject3Tag.ID: //?
- case StartSoundTag.ID:
- case FrameLabelTag.ID:
- case SoundStreamHeadTag.ID:
- case SoundStreamHead2Tag.ID:
- case SoundStreamBlockTag.ID:
- case VideoFrameTag.ID:
- case EndTag.ID:
- doParse = true;
- break;
- default:
- if (level > 0) { //No such tags in DefineSprite allowed
- logger.log(Level.FINE, "Tag({0}) found in DefineSprite => Ignored", tag.getId());
- doParse = false;
- } else {
- doParse = true;
- }
-
- }
- }
- if (parseTags && doParse) {
- if (parallel) {
- Future future = executor.submit(new TagResolutionTask(tag, di, level, parallel, skipUnusualTags, gfx));
- futureResults.add(future);
- }
- }
-
- if (tag.getId() == EndTag.ID) {
- break;
- }
- }
-
- if (parallel) {
- for (Future future : futureResults) {
- try {
- tags.add(future.get());
- } catch (InterruptedException ex) {
- future.cancel(true);
- } catch (ExecutionException e) {
- logger.log(Level.SEVERE, "Error during tag reading", e);
- }
- }
-
- executor.shutdown();
- }
- return tags;
- }
-
- public static Tag resolveTag(Tag tag, int level, boolean parallel, boolean skipUnusualTags, boolean gfx) throws InterruptedException {
- Tag ret;
-
- if (!(tag instanceof TagStub)) {
- return tag;
- }
-
- ByteArrayRange data = tag.getOriginalRange();
- SWF swf = tag.getSwf();
- TagStub tagStub = (TagStub) tag;
- SWFInputStream sis = tagStub.getDataStream();
-
- try {
- switch (tag.getId()) {
- case 0:
- ret = new EndTag(swf, data);
- break;
- case 1:
- ret = new ShowFrameTag(swf, data);
- break;
- case 2:
- ret = new DefineShapeTag(sis, data);
- break;
- //case 3: FreeCharacter
- case 4:
- ret = new PlaceObjectTag(sis, data);
- break;
- case 5:
- ret = new RemoveObjectTag(sis, data);
- break;
- case 6:
- ret = new DefineBitsTag(sis, data);
- break;
- case 7:
- ret = new DefineButtonTag(sis, data);
- break;
- case 8:
- ret = new JPEGTablesTag(sis, data);
- break;
- case 9:
- ret = new SetBackgroundColorTag(sis, data);
- break;
- case 10:
- ret = new DefineFontTag(sis, data);
- break;
- case 11:
- ret = new DefineTextTag(sis, data);
- break;
- case 12:
- ret = new DoActionTag(sis, data);
- break;
- case 13:
- ret = new DefineFontInfoTag(sis, data);
- break;
- case 14:
- ret = new DefineSoundTag(sis, data);
- break;
- case 15:
- ret = new StartSoundTag(sis, data);
- break;
- //case 16:
- case 17:
- ret = new DefineButtonSoundTag(sis, data);
- break;
- case 18:
- ret = new SoundStreamHeadTag(sis, data);
- break;
- case 19:
- ret = new SoundStreamBlockTag(sis, data);
- break;
- case 21:
- ret = new DefineBitsJPEG2Tag(sis, data);
- break;
- case 20:
- ret = new DefineBitsLosslessTag(sis, data);
- break;
- case 22:
- ret = new DefineShape2Tag(sis, data);
- break;
- case 23:
- ret = new DefineButtonCxformTag(sis, data);
- break;
- case 24:
- ret = new ProtectTag(sis, data);
- break;
- //case 25: PathsArePostscript
- case 26:
- ret = new PlaceObject2Tag(sis, data);
- break;
- //case 27:
- case 28:
- ret = new RemoveObject2Tag(sis, data);
- break;
- //case 29: SyncFrame
- //case 30:
- //case 31: FreeAll
- case 32:
- ret = new DefineShape3Tag(sis, data);
- break;
- case 33:
- ret = new DefineText2Tag(sis, data);
- break;
- case 34:
- ret = new DefineButton2Tag(sis, data);
- break;
- case 35:
- ret = new DefineBitsJPEG3Tag(sis, data);
- break;
- case 36:
- ret = new DefineBitsLossless2Tag(sis, data);
- break;
- case 37:
- ret = new DefineEditTextTag(sis, data);
- break;
- //case 38: DefineVideo
- case 39:
- ret = new DefineSpriteTag(sis, level, data, parallel, skipUnusualTags);
- break;
- //case 40: NameCharacter
- case 41:
- ret = new ProductInfoTag(sis, data);
- break;
- //case 42: DefineTextFormat
- case 43:
- ret = new FrameLabelTag(sis, data);
- break;
- //case 44:
- case 45:
- ret = new SoundStreamHead2Tag(sis, data);
- break;
- case 46:
- ret = new DefineMorphShapeTag(sis, data);
- break;
- //case 47: GenerateFrame
- case 48:
- ret = new DefineFont2Tag(sis, data);
- break;
- //case 49: GeneratorCommand
- //case 50: DefineCommandObject
- //case 51: CharacterSet
- //case 52: ExternalFont
- //case 53-55
- case 56:
- ret = new ExportAssetsTag(sis, data);
- break;
- case 57:
- ret = new ImportAssetsTag(sis, data);
- break;
- case 58:
- ret = new EnableDebuggerTag(sis, data);
- break;
- case 59:
- ret = new DoInitActionTag(sis, data);
- break;
- case 60:
- ret = new DefineVideoStreamTag(sis, data);
- break;
- case 61:
- ret = new VideoFrameTag(sis, data);
- break;
- case 62:
- ret = new DefineFontInfo2Tag(sis, data);
- break;
- case 63:
- ret = new DebugIDTag(sis, data);
- break;
- case 64:
- ret = new EnableDebugger2Tag(sis, data);
- break;
- case 65:
- ret = new ScriptLimitsTag(sis, data);
- break;
- case 66:
- ret = new SetTabIndexTag(sis, data);
- break;
- //case 67-68:
- case 69:
- ret = new FileAttributesTag(sis, data);
- break;
- case 70:
- ret = new PlaceObject3Tag(sis, data);
- break;
- case 71:
- ret = new ImportAssets2Tag(sis, data);
- break;
- case 72:
- ret = new DoABCTag(sis, data);
- break;
- case 73:
- ret = new DefineFontAlignZonesTag(sis, data);
- break;
- case 74:
- ret = new CSMTextSettingsTag(sis, data);
- break;
- case 75:
- ret = new DefineFont3Tag(sis, data);
- break;
- case 76:
- ret = new SymbolClassTag(sis, data);
- break;
- case 77:
- ret = new MetadataTag(sis, data);
- break;
- case 78:
- ret = new DefineScalingGridTag(sis, data);
- break;
- //case 79-81:
- case 82:
- ret = new DoABCDefineTag(sis, data);
- break;
- case 83:
- ret = new DefineShape4Tag(sis, data);
- break;
- case 84:
- ret = new DefineMorphShape2Tag(sis, data);
- break;
- //case 85:
- case 86:
- ret = new DefineSceneAndFrameLabelDataTag(sis, data);
- break;
- case 87:
- ret = new DefineBinaryDataTag(sis, data);
- break;
- case 88:
- ret = new DefineFontNameTag(sis, data);
- break;
- case 89:
- ret = new StartSound2Tag(sis, data);
- break;
- case 90:
- ret = new DefineBitsJPEG4Tag(sis, data);
- break;
- case 91:
- ret = new DefineFont4Tag(sis, data);
- break;
- //case 92: certificate
- case 93:
- ret = new EnableTelemetryTag(sis, data);
- break;
- case 94:
- ret = new PlaceObject4Tag(sis, data);
- break;
- default:
- if (gfx) { //GFX tags only in GFX files. There may be incorrect GFX tags in non GFX files
- switch (tag.getId()) {
- case 1000:
- ret = new ExporterInfoTag(sis, data);
- break;
- case 1001:
- ret = new DefineExternalImage(sis, data);
- break;
- case 1002:
- ret = new FontTextureInfo(sis, data);
- break;
- case 1003:
- ret = new DefineExternalGradient(sis, data);
- break;
- case 1004:
- ret = new DefineGradientMap(sis, data);
- break;
- case 1005:
- ret = new DefineCompactedFont(sis, data);
- break;
- case 1006:
- ret = new DefineExternalSound(sis, data);
- break;
- case 1007:
- ret = new DefineExternalStreamSound(sis, data);
- break;
- case 1008:
- ret = new DefineSubImage(sis, data);
- break;
- case 1009:
- ret = new DefineExternalImage2(sis, data);
- break;
- default:
- ret = new UnknownTag(swf, tag.getId(), data);
- }
- } else {
- ret = new UnknownTag(swf, tag.getId(), data);
- }
- }
- } catch (IOException ex) {
- logger.log(Level.SEVERE, "Error during tag reading", ex);
- ret = new TagStub(swf, tag.getId(), "ErrorTag", data, null);
- }
- ret.forceWriteAsLong = tag.forceWriteAsLong;
- ret.setTimelined(tag.getTimelined());
- return ret;
- }
-
- /**
- * Reads one Tag from the stream with optional resolving (= reading tag
- * content)
- *
- * @param level
- * @param pos
- * @param resolve
- * @param parallel
- * @param skipUnusualTags
- * @param gfx
- * @return Tag or null when End tag
- * @throws IOException
- * @throws java.lang.InterruptedException
- */
- public Tag readTag(int level, long pos, boolean resolve, boolean parallel, boolean skipUnusualTags, boolean gfx) throws IOException, InterruptedException {
- int tagIDTagLength = readUI16("tagIDTagLength");
- int tagID = (tagIDTagLength) >> 6;
-
- logger.log(Level.INFO, "Reading tag. ID={0}, position: {1}", new Object[]{tagID, pos});
-
- long tagLength = (tagIDTagLength & 0x003F);
- boolean readLong = false;
- if (tagLength == 0x3f) {
- tagLength = readSI32("tagLength");
- readLong = true;
- }
- int headerLength = readLong ? 6 : 2;
- SWFInputStream tagDataStream = getLimitedStream((int) tagLength);
- ByteArrayRange dataRange = new ByteArrayRange(swf.uncompressedData, (int) pos, (int) (tagLength + headerLength));
- TagStub tagStub = new TagStub(swf, tagID, "Unresolved", dataRange, tagDataStream);
- Tag ret = tagStub;
- ret.forceWriteAsLong = readLong;
- skipBytes((int) tagLength);
-
- if (resolve) {
- try {
- ret = resolveTag(ret, level, parallel, skipUnusualTags, gfx);
- } catch (EndOfStreamException ex) {
- logger.log(Level.SEVERE, null, ex);
- }
-
- if (Configuration.debugMode.get()) {
- byte[] data = ret.getOriginalData();
- byte[] dataNew = ret.getData();
- int ignoreFirst = 0;
- for (int i = 0; i < data.length; i++) {
- if (i >= dataNew.length) {
- break;
- }
- if (dataNew[i] != data[i]) {
- if (ignoreFirst > 0) {
- ignoreFirst--;
- continue;
- }
- String e = "TAG " + ret.toString() + " WRONG, ";
- for (int j = i - 10; j <= i + 5; j++) {
- while (j < 0) {
- j++;
- }
- if (j >= data.length) {
- break;
- }
- if (j >= dataNew.length) {
- break;
- }
- if (j >= i) {
- e += (Long.toHexString(data[j] & 0xff) + " ( is " + Long.toHexString(dataNew[j] & 0xff) + ") ");
- } else {
- e += (Long.toHexString(data[j] & 0xff) + " ");
- }
- }
- logger.fine(e);
- }
- }
- }
- }
- return ret;
- }
-
- /**
- * Reads one Action from the stream
- *
- * @param cpool
- * @return Action or null when ActionEndFlag or end of the stream
- * @throws IOException
- */
- public Action readAction(ConstantPool cpool) throws IOException {
- int actionCode = -1;
-
- try {
- actionCode = readUI8("actionCode");
- if (actionCode == 0) {
- return new ActionEnd();
- }
- if (actionCode == -1) {
- return null;
- }
- int actionLength = 0;
- if (actionCode >= 0x80) {
- actionLength = readUI16("actionLength");
- }
- switch (actionCode) {
- //SWF3 Actions
- case 0x81:
- return new ActionGotoFrame(actionLength, this);
- case 0x83:
- return new ActionGetURL(actionLength, this, swf.version);
- case 0x04:
- return new ActionNextFrame();
- case 0x05:
- return new ActionPrevFrame();
- case 0x06:
- return new ActionPlay();
- case 0x07:
- return new ActionStop();
- case 0x08:
- return new ActionToggleQuality();
- case 0x09:
- return new ActionStopSounds();
- case 0x8A:
- return new ActionWaitForFrame(actionLength, this, cpool);
- case 0x8B:
- return new ActionSetTarget(actionLength, this, swf.version);
- case 0x8C:
- return new ActionGoToLabel(actionLength, this, swf.version);
- //SWF4 Actions
- case 0x96:
- return new ActionPush(actionLength, this, swf.version);
- case 0x17:
- return new ActionPop();
- case 0x0A:
- return new ActionAdd();
- case 0x0B:
- return new ActionSubtract();
- case 0x0C:
- return new ActionMultiply();
- case 0x0D:
- return new ActionDivide();
- case 0x0E:
- return new ActionEquals();
- case 0x0F:
- return new ActionLess();
- case 0x10:
- return new ActionAnd();
- case 0x11:
- return new ActionOr();
- case 0x12:
- return new ActionNot();
- case 0x13:
- return new ActionStringEquals();
- case 0x14:
- return new ActionStringLength();
- case 0x21:
- return new ActionStringAdd();
- case 0x15:
- return new ActionStringExtract();
- case 0x29:
- return new ActionStringLess();
- case 0x31:
- return new ActionMBStringLength();
- case 0x35:
- return new ActionMBStringExtract();
- case 0x18:
- return new ActionToInteger();
- case 0x32:
- return new ActionCharToAscii();
- case 0x33:
- return new ActionAsciiToChar();
- case 0x36:
- return new ActionMBCharToAscii();
- case 0x37:
- return new ActionMBAsciiToChar();
- case 0x99:
- return new ActionJump(actionLength, this);
- case 0x9D:
- return new ActionIf(actionLength, this);
- case 0x9E:
- return new ActionCall(actionLength);
- case 0x1C:
- return new ActionGetVariable();
- case 0x1D:
- return new ActionSetVariable();
- case 0x9A:
- return new ActionGetURL2(actionLength, this);
- case 0x9F:
- return new ActionGotoFrame2(actionLength, this);
- case 0x20:
- return new ActionSetTarget2();
- case 0x22:
- return new ActionGetProperty();
- case 0x23:
- return new ActionSetProperty();
- case 0x24:
- return new ActionCloneSprite();
- case 0x25:
- return new ActionRemoveSprite();
- case 0x27:
- return new ActionStartDrag();
- case 0x28:
- return new ActionEndDrag();
- case 0x8D:
- return new ActionWaitForFrame2(actionLength, this, cpool);
- case 0x26:
- return new ActionTrace();
- case 0x34:
- return new ActionGetTime();
- case 0x30:
- return new ActionRandomNumber();
- //SWF5 Actions
- case 0x3D:
- return new ActionCallFunction();
- case 0x52:
- return new ActionCallMethod();
- case 0x88:
- return new ActionConstantPool(actionLength, this, swf.version);
- case 0x9B:
- return new ActionDefineFunction(actionLength, this, swf.version);
- case 0x3C:
- return new ActionDefineLocal();
- case 0x41:
- return new ActionDefineLocal2();
- case 0x3A:
- return new ActionDelete();
- case 0x3B:
- return new ActionDelete2();
- case 0x46:
- return new ActionEnumerate();
- case 0x49:
- return new ActionEquals2();
- case 0x4E:
- return new ActionGetMember();
- case 0x42:
- return new ActionInitArray();
- case 0x43:
- return new ActionInitObject();
- case 0x53:
- return new ActionNewMethod();
- case 0x40:
- return new ActionNewObject();
- case 0x4F:
- return new ActionSetMember();
- case 0x45:
- return new ActionTargetPath();
- case 0x94:
- return new ActionWith(actionLength, this, swf.version);
- case 0x4A:
- return new ActionToNumber();
- case 0x4B:
- return new ActionToString();
- case 0x44:
- return new ActionTypeOf();
- case 0x47:
- return new ActionAdd2();
- case 0x48:
- return new ActionLess2();
- case 0x3F:
- return new ActionModulo();
- case 0x60:
- return new ActionBitAnd();
- case 0x63:
- return new ActionBitLShift();
- case 0x61:
- return new ActionBitOr();
- case 0x64:
- return new ActionBitRShift();
- case 0x65:
- return new ActionBitURShift();
- case 0x62:
- return new ActionBitXor();
- case 0x51:
- return new ActionDecrement();
- case 0x50:
- return new ActionIncrement();
- case 0x4C:
- return new ActionPushDuplicate();
- case 0x3E:
- return new ActionReturn();
- case 0x4D:
- return new ActionStackSwap();
- case 0x87:
- return new ActionStoreRegister(actionLength, this);
- //SWF6 Actions
- case 0x54:
- return new ActionInstanceOf();
- case 0x55:
- return new ActionEnumerate2();
- case 0x66:
- return new ActionStrictEquals();
- case 0x67:
- return new ActionGreater();
- case 0x68:
- return new ActionStringGreater();
- //SWF7 Actions
- case 0x8E:
- return new ActionDefineFunction2(actionLength, this, swf.version);
- case 0x69:
- return new ActionExtends();
- case 0x2B:
- return new ActionCastOp();
- case 0x2C:
- return new ActionImplementsOp();
- case 0x8F:
- return new ActionTry(actionLength, this, swf.version);
- case 0x2A:
- return new ActionThrow();
- default:
- /*if (actionLength > 0) {
- //skip(actionLength);
- }*/
- //throw new UnknownActionException(actionCode);
- Action r = new ActionNop();
- r.actionCode = actionCode;
- r.actionLength = actionLength;
- return r;
- //return new Action(actionCode, actionLength);
- }
- } catch (EndOfStreamException | ArrayIndexOutOfBoundsException eos) {
- return null;
- }
- }
-
- /**
- * Reads one MATRIX value from the stream
- *
- * @param name
- * @return MATRIX value
- * @throws IOException
- */
- public MATRIX readMatrix(String name) throws IOException {
- MATRIX ret = new MATRIX();
- newDumpLevel(name, "MATRIX");
- ret.hasScale = readUB(1, "hasScale") == 1;
- if (ret.hasScale) {
- int NScaleBits = (int) readUB(5, "NScaleBits");
- ret.scaleX = (int) readSB(NScaleBits, "scaleX");
- ret.scaleY = (int) readSB(NScaleBits, "scaleY");
- ret.nScaleBits = NScaleBits;
- }
- ret.hasRotate = readUB(1, "hasRotate") == 1;
- if (ret.hasRotate) {
- int NRotateBits = (int) readUB(5, "NRotateBits");
- ret.rotateSkew0 = (int) readSB(NRotateBits, "rotateSkew0");
- ret.rotateSkew1 = (int) readSB(NRotateBits, "rotateSkew1");
- ret.nRotateBits = NRotateBits;
- }
- int NTranslateBits = (int) readUB(5, "NTranslateBits");
- ret.translateX = (int) readSB(NTranslateBits, "translateX");
- ret.translateY = (int) readSB(NTranslateBits, "translateY");
- ret.nTranslateBits = NTranslateBits;
- alignByte();
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one CXFORMWITHALPHA value from the stream
- *
- * @param name
- * @return CXFORMWITHALPHA value
- * @throws IOException
- */
- public CXFORMWITHALPHA readCXFORMWITHALPHA(String name) throws IOException {
- CXFORMWITHALPHA ret = new CXFORMWITHALPHA();
- newDumpLevel(name, "CXFORMWITHALPHA");
- ret.hasAddTerms = readUB(1, "hasAddTerms") == 1;
- ret.hasMultTerms = readUB(1, "hasMultTerms") == 1;
- int Nbits = (int) readUB(4, "Nbits");
- ret.nbits = Nbits;
- if (ret.hasMultTerms) {
- ret.redMultTerm = (int) readSB(Nbits, "redMultTerm");
- ret.greenMultTerm = (int) readSB(Nbits, "greenMultTerm");
- ret.blueMultTerm = (int) readSB(Nbits, "blueMultTerm");
- ret.alphaMultTerm = (int) readSB(Nbits, "alphaMultTerm");
- }
- if (ret.hasAddTerms) {
- ret.redAddTerm = (int) readSB(Nbits, "redAddTerm");
- ret.greenAddTerm = (int) readSB(Nbits, "greenAddTerm");
- ret.blueAddTerm = (int) readSB(Nbits, "blueAddTerm");
- ret.alphaAddTerm = (int) readSB(Nbits, "alphaAddTerm");
- }
- alignByte();
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one CXFORM value from the stream
- *
- * @param name
- * @return CXFORM value
- * @throws IOException
- */
- public CXFORM readCXFORM(String name) throws IOException {
- CXFORM ret = new CXFORM();
- newDumpLevel(name, "CXFORM");
- ret.hasAddTerms = readUB(1, "hasAddTerms") == 1;
- ret.hasMultTerms = readUB(1, "hasMultTerms") == 1;
- int Nbits = (int) readUB(4, "Nbits");
- ret.nbits = Nbits;
- if (ret.hasMultTerms) {
- ret.redMultTerm = (int) readSB(Nbits, "redMultTerm");
- ret.greenMultTerm = (int) readSB(Nbits, "greenMultTerm");
- ret.blueMultTerm = (int) readSB(Nbits, "blueMultTerm");
- }
- if (ret.hasAddTerms) {
- ret.redAddTerm = (int) readSB(Nbits, "redAddTerm");
- ret.greenAddTerm = (int) readSB(Nbits, "greenAddTerm");
- ret.blueAddTerm = (int) readSB(Nbits, "blueAddTerm");
- }
- alignByte();
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one CLIPEVENTFLAGS value from the stream
- *
- * @param name
- * @return CLIPEVENTFLAGS value
- * @throws IOException
- */
- public CLIPEVENTFLAGS readCLIPEVENTFLAGS(String name) throws IOException {
- CLIPEVENTFLAGS ret = new CLIPEVENTFLAGS();
- newDumpLevel(name, "CLIPEVENTFLAGS");
- ret.clipEventKeyUp = readUB(1, "clipEventKeyUp") == 1;
- ret.clipEventKeyDown = readUB(1, "clipEventKeyDown") == 1;
- ret.clipEventMouseUp = readUB(1, "clipEventMouseUp") == 1;
- ret.clipEventMouseDown = readUB(1, "clipEventMouseDown") == 1;
- ret.clipEventMouseMove = readUB(1, "clipEventMouseMove") == 1;
- ret.clipEventUnload = readUB(1, "clipEventUnload") == 1;
- ret.clipEventEnterFrame = readUB(1, "clipEventEnterFrame") == 1;
- ret.clipEventLoad = readUB(1, "clipEventLoad") == 1;
- ret.clipEventDragOver = readUB(1, "clipEventDragOver") == 1;
- ret.clipEventRollOut = readUB(1, "clipEventRollOut") == 1;
- ret.clipEventRollOver = readUB(1, "clipEventRollOver") == 1;
- ret.clipEventReleaseOutside = readUB(1, "clipEventReleaseOutside") == 1;
- ret.clipEventRelease = readUB(1, "clipEventRelease") == 1;
- ret.clipEventPress = readUB(1, "clipEventPress") == 1;
- ret.clipEventInitialize = readUB(1, "clipEventInitialize") == 1;
- ret.clipEventData = readUB(1, "clipEventData") == 1;
- if (swf.version >= 6) {
- ret.reserved = (int) readUB(5, "reserved");
- ret.clipEventConstruct = readUB(1, "clipEventConstruct") == 1;
- ret.clipEventKeyPress = readUB(1, "clipEventKeyPress") == 1;
- ret.clipEventDragOut = readUB(1, "clipEventDragOut") == 1;
- ret.reserved2 = (int) readUB(8, "reserved2");
- }
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one CLIPACTIONRECORD value from the stream
- *
- * @param swf
- * @param tag
- * @param name
- * @return CLIPACTIONRECORD value
- * @throws IOException
- */
- public CLIPACTIONRECORD readCLIPACTIONRECORD(SWF swf, Tag tag, String name) throws IOException {
- newDumpLevel(name, "CLIPACTIONRECORD");
- CLIPACTIONRECORD ret = new CLIPACTIONRECORD(swf, this, getPos(), tag);
- endDumpLevel();
- if (ret.eventFlags.isClear()) {
- return null;
- }
- return ret;
- }
-
- /**
- * Reads one CLIPACTIONS value from the stream
- *
- * @param swf
- * @param tag
- * @param name
- * @return CLIPACTIONS value
- * @throws IOException
- */
- public CLIPACTIONS readCLIPACTIONS(SWF swf, Tag tag, String name) throws IOException {
- CLIPACTIONS ret = new CLIPACTIONS();
- newDumpLevel(name, "CLIPACTIONS");
- ret.reserved = readUI16("reserved");
- ret.allEventFlags = readCLIPEVENTFLAGS("allEventFlags");
- CLIPACTIONRECORD cr;
- ret.clipActionRecords = new ArrayList<>();
- while ((cr = readCLIPACTIONRECORD(swf, tag, "record")) != null) {
- ret.clipActionRecords.add(cr);
- }
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one COLORMATRIXFILTER value from the stream
- *
- * @param name
- * @return COLORMATRIXFILTER value
- * @throws IOException
- */
- public COLORMATRIXFILTER readCOLORMATRIXFILTER(String name) throws IOException {
- COLORMATRIXFILTER ret = new COLORMATRIXFILTER();
- newDumpLevel(name, "COLORMATRIXFILTER");
- ret.matrix = new float[20];
- for (int i = 0; i < 20; i++) {
- ret.matrix[i] = readFLOAT("cell");
- }
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one RGBA value from the stream
- *
- * @param name
- * @return RGBA value
- * @throws IOException
- */
- public RGBA readRGBA(String name) throws IOException {
- RGBA ret = new RGBA();
- newDumpLevel(name, "RGBA");
- ret.red = readUI8("red");
- ret.green = readUI8("green");
- ret.blue = readUI8("blue");
- ret.alpha = readUI8("alpha");
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one ARGB value from the stream
- *
- * @param name
- * @return ARGB value
- * @throws IOException
- */
- public ARGB readARGB(String name) throws IOException {
- ARGB ret = new ARGB();
- newDumpLevel(name, "ARGB");
- ret.alpha = readUI8("alpha");
- ret.red = readUI8("red");
- ret.green = readUI8("green");
- ret.blue = readUI8("blue");
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one RGB value from the stream
- *
- * @param name
- * @return RGB value
- * @throws IOException
- */
- public RGB readRGB(String name) throws IOException {
- RGB ret = new RGB();
- newDumpLevel(name, "RGB");
- ret.red = readUI8("red");
- ret.green = readUI8("green");
- ret.blue = readUI8("blue");
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one CONVOLUTIONFILTER value from the stream
- *
- * @param name
- * @return CONVOLUTIONFILTER value
- * @throws IOException
- */
- public CONVOLUTIONFILTER readCONVOLUTIONFILTER(String name) throws IOException {
- CONVOLUTIONFILTER ret = new CONVOLUTIONFILTER();
- newDumpLevel(name, "CONVOLUTIONFILTER");
- ret.matrixX = readUI8("matrixX");
- ret.matrixY = readUI8("matrixY");
- ret.divisor = readFLOAT("divisor");
- ret.bias = readFLOAT("bias");
- ret.matrix = new float[ret.matrixX][ret.matrixY];
- for (int x = 0; x < ret.matrixX; x++) {
- for (int y = 0; y < ret.matrixY; y++) {
- ret.matrix[x][y] = readFLOAT("cell");
- }
- }
- ret.defaultColor = readRGBA("defaultColor");
- ret.reserved = (int) readUB(6, "reserved");
- ret.clamp = readUB(1, "clamp") == 1;
- ret.preserveAlpha = readUB(1, "preserveAlpha") == 1;
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one BLURFILTER value from the stream
- *
- * @param name
- * @return BLURFILTER value
- * @throws IOException
- */
- public BLURFILTER readBLURFILTER(String name) throws IOException {
- BLURFILTER ret = new BLURFILTER();
- newDumpLevel(name, "BLURFILTER");
- ret.blurX = readFIXED("blurX");
- ret.blurY = readFIXED("blurY");
- ret.passes = (int) readUB(5, "passes");
- ret.reserved = (int) readUB(3, "reserved");
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one DROPSHADOWFILTER value from the stream
- *
- * @param name
- * @return DROPSHADOWFILTER value
- * @throws IOException
- */
- public DROPSHADOWFILTER readDROPSHADOWFILTER(String name) throws IOException {
- DROPSHADOWFILTER ret = new DROPSHADOWFILTER();
- newDumpLevel(name, "DROPSHADOWFILTER");
- ret.dropShadowColor = readRGBA("dropShadowColor");
- ret.blurX = readFIXED("blurX");
- ret.blurY = readFIXED("blurY");
- ret.angle = readFIXED("angle");
- ret.distance = readFIXED("distance");
- ret.strength = readFIXED8("strength");
- ret.innerShadow = readUB(1, "innerShadow") == 1;
- ret.knockout = readUB(1, "knockout") == 1;
- ret.compositeSource = readUB(1, "compositeSource") == 1;
- ret.passes = (int) readUB(5, "passes");
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one GLOWFILTER value from the stream
- *
- * @param name
- * @return GLOWFILTER value
- * @throws IOException
- */
- public GLOWFILTER readGLOWFILTER(String name) throws IOException {
- GLOWFILTER ret = new GLOWFILTER();
- newDumpLevel(name, "GLOWFILTER");
- ret.glowColor = readRGBA("glowColor");
- ret.blurX = readFIXED("blurX");
- ret.blurY = readFIXED("blurY");
- ret.strength = readFIXED8("strength");
- ret.innerGlow = readUB(1, "innerGlow") == 1;
- ret.knockout = readUB(1, "knockout") == 1;
- ret.compositeSource = readUB(1, "compositeSource") == 1;
- ret.passes = (int) readUB(5, "passes");
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one BEVELFILTER value from the stream
- *
- * @param name
- * @return BEVELFILTER value
- * @throws IOException
- */
- public BEVELFILTER readBEVELFILTER(String name) throws IOException {
- BEVELFILTER ret = new BEVELFILTER();
- newDumpLevel(name, "BEVELFILTER");
- ret.highlightColor = readRGBA("highlightColor"); //Highlight color first. It it opposite of the documentation
- ret.shadowColor = readRGBA("shadowColor");
- ret.blurX = readFIXED("blurX");
- ret.blurY = readFIXED("blurY");
- ret.angle = readFIXED("angle");
- ret.distance = readFIXED("distance");
- ret.strength = readFIXED8("strength");
- ret.innerShadow = readUB(1, "innerShadow") == 1;
- ret.knockout = readUB(1, "knockout") == 1;
- ret.compositeSource = readUB(1, "compositeSource") == 1;
- ret.onTop = readUB(1, "onTop") == 1;
- ret.passes = (int) readUB(4, "passes");
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one GRADIENTGLOWFILTER value from the stream
- *
- * @param name
- * @return GRADIENTGLOWFILTER value
- * @throws IOException
- */
- public GRADIENTGLOWFILTER readGRADIENTGLOWFILTER(String name) throws IOException {
- GRADIENTGLOWFILTER ret = new GRADIENTGLOWFILTER();
- newDumpLevel(name, "GRADIENTGLOWFILTER");
- int numColors = readUI8("numColors");
- ret.gradientColors = new RGBA[numColors];
- ret.gradientRatio = new int[numColors];
- for (int i = 0; i < numColors; i++) {
- ret.gradientColors[i] = readRGBA("gradientColor");
- }
- for (int i = 0; i < numColors; i++) {
- ret.gradientRatio[i] = readUI8("gradientRatio");
- }
- ret.blurX = readFIXED("blurX");
- ret.blurY = readFIXED("blurY");
- ret.angle = readFIXED("angle");
- ret.distance = readFIXED("distance");
- ret.strength = readFIXED8("strength");
- ret.innerShadow = readUB(1, "innerShadow") == 1;
- ret.knockout = readUB(1, "knockout") == 1;
- ret.compositeSource = readUB(1, "compositeSource") == 1;
- ret.onTop = readUB(1, "onTop") == 1;
- ret.passes = (int) readUB(4, "passes");
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one GRADIENTBEVELFILTER value from the stream
- *
- * @param name
- * @return GRADIENTBEVELFILTER value
- * @throws IOException
- */
- public GRADIENTBEVELFILTER readGRADIENTBEVELFILTER(String name) throws IOException {
- GRADIENTBEVELFILTER ret = new GRADIENTBEVELFILTER();
- newDumpLevel(name, "GRADIENTBEVELFILTER");
- int numColors = readUI8("numColors");
- ret.gradientColors = new RGBA[numColors];
- ret.gradientRatio = new int[numColors];
- for (int i = 0; i < numColors; i++) {
- ret.gradientColors[i] = readRGBA("gradientColor");
- }
- for (int i = 0; i < numColors; i++) {
- ret.gradientRatio[i] = readUI8("gradientRatio");
- }
- ret.blurX = readFIXED("blurX");
- ret.blurY = readFIXED("blurY");
- ret.angle = readFIXED("angle");
- ret.distance = readFIXED("distance");
- ret.strength = readFIXED8("strength");
- ret.innerShadow = readUB(1, "innerShadow") == 1;
- ret.knockout = readUB(1, "knockout") == 1;
- ret.compositeSource = readUB(1, "compositeSource") == 1;
- ret.onTop = readUB(1, "onTop") == 1;
- ret.passes = (int) readUB(4, "passes");
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads list of FILTER values from the stream
- *
- * @param name
- * @return List of FILTER values
- * @throws IOException
- */
- public List readFILTERLIST(String name) throws IOException {
- List ret = new ArrayList<>();
- newDumpLevel(name, "FILTERLIST");
- int numberOfFilters = readUI8("numberOfFilters");
- for (int i = 0; i < numberOfFilters; i++) {
- ret.add(readFILTER("filter"));
- }
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one FILTER value from the stream
- *
- * @param name
- * @return FILTER value
- * @throws IOException
- */
- public FILTER readFILTER(String name) throws IOException {
- newDumpLevel(name, "FILTER");
- int filterId = readUI8("filterId");
- FILTER ret = null;
- switch (filterId) {
- case 0:
- ret = readDROPSHADOWFILTER("filter");
- break;
- case 1:
- ret = readBLURFILTER("filter");
- break;
- case 2:
- ret = readGLOWFILTER("filter");
- break;
- case 3:
- ret = readBEVELFILTER("filter");
- break;
- case 4:
- ret = readGRADIENTGLOWFILTER("filter");
- break;
- case 5:
- ret = readCONVOLUTIONFILTER("filter");
- break;
- case 6:
- ret = readCOLORMATRIXFILTER("filter");
- break;
- case 7:
- ret = readGRADIENTBEVELFILTER("filter");
- break;
- }
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads list of BUTTONRECORD values from the stream
- *
- * @param inDefineButton2 Whether read from inside of DefineButton2Tag or
- * not
- * @param name
- * @return List of BUTTONRECORD values
- * @throws IOException
- */
- public List readBUTTONRECORDList(boolean inDefineButton2, String name) throws IOException {
- List ret = new ArrayList<>();
- newDumpLevel(name, "BUTTONRECORDList");
- BUTTONRECORD br;
- while ((br = readBUTTONRECORD(inDefineButton2, "record")) != null) {
- ret.add(br);
- }
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one BUTTONRECORD value from the stream
- *
- * @param inDefineButton2 True when in DefineButton2
- * @param name
- * @return BUTTONRECORD value
- * @throws IOException
- */
- public BUTTONRECORD readBUTTONRECORD(boolean inDefineButton2, String name) throws IOException {
- BUTTONRECORD ret = new BUTTONRECORD();
- newDumpLevel(name, "BUTTONRECORD");
- ret.reserved = (int) readUB(2, "reserved");
- ret.buttonHasBlendMode = readUB(1, "buttonHasBlendMode") == 1;
- ret.buttonHasFilterList = readUB(1, "buttonHasFilterList") == 1;
- ret.buttonStateHitTest = readUB(1, "buttonStateHitTest") == 1;
- ret.buttonStateDown = readUB(1, "buttonStateDown") == 1;
- ret.buttonStateOver = readUB(1, "buttonStateOver") == 1;
- ret.buttonStateUp = readUB(1, "buttonStateUp") == 1;
-
- if (!ret.buttonHasBlendMode && !ret.buttonHasFilterList
- && !ret.buttonStateHitTest && !ret.buttonStateDown
- && !ret.buttonStateOver && !ret.buttonStateUp && ret.reserved == 0) {
- return null;
- }
-
- ret.characterId = readUI16("characterId");
- ret.placeDepth = readUI16("placeDepth");
- ret.placeMatrix = readMatrix("placeMatrix");
- if (inDefineButton2) {
- ret.colorTransform = readCXFORMWITHALPHA("colorTransform");
- if (ret.buttonHasFilterList) {
- ret.filterList = readFILTERLIST("filterList");
- }
- if (ret.buttonHasBlendMode) {
- ret.blendMode = readUI8("blendMode");
- }
- }
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads list of BUTTONCONDACTION values from the stream
- *
- * @param swf
- * @param tag
- * @param name
- * @return List of BUTTONCONDACTION values
- * @throws IOException
- */
- public List readBUTTONCONDACTIONList(SWF swf, Tag tag, String name) throws IOException {
- List ret = new ArrayList<>();
- newDumpLevel(name, "BUTTONCONDACTIONList");
- BUTTONCONDACTION bc;
- while (!(bc = readBUTTONCONDACTION(swf, tag, "action")).isLast) {
- ret.add(bc);
- }
- ret.add(bc);
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one BUTTONCONDACTION value from the stream
- *
- * @param swf
- * @param tag
- * @param name
- * @return BUTTONCONDACTION value
- * @throws IOException
- */
- public BUTTONCONDACTION readBUTTONCONDACTION(SWF swf, Tag tag, String name) throws IOException {
- newDumpLevel(name, "BUTTONCONDACTION");
- BUTTONCONDACTION ret = new BUTTONCONDACTION(swf, this, getPos(), tag);
- //ret.actions = readActionList();
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one GRADRECORD value from the stream
- *
- * @param shapeNum 1 in DefineShape, 2 in DefineShape2...
- * @param name
- * @return GRADRECORD value
- * @throws IOException
- */
- public GRADRECORD readGRADRECORD(int shapeNum, String name) throws IOException {
- GRADRECORD ret = new GRADRECORD();
- newDumpLevel(name, "GRADRECORD");
- ret.ratio = readUI8("ratio");
- if (shapeNum >= 3) {
- ret.color = readRGBA("color");
- } else {
- ret.color = readRGB("color");
- }
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one GRADIENT value from the stream
- *
- * @param shapeNum 1 in DefineShape, 2 in DefineShape2...
- * @param name
- * @return GRADIENT value
- * @throws IOException
- */
- public GRADIENT readGRADIENT(int shapeNum, String name) throws IOException {
- GRADIENT ret = new GRADIENT();
- newDumpLevel(name, "GRADIENT");
- ret.spreadMode = (int) readUB(2, "spreadMode");
- ret.interpolationMode = (int) readUB(2, "interpolationMode");
- int numGradients = (int) readUB(4, "numGradients");
- ret.gradientRecords = new GRADRECORD[numGradients];
- for (int i = 0; i < numGradients; i++) {
- ret.gradientRecords[i] = readGRADRECORD(shapeNum, "gradientRecord");
-
- }
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one FOCALGRADIENT value from the stream
- *
- * @param shapeNum 1 in DefineShape, 2 in DefineShape2...
- * @param name
- * @return FOCALGRADIENT value
- * @throws IOException
- */
- public FOCALGRADIENT readFOCALGRADIENT(int shapeNum, String name) throws IOException {
- FOCALGRADIENT ret = new FOCALGRADIENT();
- newDumpLevel(name, "FOCALGRADIENT");
- ret.spreadMode = (int) readUB(2, "spreadMode");
- ret.interpolationMode = (int) readUB(2, "interpolationMode");
- int numGradients = (int) readUB(4, "numGradients");
- ret.gradientRecords = new GRADRECORD[numGradients];
- for (int i = 0; i < numGradients; i++) {
- ret.gradientRecords[i] = readGRADRECORD(shapeNum, "gradientRecord");
- }
- ret.focalPoint = readFIXED8("focalPoint");
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one FILLSTYLE value from the stream
- *
- * @param shapeNum 1 in DefineShape, 2 in DefineShape2...
- * @param name
- * @return FILLSTYLE value
- * @throws IOException
- */
- public FILLSTYLE readFILLSTYLE(int shapeNum, String name) throws IOException {
- FILLSTYLE ret = new FILLSTYLE();
- newDumpLevel(name, "FILLSTYLE");
- ret.fillStyleType = readUI8("fillStyleType");
- if (ret.fillStyleType == FILLSTYLE.SOLID) {
- if (shapeNum >= 3) {
- ret.color = readRGBA("color");
- } else {
- ret.color = readRGB("color");
- }
- }
- if ((ret.fillStyleType == FILLSTYLE.LINEAR_GRADIENT)
- || (ret.fillStyleType == FILLSTYLE.RADIAL_GRADIENT)
- || (ret.fillStyleType == FILLSTYLE.FOCAL_RADIAL_GRADIENT)) {
- ret.gradientMatrix = readMatrix("gradientMatrix");
- }
- if ((ret.fillStyleType == FILLSTYLE.LINEAR_GRADIENT)
- || (ret.fillStyleType == FILLSTYLE.RADIAL_GRADIENT)) {
- ret.gradient = readGRADIENT(shapeNum, "gradient");
- }
- if (ret.fillStyleType == FILLSTYLE.FOCAL_RADIAL_GRADIENT) {
- ret.gradient = readFOCALGRADIENT(shapeNum, "gradient");
- }
-
- if ((ret.fillStyleType == FILLSTYLE.REPEATING_BITMAP)
- || (ret.fillStyleType == FILLSTYLE.CLIPPED_BITMAP)
- || (ret.fillStyleType == FILLSTYLE.NON_SMOOTHED_REPEATING_BITMAP)
- || (ret.fillStyleType == FILLSTYLE.NON_SMOOTHED_CLIPPED_BITMAP)) {
- ret.bitmapId = readUI16("bitmapId");
- ret.bitmapMatrix = readMatrix("bitmapMatrix");
- }
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one FILLSTYLEARRAY value from the stream
- *
- * @param shapeNum 1 in DefineShape, 2 in DefineShape2...
- * @param name
- * @return FILLSTYLEARRAY value
- * @throws IOException
- */
- public FILLSTYLEARRAY readFILLSTYLEARRAY(int shapeNum, String name) throws IOException {
-
- FILLSTYLEARRAY ret = new FILLSTYLEARRAY();
- newDumpLevel(name, "FILLSTYLEARRAY");
- int fillStyleCount = readUI8("fillStyleCount");
- if (((shapeNum == 2) || (shapeNum == 3) || (shapeNum == 4/*?*/)) && (fillStyleCount == 0xff)) {
- fillStyleCount = readUI16("fillStyleCount");
- }
- ret.fillStyles = new FILLSTYLE[fillStyleCount];
- for (int i = 0; i < fillStyleCount; i++) {
- ret.fillStyles[i] = readFILLSTYLE(shapeNum, "fillStyle");
- }
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one LINESTYLE value from the stream
- *
- * @param shapeNum 1 in DefineShape, 2 in DefineShape2...
- * @param name
- * @return LINESTYLE value
- * @throws IOException
- */
- public LINESTYLE readLINESTYLE(int shapeNum, String name) throws IOException {
- LINESTYLE ret = new LINESTYLE();
- newDumpLevel(name, "LINESTYLE");
- ret.width = readUI16("width");
- if ((shapeNum == 1) || (shapeNum == 2)) {
- ret.color = readRGB("color");
- }
- if (shapeNum == 3) {
- ret.color = readRGBA("color");
- }
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one LINESTYLE2 value from the stream
- *
- * @param shapeNum 1 in DefineShape, 2 in DefineShape2...
- * @param name
- * @return LINESTYLE2 value
- * @throws IOException
- */
- public LINESTYLE2 readLINESTYLE2(int shapeNum, String name) throws IOException {
- LINESTYLE2 ret = new LINESTYLE2();
- newDumpLevel(name, "LINESTYLE2");
- ret.width = readUI16("width");
- ret.startCapStyle = (int) readUB(2, "startCapStyle");
- ret.joinStyle = (int) readUB(2, "joinStyle");
- ret.hasFillFlag = (int) readUB(1, "hasFillFlag") == 1;
- ret.noHScaleFlag = (int) readUB(1, "noHScaleFlag") == 1;
- ret.noVScaleFlag = (int) readUB(1, "noVScaleFlag") == 1;
- ret.pixelHintingFlag = (int) readUB(1, "pixelHintingFlag") == 1;
- ret.reserved = (int) readUB(5, "reserved");
- ret.noClose = (int) readUB(1, "noClose") == 1;
- ret.endCapStyle = (int) readUB(2, "endCapStyle");
- if (ret.joinStyle == LINESTYLE2.MITER_JOIN) {
- ret.miterLimitFactor = readUI16("miterLimitFactor");
- }
- if (!ret.hasFillFlag) {
- ret.color = readRGBA("color");
- } else {
- ret.fillType = readFILLSTYLE(shapeNum, "fillType");
- }
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one LINESTYLEARRAY value from the stream
- *
- * @param shapeNum 1 in DefineShape, 2 in DefineShape2...
- * @param name
- * @return LINESTYLEARRAY value
- * @throws IOException
- */
- public LINESTYLEARRAY readLINESTYLEARRAY(int shapeNum, String name) throws IOException {
- LINESTYLEARRAY ret = new LINESTYLEARRAY();
- newDumpLevel(name, "LINESTYLEARRAY");
- int lineStyleCount = readUI8("lineStyleCount");
- if (lineStyleCount == 0xff) {
- lineStyleCount = readUI16("lineStyleCount");
- }
- if ((shapeNum == 1 || shapeNum == 2 || shapeNum == 3)) {
- ret.lineStyles = new LINESTYLE[lineStyleCount];
- for (int i = 0; i < lineStyleCount; i++) {
- ret.lineStyles[i] = readLINESTYLE(shapeNum, "lineStyle");
- }
- } else if (shapeNum == 4) {
- ret.lineStyles = new LINESTYLE2[lineStyleCount];
- for (int i = 0; i < lineStyleCount; i++) {
- ret.lineStyles[i] = readLINESTYLE2(shapeNum, "lineStyle");
- }
- }
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one SHAPERECORD value from the stream
- *
- * @param fillBits
- * @param lineBits
- * @param shapeNum 1 in DefineShape, 2 in DefineShape2...
- * @return SHAPERECORD value
- * @throws IOException
- */
- private SHAPERECORD readSHAPERECORD(int fillBits, int lineBits, int shapeNum, boolean morphShape, String name) throws IOException {
- SHAPERECORD ret;
- newDumpLevel(name, "SHAPERECORD");
- int typeFlag = (int) readUB(1, "typeFlag");
- if (typeFlag == 0) {
- boolean stateNewStyles = readUB(1, "stateNewStyles") == 1;
- boolean stateLineStyle = readUB(1, "stateLineStyle") == 1;
- boolean stateFillStyle1 = readUB(1, "stateFillStyle1") == 1;
- boolean stateFillStyle0 = readUB(1, "stateFillStyle0") == 1;
- boolean stateMoveTo = readUB(1, "stateMoveTo") == 1;
- if ((!stateNewStyles) && (!stateLineStyle) && (!stateFillStyle1) && (!stateFillStyle0) && (!stateMoveTo)) {
- ret = new EndShapeRecord();
- } else {
- StyleChangeRecord scr = new StyleChangeRecord();
- scr.stateNewStyles = stateNewStyles;
- scr.stateLineStyle = stateLineStyle;
- scr.stateFillStyle0 = stateFillStyle0;
- scr.stateFillStyle1 = stateFillStyle1;
- scr.stateMoveTo = stateMoveTo;
- if (stateMoveTo) {
- scr.moveBits = (int) readUB(5, "moveBits");
- scr.moveDeltaX = (int) readSB(scr.moveBits, "moveDeltaX");
- scr.moveDeltaY = (int) readSB(scr.moveBits, "moveDeltaY");
- }
- if (stateFillStyle0) {
- scr.fillStyle0 = (int) readUB(fillBits, "fillStyle0");
- }
- if (stateFillStyle1) {
- scr.fillStyle1 = (int) readUB(fillBits, "fillStyle1");
- }
- if (stateLineStyle) {
- scr.lineStyle = (int) readUB(lineBits, "lineStyle");
- }
- if (stateNewStyles) {
- if (morphShape) {
- //This should never happen
- } else {
- scr.fillStyles = readFILLSTYLEARRAY(shapeNum, "fillStyles");
- scr.lineStyles = readLINESTYLEARRAY(shapeNum, "lineStyles");
- }
- scr.numFillBits = (int) readUB(4, "numFillBits");
- scr.numLineBits = (int) readUB(4, "numLineBits");
- }
- ret = scr;
- }
- } else {//typeFlag==1
- int straightFlag = (int) readUB(1, "straightFlag");
- if (straightFlag == 1) {
- StraightEdgeRecord ser = new StraightEdgeRecord();
- ser.numBits = (int) readUB(4, "numBits");
- ser.generalLineFlag = readUB(1, "generalLineFlag") == 1;
- if (!ser.generalLineFlag) {
- ser.vertLineFlag = readUB(1, "vertLineFlag") == 1;
- }
- if (ser.generalLineFlag || (!ser.vertLineFlag)) {
- ser.deltaX = (int) readSB(ser.numBits + 2, "deltaX");
- }
- if (ser.generalLineFlag || (ser.vertLineFlag)) {
- ser.deltaY = (int) readSB(ser.numBits + 2, "deltaY");
- }
- ret = ser;
- } else {
- CurvedEdgeRecord cer = new CurvedEdgeRecord();
- cer.numBits = (int) readUB(4, "numBits");
- cer.controlDeltaX = (int) readSB(cer.numBits + 2, "controlDeltaX");
- cer.controlDeltaY = (int) readSB(cer.numBits + 2, "controlDeltaY");
- cer.anchorDeltaX = (int) readSB(cer.numBits + 2, "anchorDeltaX");
- cer.anchorDeltaY = (int) readSB(cer.numBits + 2, "anchorDeltaY");
- ret = cer;
- }
- }
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one SHAPE value from the stream
- *
- * @param shapeNum 1 in DefineShape, 2 in DefineShape2...
- * @param morphShape
- * @param name
- * @return SHAPE value
- * @throws IOException
- */
- public SHAPE readSHAPE(int shapeNum, boolean morphShape, String name) throws IOException {
- SHAPE ret = new SHAPE();
- newDumpLevel(name, "SHAPE");
- ret.numFillBits = (int) readUB(4, "numFillBits");
- ret.numLineBits = (int) readUB(4, "numLineBits");
- ret.shapeRecords = readSHAPERECORDS(shapeNum, ret.numFillBits, ret.numLineBits, morphShape, "shapeRecords");
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one SHAPEWITHSTYLE value from the stream
- *
- * @param shapeNum 1 in DefineShape, 2 in DefineShape2...
- * @param morphShape
- * @param name
- * @return SHAPEWITHSTYLE value
- * @throws IOException
- */
- public SHAPEWITHSTYLE readSHAPEWITHSTYLE(int shapeNum, boolean morphShape, String name) throws IOException {
- SHAPEWITHSTYLE ret = new SHAPEWITHSTYLE();
- newDumpLevel(name, "SHAPEWITHSTYLE");
- ret.fillStyles = readFILLSTYLEARRAY(shapeNum, "fillStyles");
- ret.lineStyles = readLINESTYLEARRAY(shapeNum, "lineStyles");
- ret.numFillBits = (int) readUB(4, "numFillBits");
- ret.numLineBits = (int) readUB(4, "numLineBits");
- ret.shapeRecords = readSHAPERECORDS(shapeNum, ret.numFillBits, ret.numLineBits, morphShape, "shapeRecords");
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads list of SHAPERECORDs from the stream
- *
- * @param shapeNum 1 in DefineShape, 2 in DefineShape2...
- * @param fillBits
- * @param lineBits
- * @return SHAPERECORDs array
- * @throws IOException
- */
- private List readSHAPERECORDS(int shapeNum, int fillBits, int lineBits, boolean morphShape, String name) throws IOException {
- List ret = new ArrayList<>();
- newDumpLevel(name, "SHAPERECORDS");
- SHAPERECORD rec;
- do {
- rec = readSHAPERECORD(fillBits, lineBits, shapeNum, morphShape, "record");
- if (rec instanceof StyleChangeRecord) {
- StyleChangeRecord scRec = (StyleChangeRecord) rec;
- if (scRec.stateNewStyles) {
- fillBits = scRec.numFillBits;
- lineBits = scRec.numLineBits;
- }
- }
- ret.add(rec);
- } while (!(rec instanceof EndShapeRecord));
- alignByte();
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one SOUNDINFO value from the stream
- *
- * @param name
- * @return SOUNDINFO value
- * @throws IOException
- */
- public SOUNDINFO readSOUNDINFO(String name) throws IOException {
- SOUNDINFO ret = new SOUNDINFO();
- newDumpLevel(name, "SOUNDINFO");
- ret.reserved = (int) readUB(2, "reserved");
- ret.syncStop = readUB(1, "syncStop") == 1;
- ret.syncNoMultiple = readUB(1, "syncNoMultiple") == 1;
- ret.hasEnvelope = readUB(1, "hasEnvelope") == 1;
- ret.hasLoops = readUB(1, "hasLoops") == 1;
- ret.hasOutPoint = readUB(1, "hasOutPoint") == 1;
- ret.hasInPoint = readUB(1, "hasInPoint") == 1;
- if (ret.hasInPoint) {
- ret.inPoint = readUI32("inPoint");
- }
- if (ret.hasOutPoint) {
- ret.outPoint = readUI32("outPoint");
- }
- if (ret.hasLoops) {
- ret.loopCount = readUI16("loopCount");
- }
- if (ret.hasEnvelope) {
- int envPoints = readUI8("envPoints");
- ret.envelopeRecords = new SOUNDENVELOPE[envPoints];
- for (int i = 0; i < envPoints; i++) {
- ret.envelopeRecords[i] = readSOUNDENVELOPE("envelopeRecord");
- }
- }
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one SOUNDENVELOPE value from the stream
- *
- * @param name
- * @return SOUNDENVELOPE value
- * @throws IOException
- */
- public SOUNDENVELOPE readSOUNDENVELOPE(String name) throws IOException {
- SOUNDENVELOPE ret = new SOUNDENVELOPE();
- newDumpLevel(name, "SOUNDENVELOPE");
- ret.pos44 = readUI32("pos44");
- ret.leftLevel = readUI16("leftLevel");
- ret.rightLevel = readUI16("rightLevel");
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one GLYPHENTRY value from the stream
- *
- * @param glyphBits
- * @param advanceBits
- * @param name
- * @return GLYPHENTRY value
- * @throws IOException
- */
- public GLYPHENTRY readGLYPHENTRY(int glyphBits, int advanceBits, String name) throws IOException {
- GLYPHENTRY ret = new GLYPHENTRY();
- newDumpLevel(name, "GLYPHENTRY");
- ret.glyphIndex = (int) readUB(glyphBits, "glyphIndex");
- ret.glyphAdvance = (int) readUB(advanceBits, "glyphAdvance");
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one TEXTRECORD value from the stream
- *
- * @param inDefineText2
- * @param glyphBits
- * @param advanceBits
- * @param name
- * @return TEXTRECORD value
- * @throws IOException
- */
- public TEXTRECORD readTEXTRECORD(boolean inDefineText2, int glyphBits, int advanceBits, String name) throws IOException {
- TEXTRECORD ret = new TEXTRECORD();
- newDumpLevel(name, "TEXTRECORD");
- int first = (int) readUB(1, "first"); //always 1
- readUB(3, "styleFlagsHasReserved"); //always 0
- ret.styleFlagsHasFont = readUB(1, "styleFlagsHasFont") == 1;
- ret.styleFlagsHasColor = readUB(1, "styleFlagsHasColor") == 1;
- ret.styleFlagsHasYOffset = readUB(1, "styleFlagsHasYOffset") == 1;
- ret.styleFlagsHasXOffset = readUB(1, "styleFlagsHasXOffset") == 1;
- if ((!ret.styleFlagsHasFont) && (!ret.styleFlagsHasColor) && (!ret.styleFlagsHasYOffset) && (!ret.styleFlagsHasXOffset) && (first == 0)) { //final text record
- endDumpLevel();
- return null;
- }
- if (ret.styleFlagsHasFont) {
- ret.fontId = readUI16("fontId");
- }
- if (ret.styleFlagsHasColor) {
- if (inDefineText2) {
- ret.textColorA = readRGBA("textColorA");
- } else {
- ret.textColor = readRGB("textColor");
- }
- }
- if (ret.styleFlagsHasXOffset) {
- ret.xOffset = readSI16("xOffset");
- }
- if (ret.styleFlagsHasYOffset) {
- ret.yOffset = readSI16("yOffset");
- }
- if (ret.styleFlagsHasFont) {
- ret.textHeight = readUI16("textHeight");
- }
- int glyphCount = readUI8("glyphCount");
- ret.glyphEntries = new GLYPHENTRY[glyphCount];
- for (int i = 0; i < glyphCount; i++) {
- ret.glyphEntries[i] = readGLYPHENTRY(glyphBits, advanceBits, "glyphEntry");
- }
- alignByte();
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one MORPHGRADRECORD value from the stream
- *
- * @param name
- * @return MORPHGRADRECORD value
- * @throws IOException
- */
- public MORPHGRADRECORD readMORPHGRADRECORD(String name) throws IOException {
- MORPHGRADRECORD ret = new MORPHGRADRECORD();
- newDumpLevel(name, "MORPHGRADRECORD");
- ret.startRatio = readUI8("startRatio");
- ret.startColor = readRGBA("startColor");
- ret.endRatio = readUI8("endRatio");
- ret.endColor = readRGBA("endColor");
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one MORPHGRADIENT value from the stream
- *
- * @param name
- * @return MORPHGRADIENT value
- * @throws IOException
- */
- public MORPHGRADIENT readMORPHGRADIENT(String name) throws IOException {
- MORPHGRADIENT ret = new MORPHGRADIENT();
- newDumpLevel(name, "MORPHGRADIENT");
- //Despite of documentation (UI8 1-8), there are two fields
- // spreadMode and interPolationMode which are same as in GRADIENT
- ret.spreadMode = (int) readUB(2, "spreadMode");
- ret.interPolationMode = (int) readUB(2, "interPolationMode");
- int numGradients = (int) readUB(4, "numGradients");
- ret.gradientRecords = new MORPHGRADRECORD[numGradients];
- for (int i = 0; i < numGradients; i++) {
- ret.gradientRecords[i] = readMORPHGRADRECORD("gradientRecord");
- }
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one MORPHFOCALGRADIENT value from the stream
- *
- * This is undocumented feature
- *
- * @param name
- * @return MORPHGRADIENT value
- * @throws IOException
- */
- public MORPHFOCALGRADIENT readMORPHFOCALGRADIENT(String name) throws IOException {
- MORPHFOCALGRADIENT ret = new MORPHFOCALGRADIENT();
- newDumpLevel(name, "MORPHFOCALGRADIENT");
- ret.spreadMode = (int) readUB(2, "spreadMode");
- ret.interPolationMode = (int) readUB(2, "interPolationMode");
- int numGradients = (int) readUB(4, "numGradients");
- ret.gradientRecords = new MORPHGRADRECORD[numGradients];
- for (int i = 0; i < numGradients; i++) {
- ret.gradientRecords[i] = readMORPHGRADRECORD("gradientRecord");
- }
- ret.startFocalPoint = readFIXED8("startFocalPoint");
- ret.endFocalPoint = readFIXED8("endFocalPoint");
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one MORPHFILLSTYLE value from the stream
- *
- * @param name
- * @return MORPHFILLSTYLE value
- * @throws IOException
- */
- public MORPHFILLSTYLE readMORPHFILLSTYLE(String name) throws IOException {
- MORPHFILLSTYLE ret = new MORPHFILLSTYLE();
- newDumpLevel(name, "MORPHFILLSTYLE");
- ret.fillStyleType = readUI8("fillStyleType");
- if (ret.fillStyleType == MORPHFILLSTYLE.SOLID) {
- ret.startColor = readRGBA("startColor");
- ret.endColor = readRGBA("endColor");
- }
- if ((ret.fillStyleType == MORPHFILLSTYLE.LINEAR_GRADIENT)
- || (ret.fillStyleType == MORPHFILLSTYLE.RADIAL_GRADIENT)
- || (ret.fillStyleType == MORPHFILLSTYLE.FOCAL_RADIAL_GRADIENT)) {
- ret.startGradientMatrix = readMatrix("startGradientMatrix");
- ret.endGradientMatrix = readMatrix("endGradientMatrix");
- }
- if ((ret.fillStyleType == MORPHFILLSTYLE.LINEAR_GRADIENT)
- || (ret.fillStyleType == MORPHFILLSTYLE.RADIAL_GRADIENT)) {
- ret.gradient = readMORPHGRADIENT("gradient");
- }
- if (ret.fillStyleType == MORPHFILLSTYLE.FOCAL_RADIAL_GRADIENT) {
- ret.gradient = readMORPHFOCALGRADIENT("gradient");
- }
-
- if ((ret.fillStyleType == MORPHFILLSTYLE.REPEATING_BITMAP)
- || (ret.fillStyleType == MORPHFILLSTYLE.CLIPPED_BITMAP)
- || (ret.fillStyleType == MORPHFILLSTYLE.NON_SMOOTHED_REPEATING_BITMAP)
- || (ret.fillStyleType == MORPHFILLSTYLE.NON_SMOOTHED_CLIPPED_BITMAP)) {
- ret.bitmapId = readUI16("bitmapId");
- ret.startBitmapMatrix = readMatrix("startBitmapMatrix");
- ret.endBitmapMatrix = readMatrix("endBitmapMatrix");
- }
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one MORPHFILLSTYLEARRAY value from the stream
- *
- * @param name
- * @return MORPHFILLSTYLEARRAY value
- * @throws IOException
- */
- public MORPHFILLSTYLEARRAY readMORPHFILLSTYLEARRAY(String name) throws IOException {
-
- MORPHFILLSTYLEARRAY ret = new MORPHFILLSTYLEARRAY();
- newDumpLevel(name, "MORPHFILLSTYLEARRAY");
- int fillStyleCount = readUI8("fillStyleCount");
- if (fillStyleCount == 0xff) {
- fillStyleCount = readUI16("fillStyleCount");
- }
- ret.fillStyles = new MORPHFILLSTYLE[fillStyleCount];
- for (int i = 0; i < fillStyleCount; i++) {
- ret.fillStyles[i] = readMORPHFILLSTYLE("fillStyle");
- }
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one MORPHLINESTYLE value from the stream
- *
- * @param name
- * @return MORPHLINESTYLE value
- * @throws IOException
- */
- public MORPHLINESTYLE readMORPHLINESTYLE(String name) throws IOException {
- MORPHLINESTYLE ret = new MORPHLINESTYLE();
- newDumpLevel(name, "MORPHLINESTYLE");
- ret.startWidth = readUI16("startWidth");
- ret.endWidth = readUI16("endWidth");
- ret.startColor = readRGBA("startColor");
- ret.endColor = readRGBA("endColor");
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one MORPHLINESTYLE2 value from the stream
- *
- * @param name
- * @return MORPHLINESTYLE2 value
- * @throws IOException
- */
- public MORPHLINESTYLE2 readMORPHLINESTYLE2(String name) throws IOException {
- MORPHLINESTYLE2 ret = new MORPHLINESTYLE2();
- newDumpLevel(name, "MORPHLINESTYLE2");
- ret.startWidth = readUI16("startWidth");
- ret.endWidth = readUI16("endWidth");
- ret.startCapStyle = (int) readUB(2, "startCapStyle");
- ret.joinStyle = (int) readUB(2, "joinStyle");
- ret.hasFillFlag = (int) readUB(1, "hasFillFlag") == 1;
- ret.noHScaleFlag = (int) readUB(1, "noHScaleFlag") == 1;
- ret.noVScaleFlag = (int) readUB(1, "noVScaleFlag") == 1;
- ret.pixelHintingFlag = (int) readUB(1, "pixelHintingFlag") == 1;
- ret.reserved = (int) readUB(5, "reserved");
- ret.noClose = (int) readUB(1, "noClose") == 1;
- ret.endCapStyle = (int) readUB(2, "endCapStyle");
- if (ret.joinStyle == LINESTYLE2.MITER_JOIN) {
- ret.miterLimitFactor = readUI16("miterLimitFactor");
- }
- if (!ret.hasFillFlag) {
- ret.startColor = readRGBA("startColor");
- ret.endColor = readRGBA("endColor");
- } else {
- ret.fillType = readMORPHFILLSTYLE("fillType");
- }
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one MORPHLINESTYLEARRAY value from the stream
- *
- * @param morphShapeNum 1 on DefineMorphShape, 2 on DefineMorphShape2
- * @param name
- * @return MORPHLINESTYLEARRAY value
- * @throws IOException
- */
- public MORPHLINESTYLEARRAY readMORPHLINESTYLEARRAY(int morphShapeNum, String name) throws IOException {
- MORPHLINESTYLEARRAY ret = new MORPHLINESTYLEARRAY();
- newDumpLevel(name, "MORPHLINESTYLEARRAY");
- int lineStyleCount = readUI8("lineStyleCount");
- if (lineStyleCount == 0xff) {
- lineStyleCount = readUI16("lineStyleCount");
- }
- if (morphShapeNum == 1) {
- ret.lineStyles = new MORPHLINESTYLE[lineStyleCount];
- for (int i = 0; i < lineStyleCount; i++) {
- ret.lineStyles[i] = readMORPHLINESTYLE("lineStyle");
- }
- } else if (morphShapeNum == 2) {
- ret.lineStyles2 = new MORPHLINESTYLE2[lineStyleCount];
- for (int i = 0; i < lineStyleCount; i++) {
- ret.lineStyles2[i] = readMORPHLINESTYLE2("lineStyle2");
- }
- }
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one KERNINGRECORD value from the stream
- *
- * @param fontFlagsWideCodes
- * @param name
- * @return KERNINGRECORD value
- * @throws IOException
- */
- public KERNINGRECORD readKERNINGRECORD(boolean fontFlagsWideCodes, String name) throws IOException {
- KERNINGRECORD ret = new KERNINGRECORD();
- newDumpLevel(name, "KERNINGRECORD");
- if (fontFlagsWideCodes) {
- ret.fontKerningCode1 = readUI16("fontKerningCode1");
- ret.fontKerningCode2 = readUI16("fontKerningCode2");
- } else {
- ret.fontKerningCode1 = readUI8("fontKerningCode1");
- ret.fontKerningCode2 = readUI8("fontKerningCode2");
- }
- ret.fontKerningAdjustment = readSI16("fontKerningAdjustment");
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one LANGCODE value from the stream
- *
- * @param name
- * @return LANGCODE value
- * @throws IOException
- */
- public LANGCODE readLANGCODE(String name) throws IOException {
- LANGCODE ret = new LANGCODE();
- newDumpLevel(name, "LANGCODE");
- ret.languageCode = readUI8("languageCode");
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one ZONERECORD value from the stream
- *
- * @param name
- * @return ZONERECORD value
- * @throws IOException
- */
- public ZONERECORD readZONERECORD(String name) throws IOException {
- ZONERECORD ret = new ZONERECORD();
- newDumpLevel(name, "ZONERECORD");
- int numZoneData = readUI8("numZoneData");
- ret.zonedata = new ZONEDATA[numZoneData];
- for (int i = 0; i < numZoneData; i++) {
- ret.zonedata[i] = readZONEDATA("zonedata");
- }
- readUB(6, "reserved");
- ret.zoneMaskY = readUB(1, "zoneMaskY") == 1;
- ret.zoneMaskX = readUB(1, "zoneMaskX") == 1;
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one ZONEDATA value from the stream
- *
- * @param name
- * @return ZONEDATA value
- * @throws IOException
- */
- public ZONEDATA readZONEDATA(String name) throws IOException {
- ZONEDATA ret = new ZONEDATA();
- newDumpLevel(name, "ZONEDATA");
- ret.alignmentCoordinate = readUI16("alignmentCoordinate");
- ret.range = readUI16("range");
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one PIX15 value from the stream
- *
- * @param name
- * @return PIX15 value
- * @throws IOException
- */
- public PIX15 readPIX15(String name) throws IOException {
- PIX15 ret = new PIX15();
- newDumpLevel(name, "PIX15");
- readUB(1, "reserved");
- ret.red = (int) readUB(5, "red");
- ret.green = (int) readUB(5, "green");
- ret.blue = (int) readUB(5, "blue");
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one PIX24 value from the stream
- *
- * @param name
- * @return PIX24 value
- * @throws IOException
- */
- public PIX24 readPIX24(String name) throws IOException {
- PIX24 ret = new PIX24();
- newDumpLevel(name, "PIX24");
- ret.reserved = readUI8("reserved");
- ret.red = readUI8("red");
- ret.green = readUI8("green");
- ret.blue = readUI8("blue");
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one COLORMAPDATA value from the stream
- *
- * @param colorTableSize
- * @param bitmapWidth
- * @param bitmapHeight
- * @param name
- * @return COLORMAPDATA value
- * @throws IOException
- */
- public COLORMAPDATA readCOLORMAPDATA(int colorTableSize, int bitmapWidth, int bitmapHeight, String name) throws IOException {
- COLORMAPDATA ret = new COLORMAPDATA();
- newDumpLevel(name, "COLORMAPDATA");
- ret.colorTableRGB = new RGB[colorTableSize + 1];
- for (int i = 0; i < colorTableSize + 1; i++) {
- ret.colorTableRGB[i] = readRGB("colorTableRGB");
- }
- int dataLen = 0;
- for (int y = 0; y < bitmapHeight; y++) {
- int x = 0;
- for (; x < bitmapWidth; x++) {
- dataLen++;
- }
- while ((x % 4) != 0) {
- dataLen++;
- x++;
- }
- }
- ret.colorMapPixelData = readBytesEx(dataLen, "colorMapPixelData");
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one BITMAPDATA value from the stream
- *
- * @param bitmapFormat
- * @param bitmapWidth
- * @param bitmapHeight
- * @param name
- * @return COLORMAPDATA value
- * @throws IOException
- */
- public BITMAPDATA readBITMAPDATA(int bitmapFormat, int bitmapWidth, int bitmapHeight, String name) throws IOException {
- BITMAPDATA ret = new BITMAPDATA();
- newDumpLevel(name, "BITMAPDATA");
- List pix15 = new ArrayList<>();
- List pix24 = new ArrayList<>();
- int dataLen = 0;
- for (int y = 0; y < bitmapHeight; y++) {
- int x = 0;
- for (; x < bitmapWidth; x++) {
- if (bitmapFormat == DefineBitsLosslessTag.FORMAT_15BIT_RGB) {
- dataLen += 2;
- pix15.add(readPIX15("pix15"));
- }
- if (bitmapFormat == DefineBitsLosslessTag.FORMAT_24BIT_RGB) {
- dataLen += 4;
- pix24.add(readPIX24("pix24"));
- }
- }
- while ((dataLen % 4) != 0) {
- dataLen++;
- readUI8("padding");
- }
- }
- if (bitmapFormat == DefineBitsLosslessTag.FORMAT_15BIT_RGB) {
- ret.bitmapPixelDataPix15 = pix15.toArray(new PIX15[pix15.size()]);
- } else if (bitmapFormat == DefineBitsLosslessTag.FORMAT_24BIT_RGB) {
- ret.bitmapPixelDataPix24 = pix24.toArray(new PIX24[pix24.size()]);
- }
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one BITMAPDATA value from the stream
- *
- * @param bitmapFormat
- * @param bitmapWidth
- * @param bitmapHeight
- * @param name
- * @return COLORMAPDATA value
- * @throws IOException
- */
- public ALPHABITMAPDATA readALPHABITMAPDATA(int bitmapFormat, int bitmapWidth, int bitmapHeight, String name) throws IOException {
- ALPHABITMAPDATA ret = new ALPHABITMAPDATA();
- newDumpLevel(name, "ALPHABITMAPDATA");
- ret.bitmapPixelData = new ARGB[bitmapWidth * bitmapHeight];
- for (int y = 0; y < bitmapHeight; y++) {
- for (int x = 0; x < bitmapWidth; x++) {
- ret.bitmapPixelData[y * bitmapWidth + x] = readARGB("bitmapPixelData");
- }
- }
- endDumpLevel();
- return ret;
- }
-
- /**
- * Reads one ALPHACOLORMAPDATA value from the stream
- *
- * @param colorTableSize
- * @param bitmapWidth
- * @param bitmapHeight
- * @param name
- * @return ALPHACOLORMAPDATA value
- * @throws IOException
- */
- public ALPHACOLORMAPDATA readALPHACOLORMAPDATA(int colorTableSize, int bitmapWidth, int bitmapHeight, String name) throws IOException {
- ALPHACOLORMAPDATA ret = new ALPHACOLORMAPDATA();
- newDumpLevel(name, "ALPHACOLORMAPDATA");
- ret.colorTableRGB = new RGBA[colorTableSize + 1];
- for (int i = 0; i < colorTableSize + 1; i++) {
- ret.colorTableRGB[i] = readRGBA("colorTableRGB");
- }
- int dataLen = 0;
- for (int y = 0; y < bitmapHeight; y++) {
- int x = 0;
- for (; x < bitmapWidth; x++) {
- dataLen++;
- }
- while ((x % 4) != 0) {
- dataLen++;
- x++;
- }
- }
- ret.colorMapPixelData = readBytesEx(dataLen, "");
- endDumpLevel();
- return ret;
- }
-
- public int available() throws IOException {
- return is.available();
- }
-
- public long availableBits() throws IOException {
- if (bitPos > 0) {
- return available() * 8 + (8 - bitPos);
- }
- return available() * 8;
- }
-
- public MemoryInputStream getBaseStream() throws IOException {
- int pos = (int) is.getPos();
- return new MemoryInputStream(is.getAllRead(), pos, pos + is.available());
- }
-
- public SWFInputStream getLimitedStream(int limit) throws IOException {
- SWFInputStream sis = new SWFInputStream(swf, is.getAllRead(), startingPos, (int) (is.getPos() + limit));
- sis.dumpInfo = dumpInfo;
- sis.seek(is.getPos() + startingPos);
- return sis;
- }
-}
+/*
+ * Copyright (C) 2010-2014 JPEXS
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.jpexs.decompiler.flash;
+
+import com.jpexs.decompiler.flash.action.Action;
+import com.jpexs.decompiler.flash.action.model.ConstantPool;
+import com.jpexs.decompiler.flash.action.special.ActionEnd;
+import com.jpexs.decompiler.flash.action.special.ActionNop;
+import com.jpexs.decompiler.flash.action.swf3.ActionGetURL;
+import com.jpexs.decompiler.flash.action.swf3.ActionGoToLabel;
+import com.jpexs.decompiler.flash.action.swf3.ActionGotoFrame;
+import com.jpexs.decompiler.flash.action.swf3.ActionNextFrame;
+import com.jpexs.decompiler.flash.action.swf3.ActionPlay;
+import com.jpexs.decompiler.flash.action.swf3.ActionPrevFrame;
+import com.jpexs.decompiler.flash.action.swf3.ActionSetTarget;
+import com.jpexs.decompiler.flash.action.swf3.ActionStop;
+import com.jpexs.decompiler.flash.action.swf3.ActionStopSounds;
+import com.jpexs.decompiler.flash.action.swf3.ActionToggleQuality;
+import com.jpexs.decompiler.flash.action.swf3.ActionWaitForFrame;
+import com.jpexs.decompiler.flash.action.swf4.ActionAdd;
+import com.jpexs.decompiler.flash.action.swf4.ActionAnd;
+import com.jpexs.decompiler.flash.action.swf4.ActionAsciiToChar;
+import com.jpexs.decompiler.flash.action.swf4.ActionCall;
+import com.jpexs.decompiler.flash.action.swf4.ActionCharToAscii;
+import com.jpexs.decompiler.flash.action.swf4.ActionCloneSprite;
+import com.jpexs.decompiler.flash.action.swf4.ActionDivide;
+import com.jpexs.decompiler.flash.action.swf4.ActionEndDrag;
+import com.jpexs.decompiler.flash.action.swf4.ActionEquals;
+import com.jpexs.decompiler.flash.action.swf4.ActionGetProperty;
+import com.jpexs.decompiler.flash.action.swf4.ActionGetTime;
+import com.jpexs.decompiler.flash.action.swf4.ActionGetURL2;
+import com.jpexs.decompiler.flash.action.swf4.ActionGetVariable;
+import com.jpexs.decompiler.flash.action.swf4.ActionGotoFrame2;
+import com.jpexs.decompiler.flash.action.swf4.ActionIf;
+import com.jpexs.decompiler.flash.action.swf4.ActionJump;
+import com.jpexs.decompiler.flash.action.swf4.ActionLess;
+import com.jpexs.decompiler.flash.action.swf4.ActionMBAsciiToChar;
+import com.jpexs.decompiler.flash.action.swf4.ActionMBCharToAscii;
+import com.jpexs.decompiler.flash.action.swf4.ActionMBStringExtract;
+import com.jpexs.decompiler.flash.action.swf4.ActionMBStringLength;
+import com.jpexs.decompiler.flash.action.swf4.ActionMultiply;
+import com.jpexs.decompiler.flash.action.swf4.ActionNot;
+import com.jpexs.decompiler.flash.action.swf4.ActionOr;
+import com.jpexs.decompiler.flash.action.swf4.ActionPop;
+import com.jpexs.decompiler.flash.action.swf4.ActionPush;
+import com.jpexs.decompiler.flash.action.swf4.ActionRandomNumber;
+import com.jpexs.decompiler.flash.action.swf4.ActionRemoveSprite;
+import com.jpexs.decompiler.flash.action.swf4.ActionSetProperty;
+import com.jpexs.decompiler.flash.action.swf4.ActionSetTarget2;
+import com.jpexs.decompiler.flash.action.swf4.ActionSetVariable;
+import com.jpexs.decompiler.flash.action.swf4.ActionStartDrag;
+import com.jpexs.decompiler.flash.action.swf4.ActionStringAdd;
+import com.jpexs.decompiler.flash.action.swf4.ActionStringEquals;
+import com.jpexs.decompiler.flash.action.swf4.ActionStringExtract;
+import com.jpexs.decompiler.flash.action.swf4.ActionStringLength;
+import com.jpexs.decompiler.flash.action.swf4.ActionStringLess;
+import com.jpexs.decompiler.flash.action.swf4.ActionSubtract;
+import com.jpexs.decompiler.flash.action.swf4.ActionToInteger;
+import com.jpexs.decompiler.flash.action.swf4.ActionTrace;
+import com.jpexs.decompiler.flash.action.swf4.ActionWaitForFrame2;
+import com.jpexs.decompiler.flash.action.swf5.ActionAdd2;
+import com.jpexs.decompiler.flash.action.swf5.ActionBitAnd;
+import com.jpexs.decompiler.flash.action.swf5.ActionBitLShift;
+import com.jpexs.decompiler.flash.action.swf5.ActionBitOr;
+import com.jpexs.decompiler.flash.action.swf5.ActionBitRShift;
+import com.jpexs.decompiler.flash.action.swf5.ActionBitURShift;
+import com.jpexs.decompiler.flash.action.swf5.ActionBitXor;
+import com.jpexs.decompiler.flash.action.swf5.ActionCallFunction;
+import com.jpexs.decompiler.flash.action.swf5.ActionCallMethod;
+import com.jpexs.decompiler.flash.action.swf5.ActionConstantPool;
+import com.jpexs.decompiler.flash.action.swf5.ActionDecrement;
+import com.jpexs.decompiler.flash.action.swf5.ActionDefineFunction;
+import com.jpexs.decompiler.flash.action.swf5.ActionDefineLocal;
+import com.jpexs.decompiler.flash.action.swf5.ActionDefineLocal2;
+import com.jpexs.decompiler.flash.action.swf5.ActionDelete;
+import com.jpexs.decompiler.flash.action.swf5.ActionDelete2;
+import com.jpexs.decompiler.flash.action.swf5.ActionEnumerate;
+import com.jpexs.decompiler.flash.action.swf5.ActionEquals2;
+import com.jpexs.decompiler.flash.action.swf5.ActionGetMember;
+import com.jpexs.decompiler.flash.action.swf5.ActionIncrement;
+import com.jpexs.decompiler.flash.action.swf5.ActionInitArray;
+import com.jpexs.decompiler.flash.action.swf5.ActionInitObject;
+import com.jpexs.decompiler.flash.action.swf5.ActionLess2;
+import com.jpexs.decompiler.flash.action.swf5.ActionModulo;
+import com.jpexs.decompiler.flash.action.swf5.ActionNewMethod;
+import com.jpexs.decompiler.flash.action.swf5.ActionNewObject;
+import com.jpexs.decompiler.flash.action.swf5.ActionPushDuplicate;
+import com.jpexs.decompiler.flash.action.swf5.ActionReturn;
+import com.jpexs.decompiler.flash.action.swf5.ActionSetMember;
+import com.jpexs.decompiler.flash.action.swf5.ActionStackSwap;
+import com.jpexs.decompiler.flash.action.swf5.ActionStoreRegister;
+import com.jpexs.decompiler.flash.action.swf5.ActionTargetPath;
+import com.jpexs.decompiler.flash.action.swf5.ActionToNumber;
+import com.jpexs.decompiler.flash.action.swf5.ActionToString;
+import com.jpexs.decompiler.flash.action.swf5.ActionTypeOf;
+import com.jpexs.decompiler.flash.action.swf5.ActionWith;
+import com.jpexs.decompiler.flash.action.swf6.ActionEnumerate2;
+import com.jpexs.decompiler.flash.action.swf6.ActionGreater;
+import com.jpexs.decompiler.flash.action.swf6.ActionInstanceOf;
+import com.jpexs.decompiler.flash.action.swf6.ActionStrictEquals;
+import com.jpexs.decompiler.flash.action.swf6.ActionStringGreater;
+import com.jpexs.decompiler.flash.action.swf7.ActionCastOp;
+import com.jpexs.decompiler.flash.action.swf7.ActionDefineFunction2;
+import com.jpexs.decompiler.flash.action.swf7.ActionExtends;
+import com.jpexs.decompiler.flash.action.swf7.ActionImplementsOp;
+import com.jpexs.decompiler.flash.action.swf7.ActionThrow;
+import com.jpexs.decompiler.flash.action.swf7.ActionTry;
+import com.jpexs.decompiler.flash.configuration.Configuration;
+import com.jpexs.decompiler.flash.dumpview.DumpInfo;
+import com.jpexs.decompiler.flash.tags.CSMTextSettingsTag;
+import com.jpexs.decompiler.flash.tags.DebugIDTag;
+import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag;
+import com.jpexs.decompiler.flash.tags.DefineBitsJPEG2Tag;
+import com.jpexs.decompiler.flash.tags.DefineBitsJPEG3Tag;
+import com.jpexs.decompiler.flash.tags.DefineBitsJPEG4Tag;
+import com.jpexs.decompiler.flash.tags.DefineBitsLossless2Tag;
+import com.jpexs.decompiler.flash.tags.DefineBitsLosslessTag;
+import com.jpexs.decompiler.flash.tags.DefineBitsTag;
+import com.jpexs.decompiler.flash.tags.DefineButton2Tag;
+import com.jpexs.decompiler.flash.tags.DefineButtonCxformTag;
+import com.jpexs.decompiler.flash.tags.DefineButtonSoundTag;
+import com.jpexs.decompiler.flash.tags.DefineButtonTag;
+import com.jpexs.decompiler.flash.tags.DefineEditTextTag;
+import com.jpexs.decompiler.flash.tags.DefineFont2Tag;
+import com.jpexs.decompiler.flash.tags.DefineFont3Tag;
+import com.jpexs.decompiler.flash.tags.DefineFont4Tag;
+import com.jpexs.decompiler.flash.tags.DefineFontAlignZonesTag;
+import com.jpexs.decompiler.flash.tags.DefineFontInfo2Tag;
+import com.jpexs.decompiler.flash.tags.DefineFontInfoTag;
+import com.jpexs.decompiler.flash.tags.DefineFontNameTag;
+import com.jpexs.decompiler.flash.tags.DefineFontTag;
+import com.jpexs.decompiler.flash.tags.DefineMorphShape2Tag;
+import com.jpexs.decompiler.flash.tags.DefineMorphShapeTag;
+import com.jpexs.decompiler.flash.tags.DefineScalingGridTag;
+import com.jpexs.decompiler.flash.tags.DefineSceneAndFrameLabelDataTag;
+import com.jpexs.decompiler.flash.tags.DefineShape2Tag;
+import com.jpexs.decompiler.flash.tags.DefineShape3Tag;
+import com.jpexs.decompiler.flash.tags.DefineShape4Tag;
+import com.jpexs.decompiler.flash.tags.DefineShapeTag;
+import com.jpexs.decompiler.flash.tags.DefineSoundTag;
+import com.jpexs.decompiler.flash.tags.DefineSpriteTag;
+import com.jpexs.decompiler.flash.tags.DefineText2Tag;
+import com.jpexs.decompiler.flash.tags.DefineTextTag;
+import com.jpexs.decompiler.flash.tags.DefineVideoStreamTag;
+import com.jpexs.decompiler.flash.tags.DoABCDefineTag;
+import com.jpexs.decompiler.flash.tags.DoABCTag;
+import com.jpexs.decompiler.flash.tags.DoActionTag;
+import com.jpexs.decompiler.flash.tags.DoInitActionTag;
+import com.jpexs.decompiler.flash.tags.EnableDebugger2Tag;
+import com.jpexs.decompiler.flash.tags.EnableDebuggerTag;
+import com.jpexs.decompiler.flash.tags.EnableTelemetryTag;
+import com.jpexs.decompiler.flash.tags.EndTag;
+import com.jpexs.decompiler.flash.tags.ExportAssetsTag;
+import com.jpexs.decompiler.flash.tags.FileAttributesTag;
+import com.jpexs.decompiler.flash.tags.FrameLabelTag;
+import com.jpexs.decompiler.flash.tags.ImportAssets2Tag;
+import com.jpexs.decompiler.flash.tags.ImportAssetsTag;
+import com.jpexs.decompiler.flash.tags.JPEGTablesTag;
+import com.jpexs.decompiler.flash.tags.MetadataTag;
+import com.jpexs.decompiler.flash.tags.PlaceObject2Tag;
+import com.jpexs.decompiler.flash.tags.PlaceObject3Tag;
+import com.jpexs.decompiler.flash.tags.PlaceObject4Tag;
+import com.jpexs.decompiler.flash.tags.PlaceObjectTag;
+import com.jpexs.decompiler.flash.tags.ProductInfoTag;
+import com.jpexs.decompiler.flash.tags.ProtectTag;
+import com.jpexs.decompiler.flash.tags.RemoveObject2Tag;
+import com.jpexs.decompiler.flash.tags.RemoveObjectTag;
+import com.jpexs.decompiler.flash.tags.ScriptLimitsTag;
+import com.jpexs.decompiler.flash.tags.SetBackgroundColorTag;
+import com.jpexs.decompiler.flash.tags.SetTabIndexTag;
+import com.jpexs.decompiler.flash.tags.ShowFrameTag;
+import com.jpexs.decompiler.flash.tags.SoundStreamBlockTag;
+import com.jpexs.decompiler.flash.tags.SoundStreamHead2Tag;
+import com.jpexs.decompiler.flash.tags.SoundStreamHeadTag;
+import com.jpexs.decompiler.flash.tags.StartSound2Tag;
+import com.jpexs.decompiler.flash.tags.StartSoundTag;
+import com.jpexs.decompiler.flash.tags.SymbolClassTag;
+import com.jpexs.decompiler.flash.tags.Tag;
+import com.jpexs.decompiler.flash.tags.TagStub;
+import com.jpexs.decompiler.flash.tags.UnknownTag;
+import com.jpexs.decompiler.flash.tags.VideoFrameTag;
+import com.jpexs.decompiler.flash.tags.gfx.DefineCompactedFont;
+import com.jpexs.decompiler.flash.tags.gfx.DefineExternalGradient;
+import com.jpexs.decompiler.flash.tags.gfx.DefineExternalImage;
+import com.jpexs.decompiler.flash.tags.gfx.DefineExternalImage2;
+import com.jpexs.decompiler.flash.tags.gfx.DefineExternalSound;
+import com.jpexs.decompiler.flash.tags.gfx.DefineExternalStreamSound;
+import com.jpexs.decompiler.flash.tags.gfx.DefineGradientMap;
+import com.jpexs.decompiler.flash.tags.gfx.DefineSubImage;
+import com.jpexs.decompiler.flash.tags.gfx.ExporterInfoTag;
+import com.jpexs.decompiler.flash.tags.gfx.FontTextureInfo;
+import com.jpexs.decompiler.flash.timeline.Timelined;
+import com.jpexs.decompiler.flash.types.ALPHABITMAPDATA;
+import com.jpexs.decompiler.flash.types.ALPHACOLORMAPDATA;
+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.COLORMAPDATA;
+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.ByteArrayRange;
+import com.jpexs.helpers.Helper;
+import com.jpexs.helpers.MemoryInputStream;
+import com.jpexs.helpers.ProgressListener;
+import com.jpexs.helpers.utf8.Utf8Helper;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.zip.InflaterInputStream;
+
+/**
+ * Class for reading data from SWF file
+ *
+ * @author JPEXS
+ */
+public class SWFInputStream implements AutoCloseable {
+
+ private MemoryInputStream is;
+ private long startingPos;
+ private static final Logger logger = Logger.getLogger(SWFInputStream.class.getName());
+ private final List listeners = new ArrayList<>();
+ private long percentMax;
+ private SWF swf;
+ public DumpInfo dumpInfo;
+
+ public void addPercentListener(ProgressListener listener) {
+ listeners.add(listener);
+ }
+
+ public void removePercentListener(ProgressListener listener) {
+ int index = listeners.indexOf(listener);
+ if (index > -1) {
+ listeners.remove(index);
+ }
+ }
+
+ private void informListeners() {
+ if (listeners.size() > 0 && percentMax > 0) {
+ int percent = (int) (getPos() * 100 / percentMax);
+ if (lastPercent != percent) {
+ for (ProgressListener pl : listeners) {
+ pl.progress(percent);
+ }
+ lastPercent = percent;
+ }
+ }
+ }
+
+ public void setPercentMax(long percentMax) {
+ this.percentMax = percentMax;
+ }
+
+ /**
+ * Constructor
+ *
+ * @param swf SWF to read
+ * @param data SWF data
+ * @param startingPos
+ * @param limit
+ * @throws java.io.IOException
+ */
+ public SWFInputStream(SWF swf, byte[] data, long startingPos, int limit) throws IOException {
+ this.swf = swf;
+ this.startingPos = startingPos;
+ is = new MemoryInputStream(data, 0, limit);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param swf SWF to read
+ * @param data SWF data
+ * @throws java.io.IOException
+ */
+ public SWFInputStream(SWF swf, byte[] data) throws IOException {
+ this(swf, data, 0L, data.length);
+ }
+
+ public SWF getSwf() {
+ return swf;
+ }
+
+ /**
+ * Gets position in bytes in the stream
+ *
+ * @return Number of bytes
+ */
+ public long getPos() {
+ return startingPos + is.getPos();
+ }
+
+ /**
+ * Sets position in bytes in the stream
+ *
+ * @param pos Number of bytes
+ * @throws java.io.IOException
+ */
+ public void seek(long pos) throws IOException {
+ is.seek(pos - startingPos);
+ }
+
+ private void newDumpLevel(String name, String type) {
+ if (dumpInfo != null) {
+ long startByte = is.getPos();
+ if (bitPos > 0) {
+ startByte--;
+ }
+ DumpInfo di = new DumpInfo(name, type, null, startByte, bitPos, 0, 0);
+ di.parent = dumpInfo;
+ dumpInfo.getChildInfos().add(di);
+ dumpInfo = di;
+ }
+ }
+
+ private void endDumpLevel() {
+ endDumpLevel(null);
+ }
+
+ private void endDumpLevel(Object value) {
+ if (dumpInfo != null) {
+ if (dumpInfo.startBit == 0 && bitPos == 0) {
+ dumpInfo.lengthBytes = is.getPos() - dumpInfo.startByte;
+ } else {
+ dumpInfo.lengthBits = (int) ((is.getPos() - dumpInfo.startByte - 1) * 8 - dumpInfo.startBit + (bitPos == 0 ? 8 : bitPos));
+ }
+ dumpInfo.previewValue = value;
+ dumpInfo = dumpInfo.parent;
+ }
+ }
+
+ /**
+ * Reads one byte from the stream
+ *
+ * @return byte
+ * @throws IOException
+ */
+ private int readEx() throws IOException {
+ bitPos = 0;
+ return readNoBitReset();
+ }
+
+ private void alignByte() {
+ bitPos = 0;
+ }
+
+ private int lastPercent = -1;
+
+ private int readNoBitReset() throws IOException, EndOfStreamException {
+ informListeners();
+ int r = is.read();
+ if (r == -1) {
+ throw new EndOfStreamException();
+ }
+ return r;
+ }
+
+ /**
+ * Reads one UI8 (Unsigned 8bit integer) value from the stream
+ *
+ * @param name
+ * @return UI8 value or -1 on error
+ * @throws IOException
+ */
+ public int readUI8(String name) throws IOException {
+ newDumpLevel(name, "UI8");
+ int ret = readEx();
+ endDumpLevel(ret);
+ return ret;
+ }
+
+ /**
+ * 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 = readEx();
+ if (r == 0) {
+ endDumpLevel();
+ return new String(baos.toByteArray(), Utf8Helper.charset);
+ }
+ baos.write(r);
+ }
+ }
+
+ /**
+ * Reads one UI32 (Unsigned 32bit integer) value from the stream
+ *
+ * @param name
+ * @return UI32 value
+ * @throws IOException
+ */
+ public long readUI32(String name) throws IOException {
+ newDumpLevel(name, "UI32");
+ long ret = readUI32Internal();
+ endDumpLevel(ret);
+ return ret;
+ }
+
+ /**
+ * Reads one UI32 (Unsigned 32bit integer) value from the stream
+ *
+ * @return UI32 value
+ * @throws IOException
+ */
+ private long readUI32Internal() throws IOException {
+ return (readEx() + (readEx() << 8) + (readEx() << 16) + (readEx() << 24)) & 0xffffffff;
+ }
+
+ /**
+ * Reads one UI16 (Unsigned 16bit integer) value from the stream
+ *
+ * @param name
+ * @return UI16 value
+ * @throws IOException
+ */
+ public int readUI16(String name) throws IOException {
+ newDumpLevel(name, "UI16");
+ int ret = readUI16Internal();
+ endDumpLevel(ret);
+ return ret;
+ }
+
+ /**
+ * Reads one UI16 (Unsigned 16bit integer) value from the stream
+ *
+ * @return UI16 value
+ * @throws IOException
+ */
+ private int readUI16Internal() throws IOException {
+ return readEx() + (readEx() << 8);
+ }
+
+ public int readUI24(String name) throws IOException {
+ newDumpLevel(name, "UI24");
+ int ret = readEx() + (readEx() << 8) + (readEx() << 16);
+ endDumpLevel(ret);
+ return ret;
+ }
+
+ /**
+ * Reads one SI32 (Signed 32bit integer) value from the stream
+ *
+ * @param name
+ * @return SI32 value
+ * @throws IOException
+ */
+ public long readSI32(String name) throws IOException {
+ newDumpLevel(name, "SI32");
+ long uval = readEx() + (readEx() << 8) + (readEx() << 16) + (readEx() << 24);
+ if (uval >= 0x80000000) {
+ uval = -(((~uval) & 0xffffffff) + 1);
+ }
+ endDumpLevel(uval);
+ return uval;
+ }
+
+ /**
+ * 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 = readEx() + (readEx() << 8);
+ if (uval >= 0x8000) {
+ uval = -(((~uval) & 0xffff) + 1);
+ }
+ endDumpLevel(uval);
+ return uval;
+ }
+
+ /**
+ * Reads one SI8 (Signed 8bit integer) value from the stream
+ *
+ * @param name
+ * @return SI8 value
+ * @throws IOException
+ */
+ public int readSI8(String name) throws IOException {
+ newDumpLevel(name, "SI8");
+ int uval = readEx();
+ if (uval >= 0x80) {
+ uval = -(((~uval) & 0xff) + 1);
+ }
+ endDumpLevel(uval);
+ return uval;
+ }
+
+ /**
+ * Reads one FIXED (Fixed point 16.16) value from the stream
+ *
+ * @param name
+ * @return FIXED value
+ * @throws IOException
+ */
+ public double readFIXED(String name) throws IOException {
+ newDumpLevel(name, "FIXED");
+ int afterPoint = readUI16Internal();
+ int beforePoint = readUI16Internal();
+ double ret = ((double) ((beforePoint << 16) + afterPoint)) / 65536;
+ endDumpLevel(ret);
+ return ret;
+ }
+
+ /**
+ * Reads one FIXED8 (Fixed point 8.8) value from the stream
+ *
+ * @param name
+ * @return FIXED8 value
+ * @throws IOException
+ */
+ public float readFIXED8(String name) throws IOException {
+ newDumpLevel(name, "FIXED8");
+ int afterPoint = readEx();
+ int beforePoint = readEx();
+ float ret = beforePoint + (((float) afterPoint) / 256);
+ endDumpLevel(ret);
+ return ret;
+ }
+
+ private long readLong() throws IOException {
+ byte[] readBuffer = readBytesInternalEx(8);
+ return (((long) readBuffer[3] << 56)
+ + ((long) (readBuffer[2] & 255) << 48)
+ + ((long) (readBuffer[1] & 255) << 40)
+ + ((long) (readBuffer[0] & 255) << 32)
+ + ((long) (readBuffer[7] & 255) << 24)
+ + ((readBuffer[6] & 255) << 16)
+ + ((readBuffer[5] & 255) << 8)
+ + ((readBuffer[4] & 255)));
+ }
+
+ /**
+ * Reads one DOUBLE (double precision floating point value) value from the
+ * stream
+ *
+ * @param name
+ * @return DOUBLE value
+ * @throws IOException
+ */
+ public double readDOUBLE(String name) throws IOException {
+ newDumpLevel(name, "DOUBLE");
+ long el = readLong();
+ double ret = Double.longBitsToDouble(el);
+ endDumpLevel(ret);
+ return ret;
+ }
+
+ /**
+ * Reads one FLOAT (single precision floating point value) value from the
+ * stream
+ *
+ * @param name
+ * @return FLOAT value
+ * @throws IOException
+ */
+ public float readFLOAT(String name) throws IOException {
+ newDumpLevel(name, "FLOAT");
+ int val = (int) readUI32Internal();
+ float ret = Float.intBitsToFloat(val);
+ endDumpLevel(ret);
+ /*int sign = val >> 31;
+ int mantisa = val & 0x3FFFFF;
+ int exp = (val >> 22) & 0xFF;
+ float ret =(sign == 1 ? -1 : 1) * (float) Math.pow(2, exp)* (1+((mantisa)/ (float)(1<<23)));*/
+ return ret;
+ }
+
+ /**
+ * Reads one FLOAT16 (16bit floating point value) value from the stream
+ *
+ * @param name
+ * @return FLOAT16 value
+ * @throws IOException
+ */
+ public float readFLOAT16(String name) throws IOException {
+ newDumpLevel(name, "FLOAT16");
+ int val = readUI16Internal();
+ int sign = val >> 15;
+ int mantisa = val & 0x3FF;
+ int exp = (val >> 10) & 0x1F;
+ float ret = (sign == 1 ? -1 : 1) * (float) Math.pow(2, exp) * (1 + ((mantisa) / (float) (1 << 10)));
+ endDumpLevel(ret);
+ return ret;
+ }
+
+ /**
+ * Reads bytes from the stream
+ *
+ * @param count Number of bytes to read
+ * @param name
+ * @return Array of read bytes
+ * @throws IOException
+ */
+ public byte[] readBytesEx(long count, String name) throws IOException {
+ if (count <= 0) {
+ return new byte[0];
+ }
+ newDumpLevel(name, "bytes");
+ byte[] ret = readBytesInternalEx(count);
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads bytes from the stream
+ *
+ * @param count Number of bytes to read
+ * @return Array of read bytes
+ * @throws IOException
+ */
+ private byte[] readBytesInternalEx(long count) throws IOException {
+ if (count <= 0) {
+ return new byte[0];
+ }
+
+ informListeners();
+ bitPos = 0;
+ byte[] ret = new byte[(int) count];
+ if (is.read(ret) != count) {
+ throw new EndOfStreamException();
+ }
+
+ return ret;
+ }
+
+ /**
+ * Skip bytes from the stream
+ *
+ * @param count Number of bytes to skip
+ * @throws IOException
+ */
+ public void skipBytes(int count) throws IOException {
+ try {
+ bitPos = 0;
+ for (int i = 0; i < count; i++) {
+ readNoBitReset();
+ }
+ } catch (EOFException | EndOfStreamException ex) {
+ logger.log(Level.SEVERE, null, ex);
+ }
+ }
+
+ /**
+ * Reads bytes from the stream
+ *
+ * @param count Number of bytes to read
+ * @param name
+ * @return Array of read bytes
+ * @throws IOException
+ */
+ public byte[] readBytes(int count, String name) throws IOException {
+ if (count <= 0) {
+ return new byte[0];
+ }
+ newDumpLevel(name, "bytes");
+ byte[] ret = new byte[count];
+ int i = 0;
+ try {
+ for (i = 0; i < count; i++) {
+ ret[i] = (byte) readEx();
+ }
+ } catch (EOFException | EndOfStreamException ex) {
+ ret = Arrays.copyOf(ret, i); // truncate array
+ logger.log(Level.SEVERE, null, ex);
+ }
+ endDumpLevel();
+ return ret;
+ }
+
+ public byte[] readBytesZlib(long count, String name) throws IOException {
+ newDumpLevel(name, "bytesZlib");
+ byte[] data = readBytesInternalEx(count);
+ endDumpLevel();
+ InflaterInputStream dis = new InflaterInputStream(new ByteArrayInputStream(data));
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ byte[] buf = new byte[4096];
+ int c = 0;
+ while ((c = dis.read(buf)) > 0) {
+ baos.write(buf, 0, c);
+ }
+ return baos.toByteArray();
+ }
+
+ /**
+ * Reads one EncodedU32 (Encoded unsigned 32bit value) value from the stream
+ *
+ * @param name
+ * @return U32 value
+ * @throws IOException
+ */
+ public long readEncodedU32(String name) throws IOException {
+ newDumpLevel(name, "encodedU32");
+ int result = readEx();
+ if ((result & 0x00000080) == 0) {
+ endDumpLevel(result);
+ return result;
+ }
+ result = (result & 0x0000007f) | (readEx()) << 7;
+ if ((result & 0x00004000) == 0) {
+ endDumpLevel(result);
+ return result;
+ }
+ result = (result & 0x00003fff) | (readEx()) << 14;
+ if ((result & 0x00200000) == 0) {
+ endDumpLevel(result);
+ return result;
+ }
+ result = (result & 0x001fffff) | (readEx()) << 21;
+ if ((result & 0x10000000) == 0) {
+ endDumpLevel(result);
+ return result;
+ }
+ result = (result & 0x0fffffff) | (readEx()) << 28;
+ endDumpLevel(result);
+ return result;
+ }
+ private int bitPos = 0;
+ private int tempByte = 0;
+
+ /**
+ * Reads UB[nBits] (Unsigned-bit value) value from the stream
+ *
+ * @param nBits Number of bits which represent value
+ * @param name
+ * @return Unsigned value
+ * @throws IOException
+ */
+ public long readUB(int nBits, String name) throws IOException {
+ if (nBits == 0) {
+ return 0;
+ }
+ newDumpLevel(name, "UB");
+ long ret = readUBInternal(nBits);
+ endDumpLevel(ret);
+ return ret;
+ }
+
+ /**
+ * Reads UB[nBits] (Unsigned-bit value) value from the stream
+ *
+ * @param nBits Number of bits which represent value
+ * @return Unsigned value
+ * @throws IOException
+ */
+ private long readUBInternal(int nBits) throws IOException {
+ if (nBits == 0) {
+ return 0;
+ }
+ long ret = 0;
+ if (bitPos == 0) {
+ tempByte = readNoBitReset();
+ }
+ for (int bit = 0; bit < nBits; bit++) {
+ int nb = (tempByte >> (7 - bitPos)) & 1;
+ ret += (nb << (nBits - 1 - bit));
+ bitPos++;
+ if (bitPos == 8) {
+ bitPos = 0;
+ if (bit != nBits - 1) {
+ tempByte = readNoBitReset();
+ }
+ }
+ }
+ return ret;
+ }
+
+ /**
+ * Reads SB[nBits] (Signed-bit value) value from the stream
+ *
+ * @param nBits Number of bits which represent value
+ * @param name
+ * @return Signed value
+ * @throws IOException
+ */
+ public long readSB(int nBits, String name) throws IOException {
+ newDumpLevel(name, "SB");
+ long ret = readSBInternal(nBits);
+ endDumpLevel(ret);
+ return ret;
+ }
+
+ /**
+ * Reads SB[nBits] (Signed-bit value) value from the stream
+ *
+ * @param nBits Number of bits which represent value
+ * @return Signed value
+ * @throws IOException
+ */
+ private long readSBInternal(int nBits) throws IOException {
+ int uval = (int) readUBInternal(nBits);
+
+ int shift = 32 - nBits;
+ // sign extension
+ uval = (uval << shift) >> shift;
+ return uval;
+ }
+
+ /**
+ * Reads FB[nBits] (Signed fixed-point bit value) value from the stream
+ *
+ * @param nBits Number of bits which represent value
+ * @param name
+ * @return Fixed-point value
+ * @throws IOException
+ */
+ public float readFB(int nBits, String name) throws IOException {
+ if (nBits == 0) {
+ return 0;
+ }
+ newDumpLevel(name, "FB");
+ float val = readSBInternal(nBits);
+ float ret = val / 0x10000;
+ endDumpLevel(ret);
+ return ret;
+ }
+
+ /**
+ * Reads one RECT value from the stream
+ *
+ * @param name
+ * @return RECT value
+ * @throws IOException
+ */
+ public RECT readRECT(String name) throws IOException {
+ RECT ret = new RECT();
+ newDumpLevel(name, "RECT");
+ int NBits = (int) readUB(5, "NBits");
+ ret.Xmin = (int) readSB(NBits, "Xmin");
+ ret.Xmax = (int) readSB(NBits, "Xmax");
+ ret.Ymin = (int) readSB(NBits, "Ymin");
+ ret.Ymax = (int) readSB(NBits, "Ymax");
+ ret.nbits = NBits;
+ alignByte();
+ endDumpLevel();
+ return ret;
+ }
+
+ private static void dumpTag(PrintStream out, int version, Tag tag, int level) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(Helper.formatHex((int) tag.getPos(), 8));
+ sb.append(": ");
+ sb.append(Helper.indent(level, "", " "));
+ sb.append(Helper.format(tag.toString(), 25 - 2 * level));
+ sb.append(" tagId=");
+ sb.append(Helper.formatInt(tag.getId(), 3));
+ sb.append(" len=");
+ sb.append(Helper.formatInt(tag.getOriginalDataLength(), 8));
+ sb.append(" ");
+ sb.append(Helper.bytesToHexString(64, tag.getData(), 0));
+ out.println(sb.toString());
+// out.println(Utils.formatHex((int)tag.getPos(), 8) + ": " + Utils.indent(level, "") + Utils.format(tag.toString(), 25 - 2*level) + " tagId="+tag.getId()+" len="+tag.getOrigDataLength()+": "+Utils.bytesToHexString(64, tag.getData(version), 0));
+ if (tag.hasSubTags()) {
+ for (Tag subTag : tag.getSubTags()) {
+ dumpTag(out, version, subTag, level + 1);
+ }
+ }
+ }
+
+ @Override
+ public void close() {
+ }
+
+ private class TagResolutionTask implements Callable {
+
+ private final Tag tag;
+ private final DumpInfo dumpInfo;
+ private final int level;
+ private final boolean parallel;
+ private final boolean skipUnusualTags;
+ private final boolean gfx;
+
+ public TagResolutionTask(Tag tag, DumpInfo dumpInfo, int level, boolean parallel, boolean skipUnusualTags, boolean gfx) {
+ this.tag = tag;
+ this.dumpInfo = dumpInfo;
+ this.level = level;
+ this.parallel = parallel;
+ this.skipUnusualTags = skipUnusualTags;
+ this.gfx = gfx;
+ }
+
+ @Override
+ public Tag call() throws Exception {
+ try {
+ Tag t = resolveTag(tag, level, parallel, skipUnusualTags, gfx);
+ if (dumpInfo!= null && t != null) {
+ dumpInfo.name = t.getName();
+ }
+ return t;
+ } catch (EndOfStreamException ex) {
+ logger.log(Level.SEVERE, null, ex);
+ return tag;
+ }
+ }
+ }
+
+ /**
+ * Reads list of tags from the stream. Reading ends with End tag(=0) or end
+ * of the stream. Optionally can skip AS1/2 tags when file is AS3
+ *
+ * @param timelined
+ * @param level
+ * @param parallel
+ * @param skipUnusualTags
+ * @param parseTags
+ * @param gfx
+ * @return List of tags
+ * @throws IOException
+ * @throws java.lang.InterruptedException
+ */
+ public List readTagList(Timelined timelined, int level, boolean parallel, boolean skipUnusualTags, boolean parseTags, boolean gfx) throws IOException, InterruptedException {
+ ExecutorService executor = null;
+ List> futureResults = new ArrayList<>();
+ if (parallel) {
+ executor = Executors.newFixedThreadPool(Configuration.parallelThreadCount.get());
+ futureResults = new ArrayList<>();
+ }
+ List tags = new ArrayList<>();
+ Tag tag;
+ boolean isAS3 = false;
+ while (true) {
+ long pos = getPos();
+ newDumpLevel(null, "TAG");
+ try {
+ tag = readTag(timelined, level, pos, parseTags && !parallel, parallel, skipUnusualTags, gfx);
+ } catch (EOFException | EndOfStreamException ex) {
+ tag = null;
+ }
+ DumpInfo di = dumpInfo;
+ if (di != null && tag != null) {
+ di.name = tag.getName();
+ }
+ endDumpLevel(tag == null ? null : tag.getId());
+ if (tag == null) {
+ break;
+ }
+
+ tag.setTimelined(timelined);
+ if (!parallel) {
+ tags.add(tag);
+ }
+ if (Configuration.dumpTags.get() && level == 0) {
+ dumpTag(System.out, swf.version, tag, level);
+ }
+
+ boolean doParse;
+ if (!skipUnusualTags) {
+ doParse = true;
+ } else {
+ switch (tag.getId()) {
+ case FileAttributesTag.ID: //FileAttributes
+ tag = resolveTag(tag, level, parallel, skipUnusualTags, gfx);
+ FileAttributesTag fileAttributes = (FileAttributesTag) tag;
+ if (fileAttributes.actionScript3) {
+ isAS3 = true;
+ }
+ doParse = true;
+ break;
+ case DoActionTag.ID:
+ case DoInitActionTag.ID:
+ if (isAS3) {
+ doParse = false;
+ } else {
+ doParse = true;
+ }
+ break;
+ case ShowFrameTag.ID:
+ case PlaceObjectTag.ID:
+ case PlaceObject2Tag.ID:
+ case RemoveObjectTag.ID:
+ case RemoveObject2Tag.ID:
+ case PlaceObject3Tag.ID: //?
+ case StartSoundTag.ID:
+ case FrameLabelTag.ID:
+ case SoundStreamHeadTag.ID:
+ case SoundStreamHead2Tag.ID:
+ case SoundStreamBlockTag.ID:
+ case VideoFrameTag.ID:
+ case EndTag.ID:
+ doParse = true;
+ break;
+ default:
+ if (level > 0) { //No such tags in DefineSprite allowed
+ logger.log(Level.FINE, "Tag({0}) found in DefineSprite => Ignored", tag.getId());
+ doParse = false;
+ } else {
+ doParse = true;
+ }
+
+ }
+ }
+ if (parseTags && doParse) {
+ if (parallel) {
+ Future future = executor.submit(new TagResolutionTask(tag, di, level, parallel, skipUnusualTags, gfx));
+ futureResults.add(future);
+ }
+ }
+
+ if (tag.getId() == EndTag.ID) {
+ break;
+ }
+ }
+
+ if (parallel) {
+ for (Future future : futureResults) {
+ try {
+ tags.add(future.get());
+ } catch (InterruptedException ex) {
+ future.cancel(true);
+ } catch (ExecutionException e) {
+ logger.log(Level.SEVERE, "Error during tag reading", e);
+ }
+ }
+
+ executor.shutdown();
+ }
+ return tags;
+ }
+
+ public static Tag resolveTag(Tag tag, int level, boolean parallel, boolean skipUnusualTags, boolean gfx) throws InterruptedException {
+ Tag ret;
+
+ if (!(tag instanceof TagStub)) {
+ return tag;
+ }
+
+ ByteArrayRange data = tag.getOriginalRange();
+ SWF swf = tag.getSwf();
+ TagStub tagStub = (TagStub) tag;
+ SWFInputStream sis = tagStub.getDataStream();
+
+ try {
+ switch (tag.getId()) {
+ case 0:
+ ret = new EndTag(swf, data);
+ break;
+ case 1:
+ ret = new ShowFrameTag(swf, data);
+ break;
+ case 2:
+ ret = new DefineShapeTag(sis, data);
+ break;
+ //case 3: FreeCharacter
+ case 4:
+ ret = new PlaceObjectTag(sis, data);
+ break;
+ case 5:
+ ret = new RemoveObjectTag(sis, data);
+ break;
+ case 6:
+ ret = new DefineBitsTag(sis, data);
+ break;
+ case 7:
+ ret = new DefineButtonTag(sis, data);
+ break;
+ case 8:
+ ret = new JPEGTablesTag(sis, data);
+ break;
+ case 9:
+ ret = new SetBackgroundColorTag(sis, data);
+ break;
+ case 10:
+ ret = new DefineFontTag(sis, data);
+ break;
+ case 11:
+ ret = new DefineTextTag(sis, data);
+ break;
+ case 12:
+ ret = new DoActionTag(sis, data);
+ break;
+ case 13:
+ ret = new DefineFontInfoTag(sis, data);
+ break;
+ case 14:
+ ret = new DefineSoundTag(sis, data);
+ break;
+ case 15:
+ ret = new StartSoundTag(sis, data);
+ break;
+ //case 16:
+ case 17:
+ ret = new DefineButtonSoundTag(sis, data);
+ break;
+ case 18:
+ ret = new SoundStreamHeadTag(sis, data);
+ break;
+ case 19:
+ ret = new SoundStreamBlockTag(sis, data);
+ break;
+ case 21:
+ ret = new DefineBitsJPEG2Tag(sis, data);
+ break;
+ case 20:
+ ret = new DefineBitsLosslessTag(sis, data);
+ break;
+ case 22:
+ ret = new DefineShape2Tag(sis, data);
+ break;
+ case 23:
+ ret = new DefineButtonCxformTag(sis, data);
+ break;
+ case 24:
+ ret = new ProtectTag(sis, data);
+ break;
+ //case 25: PathsArePostscript
+ case 26:
+ ret = new PlaceObject2Tag(sis, data);
+ break;
+ //case 27:
+ case 28:
+ ret = new RemoveObject2Tag(sis, data);
+ break;
+ //case 29: SyncFrame
+ //case 30:
+ //case 31: FreeAll
+ case 32:
+ ret = new DefineShape3Tag(sis, data);
+ break;
+ case 33:
+ ret = new DefineText2Tag(sis, data);
+ break;
+ case 34:
+ ret = new DefineButton2Tag(sis, data);
+ break;
+ case 35:
+ ret = new DefineBitsJPEG3Tag(sis, data);
+ break;
+ case 36:
+ ret = new DefineBitsLossless2Tag(sis, data);
+ break;
+ case 37:
+ ret = new DefineEditTextTag(sis, data);
+ break;
+ //case 38: DefineVideo
+ case 39:
+ ret = new DefineSpriteTag(sis, level, data, parallel, skipUnusualTags);
+ break;
+ //case 40: NameCharacter
+ case 41:
+ ret = new ProductInfoTag(sis, data);
+ break;
+ //case 42: DefineTextFormat
+ case 43:
+ ret = new FrameLabelTag(sis, data);
+ break;
+ //case 44:
+ case 45:
+ ret = new SoundStreamHead2Tag(sis, data);
+ break;
+ case 46:
+ ret = new DefineMorphShapeTag(sis, data);
+ break;
+ //case 47: GenerateFrame
+ case 48:
+ ret = new DefineFont2Tag(sis, data);
+ break;
+ //case 49: GeneratorCommand
+ //case 50: DefineCommandObject
+ //case 51: CharacterSet
+ //case 52: ExternalFont
+ //case 53-55
+ case 56:
+ ret = new ExportAssetsTag(sis, data);
+ break;
+ case 57:
+ ret = new ImportAssetsTag(sis, data);
+ break;
+ case 58:
+ ret = new EnableDebuggerTag(sis, data);
+ break;
+ case 59:
+ ret = new DoInitActionTag(sis, data);
+ break;
+ case 60:
+ ret = new DefineVideoStreamTag(sis, data);
+ break;
+ case 61:
+ ret = new VideoFrameTag(sis, data);
+ break;
+ case 62:
+ ret = new DefineFontInfo2Tag(sis, data);
+ break;
+ case 63:
+ ret = new DebugIDTag(sis, data);
+ break;
+ case 64:
+ ret = new EnableDebugger2Tag(sis, data);
+ break;
+ case 65:
+ ret = new ScriptLimitsTag(sis, data);
+ break;
+ case 66:
+ ret = new SetTabIndexTag(sis, data);
+ break;
+ //case 67-68:
+ case 69:
+ ret = new FileAttributesTag(sis, data);
+ break;
+ case 70:
+ ret = new PlaceObject3Tag(sis, data);
+ break;
+ case 71:
+ ret = new ImportAssets2Tag(sis, data);
+ break;
+ case 72:
+ ret = new DoABCTag(sis, data);
+ break;
+ case 73:
+ ret = new DefineFontAlignZonesTag(sis, data);
+ break;
+ case 74:
+ ret = new CSMTextSettingsTag(sis, data);
+ break;
+ case 75:
+ ret = new DefineFont3Tag(sis, data);
+ break;
+ case 76:
+ ret = new SymbolClassTag(sis, data);
+ break;
+ case 77:
+ ret = new MetadataTag(sis, data);
+ break;
+ case 78:
+ ret = new DefineScalingGridTag(sis, data);
+ break;
+ //case 79-81:
+ case 82:
+ ret = new DoABCDefineTag(sis, data);
+ break;
+ case 83:
+ ret = new DefineShape4Tag(sis, data);
+ break;
+ case 84:
+ ret = new DefineMorphShape2Tag(sis, data);
+ break;
+ //case 85:
+ case 86:
+ ret = new DefineSceneAndFrameLabelDataTag(sis, data);
+ break;
+ case 87:
+ ret = new DefineBinaryDataTag(sis, data);
+ break;
+ case 88:
+ ret = new DefineFontNameTag(sis, data);
+ break;
+ case 89:
+ ret = new StartSound2Tag(sis, data);
+ break;
+ case 90:
+ ret = new DefineBitsJPEG4Tag(sis, data);
+ break;
+ case 91:
+ ret = new DefineFont4Tag(sis, data);
+ break;
+ //case 92: certificate
+ case 93:
+ ret = new EnableTelemetryTag(sis, data);
+ break;
+ case 94:
+ ret = new PlaceObject4Tag(sis, data);
+ break;
+ default:
+ if (gfx) { //GFX tags only in GFX files. There may be incorrect GFX tags in non GFX files
+ switch (tag.getId()) {
+ case 1000:
+ ret = new ExporterInfoTag(sis, data);
+ break;
+ case 1001:
+ ret = new DefineExternalImage(sis, data);
+ break;
+ case 1002:
+ ret = new FontTextureInfo(sis, data);
+ break;
+ case 1003:
+ ret = new DefineExternalGradient(sis, data);
+ break;
+ case 1004:
+ ret = new DefineGradientMap(sis, data);
+ break;
+ case 1005:
+ ret = new DefineCompactedFont(sis, data);
+ break;
+ case 1006:
+ ret = new DefineExternalSound(sis, data);
+ break;
+ case 1007:
+ ret = new DefineExternalStreamSound(sis, data);
+ break;
+ case 1008:
+ ret = new DefineSubImage(sis, data);
+ break;
+ case 1009:
+ ret = new DefineExternalImage2(sis, data);
+ break;
+ default:
+ ret = new UnknownTag(swf, tag.getId(), data);
+ }
+ } else {
+ ret = new UnknownTag(swf, tag.getId(), data);
+ }
+ }
+ } catch (IOException ex) {
+ logger.log(Level.SEVERE, "Error during tag reading", ex);
+ ret = new TagStub(swf, tag.getId(), "ErrorTag", data, null);
+ }
+ ret.forceWriteAsLong = tag.forceWriteAsLong;
+ ret.setTimelined(tag.getTimelined());
+ return ret;
+ }
+
+ /**
+ * Reads one Tag from the stream with optional resolving (= reading tag
+ * content)
+ *
+ * @param timelined
+ * @param level
+ * @param pos
+ * @param resolve
+ * @param parallel
+ * @param skipUnusualTags
+ * @param gfx
+ * @return Tag or null when End tag
+ * @throws IOException
+ * @throws java.lang.InterruptedException
+ */
+ public Tag readTag(Timelined timelined, int level, long pos, boolean resolve, boolean parallel, boolean skipUnusualTags, boolean gfx) throws IOException, InterruptedException {
+ int tagIDTagLength = readUI16("tagIDTagLength");
+ int tagID = (tagIDTagLength) >> 6;
+
+ logger.log(Level.INFO, "Reading tag. ID={0}, position: {1}", new Object[]{tagID, pos});
+
+ long tagLength = (tagIDTagLength & 0x003F);
+ boolean readLong = false;
+ if (tagLength == 0x3f) {
+ tagLength = readSI32("tagLength");
+ readLong = true;
+ }
+ int headerLength = readLong ? 6 : 2;
+ SWFInputStream tagDataStream = getLimitedStream((int) tagLength);
+ ByteArrayRange dataRange = new ByteArrayRange(swf.uncompressedData, (int) pos, (int) (tagLength + headerLength));
+ TagStub tagStub = new TagStub(swf, tagID, "Unresolved", dataRange, tagDataStream);
+ Tag ret = tagStub;
+ ret.forceWriteAsLong = readLong;
+ skipBytes((int) tagLength);
+
+ if (resolve) {
+ try {
+ ret = resolveTag(ret, level, parallel, skipUnusualTags, gfx);
+ } catch (EndOfStreamException ex) {
+ logger.log(Level.SEVERE, "Problem in " + timelined.toString(), ex);
+ }
+
+ if (Configuration.debugMode.get()) {
+ byte[] data = ret.getOriginalData();
+ byte[] dataNew = ret.getData();
+ int ignoreFirst = 0;
+ for (int i = 0; i < data.length; i++) {
+ if (i >= dataNew.length) {
+ break;
+ }
+ if (dataNew[i] != data[i]) {
+ if (ignoreFirst > 0) {
+ ignoreFirst--;
+ continue;
+ }
+ String e = "TAG " + ret.toString() + " WRONG, ";
+ for (int j = i - 10; j <= i + 5; j++) {
+ while (j < 0) {
+ j++;
+ }
+ if (j >= data.length) {
+ break;
+ }
+ if (j >= dataNew.length) {
+ break;
+ }
+ if (j >= i) {
+ e += (Long.toHexString(data[j] & 0xff) + " ( is " + Long.toHexString(dataNew[j] & 0xff) + ") ");
+ } else {
+ e += (Long.toHexString(data[j] & 0xff) + " ");
+ }
+ }
+ logger.fine(e);
+ }
+ }
+ }
+ }
+ return ret;
+ }
+
+ /**
+ * Reads one Action from the stream
+ *
+ * @param cpool
+ * @return Action or null when ActionEndFlag or end of the stream
+ * @throws IOException
+ */
+ public Action readAction(ConstantPool cpool) throws IOException {
+ int actionCode = -1;
+
+ try {
+ actionCode = readUI8("actionCode");
+ if (actionCode == 0) {
+ return new ActionEnd();
+ }
+ if (actionCode == -1) {
+ return null;
+ }
+ int actionLength = 0;
+ if (actionCode >= 0x80) {
+ actionLength = readUI16("actionLength");
+ }
+ switch (actionCode) {
+ //SWF3 Actions
+ case 0x81:
+ return new ActionGotoFrame(actionLength, this);
+ case 0x83:
+ return new ActionGetURL(actionLength, this, swf.version);
+ case 0x04:
+ return new ActionNextFrame();
+ case 0x05:
+ return new ActionPrevFrame();
+ case 0x06:
+ return new ActionPlay();
+ case 0x07:
+ return new ActionStop();
+ case 0x08:
+ return new ActionToggleQuality();
+ case 0x09:
+ return new ActionStopSounds();
+ case 0x8A:
+ return new ActionWaitForFrame(actionLength, this, cpool);
+ case 0x8B:
+ return new ActionSetTarget(actionLength, this, swf.version);
+ case 0x8C:
+ return new ActionGoToLabel(actionLength, this, swf.version);
+ //SWF4 Actions
+ case 0x96:
+ return new ActionPush(actionLength, this, swf.version);
+ case 0x17:
+ return new ActionPop();
+ case 0x0A:
+ return new ActionAdd();
+ case 0x0B:
+ return new ActionSubtract();
+ case 0x0C:
+ return new ActionMultiply();
+ case 0x0D:
+ return new ActionDivide();
+ case 0x0E:
+ return new ActionEquals();
+ case 0x0F:
+ return new ActionLess();
+ case 0x10:
+ return new ActionAnd();
+ case 0x11:
+ return new ActionOr();
+ case 0x12:
+ return new ActionNot();
+ case 0x13:
+ return new ActionStringEquals();
+ case 0x14:
+ return new ActionStringLength();
+ case 0x21:
+ return new ActionStringAdd();
+ case 0x15:
+ return new ActionStringExtract();
+ case 0x29:
+ return new ActionStringLess();
+ case 0x31:
+ return new ActionMBStringLength();
+ case 0x35:
+ return new ActionMBStringExtract();
+ case 0x18:
+ return new ActionToInteger();
+ case 0x32:
+ return new ActionCharToAscii();
+ case 0x33:
+ return new ActionAsciiToChar();
+ case 0x36:
+ return new ActionMBCharToAscii();
+ case 0x37:
+ return new ActionMBAsciiToChar();
+ case 0x99:
+ return new ActionJump(actionLength, this);
+ case 0x9D:
+ return new ActionIf(actionLength, this);
+ case 0x9E:
+ return new ActionCall(actionLength);
+ case 0x1C:
+ return new ActionGetVariable();
+ case 0x1D:
+ return new ActionSetVariable();
+ case 0x9A:
+ return new ActionGetURL2(actionLength, this);
+ case 0x9F:
+ return new ActionGotoFrame2(actionLength, this);
+ case 0x20:
+ return new ActionSetTarget2();
+ case 0x22:
+ return new ActionGetProperty();
+ case 0x23:
+ return new ActionSetProperty();
+ case 0x24:
+ return new ActionCloneSprite();
+ case 0x25:
+ return new ActionRemoveSprite();
+ case 0x27:
+ return new ActionStartDrag();
+ case 0x28:
+ return new ActionEndDrag();
+ case 0x8D:
+ return new ActionWaitForFrame2(actionLength, this, cpool);
+ case 0x26:
+ return new ActionTrace();
+ case 0x34:
+ return new ActionGetTime();
+ case 0x30:
+ return new ActionRandomNumber();
+ //SWF5 Actions
+ case 0x3D:
+ return new ActionCallFunction();
+ case 0x52:
+ return new ActionCallMethod();
+ case 0x88:
+ return new ActionConstantPool(actionLength, this, swf.version);
+ case 0x9B:
+ return new ActionDefineFunction(actionLength, this, swf.version);
+ case 0x3C:
+ return new ActionDefineLocal();
+ case 0x41:
+ return new ActionDefineLocal2();
+ case 0x3A:
+ return new ActionDelete();
+ case 0x3B:
+ return new ActionDelete2();
+ case 0x46:
+ return new ActionEnumerate();
+ case 0x49:
+ return new ActionEquals2();
+ case 0x4E:
+ return new ActionGetMember();
+ case 0x42:
+ return new ActionInitArray();
+ case 0x43:
+ return new ActionInitObject();
+ case 0x53:
+ return new ActionNewMethod();
+ case 0x40:
+ return new ActionNewObject();
+ case 0x4F:
+ return new ActionSetMember();
+ case 0x45:
+ return new ActionTargetPath();
+ case 0x94:
+ return new ActionWith(actionLength, this, swf.version);
+ case 0x4A:
+ return new ActionToNumber();
+ case 0x4B:
+ return new ActionToString();
+ case 0x44:
+ return new ActionTypeOf();
+ case 0x47:
+ return new ActionAdd2();
+ case 0x48:
+ return new ActionLess2();
+ case 0x3F:
+ return new ActionModulo();
+ case 0x60:
+ return new ActionBitAnd();
+ case 0x63:
+ return new ActionBitLShift();
+ case 0x61:
+ return new ActionBitOr();
+ case 0x64:
+ return new ActionBitRShift();
+ case 0x65:
+ return new ActionBitURShift();
+ case 0x62:
+ return new ActionBitXor();
+ case 0x51:
+ return new ActionDecrement();
+ case 0x50:
+ return new ActionIncrement();
+ case 0x4C:
+ return new ActionPushDuplicate();
+ case 0x3E:
+ return new ActionReturn();
+ case 0x4D:
+ return new ActionStackSwap();
+ case 0x87:
+ return new ActionStoreRegister(actionLength, this);
+ //SWF6 Actions
+ case 0x54:
+ return new ActionInstanceOf();
+ case 0x55:
+ return new ActionEnumerate2();
+ case 0x66:
+ return new ActionStrictEquals();
+ case 0x67:
+ return new ActionGreater();
+ case 0x68:
+ return new ActionStringGreater();
+ //SWF7 Actions
+ case 0x8E:
+ return new ActionDefineFunction2(actionLength, this, swf.version);
+ case 0x69:
+ return new ActionExtends();
+ case 0x2B:
+ return new ActionCastOp();
+ case 0x2C:
+ return new ActionImplementsOp();
+ case 0x8F:
+ return new ActionTry(actionLength, this, swf.version);
+ case 0x2A:
+ return new ActionThrow();
+ default:
+ /*if (actionLength > 0) {
+ //skip(actionLength);
+ }*/
+ //throw new UnknownActionException(actionCode);
+ Action r = new ActionNop();
+ r.actionCode = actionCode;
+ r.actionLength = actionLength;
+ return r;
+ //return new Action(actionCode, actionLength);
+ }
+ } catch (EndOfStreamException | ArrayIndexOutOfBoundsException eos) {
+ return null;
+ }
+ }
+
+ /**
+ * Reads one MATRIX value from the stream
+ *
+ * @param name
+ * @return MATRIX value
+ * @throws IOException
+ */
+ public MATRIX readMatrix(String name) throws IOException {
+ MATRIX ret = new MATRIX();
+ newDumpLevel(name, "MATRIX");
+ ret.hasScale = readUB(1, "hasScale") == 1;
+ if (ret.hasScale) {
+ int NScaleBits = (int) readUB(5, "NScaleBits");
+ ret.scaleX = (int) readSB(NScaleBits, "scaleX");
+ ret.scaleY = (int) readSB(NScaleBits, "scaleY");
+ ret.nScaleBits = NScaleBits;
+ }
+ ret.hasRotate = readUB(1, "hasRotate") == 1;
+ if (ret.hasRotate) {
+ int NRotateBits = (int) readUB(5, "NRotateBits");
+ ret.rotateSkew0 = (int) readSB(NRotateBits, "rotateSkew0");
+ ret.rotateSkew1 = (int) readSB(NRotateBits, "rotateSkew1");
+ ret.nRotateBits = NRotateBits;
+ }
+ int NTranslateBits = (int) readUB(5, "NTranslateBits");
+ ret.translateX = (int) readSB(NTranslateBits, "translateX");
+ ret.translateY = (int) readSB(NTranslateBits, "translateY");
+ ret.nTranslateBits = NTranslateBits;
+ alignByte();
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one CXFORMWITHALPHA value from the stream
+ *
+ * @param name
+ * @return CXFORMWITHALPHA value
+ * @throws IOException
+ */
+ public CXFORMWITHALPHA readCXFORMWITHALPHA(String name) throws IOException {
+ CXFORMWITHALPHA ret = new CXFORMWITHALPHA();
+ newDumpLevel(name, "CXFORMWITHALPHA");
+ ret.hasAddTerms = readUB(1, "hasAddTerms") == 1;
+ ret.hasMultTerms = readUB(1, "hasMultTerms") == 1;
+ int Nbits = (int) readUB(4, "Nbits");
+ ret.nbits = Nbits;
+ if (ret.hasMultTerms) {
+ ret.redMultTerm = (int) readSB(Nbits, "redMultTerm");
+ ret.greenMultTerm = (int) readSB(Nbits, "greenMultTerm");
+ ret.blueMultTerm = (int) readSB(Nbits, "blueMultTerm");
+ ret.alphaMultTerm = (int) readSB(Nbits, "alphaMultTerm");
+ }
+ if (ret.hasAddTerms) {
+ ret.redAddTerm = (int) readSB(Nbits, "redAddTerm");
+ ret.greenAddTerm = (int) readSB(Nbits, "greenAddTerm");
+ ret.blueAddTerm = (int) readSB(Nbits, "blueAddTerm");
+ ret.alphaAddTerm = (int) readSB(Nbits, "alphaAddTerm");
+ }
+ alignByte();
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one CXFORM value from the stream
+ *
+ * @param name
+ * @return CXFORM value
+ * @throws IOException
+ */
+ public CXFORM readCXFORM(String name) throws IOException {
+ CXFORM ret = new CXFORM();
+ newDumpLevel(name, "CXFORM");
+ ret.hasAddTerms = readUB(1, "hasAddTerms") == 1;
+ ret.hasMultTerms = readUB(1, "hasMultTerms") == 1;
+ int Nbits = (int) readUB(4, "Nbits");
+ ret.nbits = Nbits;
+ if (ret.hasMultTerms) {
+ ret.redMultTerm = (int) readSB(Nbits, "redMultTerm");
+ ret.greenMultTerm = (int) readSB(Nbits, "greenMultTerm");
+ ret.blueMultTerm = (int) readSB(Nbits, "blueMultTerm");
+ }
+ if (ret.hasAddTerms) {
+ ret.redAddTerm = (int) readSB(Nbits, "redAddTerm");
+ ret.greenAddTerm = (int) readSB(Nbits, "greenAddTerm");
+ ret.blueAddTerm = (int) readSB(Nbits, "blueAddTerm");
+ }
+ alignByte();
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one CLIPEVENTFLAGS value from the stream
+ *
+ * @param name
+ * @return CLIPEVENTFLAGS value
+ * @throws IOException
+ */
+ public CLIPEVENTFLAGS readCLIPEVENTFLAGS(String name) throws IOException {
+ CLIPEVENTFLAGS ret = new CLIPEVENTFLAGS();
+ newDumpLevel(name, "CLIPEVENTFLAGS");
+ ret.clipEventKeyUp = readUB(1, "clipEventKeyUp") == 1;
+ ret.clipEventKeyDown = readUB(1, "clipEventKeyDown") == 1;
+ ret.clipEventMouseUp = readUB(1, "clipEventMouseUp") == 1;
+ ret.clipEventMouseDown = readUB(1, "clipEventMouseDown") == 1;
+ ret.clipEventMouseMove = readUB(1, "clipEventMouseMove") == 1;
+ ret.clipEventUnload = readUB(1, "clipEventUnload") == 1;
+ ret.clipEventEnterFrame = readUB(1, "clipEventEnterFrame") == 1;
+ ret.clipEventLoad = readUB(1, "clipEventLoad") == 1;
+ ret.clipEventDragOver = readUB(1, "clipEventDragOver") == 1;
+ ret.clipEventRollOut = readUB(1, "clipEventRollOut") == 1;
+ ret.clipEventRollOver = readUB(1, "clipEventRollOver") == 1;
+ ret.clipEventReleaseOutside = readUB(1, "clipEventReleaseOutside") == 1;
+ ret.clipEventRelease = readUB(1, "clipEventRelease") == 1;
+ ret.clipEventPress = readUB(1, "clipEventPress") == 1;
+ ret.clipEventInitialize = readUB(1, "clipEventInitialize") == 1;
+ ret.clipEventData = readUB(1, "clipEventData") == 1;
+ if (swf.version >= 6) {
+ ret.reserved = (int) readUB(5, "reserved");
+ ret.clipEventConstruct = readUB(1, "clipEventConstruct") == 1;
+ ret.clipEventKeyPress = readUB(1, "clipEventKeyPress") == 1;
+ ret.clipEventDragOut = readUB(1, "clipEventDragOut") == 1;
+ ret.reserved2 = (int) readUB(8, "reserved2");
+ }
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one CLIPACTIONRECORD value from the stream
+ *
+ * @param swf
+ * @param tag
+ * @param name
+ * @return CLIPACTIONRECORD value
+ * @throws IOException
+ */
+ public CLIPACTIONRECORD readCLIPACTIONRECORD(SWF swf, Tag tag, String name) throws IOException {
+ newDumpLevel(name, "CLIPACTIONRECORD");
+ CLIPACTIONRECORD ret = new CLIPACTIONRECORD(swf, this, getPos(), tag);
+ endDumpLevel();
+ if (ret.eventFlags.isClear()) {
+ return null;
+ }
+ return ret;
+ }
+
+ /**
+ * Reads one CLIPACTIONS value from the stream
+ *
+ * @param swf
+ * @param tag
+ * @param name
+ * @return CLIPACTIONS value
+ * @throws IOException
+ */
+ public CLIPACTIONS readCLIPACTIONS(SWF swf, Tag tag, String name) throws IOException {
+ CLIPACTIONS ret = new CLIPACTIONS();
+ newDumpLevel(name, "CLIPACTIONS");
+ ret.reserved = readUI16("reserved");
+ ret.allEventFlags = readCLIPEVENTFLAGS("allEventFlags");
+ CLIPACTIONRECORD cr;
+ ret.clipActionRecords = new ArrayList<>();
+ while ((cr = readCLIPACTIONRECORD(swf, tag, "record")) != null) {
+ ret.clipActionRecords.add(cr);
+ }
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one COLORMATRIXFILTER value from the stream
+ *
+ * @param name
+ * @return COLORMATRIXFILTER value
+ * @throws IOException
+ */
+ public COLORMATRIXFILTER readCOLORMATRIXFILTER(String name) throws IOException {
+ COLORMATRIXFILTER ret = new COLORMATRIXFILTER();
+ newDumpLevel(name, "COLORMATRIXFILTER");
+ ret.matrix = new float[20];
+ for (int i = 0; i < 20; i++) {
+ ret.matrix[i] = readFLOAT("cell");
+ }
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one RGBA value from the stream
+ *
+ * @param name
+ * @return RGBA value
+ * @throws IOException
+ */
+ public RGBA readRGBA(String name) throws IOException {
+ RGBA ret = new RGBA();
+ newDumpLevel(name, "RGBA");
+ ret.red = readUI8("red");
+ ret.green = readUI8("green");
+ ret.blue = readUI8("blue");
+ ret.alpha = readUI8("alpha");
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one ARGB value from the stream
+ *
+ * @param name
+ * @return ARGB value
+ * @throws IOException
+ */
+ public ARGB readARGB(String name) throws IOException {
+ ARGB ret = new ARGB();
+ newDumpLevel(name, "ARGB");
+ ret.alpha = readUI8("alpha");
+ ret.red = readUI8("red");
+ ret.green = readUI8("green");
+ ret.blue = readUI8("blue");
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one RGB value from the stream
+ *
+ * @param name
+ * @return RGB value
+ * @throws IOException
+ */
+ public RGB readRGB(String name) throws IOException {
+ RGB ret = new RGB();
+ newDumpLevel(name, "RGB");
+ ret.red = readUI8("red");
+ ret.green = readUI8("green");
+ ret.blue = readUI8("blue");
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one CONVOLUTIONFILTER value from the stream
+ *
+ * @param name
+ * @return CONVOLUTIONFILTER value
+ * @throws IOException
+ */
+ public CONVOLUTIONFILTER readCONVOLUTIONFILTER(String name) throws IOException {
+ CONVOLUTIONFILTER ret = new CONVOLUTIONFILTER();
+ newDumpLevel(name, "CONVOLUTIONFILTER");
+ ret.matrixX = readUI8("matrixX");
+ ret.matrixY = readUI8("matrixY");
+ ret.divisor = readFLOAT("divisor");
+ ret.bias = readFLOAT("bias");
+ ret.matrix = new float[ret.matrixX][ret.matrixY];
+ for (int x = 0; x < ret.matrixX; x++) {
+ for (int y = 0; y < ret.matrixY; y++) {
+ ret.matrix[x][y] = readFLOAT("cell");
+ }
+ }
+ ret.defaultColor = readRGBA("defaultColor");
+ ret.reserved = (int) readUB(6, "reserved");
+ ret.clamp = readUB(1, "clamp") == 1;
+ ret.preserveAlpha = readUB(1, "preserveAlpha") == 1;
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one BLURFILTER value from the stream
+ *
+ * @param name
+ * @return BLURFILTER value
+ * @throws IOException
+ */
+ public BLURFILTER readBLURFILTER(String name) throws IOException {
+ BLURFILTER ret = new BLURFILTER();
+ newDumpLevel(name, "BLURFILTER");
+ ret.blurX = readFIXED("blurX");
+ ret.blurY = readFIXED("blurY");
+ ret.passes = (int) readUB(5, "passes");
+ ret.reserved = (int) readUB(3, "reserved");
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one DROPSHADOWFILTER value from the stream
+ *
+ * @param name
+ * @return DROPSHADOWFILTER value
+ * @throws IOException
+ */
+ public DROPSHADOWFILTER readDROPSHADOWFILTER(String name) throws IOException {
+ DROPSHADOWFILTER ret = new DROPSHADOWFILTER();
+ newDumpLevel(name, "DROPSHADOWFILTER");
+ ret.dropShadowColor = readRGBA("dropShadowColor");
+ ret.blurX = readFIXED("blurX");
+ ret.blurY = readFIXED("blurY");
+ ret.angle = readFIXED("angle");
+ ret.distance = readFIXED("distance");
+ ret.strength = readFIXED8("strength");
+ ret.innerShadow = readUB(1, "innerShadow") == 1;
+ ret.knockout = readUB(1, "knockout") == 1;
+ ret.compositeSource = readUB(1, "compositeSource") == 1;
+ ret.passes = (int) readUB(5, "passes");
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one GLOWFILTER value from the stream
+ *
+ * @param name
+ * @return GLOWFILTER value
+ * @throws IOException
+ */
+ public GLOWFILTER readGLOWFILTER(String name) throws IOException {
+ GLOWFILTER ret = new GLOWFILTER();
+ newDumpLevel(name, "GLOWFILTER");
+ ret.glowColor = readRGBA("glowColor");
+ ret.blurX = readFIXED("blurX");
+ ret.blurY = readFIXED("blurY");
+ ret.strength = readFIXED8("strength");
+ ret.innerGlow = readUB(1, "innerGlow") == 1;
+ ret.knockout = readUB(1, "knockout") == 1;
+ ret.compositeSource = readUB(1, "compositeSource") == 1;
+ ret.passes = (int) readUB(5, "passes");
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one BEVELFILTER value from the stream
+ *
+ * @param name
+ * @return BEVELFILTER value
+ * @throws IOException
+ */
+ public BEVELFILTER readBEVELFILTER(String name) throws IOException {
+ BEVELFILTER ret = new BEVELFILTER();
+ newDumpLevel(name, "BEVELFILTER");
+ ret.highlightColor = readRGBA("highlightColor"); //Highlight color first. It it opposite of the documentation
+ ret.shadowColor = readRGBA("shadowColor");
+ ret.blurX = readFIXED("blurX");
+ ret.blurY = readFIXED("blurY");
+ ret.angle = readFIXED("angle");
+ ret.distance = readFIXED("distance");
+ ret.strength = readFIXED8("strength");
+ ret.innerShadow = readUB(1, "innerShadow") == 1;
+ ret.knockout = readUB(1, "knockout") == 1;
+ ret.compositeSource = readUB(1, "compositeSource") == 1;
+ ret.onTop = readUB(1, "onTop") == 1;
+ ret.passes = (int) readUB(4, "passes");
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one GRADIENTGLOWFILTER value from the stream
+ *
+ * @param name
+ * @return GRADIENTGLOWFILTER value
+ * @throws IOException
+ */
+ public GRADIENTGLOWFILTER readGRADIENTGLOWFILTER(String name) throws IOException {
+ GRADIENTGLOWFILTER ret = new GRADIENTGLOWFILTER();
+ newDumpLevel(name, "GRADIENTGLOWFILTER");
+ int numColors = readUI8("numColors");
+ ret.gradientColors = new RGBA[numColors];
+ ret.gradientRatio = new int[numColors];
+ for (int i = 0; i < numColors; i++) {
+ ret.gradientColors[i] = readRGBA("gradientColor");
+ }
+ for (int i = 0; i < numColors; i++) {
+ ret.gradientRatio[i] = readUI8("gradientRatio");
+ }
+ ret.blurX = readFIXED("blurX");
+ ret.blurY = readFIXED("blurY");
+ ret.angle = readFIXED("angle");
+ ret.distance = readFIXED("distance");
+ ret.strength = readFIXED8("strength");
+ ret.innerShadow = readUB(1, "innerShadow") == 1;
+ ret.knockout = readUB(1, "knockout") == 1;
+ ret.compositeSource = readUB(1, "compositeSource") == 1;
+ ret.onTop = readUB(1, "onTop") == 1;
+ ret.passes = (int) readUB(4, "passes");
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one GRADIENTBEVELFILTER value from the stream
+ *
+ * @param name
+ * @return GRADIENTBEVELFILTER value
+ * @throws IOException
+ */
+ public GRADIENTBEVELFILTER readGRADIENTBEVELFILTER(String name) throws IOException {
+ GRADIENTBEVELFILTER ret = new GRADIENTBEVELFILTER();
+ newDumpLevel(name, "GRADIENTBEVELFILTER");
+ int numColors = readUI8("numColors");
+ ret.gradientColors = new RGBA[numColors];
+ ret.gradientRatio = new int[numColors];
+ for (int i = 0; i < numColors; i++) {
+ ret.gradientColors[i] = readRGBA("gradientColor");
+ }
+ for (int i = 0; i < numColors; i++) {
+ ret.gradientRatio[i] = readUI8("gradientRatio");
+ }
+ ret.blurX = readFIXED("blurX");
+ ret.blurY = readFIXED("blurY");
+ ret.angle = readFIXED("angle");
+ ret.distance = readFIXED("distance");
+ ret.strength = readFIXED8("strength");
+ ret.innerShadow = readUB(1, "innerShadow") == 1;
+ ret.knockout = readUB(1, "knockout") == 1;
+ ret.compositeSource = readUB(1, "compositeSource") == 1;
+ ret.onTop = readUB(1, "onTop") == 1;
+ ret.passes = (int) readUB(4, "passes");
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads list of FILTER values from the stream
+ *
+ * @param name
+ * @return List of FILTER values
+ * @throws IOException
+ */
+ public List readFILTERLIST(String name) throws IOException {
+ List ret = new ArrayList<>();
+ newDumpLevel(name, "FILTERLIST");
+ int numberOfFilters = readUI8("numberOfFilters");
+ for (int i = 0; i < numberOfFilters; i++) {
+ ret.add(readFILTER("filter"));
+ }
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one FILTER value from the stream
+ *
+ * @param name
+ * @return FILTER value
+ * @throws IOException
+ */
+ public FILTER readFILTER(String name) throws IOException {
+ newDumpLevel(name, "FILTER");
+ int filterId = readUI8("filterId");
+ FILTER ret = null;
+ switch (filterId) {
+ case 0:
+ ret = readDROPSHADOWFILTER("filter");
+ break;
+ case 1:
+ ret = readBLURFILTER("filter");
+ break;
+ case 2:
+ ret = readGLOWFILTER("filter");
+ break;
+ case 3:
+ ret = readBEVELFILTER("filter");
+ break;
+ case 4:
+ ret = readGRADIENTGLOWFILTER("filter");
+ break;
+ case 5:
+ ret = readCONVOLUTIONFILTER("filter");
+ break;
+ case 6:
+ ret = readCOLORMATRIXFILTER("filter");
+ break;
+ case 7:
+ ret = readGRADIENTBEVELFILTER("filter");
+ break;
+ }
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads list of BUTTONRECORD values from the stream
+ *
+ * @param inDefineButton2 Whether read from inside of DefineButton2Tag or
+ * not
+ * @param name
+ * @return List of BUTTONRECORD values
+ * @throws IOException
+ */
+ public List readBUTTONRECORDList(boolean inDefineButton2, String name) throws IOException {
+ List ret = new ArrayList<>();
+ newDumpLevel(name, "BUTTONRECORDList");
+ BUTTONRECORD br;
+ while ((br = readBUTTONRECORD(inDefineButton2, "record")) != null) {
+ ret.add(br);
+ }
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one BUTTONRECORD value from the stream
+ *
+ * @param inDefineButton2 True when in DefineButton2
+ * @param name
+ * @return BUTTONRECORD value
+ * @throws IOException
+ */
+ public BUTTONRECORD readBUTTONRECORD(boolean inDefineButton2, String name) throws IOException {
+ BUTTONRECORD ret = new BUTTONRECORD();
+ newDumpLevel(name, "BUTTONRECORD");
+ ret.reserved = (int) readUB(2, "reserved");
+ ret.buttonHasBlendMode = readUB(1, "buttonHasBlendMode") == 1;
+ ret.buttonHasFilterList = readUB(1, "buttonHasFilterList") == 1;
+ ret.buttonStateHitTest = readUB(1, "buttonStateHitTest") == 1;
+ ret.buttonStateDown = readUB(1, "buttonStateDown") == 1;
+ ret.buttonStateOver = readUB(1, "buttonStateOver") == 1;
+ ret.buttonStateUp = readUB(1, "buttonStateUp") == 1;
+
+ if (!ret.buttonHasBlendMode && !ret.buttonHasFilterList
+ && !ret.buttonStateHitTest && !ret.buttonStateDown
+ && !ret.buttonStateOver && !ret.buttonStateUp && ret.reserved == 0) {
+ return null;
+ }
+
+ ret.characterId = readUI16("characterId");
+ ret.placeDepth = readUI16("placeDepth");
+ ret.placeMatrix = readMatrix("placeMatrix");
+ if (inDefineButton2) {
+ ret.colorTransform = readCXFORMWITHALPHA("colorTransform");
+ if (ret.buttonHasFilterList) {
+ ret.filterList = readFILTERLIST("filterList");
+ }
+ if (ret.buttonHasBlendMode) {
+ ret.blendMode = readUI8("blendMode");
+ }
+ }
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads list of BUTTONCONDACTION values from the stream
+ *
+ * @param swf
+ * @param tag
+ * @param name
+ * @return List of BUTTONCONDACTION values
+ * @throws IOException
+ */
+ public List readBUTTONCONDACTIONList(SWF swf, Tag tag, String name) throws IOException {
+ List ret = new ArrayList<>();
+ newDumpLevel(name, "BUTTONCONDACTIONList");
+ BUTTONCONDACTION bc;
+ while (!(bc = readBUTTONCONDACTION(swf, tag, "action")).isLast) {
+ ret.add(bc);
+ }
+ ret.add(bc);
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one BUTTONCONDACTION value from the stream
+ *
+ * @param swf
+ * @param tag
+ * @param name
+ * @return BUTTONCONDACTION value
+ * @throws IOException
+ */
+ public BUTTONCONDACTION readBUTTONCONDACTION(SWF swf, Tag tag, String name) throws IOException {
+ newDumpLevel(name, "BUTTONCONDACTION");
+ BUTTONCONDACTION ret = new BUTTONCONDACTION(swf, this, getPos(), tag);
+ //ret.actions = readActionList();
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one GRADRECORD value from the stream
+ *
+ * @param shapeNum 1 in DefineShape, 2 in DefineShape2...
+ * @param name
+ * @return GRADRECORD value
+ * @throws IOException
+ */
+ public GRADRECORD readGRADRECORD(int shapeNum, String name) throws IOException {
+ GRADRECORD ret = new GRADRECORD();
+ newDumpLevel(name, "GRADRECORD");
+ ret.ratio = readUI8("ratio");
+ if (shapeNum >= 3) {
+ ret.color = readRGBA("color");
+ } else {
+ ret.color = readRGB("color");
+ }
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one GRADIENT value from the stream
+ *
+ * @param shapeNum 1 in DefineShape, 2 in DefineShape2...
+ * @param name
+ * @return GRADIENT value
+ * @throws IOException
+ */
+ public GRADIENT readGRADIENT(int shapeNum, String name) throws IOException {
+ GRADIENT ret = new GRADIENT();
+ newDumpLevel(name, "GRADIENT");
+ ret.spreadMode = (int) readUB(2, "spreadMode");
+ ret.interpolationMode = (int) readUB(2, "interpolationMode");
+ int numGradients = (int) readUB(4, "numGradients");
+ ret.gradientRecords = new GRADRECORD[numGradients];
+ for (int i = 0; i < numGradients; i++) {
+ ret.gradientRecords[i] = readGRADRECORD(shapeNum, "gradientRecord");
+
+ }
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one FOCALGRADIENT value from the stream
+ *
+ * @param shapeNum 1 in DefineShape, 2 in DefineShape2...
+ * @param name
+ * @return FOCALGRADIENT value
+ * @throws IOException
+ */
+ public FOCALGRADIENT readFOCALGRADIENT(int shapeNum, String name) throws IOException {
+ FOCALGRADIENT ret = new FOCALGRADIENT();
+ newDumpLevel(name, "FOCALGRADIENT");
+ ret.spreadMode = (int) readUB(2, "spreadMode");
+ ret.interpolationMode = (int) readUB(2, "interpolationMode");
+ int numGradients = (int) readUB(4, "numGradients");
+ ret.gradientRecords = new GRADRECORD[numGradients];
+ for (int i = 0; i < numGradients; i++) {
+ ret.gradientRecords[i] = readGRADRECORD(shapeNum, "gradientRecord");
+ }
+ ret.focalPoint = readFIXED8("focalPoint");
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one FILLSTYLE value from the stream
+ *
+ * @param shapeNum 1 in DefineShape, 2 in DefineShape2...
+ * @param name
+ * @return FILLSTYLE value
+ * @throws IOException
+ */
+ public FILLSTYLE readFILLSTYLE(int shapeNum, String name) throws IOException {
+ FILLSTYLE ret = new FILLSTYLE();
+ newDumpLevel(name, "FILLSTYLE");
+ ret.fillStyleType = readUI8("fillStyleType");
+ if (ret.fillStyleType == FILLSTYLE.SOLID) {
+ if (shapeNum >= 3) {
+ ret.color = readRGBA("color");
+ } else {
+ ret.color = readRGB("color");
+ }
+ }
+ if ((ret.fillStyleType == FILLSTYLE.LINEAR_GRADIENT)
+ || (ret.fillStyleType == FILLSTYLE.RADIAL_GRADIENT)
+ || (ret.fillStyleType == FILLSTYLE.FOCAL_RADIAL_GRADIENT)) {
+ ret.gradientMatrix = readMatrix("gradientMatrix");
+ }
+ if ((ret.fillStyleType == FILLSTYLE.LINEAR_GRADIENT)
+ || (ret.fillStyleType == FILLSTYLE.RADIAL_GRADIENT)) {
+ ret.gradient = readGRADIENT(shapeNum, "gradient");
+ }
+ if (ret.fillStyleType == FILLSTYLE.FOCAL_RADIAL_GRADIENT) {
+ ret.gradient = readFOCALGRADIENT(shapeNum, "gradient");
+ }
+
+ if ((ret.fillStyleType == FILLSTYLE.REPEATING_BITMAP)
+ || (ret.fillStyleType == FILLSTYLE.CLIPPED_BITMAP)
+ || (ret.fillStyleType == FILLSTYLE.NON_SMOOTHED_REPEATING_BITMAP)
+ || (ret.fillStyleType == FILLSTYLE.NON_SMOOTHED_CLIPPED_BITMAP)) {
+ ret.bitmapId = readUI16("bitmapId");
+ ret.bitmapMatrix = readMatrix("bitmapMatrix");
+ }
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one FILLSTYLEARRAY value from the stream
+ *
+ * @param shapeNum 1 in DefineShape, 2 in DefineShape2...
+ * @param name
+ * @return FILLSTYLEARRAY value
+ * @throws IOException
+ */
+ public FILLSTYLEARRAY readFILLSTYLEARRAY(int shapeNum, String name) throws IOException {
+
+ FILLSTYLEARRAY ret = new FILLSTYLEARRAY();
+ newDumpLevel(name, "FILLSTYLEARRAY");
+ int fillStyleCount = readUI8("fillStyleCount");
+ if (((shapeNum == 2) || (shapeNum == 3) || (shapeNum == 4/*?*/)) && (fillStyleCount == 0xff)) {
+ fillStyleCount = readUI16("fillStyleCount");
+ }
+ ret.fillStyles = new FILLSTYLE[fillStyleCount];
+ for (int i = 0; i < fillStyleCount; i++) {
+ ret.fillStyles[i] = readFILLSTYLE(shapeNum, "fillStyle");
+ }
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one LINESTYLE value from the stream
+ *
+ * @param shapeNum 1 in DefineShape, 2 in DefineShape2...
+ * @param name
+ * @return LINESTYLE value
+ * @throws IOException
+ */
+ public LINESTYLE readLINESTYLE(int shapeNum, String name) throws IOException {
+ LINESTYLE ret = new LINESTYLE();
+ newDumpLevel(name, "LINESTYLE");
+ ret.width = readUI16("width");
+ if ((shapeNum == 1) || (shapeNum == 2)) {
+ ret.color = readRGB("color");
+ }
+ if (shapeNum == 3) {
+ ret.color = readRGBA("color");
+ }
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one LINESTYLE2 value from the stream
+ *
+ * @param shapeNum 1 in DefineShape, 2 in DefineShape2...
+ * @param name
+ * @return LINESTYLE2 value
+ * @throws IOException
+ */
+ public LINESTYLE2 readLINESTYLE2(int shapeNum, String name) throws IOException {
+ LINESTYLE2 ret = new LINESTYLE2();
+ newDumpLevel(name, "LINESTYLE2");
+ ret.width = readUI16("width");
+ ret.startCapStyle = (int) readUB(2, "startCapStyle");
+ ret.joinStyle = (int) readUB(2, "joinStyle");
+ ret.hasFillFlag = (int) readUB(1, "hasFillFlag") == 1;
+ ret.noHScaleFlag = (int) readUB(1, "noHScaleFlag") == 1;
+ ret.noVScaleFlag = (int) readUB(1, "noVScaleFlag") == 1;
+ ret.pixelHintingFlag = (int) readUB(1, "pixelHintingFlag") == 1;
+ ret.reserved = (int) readUB(5, "reserved");
+ ret.noClose = (int) readUB(1, "noClose") == 1;
+ ret.endCapStyle = (int) readUB(2, "endCapStyle");
+ if (ret.joinStyle == LINESTYLE2.MITER_JOIN) {
+ ret.miterLimitFactor = readUI16("miterLimitFactor");
+ }
+ if (!ret.hasFillFlag) {
+ ret.color = readRGBA("color");
+ } else {
+ ret.fillType = readFILLSTYLE(shapeNum, "fillType");
+ }
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one LINESTYLEARRAY value from the stream
+ *
+ * @param shapeNum 1 in DefineShape, 2 in DefineShape2...
+ * @param name
+ * @return LINESTYLEARRAY value
+ * @throws IOException
+ */
+ public LINESTYLEARRAY readLINESTYLEARRAY(int shapeNum, String name) throws IOException {
+ LINESTYLEARRAY ret = new LINESTYLEARRAY();
+ newDumpLevel(name, "LINESTYLEARRAY");
+ int lineStyleCount = readUI8("lineStyleCount");
+ if (lineStyleCount == 0xff) {
+ lineStyleCount = readUI16("lineStyleCount");
+ }
+ if ((shapeNum == 1 || shapeNum == 2 || shapeNum == 3)) {
+ ret.lineStyles = new LINESTYLE[lineStyleCount];
+ for (int i = 0; i < lineStyleCount; i++) {
+ ret.lineStyles[i] = readLINESTYLE(shapeNum, "lineStyle");
+ }
+ } else if (shapeNum == 4) {
+ ret.lineStyles = new LINESTYLE2[lineStyleCount];
+ for (int i = 0; i < lineStyleCount; i++) {
+ ret.lineStyles[i] = readLINESTYLE2(shapeNum, "lineStyle");
+ }
+ }
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one SHAPERECORD value from the stream
+ *
+ * @param fillBits
+ * @param lineBits
+ * @param shapeNum 1 in DefineShape, 2 in DefineShape2...
+ * @return SHAPERECORD value
+ * @throws IOException
+ */
+ private SHAPERECORD readSHAPERECORD(int fillBits, int lineBits, int shapeNum, boolean morphShape, String name) throws IOException {
+ SHAPERECORD ret;
+ newDumpLevel(name, "SHAPERECORD");
+ int typeFlag = (int) readUB(1, "typeFlag");
+ if (typeFlag == 0) {
+ boolean stateNewStyles = readUB(1, "stateNewStyles") == 1;
+ boolean stateLineStyle = readUB(1, "stateLineStyle") == 1;
+ boolean stateFillStyle1 = readUB(1, "stateFillStyle1") == 1;
+ boolean stateFillStyle0 = readUB(1, "stateFillStyle0") == 1;
+ boolean stateMoveTo = readUB(1, "stateMoveTo") == 1;
+ if ((!stateNewStyles) && (!stateLineStyle) && (!stateFillStyle1) && (!stateFillStyle0) && (!stateMoveTo)) {
+ ret = new EndShapeRecord();
+ } else {
+ StyleChangeRecord scr = new StyleChangeRecord();
+ scr.stateNewStyles = stateNewStyles;
+ scr.stateLineStyle = stateLineStyle;
+ scr.stateFillStyle0 = stateFillStyle0;
+ scr.stateFillStyle1 = stateFillStyle1;
+ scr.stateMoveTo = stateMoveTo;
+ if (stateMoveTo) {
+ scr.moveBits = (int) readUB(5, "moveBits");
+ scr.moveDeltaX = (int) readSB(scr.moveBits, "moveDeltaX");
+ scr.moveDeltaY = (int) readSB(scr.moveBits, "moveDeltaY");
+ }
+ if (stateFillStyle0) {
+ scr.fillStyle0 = (int) readUB(fillBits, "fillStyle0");
+ }
+ if (stateFillStyle1) {
+ scr.fillStyle1 = (int) readUB(fillBits, "fillStyle1");
+ }
+ if (stateLineStyle) {
+ scr.lineStyle = (int) readUB(lineBits, "lineStyle");
+ }
+ if (stateNewStyles) {
+ if (morphShape) {
+ //This should never happen
+ } else {
+ scr.fillStyles = readFILLSTYLEARRAY(shapeNum, "fillStyles");
+ scr.lineStyles = readLINESTYLEARRAY(shapeNum, "lineStyles");
+ }
+ scr.numFillBits = (int) readUB(4, "numFillBits");
+ scr.numLineBits = (int) readUB(4, "numLineBits");
+ }
+ ret = scr;
+ }
+ } else {//typeFlag==1
+ int straightFlag = (int) readUB(1, "straightFlag");
+ if (straightFlag == 1) {
+ StraightEdgeRecord ser = new StraightEdgeRecord();
+ ser.numBits = (int) readUB(4, "numBits");
+ ser.generalLineFlag = readUB(1, "generalLineFlag") == 1;
+ if (!ser.generalLineFlag) {
+ ser.vertLineFlag = readUB(1, "vertLineFlag") == 1;
+ }
+ if (ser.generalLineFlag || (!ser.vertLineFlag)) {
+ ser.deltaX = (int) readSB(ser.numBits + 2, "deltaX");
+ }
+ if (ser.generalLineFlag || (ser.vertLineFlag)) {
+ ser.deltaY = (int) readSB(ser.numBits + 2, "deltaY");
+ }
+ ret = ser;
+ } else {
+ CurvedEdgeRecord cer = new CurvedEdgeRecord();
+ cer.numBits = (int) readUB(4, "numBits");
+ cer.controlDeltaX = (int) readSB(cer.numBits + 2, "controlDeltaX");
+ cer.controlDeltaY = (int) readSB(cer.numBits + 2, "controlDeltaY");
+ cer.anchorDeltaX = (int) readSB(cer.numBits + 2, "anchorDeltaX");
+ cer.anchorDeltaY = (int) readSB(cer.numBits + 2, "anchorDeltaY");
+ ret = cer;
+ }
+ }
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one SHAPE value from the stream
+ *
+ * @param shapeNum 1 in DefineShape, 2 in DefineShape2...
+ * @param morphShape
+ * @param name
+ * @return SHAPE value
+ * @throws IOException
+ */
+ public SHAPE readSHAPE(int shapeNum, boolean morphShape, String name) throws IOException {
+ SHAPE ret = new SHAPE();
+ newDumpLevel(name, "SHAPE");
+ ret.numFillBits = (int) readUB(4, "numFillBits");
+ ret.numLineBits = (int) readUB(4, "numLineBits");
+ ret.shapeRecords = readSHAPERECORDS(shapeNum, ret.numFillBits, ret.numLineBits, morphShape, "shapeRecords");
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one SHAPEWITHSTYLE value from the stream
+ *
+ * @param shapeNum 1 in DefineShape, 2 in DefineShape2...
+ * @param morphShape
+ * @param name
+ * @return SHAPEWITHSTYLE value
+ * @throws IOException
+ */
+ public SHAPEWITHSTYLE readSHAPEWITHSTYLE(int shapeNum, boolean morphShape, String name) throws IOException {
+ SHAPEWITHSTYLE ret = new SHAPEWITHSTYLE();
+ newDumpLevel(name, "SHAPEWITHSTYLE");
+ ret.fillStyles = readFILLSTYLEARRAY(shapeNum, "fillStyles");
+ ret.lineStyles = readLINESTYLEARRAY(shapeNum, "lineStyles");
+ ret.numFillBits = (int) readUB(4, "numFillBits");
+ ret.numLineBits = (int) readUB(4, "numLineBits");
+ ret.shapeRecords = readSHAPERECORDS(shapeNum, ret.numFillBits, ret.numLineBits, morphShape, "shapeRecords");
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads list of SHAPERECORDs from the stream
+ *
+ * @param shapeNum 1 in DefineShape, 2 in DefineShape2...
+ * @param fillBits
+ * @param lineBits
+ * @return SHAPERECORDs array
+ * @throws IOException
+ */
+ private List readSHAPERECORDS(int shapeNum, int fillBits, int lineBits, boolean morphShape, String name) throws IOException {
+ List ret = new ArrayList<>();
+ newDumpLevel(name, "SHAPERECORDS");
+ SHAPERECORD rec;
+ do {
+ rec = readSHAPERECORD(fillBits, lineBits, shapeNum, morphShape, "record");
+ if (rec instanceof StyleChangeRecord) {
+ StyleChangeRecord scRec = (StyleChangeRecord) rec;
+ if (scRec.stateNewStyles) {
+ fillBits = scRec.numFillBits;
+ lineBits = scRec.numLineBits;
+ }
+ }
+ ret.add(rec);
+ } while (!(rec instanceof EndShapeRecord));
+ alignByte();
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one SOUNDINFO value from the stream
+ *
+ * @param name
+ * @return SOUNDINFO value
+ * @throws IOException
+ */
+ public SOUNDINFO readSOUNDINFO(String name) throws IOException {
+ SOUNDINFO ret = new SOUNDINFO();
+ newDumpLevel(name, "SOUNDINFO");
+ ret.reserved = (int) readUB(2, "reserved");
+ ret.syncStop = readUB(1, "syncStop") == 1;
+ ret.syncNoMultiple = readUB(1, "syncNoMultiple") == 1;
+ ret.hasEnvelope = readUB(1, "hasEnvelope") == 1;
+ ret.hasLoops = readUB(1, "hasLoops") == 1;
+ ret.hasOutPoint = readUB(1, "hasOutPoint") == 1;
+ ret.hasInPoint = readUB(1, "hasInPoint") == 1;
+ if (ret.hasInPoint) {
+ ret.inPoint = readUI32("inPoint");
+ }
+ if (ret.hasOutPoint) {
+ ret.outPoint = readUI32("outPoint");
+ }
+ if (ret.hasLoops) {
+ ret.loopCount = readUI16("loopCount");
+ }
+ if (ret.hasEnvelope) {
+ int envPoints = readUI8("envPoints");
+ ret.envelopeRecords = new SOUNDENVELOPE[envPoints];
+ for (int i = 0; i < envPoints; i++) {
+ ret.envelopeRecords[i] = readSOUNDENVELOPE("envelopeRecord");
+ }
+ }
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one SOUNDENVELOPE value from the stream
+ *
+ * @param name
+ * @return SOUNDENVELOPE value
+ * @throws IOException
+ */
+ public SOUNDENVELOPE readSOUNDENVELOPE(String name) throws IOException {
+ SOUNDENVELOPE ret = new SOUNDENVELOPE();
+ newDumpLevel(name, "SOUNDENVELOPE");
+ ret.pos44 = readUI32("pos44");
+ ret.leftLevel = readUI16("leftLevel");
+ ret.rightLevel = readUI16("rightLevel");
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one GLYPHENTRY value from the stream
+ *
+ * @param glyphBits
+ * @param advanceBits
+ * @param name
+ * @return GLYPHENTRY value
+ * @throws IOException
+ */
+ public GLYPHENTRY readGLYPHENTRY(int glyphBits, int advanceBits, String name) throws IOException {
+ GLYPHENTRY ret = new GLYPHENTRY();
+ newDumpLevel(name, "GLYPHENTRY");
+ ret.glyphIndex = (int) readUB(glyphBits, "glyphIndex");
+ ret.glyphAdvance = (int) readUB(advanceBits, "glyphAdvance");
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one TEXTRECORD value from the stream
+ *
+ * @param inDefineText2
+ * @param glyphBits
+ * @param advanceBits
+ * @param name
+ * @return TEXTRECORD value
+ * @throws IOException
+ */
+ public TEXTRECORD readTEXTRECORD(boolean inDefineText2, int glyphBits, int advanceBits, String name) throws IOException {
+ TEXTRECORD ret = new TEXTRECORD();
+ newDumpLevel(name, "TEXTRECORD");
+ int first = (int) readUB(1, "first"); //always 1
+ readUB(3, "styleFlagsHasReserved"); //always 0
+ ret.styleFlagsHasFont = readUB(1, "styleFlagsHasFont") == 1;
+ ret.styleFlagsHasColor = readUB(1, "styleFlagsHasColor") == 1;
+ ret.styleFlagsHasYOffset = readUB(1, "styleFlagsHasYOffset") == 1;
+ ret.styleFlagsHasXOffset = readUB(1, "styleFlagsHasXOffset") == 1;
+ if ((!ret.styleFlagsHasFont) && (!ret.styleFlagsHasColor) && (!ret.styleFlagsHasYOffset) && (!ret.styleFlagsHasXOffset) && (first == 0)) { //final text record
+ endDumpLevel();
+ return null;
+ }
+ if (ret.styleFlagsHasFont) {
+ ret.fontId = readUI16("fontId");
+ }
+ if (ret.styleFlagsHasColor) {
+ if (inDefineText2) {
+ ret.textColorA = readRGBA("textColorA");
+ } else {
+ ret.textColor = readRGB("textColor");
+ }
+ }
+ if (ret.styleFlagsHasXOffset) {
+ ret.xOffset = readSI16("xOffset");
+ }
+ if (ret.styleFlagsHasYOffset) {
+ ret.yOffset = readSI16("yOffset");
+ }
+ if (ret.styleFlagsHasFont) {
+ ret.textHeight = readUI16("textHeight");
+ }
+ int glyphCount = readUI8("glyphCount");
+ ret.glyphEntries = new GLYPHENTRY[glyphCount];
+ for (int i = 0; i < glyphCount; i++) {
+ ret.glyphEntries[i] = readGLYPHENTRY(glyphBits, advanceBits, "glyphEntry");
+ }
+ alignByte();
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one MORPHGRADRECORD value from the stream
+ *
+ * @param name
+ * @return MORPHGRADRECORD value
+ * @throws IOException
+ */
+ public MORPHGRADRECORD readMORPHGRADRECORD(String name) throws IOException {
+ MORPHGRADRECORD ret = new MORPHGRADRECORD();
+ newDumpLevel(name, "MORPHGRADRECORD");
+ ret.startRatio = readUI8("startRatio");
+ ret.startColor = readRGBA("startColor");
+ ret.endRatio = readUI8("endRatio");
+ ret.endColor = readRGBA("endColor");
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one MORPHGRADIENT value from the stream
+ *
+ * @param name
+ * @return MORPHGRADIENT value
+ * @throws IOException
+ */
+ public MORPHGRADIENT readMORPHGRADIENT(String name) throws IOException {
+ MORPHGRADIENT ret = new MORPHGRADIENT();
+ newDumpLevel(name, "MORPHGRADIENT");
+ //Despite of documentation (UI8 1-8), there are two fields
+ // spreadMode and interPolationMode which are same as in GRADIENT
+ ret.spreadMode = (int) readUB(2, "spreadMode");
+ ret.interPolationMode = (int) readUB(2, "interPolationMode");
+ int numGradients = (int) readUB(4, "numGradients");
+ ret.gradientRecords = new MORPHGRADRECORD[numGradients];
+ for (int i = 0; i < numGradients; i++) {
+ ret.gradientRecords[i] = readMORPHGRADRECORD("gradientRecord");
+ }
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one MORPHFOCALGRADIENT value from the stream
+ *
+ * This is undocumented feature
+ *
+ * @param name
+ * @return MORPHGRADIENT value
+ * @throws IOException
+ */
+ public MORPHFOCALGRADIENT readMORPHFOCALGRADIENT(String name) throws IOException {
+ MORPHFOCALGRADIENT ret = new MORPHFOCALGRADIENT();
+ newDumpLevel(name, "MORPHFOCALGRADIENT");
+ ret.spreadMode = (int) readUB(2, "spreadMode");
+ ret.interPolationMode = (int) readUB(2, "interPolationMode");
+ int numGradients = (int) readUB(4, "numGradients");
+ ret.gradientRecords = new MORPHGRADRECORD[numGradients];
+ for (int i = 0; i < numGradients; i++) {
+ ret.gradientRecords[i] = readMORPHGRADRECORD("gradientRecord");
+ }
+ ret.startFocalPoint = readFIXED8("startFocalPoint");
+ ret.endFocalPoint = readFIXED8("endFocalPoint");
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one MORPHFILLSTYLE value from the stream
+ *
+ * @param name
+ * @return MORPHFILLSTYLE value
+ * @throws IOException
+ */
+ public MORPHFILLSTYLE readMORPHFILLSTYLE(String name) throws IOException {
+ MORPHFILLSTYLE ret = new MORPHFILLSTYLE();
+ newDumpLevel(name, "MORPHFILLSTYLE");
+ ret.fillStyleType = readUI8("fillStyleType");
+ if (ret.fillStyleType == MORPHFILLSTYLE.SOLID) {
+ ret.startColor = readRGBA("startColor");
+ ret.endColor = readRGBA("endColor");
+ }
+ if ((ret.fillStyleType == MORPHFILLSTYLE.LINEAR_GRADIENT)
+ || (ret.fillStyleType == MORPHFILLSTYLE.RADIAL_GRADIENT)
+ || (ret.fillStyleType == MORPHFILLSTYLE.FOCAL_RADIAL_GRADIENT)) {
+ ret.startGradientMatrix = readMatrix("startGradientMatrix");
+ ret.endGradientMatrix = readMatrix("endGradientMatrix");
+ }
+ if ((ret.fillStyleType == MORPHFILLSTYLE.LINEAR_GRADIENT)
+ || (ret.fillStyleType == MORPHFILLSTYLE.RADIAL_GRADIENT)) {
+ ret.gradient = readMORPHGRADIENT("gradient");
+ }
+ if (ret.fillStyleType == MORPHFILLSTYLE.FOCAL_RADIAL_GRADIENT) {
+ ret.gradient = readMORPHFOCALGRADIENT("gradient");
+ }
+
+ if ((ret.fillStyleType == MORPHFILLSTYLE.REPEATING_BITMAP)
+ || (ret.fillStyleType == MORPHFILLSTYLE.CLIPPED_BITMAP)
+ || (ret.fillStyleType == MORPHFILLSTYLE.NON_SMOOTHED_REPEATING_BITMAP)
+ || (ret.fillStyleType == MORPHFILLSTYLE.NON_SMOOTHED_CLIPPED_BITMAP)) {
+ ret.bitmapId = readUI16("bitmapId");
+ ret.startBitmapMatrix = readMatrix("startBitmapMatrix");
+ ret.endBitmapMatrix = readMatrix("endBitmapMatrix");
+ }
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one MORPHFILLSTYLEARRAY value from the stream
+ *
+ * @param name
+ * @return MORPHFILLSTYLEARRAY value
+ * @throws IOException
+ */
+ public MORPHFILLSTYLEARRAY readMORPHFILLSTYLEARRAY(String name) throws IOException {
+
+ MORPHFILLSTYLEARRAY ret = new MORPHFILLSTYLEARRAY();
+ newDumpLevel(name, "MORPHFILLSTYLEARRAY");
+ int fillStyleCount = readUI8("fillStyleCount");
+ if (fillStyleCount == 0xff) {
+ fillStyleCount = readUI16("fillStyleCount");
+ }
+ ret.fillStyles = new MORPHFILLSTYLE[fillStyleCount];
+ for (int i = 0; i < fillStyleCount; i++) {
+ ret.fillStyles[i] = readMORPHFILLSTYLE("fillStyle");
+ }
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one MORPHLINESTYLE value from the stream
+ *
+ * @param name
+ * @return MORPHLINESTYLE value
+ * @throws IOException
+ */
+ public MORPHLINESTYLE readMORPHLINESTYLE(String name) throws IOException {
+ MORPHLINESTYLE ret = new MORPHLINESTYLE();
+ newDumpLevel(name, "MORPHLINESTYLE");
+ ret.startWidth = readUI16("startWidth");
+ ret.endWidth = readUI16("endWidth");
+ ret.startColor = readRGBA("startColor");
+ ret.endColor = readRGBA("endColor");
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one MORPHLINESTYLE2 value from the stream
+ *
+ * @param name
+ * @return MORPHLINESTYLE2 value
+ * @throws IOException
+ */
+ public MORPHLINESTYLE2 readMORPHLINESTYLE2(String name) throws IOException {
+ MORPHLINESTYLE2 ret = new MORPHLINESTYLE2();
+ newDumpLevel(name, "MORPHLINESTYLE2");
+ ret.startWidth = readUI16("startWidth");
+ ret.endWidth = readUI16("endWidth");
+ ret.startCapStyle = (int) readUB(2, "startCapStyle");
+ ret.joinStyle = (int) readUB(2, "joinStyle");
+ ret.hasFillFlag = (int) readUB(1, "hasFillFlag") == 1;
+ ret.noHScaleFlag = (int) readUB(1, "noHScaleFlag") == 1;
+ ret.noVScaleFlag = (int) readUB(1, "noVScaleFlag") == 1;
+ ret.pixelHintingFlag = (int) readUB(1, "pixelHintingFlag") == 1;
+ ret.reserved = (int) readUB(5, "reserved");
+ ret.noClose = (int) readUB(1, "noClose") == 1;
+ ret.endCapStyle = (int) readUB(2, "endCapStyle");
+ if (ret.joinStyle == LINESTYLE2.MITER_JOIN) {
+ ret.miterLimitFactor = readUI16("miterLimitFactor");
+ }
+ if (!ret.hasFillFlag) {
+ ret.startColor = readRGBA("startColor");
+ ret.endColor = readRGBA("endColor");
+ } else {
+ ret.fillType = readMORPHFILLSTYLE("fillType");
+ }
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one MORPHLINESTYLEARRAY value from the stream
+ *
+ * @param morphShapeNum 1 on DefineMorphShape, 2 on DefineMorphShape2
+ * @param name
+ * @return MORPHLINESTYLEARRAY value
+ * @throws IOException
+ */
+ public MORPHLINESTYLEARRAY readMORPHLINESTYLEARRAY(int morphShapeNum, String name) throws IOException {
+ MORPHLINESTYLEARRAY ret = new MORPHLINESTYLEARRAY();
+ newDumpLevel(name, "MORPHLINESTYLEARRAY");
+ int lineStyleCount = readUI8("lineStyleCount");
+ if (lineStyleCount == 0xff) {
+ lineStyleCount = readUI16("lineStyleCount");
+ }
+ if (morphShapeNum == 1) {
+ ret.lineStyles = new MORPHLINESTYLE[lineStyleCount];
+ for (int i = 0; i < lineStyleCount; i++) {
+ ret.lineStyles[i] = readMORPHLINESTYLE("lineStyle");
+ }
+ } else if (morphShapeNum == 2) {
+ ret.lineStyles2 = new MORPHLINESTYLE2[lineStyleCount];
+ for (int i = 0; i < lineStyleCount; i++) {
+ ret.lineStyles2[i] = readMORPHLINESTYLE2("lineStyle2");
+ }
+ }
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one KERNINGRECORD value from the stream
+ *
+ * @param fontFlagsWideCodes
+ * @param name
+ * @return KERNINGRECORD value
+ * @throws IOException
+ */
+ public KERNINGRECORD readKERNINGRECORD(boolean fontFlagsWideCodes, String name) throws IOException {
+ KERNINGRECORD ret = new KERNINGRECORD();
+ newDumpLevel(name, "KERNINGRECORD");
+ if (fontFlagsWideCodes) {
+ ret.fontKerningCode1 = readUI16("fontKerningCode1");
+ ret.fontKerningCode2 = readUI16("fontKerningCode2");
+ } else {
+ ret.fontKerningCode1 = readUI8("fontKerningCode1");
+ ret.fontKerningCode2 = readUI8("fontKerningCode2");
+ }
+ ret.fontKerningAdjustment = readSI16("fontKerningAdjustment");
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one LANGCODE value from the stream
+ *
+ * @param name
+ * @return LANGCODE value
+ * @throws IOException
+ */
+ public LANGCODE readLANGCODE(String name) throws IOException {
+ LANGCODE ret = new LANGCODE();
+ newDumpLevel(name, "LANGCODE");
+ ret.languageCode = readUI8("languageCode");
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one ZONERECORD value from the stream
+ *
+ * @param name
+ * @return ZONERECORD value
+ * @throws IOException
+ */
+ public ZONERECORD readZONERECORD(String name) throws IOException {
+ ZONERECORD ret = new ZONERECORD();
+ newDumpLevel(name, "ZONERECORD");
+ int numZoneData = readUI8("numZoneData");
+ ret.zonedata = new ZONEDATA[numZoneData];
+ for (int i = 0; i < numZoneData; i++) {
+ ret.zonedata[i] = readZONEDATA("zonedata");
+ }
+ readUB(6, "reserved");
+ ret.zoneMaskY = readUB(1, "zoneMaskY") == 1;
+ ret.zoneMaskX = readUB(1, "zoneMaskX") == 1;
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one ZONEDATA value from the stream
+ *
+ * @param name
+ * @return ZONEDATA value
+ * @throws IOException
+ */
+ public ZONEDATA readZONEDATA(String name) throws IOException {
+ ZONEDATA ret = new ZONEDATA();
+ newDumpLevel(name, "ZONEDATA");
+ ret.alignmentCoordinate = readUI16("alignmentCoordinate");
+ ret.range = readUI16("range");
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one PIX15 value from the stream
+ *
+ * @param name
+ * @return PIX15 value
+ * @throws IOException
+ */
+ public PIX15 readPIX15(String name) throws IOException {
+ PIX15 ret = new PIX15();
+ newDumpLevel(name, "PIX15");
+ readUB(1, "reserved");
+ ret.red = (int) readUB(5, "red");
+ ret.green = (int) readUB(5, "green");
+ ret.blue = (int) readUB(5, "blue");
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one PIX24 value from the stream
+ *
+ * @param name
+ * @return PIX24 value
+ * @throws IOException
+ */
+ public PIX24 readPIX24(String name) throws IOException {
+ PIX24 ret = new PIX24();
+ newDumpLevel(name, "PIX24");
+ ret.reserved = readUI8("reserved");
+ ret.red = readUI8("red");
+ ret.green = readUI8("green");
+ ret.blue = readUI8("blue");
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one COLORMAPDATA value from the stream
+ *
+ * @param colorTableSize
+ * @param bitmapWidth
+ * @param bitmapHeight
+ * @param name
+ * @return COLORMAPDATA value
+ * @throws IOException
+ */
+ public COLORMAPDATA readCOLORMAPDATA(int colorTableSize, int bitmapWidth, int bitmapHeight, String name) throws IOException {
+ COLORMAPDATA ret = new COLORMAPDATA();
+ newDumpLevel(name, "COLORMAPDATA");
+ ret.colorTableRGB = new RGB[colorTableSize + 1];
+ for (int i = 0; i < colorTableSize + 1; i++) {
+ ret.colorTableRGB[i] = readRGB("colorTableRGB");
+ }
+ int dataLen = 0;
+ for (int y = 0; y < bitmapHeight; y++) {
+ int x = 0;
+ for (; x < bitmapWidth; x++) {
+ dataLen++;
+ }
+ while ((x % 4) != 0) {
+ dataLen++;
+ x++;
+ }
+ }
+ ret.colorMapPixelData = readBytesEx(dataLen, "colorMapPixelData");
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one BITMAPDATA value from the stream
+ *
+ * @param bitmapFormat
+ * @param bitmapWidth
+ * @param bitmapHeight
+ * @param name
+ * @return COLORMAPDATA value
+ * @throws IOException
+ */
+ public BITMAPDATA readBITMAPDATA(int bitmapFormat, int bitmapWidth, int bitmapHeight, String name) throws IOException {
+ BITMAPDATA ret = new BITMAPDATA();
+ newDumpLevel(name, "BITMAPDATA");
+ List pix15 = new ArrayList<>();
+ List pix24 = new ArrayList<>();
+ int dataLen = 0;
+ for (int y = 0; y < bitmapHeight; y++) {
+ int x = 0;
+ for (; x < bitmapWidth; x++) {
+ if (bitmapFormat == DefineBitsLosslessTag.FORMAT_15BIT_RGB) {
+ dataLen += 2;
+ pix15.add(readPIX15("pix15"));
+ }
+ if (bitmapFormat == DefineBitsLosslessTag.FORMAT_24BIT_RGB) {
+ dataLen += 4;
+ pix24.add(readPIX24("pix24"));
+ }
+ }
+ while ((dataLen % 4) != 0) {
+ dataLen++;
+ readUI8("padding");
+ }
+ }
+ if (bitmapFormat == DefineBitsLosslessTag.FORMAT_15BIT_RGB) {
+ ret.bitmapPixelDataPix15 = pix15.toArray(new PIX15[pix15.size()]);
+ } else if (bitmapFormat == DefineBitsLosslessTag.FORMAT_24BIT_RGB) {
+ ret.bitmapPixelDataPix24 = pix24.toArray(new PIX24[pix24.size()]);
+ }
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one BITMAPDATA value from the stream
+ *
+ * @param bitmapFormat
+ * @param bitmapWidth
+ * @param bitmapHeight
+ * @param name
+ * @return COLORMAPDATA value
+ * @throws IOException
+ */
+ public ALPHABITMAPDATA readALPHABITMAPDATA(int bitmapFormat, int bitmapWidth, int bitmapHeight, String name) throws IOException {
+ ALPHABITMAPDATA ret = new ALPHABITMAPDATA();
+ newDumpLevel(name, "ALPHABITMAPDATA");
+ ret.bitmapPixelData = new ARGB[bitmapWidth * bitmapHeight];
+ for (int y = 0; y < bitmapHeight; y++) {
+ for (int x = 0; x < bitmapWidth; x++) {
+ ret.bitmapPixelData[y * bitmapWidth + x] = readARGB("bitmapPixelData");
+ }
+ }
+ endDumpLevel();
+ return ret;
+ }
+
+ /**
+ * Reads one ALPHACOLORMAPDATA value from the stream
+ *
+ * @param colorTableSize
+ * @param bitmapWidth
+ * @param bitmapHeight
+ * @param name
+ * @return ALPHACOLORMAPDATA value
+ * @throws IOException
+ */
+ public ALPHACOLORMAPDATA readALPHACOLORMAPDATA(int colorTableSize, int bitmapWidth, int bitmapHeight, String name) throws IOException {
+ ALPHACOLORMAPDATA ret = new ALPHACOLORMAPDATA();
+ newDumpLevel(name, "ALPHACOLORMAPDATA");
+ ret.colorTableRGB = new RGBA[colorTableSize + 1];
+ for (int i = 0; i < colorTableSize + 1; i++) {
+ ret.colorTableRGB[i] = readRGBA("colorTableRGB");
+ }
+ int dataLen = 0;
+ for (int y = 0; y < bitmapHeight; y++) {
+ int x = 0;
+ for (; x < bitmapWidth; x++) {
+ dataLen++;
+ }
+ while ((x % 4) != 0) {
+ dataLen++;
+ x++;
+ }
+ }
+ ret.colorMapPixelData = readBytesEx(dataLen, "");
+ endDumpLevel();
+ return ret;
+ }
+
+ public int available() throws IOException {
+ return is.available();
+ }
+
+ public long availableBits() throws IOException {
+ if (bitPos > 0) {
+ return available() * 8 + (8 - bitPos);
+ }
+ return available() * 8;
+ }
+
+ public MemoryInputStream getBaseStream() throws IOException {
+ int pos = (int) is.getPos();
+ return new MemoryInputStream(is.getAllRead(), pos, pos + is.available());
+ }
+
+ public SWFInputStream getLimitedStream(int limit) throws IOException {
+ SWFInputStream sis = new SWFInputStream(swf, is.getAllRead(), startingPos, (int) (is.getPos() + limit));
+ sis.dumpInfo = dumpInfo;
+ sis.seek(is.getPos() + startingPos);
+ return sis;
+ }
+}