diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java index 1b28683ba..2f7ee5f41 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java @@ -1,2776 +1,2776 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash; - -import SevenZip.Compression.LZMA.Decoder; -import SevenZip.Compression.LZMA.Encoder; -import com.jpexs.decompiler.flash.abc.ABC; -import com.jpexs.decompiler.flash.abc.CachedDecompilation; -import com.jpexs.decompiler.flash.abc.ClassPath; -import com.jpexs.decompiler.flash.abc.RenameType; -import com.jpexs.decompiler.flash.abc.ScriptPack; -import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; -import com.jpexs.decompiler.flash.abc.types.MethodBody; -import com.jpexs.decompiler.flash.abc.types.ScriptInfo; -import com.jpexs.decompiler.flash.action.Action; -import com.jpexs.decompiler.flash.action.ActionGraphSource; -import com.jpexs.decompiler.flash.action.ActionList; -import com.jpexs.decompiler.flash.action.ActionLocalData; -import com.jpexs.decompiler.flash.action.CachedScript; -import com.jpexs.decompiler.flash.action.model.ConstantPool; -import com.jpexs.decompiler.flash.action.model.DirectValueActionItem; -import com.jpexs.decompiler.flash.action.model.FunctionActionItem; -import com.jpexs.decompiler.flash.action.model.GetMemberActionItem; -import com.jpexs.decompiler.flash.action.model.GetVariableActionItem; -import com.jpexs.decompiler.flash.action.model.clauses.ClassActionItem; -import com.jpexs.decompiler.flash.action.model.clauses.InterfaceActionItem; -import com.jpexs.decompiler.flash.action.swf4.ActionEquals; -import com.jpexs.decompiler.flash.action.swf4.ActionGetVariable; -import com.jpexs.decompiler.flash.action.swf4.ActionIf; -import com.jpexs.decompiler.flash.action.swf4.ActionPush; -import com.jpexs.decompiler.flash.action.swf4.ActionSetVariable; -import com.jpexs.decompiler.flash.action.swf4.ConstantIndex; -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.ActionDefineFunction; -import com.jpexs.decompiler.flash.action.swf5.ActionDefineLocal; -import com.jpexs.decompiler.flash.action.swf5.ActionDefineLocal2; -import com.jpexs.decompiler.flash.action.swf5.ActionEquals2; -import com.jpexs.decompiler.flash.action.swf5.ActionGetMember; -import com.jpexs.decompiler.flash.action.swf5.ActionNewMethod; -import com.jpexs.decompiler.flash.action.swf5.ActionNewObject; -import com.jpexs.decompiler.flash.action.swf5.ActionSetMember; -import com.jpexs.decompiler.flash.action.swf7.ActionDefineFunction2; -import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.decompiler.flash.dumpview.DumpInfo; -import com.jpexs.decompiler.flash.dumpview.DumpInfoSwfNode; -import com.jpexs.decompiler.flash.ecma.Null; -import com.jpexs.decompiler.flash.exporters.commonshape.ExportRectangle; -import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; -import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; -import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; -import com.jpexs.decompiler.flash.exporters.script.AS2ScriptExporter; -import com.jpexs.decompiler.flash.exporters.script.AS3ScriptExporter; -import com.jpexs.decompiler.flash.exporters.settings.ScriptExportSettings; -import com.jpexs.decompiler.flash.helpers.HighlightedText; -import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter; -import com.jpexs.decompiler.flash.helpers.ImageHelper; -import com.jpexs.decompiler.flash.helpers.SWFDecompilerPlugin; -import com.jpexs.decompiler.flash.helpers.collections.MyEntry; -import com.jpexs.decompiler.flash.helpers.hilight.Highlighting; -import com.jpexs.decompiler.flash.tags.ABCContainerTag; -import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag; -import com.jpexs.decompiler.flash.tags.DefineButton2Tag; -import com.jpexs.decompiler.flash.tags.DefineButtonTag; -import com.jpexs.decompiler.flash.tags.DefineSpriteTag; -import com.jpexs.decompiler.flash.tags.DoInitActionTag; -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.JPEGTablesTag; -import com.jpexs.decompiler.flash.tags.ShowFrameTag; -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.VideoFrameTag; -import com.jpexs.decompiler.flash.tags.base.ASMSource; -import com.jpexs.decompiler.flash.tags.base.ASMSourceContainer; -import com.jpexs.decompiler.flash.tags.base.BoundedTag; -import com.jpexs.decompiler.flash.tags.base.ButtonTag; -import com.jpexs.decompiler.flash.tags.base.CharacterIdTag; -import com.jpexs.decompiler.flash.tags.base.CharacterTag; -import com.jpexs.decompiler.flash.tags.base.DrawableTag; -import com.jpexs.decompiler.flash.tags.base.Exportable; -import com.jpexs.decompiler.flash.tags.base.FontTag; -import com.jpexs.decompiler.flash.tags.base.ImageTag; -import com.jpexs.decompiler.flash.tags.base.MorphShapeTag; -import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag; -import com.jpexs.decompiler.flash.tags.base.RemoveTag; -import com.jpexs.decompiler.flash.tags.base.RenderContext; -import com.jpexs.decompiler.flash.tags.base.ShapeTag; -import com.jpexs.decompiler.flash.tags.base.TextTag; -import com.jpexs.decompiler.flash.timeline.AS2Package; -import com.jpexs.decompiler.flash.timeline.Clip; -import com.jpexs.decompiler.flash.timeline.DepthState; -import com.jpexs.decompiler.flash.timeline.Frame; -import com.jpexs.decompiler.flash.timeline.FrameScript; -import com.jpexs.decompiler.flash.timeline.SvgClip; -import com.jpexs.decompiler.flash.timeline.TagScript; -import com.jpexs.decompiler.flash.timeline.Timeline; -import com.jpexs.decompiler.flash.timeline.Timelined; -import com.jpexs.decompiler.flash.treeitems.SWFList; -import com.jpexs.decompiler.flash.treeitems.TreeItem; -import com.jpexs.decompiler.flash.types.ColorTransform; -import com.jpexs.decompiler.flash.types.MATRIX; -import com.jpexs.decompiler.flash.types.RECT; -import com.jpexs.decompiler.flash.types.annotations.Internal; -import com.jpexs.decompiler.flash.types.filters.BlendComposite; -import com.jpexs.decompiler.flash.types.filters.FILTER; -import com.jpexs.decompiler.flash.xfl.FLAVersion; -import com.jpexs.decompiler.flash.xfl.XFLConverter; -import com.jpexs.decompiler.graph.Graph; -import com.jpexs.decompiler.graph.GraphSourceItem; -import com.jpexs.decompiler.graph.GraphSourceItemContainer; -import com.jpexs.decompiler.graph.GraphTargetItem; -import com.jpexs.decompiler.graph.TranslateStack; -import com.jpexs.decompiler.graph.model.LocalData; -import com.jpexs.helpers.Cache; -import com.jpexs.helpers.Helper; -import com.jpexs.helpers.NulStream; -import com.jpexs.helpers.ProgressListener; -import com.jpexs.helpers.SerializableImage; -import com.jpexs.helpers.utf8.Utf8Helper; -import java.awt.AlphaComposite; -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.Rectangle; -import java.awt.RenderingHints; -import java.awt.Shape; -import java.awt.geom.AffineTransform; -import java.awt.image.BufferedImage; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.EmptyStackException; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; -import java.util.Stack; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.zip.DeflaterOutputStream; -import java.util.zip.InflaterInputStream; - -/** - * Class representing SWF file - * - * @author JPEXS - */ -public final class SWF implements SWFContainerItem, Timelined { - - // big object for testing cleanup - //BigObject bigObj = new BigObject(); - /** - * Default version of SWF file format - */ - public static final int DEFAULT_VERSION = 10; - - /** - * Maximum SWF file format version - * Needs to be fixed when SWF versions reaches this value - */ - public static final int MAX_VERSION = 30; - - /** - * Tags inside of file - */ - public List tags = new ArrayList<>(); - - @Internal - public boolean hasEndTag = true; - - /** - * ExportRectangle for the display - */ - public RECT displayRect; - - /** - * Movie frame rate - */ - public int frameRate; - - /** - * Number of frames in movie - */ - public int frameCount; - - /** - * Version of SWF - */ - public int version; - - /** - * Uncompressed size of the file - */ - @Internal - public long fileSize; - - /** - * Used compression mode - */ - public SWFCompression compression = SWFCompression.NONE; - - /** - * Compressed size of the file (LZMA) - */ - @Internal - public long compressedSize; - - /** - * LZMA Properties - */ - public byte[] lzmaProperties; - - @Internal - public byte[] uncompressedData; - - @Internal - public byte[] originalUncompressedData; - - /** - * ScaleForm GFx - */ - public boolean gfx = false; - - @Internal - public SWFList swfList; - - @Internal - private String file; - - @Internal - private String fileTitle; - - @Internal - private Map characters; - - @Internal - private List abcList; - - @Internal - private JPEGTablesTag jtt; - - @Internal - public Map sourceFontNamesMap = new HashMap<>(); - - public static final double unitDivisor = 20; - - private static final Logger logger = Logger.getLogger(SWF.class.getName()); - - @Internal - private Timeline timeline; - - @Internal - public DumpInfoSwfNode dumpInfo; - - @Internal - public DefineBinaryDataTag binaryData; - - @Internal - private final HashMap deobfuscated = new HashMap<>(); - - @Internal - private final IdentifiersDeobfuscation deobfuscation = new IdentifiersDeobfuscation(); - - @Internal - private Cache frameCache = Cache.getInstance(false, false, "frame"); - - @Internal - private final Cache as2Cache = Cache.getInstance(true, false, "as2"); - - @Internal - private final Cache as3Cache = Cache.getInstance(true, false, "as3"); - - public void updateCharacters() { - characters = null; - } - - public void clearTagSwfs() { - resetTimelines(this); - updateCharacters(); - - for (Tag tag : tags) { - if (tag instanceof DefineSpriteTag) { - DefineSpriteTag spriteTag = (DefineSpriteTag) tag; - for (Tag tag1 : spriteTag.subTags) { - tag1.setSwf(null); - } - - spriteTag.subTags.clear(); - } - - if (tag instanceof DefineBinaryDataTag) { - DefineBinaryDataTag binaryTag = (DefineBinaryDataTag) tag; - if (binaryTag.innerSwf != null) { - binaryTag.innerSwf.clearTagSwfs(); - } - } - - tag.setSwf(null); - } - - tags.clear(); - if (abcList != null) { - abcList.clear(); - } - - if (swfList != null) { - swfList.swfs.clear(); - } - - as2Cache.clear(); - as3Cache.clear(); - frameCache.clear(); - - timeline = null; - clearDumpInfo(dumpInfo); - dumpInfo = null; - jtt = null; - binaryData = null; - } - - private void clearDumpInfo(DumpInfo di) { - for (DumpInfo childInfo : di.getChildInfos()) { - clearDumpInfo(childInfo); - } - - di.getChildInfos().clear(); - } - - public Map getCharacters() { - if (characters == null) { - synchronized (this) { - if (characters == null) { - Map chars = new HashMap<>(); - parseCharacters(tags, chars); - characters = Collections.unmodifiableMap(chars); - } - } - } - - return characters; - } - - public CharacterTag getCharacter(int characterId) { - return getCharacters().get(characterId); - } - - public String getExportName(int characterId) { - CharacterTag characterTag = getCharacters().get(characterId); - String exportName = characterTag != null ? characterTag.getExportName() : null; - return exportName; - } - - public FontTag getFont(int fontId) { - CharacterTag characterTag = getCharacters().get(fontId); - if (characterTag instanceof FontTag) { - return (FontTag) characterTag; - } - - if (characterTag != null) { - logger.log(Level.SEVERE, "CharacterTag should be a FontTag. characterId: {0}", fontId); - } - - return null; - } - - public ImageTag getImage(int imageId) { - CharacterTag characterTag = getCharacters().get(imageId); - if (characterTag instanceof ImageTag) { - return (ImageTag) characterTag; - } - - if (characterTag != null) { - logger.log(Level.SEVERE, "CharacterTag should be an ImageTag. characterId: {0}", imageId); - } - - return null; - } - - public TextTag getText(int textId) { - CharacterTag characterTag = getCharacters().get(textId); - if (characterTag instanceof TextTag) { - return (TextTag) characterTag; - } - - if (characterTag != null) { - logger.log(Level.SEVERE, "CharacterTag should be a TextTag. characterId: {0}", textId); - } - - return null; - } - - public List getAbcList() { - if (abcList == null) { - synchronized (this) { - if (abcList == null) { - ArrayList newAbcList = new ArrayList<>(); - getAbcTags(tags, newAbcList); - abcList = newAbcList; - } - } - } - - return abcList; - } - - public boolean isAS3() { - FileAttributesTag fileAttributes = getFileAttributes(); - return (fileAttributes != null && fileAttributes.actionScript3) || (fileAttributes == null && !getAbcList().isEmpty()); - } - - public FileAttributesTag getFileAttributes() { - for (Tag t : tags) { - if (t instanceof FileAttributesTag) { - return (FileAttributesTag) t; - } - } - - return null; - } - - public int getNextCharacterId() { - int max = -1; - for (int characterId : getCharacters().keySet()) { - if (characterId > max) { - max = characterId; - } - } - - return max + 1; - } - - public synchronized JPEGTablesTag getJtt() { - if (jtt == null) { - synchronized (this) { - if (jtt == null) { - for (Tag t : tags) { - if (t instanceof JPEGTablesTag) { - jtt = (JPEGTablesTag) t; - break; - } - } - } - } - } - - return jtt; - } - - public String getDocumentClass() { - for (Tag t : tags) { - if (t instanceof SymbolClassTag) { - SymbolClassTag sc = (SymbolClassTag) t; - for (int i = 0; i < sc.tags.size(); i++) { - if (sc.tags.get(i) == 0) { - return sc.names.get(i); - } - } - } - } - - return null; - } - - public void fixCharactersOrder(boolean checkAll) { - Set addedCharacterIds = new HashSet<>(); - Set movedTags = new HashSet<>(); - for (int i = 0; i < tags.size(); i++) { - Tag tag = tags.get(i); - if (checkAll || tag.isModified()) { - Set needed = new HashSet<>(); - tag.getNeededCharacters(needed); - if (tag instanceof CharacterTag) { - CharacterTag characterTag = (CharacterTag) tag; - needed.remove(characterTag.getCharacterId()); - } - boolean moved = false; - for (Integer id : needed) { - if (!addedCharacterIds.contains(id)) { - CharacterTag neededCharacter = getCharacter(id); - if (neededCharacter == null) { - continue; - } - - if (movedTags.contains(neededCharacter)) { - logger.log(Level.SEVERE, "Fixing characters order failed, recursion detected."); - return; - } - - // move the needed character to the current position - tags.remove(neededCharacter); - tags.add(i, neededCharacter); - movedTags.add(neededCharacter); - moved = true; - } - } - - if (moved) { - i--; - continue; - } - } - if (tag instanceof CharacterTag) { - addedCharacterIds.add(((CharacterTag) tag).getCharacterId()); - } - } - } - - public void resetTimelines(Timelined timelined) { - timelined.resetTimeline(); - if (timelined instanceof SWF) { - for (Tag t : ((SWF) timelined).tags) { - if (t instanceof Timelined) { - resetTimelines((Timelined) t); - } - } - } - } - - private void parseCharacters(List list, Map characters) { - for (Tag t : list) { - if (t instanceof CharacterTag) { - int characterId = ((CharacterTag) t).getCharacterId(); - if (characters.containsKey(characterId)) { - logger.log(Level.SEVERE, "SWF already contains characterId={0}", characterId); - } - - if (characterId != 0) { - characters.put(characterId, (CharacterTag) t); - } - } - if (t instanceof DefineSpriteTag) { - parseCharacters(((DefineSpriteTag) t).getSubTags(), characters); - } - } - } - - /** - * Unresolve recursive sprites - */ - private void checkInvalidSprites() { - for (int i = 0; i < tags.size(); i++) { - Tag t = tags.get(i); - if (t instanceof DefineSpriteTag) { - if (!isSpriteValid((DefineSpriteTag) t, new ArrayList())) { - tags.set(i, new TagStub(this, t.getId(), "InvalidSprite", t.getOriginalRange(), null)); - } - } - } - } - - private boolean isSpriteValid(DefineSpriteTag sprite, List path) { - if (path.contains(sprite.spriteId)) { - return false; - } - path.add(sprite.spriteId); - for (Tag t : sprite.subTags) { - if (t instanceof DefineSpriteTag) { - if (!isSpriteValid((DefineSpriteTag) t, path)) { - return false; - } - } - } - path.remove((Integer) sprite.spriteId); - return true; - } - - @Override - public Timeline getTimeline() { - if (timeline == null) { - timeline = new Timeline(this); - } - return timeline; - } - - @Override - public void resetTimeline() { - if (timeline != null) { - timeline.reset(this); - } - } - - /** - * Gets all tags with specified id - * - * @param tagId Identificator of tag type - * @return List of tags - */ - public List getTagData(int tagId) { - List ret = new ArrayList<>(); - for (Tag tag : tags) { - if (tag.getId() == tagId) { - ret.add(tag); - } - } - return ret; - } - - /** - * Saves this SWF into new file - * - * @param os OutputStream to save SWF in - * @throws IOException - */ - public void saveTo(OutputStream os) throws IOException { - saveTo(os, compression); - } - - public String getHeaderBytes() { - return getHeaderBytes(compression, gfx); - } - - private String getHeaderBytes(SWFCompression compression, boolean gfx) { - if (compression == SWFCompression.LZMA_ABC) { - return "ABC"; - } - - String ret = ""; - if (compression == SWFCompression.LZMA) { - ret += 'Z'; - } else if (compression == SWFCompression.ZLIB) { - ret += 'C'; - } else { - if (gfx) { - ret += 'G'; - } else { - ret += 'F'; - } - } - if (gfx) { - ret += 'F'; - ret += 'X'; - } else { - ret += 'W'; - ret += 'S'; - } - return ret; - } - - /** - * Saves this SWF into new file - * - * @param os OutputStream to save SWF in - * @param compression - * @throws IOException - */ - public void saveTo(OutputStream os, SWFCompression compression) throws IOException { - try { - fixCharactersOrder(false); - - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - SWFOutputStream sos = new SWFOutputStream(baos, version); - sos.writeRECT(displayRect); - sos.writeUI8(0); - sos.writeUI8(frameRate); - sos.writeUI16(frameCount); - - sos.writeTags(tags); - if (hasEndTag) { - sos.writeUI16(0); - } - - sos.close(); - os.write(Utf8Helper.getBytes(getHeaderBytes(compression, gfx))); - os.write(version); - byte[] data = baos.toByteArray(); - sos = new SWFOutputStream(os, version); - sos.writeUI32(data.length + 8); - - if (compression == SWFCompression.LZMA || compression == SWFCompression.LZMA_ABC) { - long uncompressedLength = data.length; - Encoder enc = new Encoder(); - int val = lzmaProperties[0] & 0xFF; - int lc = val % 9; - int remainder = val / 9; - int lp = remainder % 5; - int pb = remainder / 5; - int dictionarySize = 0; - for (int i = 0; i < 4; i++) { - dictionarySize += ((int) (lzmaProperties[1 + i]) & 0xFF) << (i * 8); - } - if (Configuration.lzmaFastBytes.get() > 0) { - enc.SetNumFastBytes(Configuration.lzmaFastBytes.get()); - } - enc.SetDictionarySize(dictionarySize); - enc.SetLcLpPb(lc, lp, pb); - baos = new ByteArrayOutputStream(); - enc.SetEndMarkerMode(true); - enc.Code(new ByteArrayInputStream(data), baos, -1, -1, null); - data = baos.toByteArray(); - if (compression == SWFCompression.LZMA) { - byte[] udata = new byte[4]; - udata[0] = (byte) (data.length & 0xFF); - udata[1] = (byte) ((data.length >> 8) & 0xFF); - udata[2] = (byte) ((data.length >> 16) & 0xFF); - udata[3] = (byte) ((data.length >> 24) & 0xFF); - os.write(udata); - } - enc.WriteCoderProperties(os); - if (compression == SWFCompression.LZMA_ABC) { - byte[] udata = new byte[8]; - udata[0] = (byte) (uncompressedLength & 0xFF); - udata[1] = (byte) ((uncompressedLength >> 8) & 0xFF); - udata[2] = (byte) ((uncompressedLength >> 16) & 0xFF); - udata[3] = (byte) ((uncompressedLength >> 24) & 0xFF); - udata[4] = (byte) ((uncompressedLength >> 32) & 0xFF); - udata[5] = (byte) ((uncompressedLength >> 40) & 0xFF); - udata[6] = (byte) ((uncompressedLength >> 48) & 0xFF); - udata[7] = (byte) ((uncompressedLength >> 56) & 0xFF); - os.write(udata); - } - } else if (compression == SWFCompression.ZLIB) { - os = new DeflaterOutputStream(os); - } - - os.write(data); - } finally { - if (os != null) { - os.close(); - } - } - } - - public boolean isModified() { - for (Tag tag : tags) { - if (tag.isModified()) { - return true; - } - } - return false; - } - - public void clearModified() { - for (Tag tag : tags) { - if (tag.isModified()) { - tag.createOriginalData(); - tag.setModified(false); - } - } - - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try { - saveTo(baos, SWFCompression.NONE); - byte[] swfData = baos.toByteArray(); - uncompressedData = swfData; - } catch (IOException ex) { - logger.log(Level.SEVERE, "Cannot save SWF", ex); - } - } - - /** - * Constructs an empty SWF - */ - public SWF() { - - } - - /** - * Construct SWF from stream - * - * @param is Stream to read SWF from - * @param parallelRead Use parallel threads? - * @throws IOException - * @throws java.lang.InterruptedException - */ - public SWF(InputStream is, boolean parallelRead) throws IOException, InterruptedException { - this(is, null, null, null, parallelRead, false, true); - } - - /** - * Construct SWF from stream - * - * @param is Stream to read SWF from - * @param parallelRead Use parallel threads? - * @param lazy - * @throws IOException - * @throws java.lang.InterruptedException - */ - public SWF(InputStream is, boolean parallelRead, boolean lazy) throws IOException, InterruptedException { - this(is, null, null, null, parallelRead, false, lazy); - } - - /** - * Construct SWF from stream - * - * @param is Stream to read SWF from - * @param file Path to the file - * @param fileTitle Title of the SWF - * @param parallelRead Use parallel threads? - * @throws IOException - * @throws java.lang.InterruptedException - */ - public SWF(InputStream is, String file, String fileTitle, boolean parallelRead) throws IOException, InterruptedException { - this(is, file, fileTitle, null, parallelRead, false, true); - } - - /** - * Construct SWF from stream - * - * @param is Stream to read SWF from - * @param listener - * @param parallelRead Use parallel threads? - * @throws IOException - * @throws java.lang.InterruptedException - */ - public SWF(InputStream is, ProgressListener listener, boolean parallelRead) throws IOException, InterruptedException { - this(is, null, null, listener, parallelRead, false, true); - } - - /** - * Construct SWF from stream - * - * @param is Stream to read SWF from - * @param file Path to the file - * @param fileTitle Title of the SWF - * @param listener - * @param parallelRead Use parallel threads? - * @throws IOException - * @throws java.lang.InterruptedException - */ - public SWF(InputStream is, String file, String fileTitle, ProgressListener listener, boolean parallelRead) throws IOException, InterruptedException { - this(is, file, fileTitle, listener, parallelRead, false, true); - } - - /** - * Faster constructor to check SWF only - * - * @param is - * @throws java.io.IOException - */ - public SWF(InputStream is) throws IOException { - decompress(is, new NulStream(), true); - } - - /** - * Construct SWF from stream - * - * @param is Stream to read SWF from - * @param file Path to the file - * @param fileTitle Title of the SWF - * @param listener - * @param parallelRead Use parallel threads? - * @param checkOnly Check only file validity - * @param lazy - * @throws IOException - * @throws java.lang.InterruptedException - */ - public SWF(InputStream is, String file, String fileTitle, ProgressListener listener, boolean parallelRead, boolean checkOnly, boolean lazy) throws IOException, InterruptedException { - this.file = file; - this.fileTitle = fileTitle; - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - SWFHeader header = decompress(is, baos, true); - gfx = header.gfx; - compression = header.compression; - lzmaProperties = header.lzmaProperties; - uncompressedData = baos.toByteArray(); - originalUncompressedData = uncompressedData; - - SWFInputStream sis = new SWFInputStream(this, uncompressedData); - dumpInfo = new DumpInfoSwfNode(this, "rootswf", "", null, 0, 0); - sis.dumpInfo = dumpInfo; - sis.readBytesEx(3, "signature"); // skip siganture - version = sis.readUI8("version"); - fileSize = sis.readUI32("fileSize"); - dumpInfo.lengthBytes = fileSize; - if (listener != null) { - sis.addPercentListener(listener); - } - sis.setPercentMax(fileSize); - displayRect = sis.readRECT("displayRect"); - // FIXED8 (16 bit fixed point) frameRate - sis.readUI8("tmpFirstByetOfFrameRate"); // tmpFirstByetOfFrameRate - frameRate = sis.readUI8("frameRate"); - frameCount = sis.readUI16("frameCount"); - List tags = sis.readTagList(this, 0, parallelRead, true, !checkOnly, lazy); - if (tags.size() > 0 && tags.get(tags.size() - 1).getId() == EndTag.ID) { - tags.remove(tags.size() - 1); - } else { - hasEndTag = false; - } - this.tags = tags; - if (!checkOnly) { - checkInvalidSprites(); - updateCharacters(); - assignExportNamesToSymbols(); - assignClassesToSymbols(); - SWFDecompilerPlugin.fireSwfParsed(this); - } else { - boolean hasNonUnknownTag = false; - for (Tag tag : tags) { - if (tag.getOriginalDataLength() > 0 && Tag.getRequiredTags().contains(tag.getId())) { - hasNonUnknownTag = true; - } - } - if (!hasNonUnknownTag) { - throw new IOException("Invalid SWF file. No known tag found."); - } - } - - /*preload shape tags - for (Tag tag : tags) { - if (tag instanceof ShapeTag) { - ((ShapeTag) tag).getShapes(); - } - }*/ - } - - @Override - public SWF getSwf() { - return this; - } - - public SWF getRootSwf() { - SWF result = this; - while (result.binaryData != null) { - result = result.binaryData.getSwf(); - } - - return result; - } - - public String getFile() { - return file; - } - - /** - * Get title of the file - * - * @return file title - */ - public String getFileTitle() { - if (fileTitle != null) { - return fileTitle; - } - return file; - } - - public String getShortFileName() { - String title = getFileTitle(); - if (title == null) { - return ""; - } - return new File(title).getName(); - } - - public void setFile(String file) { - this.file = file; - fileTitle = null; - } - - private static void getAbcTags(List list, List actionScripts) { - for (Tag t : list) { - if (t instanceof DefineSpriteTag) { - getAbcTags(((DefineSpriteTag) t).getSubTags(), actionScripts); - } - if (t instanceof ABCContainerTag) { - actionScripts.add((ABCContainerTag) t); - } - } - } - - public void assignExportNamesToSymbols() { - HashMap exportNames = new HashMap<>(); - for (Tag t : tags) { - if (t instanceof ExportAssetsTag) { - ExportAssetsTag eat = (ExportAssetsTag) t; - for (int i = 0; i < eat.tags.size(); i++) { - Integer tagId = eat.tags.get(i); - String name = eat.names.get(i); - if ((!exportNames.containsKey(tagId)) && (!exportNames.containsValue(name))) { - exportNames.put(tagId, name); - } - } - } - } - for (Tag t : tags) { - if (t instanceof CharacterTag) { - CharacterTag ct = (CharacterTag) t; - if (exportNames.containsKey(ct.getCharacterId())) { - ct.setExportName(exportNames.get(ct.getCharacterId())); - } - } - } - } - - public void assignClassesToSymbols() { - HashMap classes = new HashMap<>(); - for (Tag t : tags) { - if (t instanceof SymbolClassTag) { - SymbolClassTag sct = (SymbolClassTag) t; - for (int i = 0; i < sct.tags.size(); i++) { - if ((!classes.containsKey(sct.tags.get(i))) && (!classes.containsValue(sct.names.get(i)))) { - classes.put(sct.tags.get(i), sct.names.get(i)); - } - } - } - } - for (Tag t : tags) { - if (t instanceof CharacterTag) { - CharacterTag ct = (CharacterTag) t; - if (classes.containsKey(ct.getCharacterId())) { - ct.setClassName(classes.get(ct.getCharacterId())); - } - } - } - } - - /** - * Compress SWF file - * - * @param fis Input stream - * @param fos Output stream - * @return True on success - */ - public static boolean fws2cws(InputStream fis, OutputStream fos) { - try { - byte[] swfHead = new byte[8]; - fis.read(swfHead); - - if (swfHead[0] != 'F') { - fis.close(); - return false; - } - swfHead[0] = 'C'; - fos.write(swfHead); - fos = new DeflaterOutputStream(fos); - int i; - while ((i = fis.read()) != -1) { - fos.write(i); - } - - fis.close(); - fos.close(); - } catch (IOException ex) { - return false; - } - return true; - } - - public static boolean decompress(InputStream fis, OutputStream fos) { - try { - decompress(fis, fos, false); - return true; - } catch (IOException ex) { - return false; - } - } - - private static void decodeLZMAStream(InputStream is, OutputStream os, byte[] lzmaProperties, long fileSize) throws IOException { - Decoder decoder = new Decoder(); - if (!decoder.SetDecoderProperties(lzmaProperties)) { - throw new IOException("LZMA:Incorrect stream properties"); - } - if (!decoder.Code(is, os, fileSize - 8)) { - throw new IOException("LZMA:Error in data stream"); - } - } - - private static SWFHeader decompress(InputStream is, OutputStream os, boolean allowUncompressed) throws IOException { - byte[] hdr = new byte[8]; - - // SWFheader: signature, version and fileSize - if (is.read(hdr) != 8) { - throw new IOException("SWF header is too short"); - } - - String signature = new String(hdr, 0, 3, Utf8Helper.charset); - if (!Arrays.asList( - "FWS", // Uncompressed Flash - "CWS", // ZLib compressed Flash - "ZWS", // LZMA compressed Flash - "GFX", // Uncompressed ScaleForm GFx - "CFX", // Compressed ScaleForm GFx - "ABC" // Non-standard LZMA compressed Flash - ).contains(signature)) { - throw new IOException("Invalid SWF file"); - } - - int version = hdr[3]; - SWFInputStream sis = new SWFInputStream(null, Arrays.copyOfRange(hdr, 4, 8), 4, 4); - long fileSize = sis.readUI32("fileSize"); - SWFHeader header = new SWFHeader(); - header.version = version; - header.fileSize = fileSize; - - if (hdr[1] == 'F' && hdr[2] == 'X') { - header.gfx = true; - } - - try (SWFOutputStream sos = new SWFOutputStream(os, version)) { - sos.write(Utf8Helper.getBytes(header.gfx ? "GFX" : "FWS")); - sos.writeUI8(version); - sos.writeUI32(fileSize); - - switch (hdr[0]) { - case 'C': { // CWS, CFX - Helper.copyStream(new InflaterInputStream(is), os, fileSize - 8); - header.compression = SWFCompression.ZLIB; - break; - } - case 'Z': { // ZWS - byte[] lzmaprop = new byte[9]; - is.read(lzmaprop); - sis = new SWFInputStream(null, lzmaprop); - sis.readUI32("LZMAsize"); // compressed LZMA data size = compressed SWF - 17 byte, - // where 17 = 8 byte header + this 4 byte + 5 bytes decoder properties - int propertiesSize = 5; - byte[] lzmaProperties = sis.readBytes(propertiesSize, "lzmaproperties"); - if (lzmaProperties.length != propertiesSize) { - throw new IOException("LZMA:input .lzma file is too short"); - } - - decodeLZMAStream(is, os, lzmaProperties, fileSize); - - header.compression = SWFCompression.LZMA; - header.lzmaProperties = lzmaProperties; - break; - } - case 'A': { // ABC - byte[] lzmaProperties = new byte[5]; - is.read(lzmaProperties); - byte[] uncompressedLength = new byte[8]; - is.read(uncompressedLength); - - decodeLZMAStream(is, os, lzmaProperties, fileSize); - - header.compression = SWFCompression.LZMA_ABC; - header.lzmaProperties = lzmaProperties; - break; - } - default: { // FWS, GFX - if (allowUncompressed) { - Helper.copyStream(is, os, fileSize - 8); - } else { - throw new IOException("SWF is not compressed"); - } - } - } - - return header; - } - } - - public static boolean renameInvalidIdentifiers(RenameType renameType, InputStream fis, OutputStream fos) { - try { - SWF swf = new SWF(fis, Configuration.parallelSpeedUp.get()); - int cnt = swf.deobfuscateIdentifiers(renameType); - swf.assignClassesToSymbols(); - System.out.println(cnt + " identifiers renamed."); - swf.saveTo(fos); - } catch (InterruptedException ex) { - return false; - } catch (IOException ex) { - return false; - } - return true; - } - - public boolean exportAS3Class(String className, String outdir, ScriptExportSettings exportSettings, boolean parallel, EventListener evl) throws Exception { - boolean exported = false; - - List abcList = getAbcList(); - for (int i = 0; i < abcList.size(); i++) { - ABC abc = abcList.get(i).getABC(); - List scrs = abc.findScriptPacksByPath(className); - for (int j = 0; j < scrs.size(); j++) { - ScriptPack scr = scrs.get(j); - String cnt = ""; - if (scrs.size() > 1) { - cnt = "script " + (j + 1) + "/" + scrs.size() + " "; - } - String eventData = cnt + scr.getPath() + " ..."; - evl.handleExportingEvent("tag", i + 1, abcList.size(), eventData); - scr.export(outdir, exportSettings, parallel); - evl.handleExportedEvent("tag", i + 1, abcList.size(), eventData); - exported = true; - } - } - return exported; - } - - private List uniqueAS3Packs(List packs) { - List ret = new ArrayList<>(); - Set classPaths = new HashSet<>(); - for (ScriptPack item : packs) { - ClassPath key = item.getClassPath(); - if (classPaths.contains(key)) { - logger.log(Level.SEVERE, "Duplicate pack path found (" + key + ")!"); - } else { - classPaths.add(key); - ret.add(item); - } - } - return ret; - } - - public List getAS3Packs() { - List packs = new ArrayList<>(); - for (ABCContainerTag abcTag : getAbcList()) { - packs.addAll(abcTag.getABC().getScriptPacks(null)); - } - return uniqueAS3Packs(packs); - } - - @Override - public RECT getRect() { - return displayRect; - } - - @Override - public RECT getRect(Set added) { - return displayRect; - } - - public EventListener getExportEventListener() { - EventListener evl = new EventListener() { - @Override - public void handleExportingEvent(String type, int index, int count, Object data) { - for (EventListener listener : listeners) { - listener.handleExportingEvent(type, index, count, data); - } - } - - @Override - public void handleExportedEvent(String type, int index, int count, Object data) { - for (EventListener listener : listeners) { - listener.handleExportedEvent(type, index, count, data); - } - } - - @Override - public void handleEvent(String event, Object data) { - informListeners(event, data); - } - }; - - return evl; - } - - public List exportActionScript(AbortRetryIgnoreHandler handler, String outdir, ScriptExportSettings exportSettings, boolean parallel, EventListener evl) throws IOException { - List ret = new ArrayList<>(); - - if (isAS3()) { - ret.addAll(new AS3ScriptExporter().exportActionScript3(this, handler, outdir, exportSettings, parallel, evl)); - } else { - ret.addAll(new AS2ScriptExporter().exportAS2ScriptsTimeout(handler, outdir, getASMs(true), exportSettings, evl)); - } - return ret; - } - - public Map getASMs(boolean exportFileNames) { - return getASMs(exportFileNames, new ArrayList(), true); - } - - public Map getASMs(boolean exportFileNames, List nodesToExport, boolean exportAll) { - Map asmsToExport = new HashMap<>(); - for (TreeItem treeItem : getFirstLevelASMNodes(null)) { - getASMs(exportFileNames, treeItem, nodesToExport, exportAll, asmsToExport, File.separator + getASMPath(exportFileNames, treeItem)); - } - - return asmsToExport; - } - - private void getASMs(boolean exportFileNames, TreeItem treeItem, List nodesToExport, boolean exportAll, Map asmsToExport, String path) { - boolean exportNode = nodesToExport.contains(treeItem); - TreeItem realItem = treeItem instanceof TagScript ? ((TagScript) treeItem).getTag() : treeItem; - if (realItem instanceof ASMSource && (exportAll || exportNode)) { - String npath = path; - int ppos = 1; - while (asmsToExport.containsKey(npath)) { - ppos++; - npath = path + (exportFileNames ? "[" + ppos + "]" : "_" + ppos); - } - asmsToExport.put(npath, (ASMSource) realItem); - } - - if (treeItem instanceof TagScript) { - TagScript tagScript = (TagScript) treeItem; - for (TreeItem subItem : tagScript.getFrames()) { - getASMs(exportFileNames, subItem, nodesToExport, exportAll, asmsToExport, path + File.separator + getASMPath(exportFileNames, subItem)); - } - } else if (treeItem instanceof FrameScript) { - FrameScript frameScript = (FrameScript) treeItem; - Frame parentFrame = frameScript.getFrame(); - for (TreeItem subItem : parentFrame.actionContainers) { - getASMs(exportFileNames, getASMWrapToTagScript(subItem), nodesToExport, exportAll || exportNode, asmsToExport, path + File.separator + getASMPath(exportFileNames, subItem)); - } - for (TreeItem subItem : parentFrame.actions) { - getASMs(exportFileNames, getASMWrapToTagScript(subItem), nodesToExport, exportAll || exportNode, asmsToExport, path + File.separator + getASMPath(exportFileNames, subItem)); - } - } else if (treeItem instanceof AS2Package) { - AS2Package as2Package = (AS2Package) treeItem; - for (TreeItem subItem : as2Package.subPackages.values()) { - getASMs(exportFileNames, subItem, nodesToExport, exportAll, asmsToExport, path + File.separator + getASMPath(exportFileNames, subItem)); - } - for (TreeItem subItem : as2Package.scripts.values()) { - getASMs(exportFileNames, subItem, nodesToExport, exportAll, asmsToExport, path + File.separator + getASMPath(exportFileNames, subItem)); - } - } - } - - private String getASMPath(boolean exportFileName, TreeItem treeItem) { - if (!exportFileName) { - return treeItem.toString(); - } - - String result; - if (treeItem instanceof Exportable) { - result = ((Exportable) treeItem).getExportFileName(); - } else { - result = treeItem.toString(); - } - - return Helper.makeFileName(result); - } - - private TreeItem getASMWrapToTagScript(TreeItem treeItem) { - if (treeItem instanceof Tag) { - Tag resultTag = (Tag) treeItem; - List subNodes = new ArrayList<>(); - if (treeItem instanceof ASMSourceContainer) { - for (ASMSource item : ((ASMSourceContainer) treeItem).getSubItems()) { - subNodes.add(item); - } - } - - TagScript tagScript = new TagScript(treeItem.getSwf(), resultTag, subNodes); - return tagScript; - } - - return treeItem; - } - - public List getFirstLevelASMNodes(Map tagScriptCache) { - Timeline timeline = getTimeline(); - List subNodes = new ArrayList<>(); - List subFrames = new ArrayList<>(); - subNodes.addAll(timeline.getAS2RootPackage().subPackages.values()); - subNodes.addAll(timeline.getAS2RootPackage().scripts.values()); - - for (Tag tag : timeline.otherTags) { - boolean hasInnerFrames = false; - List tagSubNodes = new ArrayList<>(); - if (tag instanceof Timelined) { - Timeline timeline2 = ((Timelined) tag).getTimeline(); - for (Frame frame : timeline2.getFrames()) { - if (!frame.actions.isEmpty() || !frame.actionContainers.isEmpty()) { - FrameScript frameScript = new FrameScript(this, frame); - tagSubNodes.add(frameScript); - hasInnerFrames = true; - } - } - } - - if (tag instanceof ASMSourceContainer) { - for (ASMSource asm : ((ASMSourceContainer) tag).getSubItems()) { - tagSubNodes.add(asm); - } - } - - if (!tagSubNodes.isEmpty()) { - TagScript ts = new TagScript(this, tag, tagSubNodes); - if (tagScriptCache != null) { - tagScriptCache.put(tag, ts); - } - if (hasInnerFrames) { - subFrames.add(ts); - } else { - subNodes.add(ts); - } - } - } - - subNodes.addAll(subFrames); - for (Frame frame : timeline.getFrames()) { - if (!frame.actions.isEmpty() || !frame.actionContainers.isEmpty()) { - FrameScript frameScript = new FrameScript(this, frame); - subNodes.add(frameScript); - } - } - - return subNodes; - } - - private final HashSet listeners = new HashSet<>(); - - public final void addEventListener(EventListener listener) { - listeners.add(listener); - for (Tag t : tags) { - if (t instanceof ABCContainerTag) { - (((ABCContainerTag) t).getABC()).addEventListener(listener); - } - } - } - - public final void removeEventListener(EventListener listener) { - listeners.remove(listener); - for (Tag t : tags) { - if (t instanceof ABCContainerTag) { - (((ABCContainerTag) t).getABC()).removeEventListener(listener); - } - } - } - - protected void informListeners(String event, Object data) { - for (EventListener listener : listeners) { - listener.handleEvent(event, data); - } - } - - public static void populateVideoFrames(int streamId, List tags, HashMap output) { - for (Tag t : tags) { - if (t instanceof VideoFrameTag) { - output.put(((VideoFrameTag) t).frameNum, (VideoFrameTag) t); - } - if (t instanceof DefineSpriteTag) { - populateVideoFrames(streamId, ((DefineSpriteTag) t).getSubTags(), output); - } - } - } - - private static void writeLE(OutputStream os, long val, int size) throws IOException { - for (int i = 0; i < size; i++) { - os.write((int) (val & 0xff)); - val >>= 8; - } - } - - public static void createWavFromPcmData(OutputStream fos, int soundRateHz, boolean soundSize, boolean soundType, byte[] data) throws IOException { - ByteArrayOutputStream subChunk1Data = new ByteArrayOutputStream(); - int audioFormat = 1; // PCM - writeLE(subChunk1Data, audioFormat, 2); - int numChannels = soundType ? 2 : 1; - writeLE(subChunk1Data, numChannels, 2); - int[] rateMap = {5512, 11025, 22050, 44100}; - int sampleRate = soundRateHz; // rateMap[soundRate]; - writeLE(subChunk1Data, sampleRate, 4); - int bitsPerSample = soundSize ? 16 : 8; - int byteRate = sampleRate * numChannels * bitsPerSample / 8; - writeLE(subChunk1Data, byteRate, 4); - int blockAlign = numChannels * bitsPerSample / 8; - writeLE(subChunk1Data, blockAlign, 2); - writeLE(subChunk1Data, bitsPerSample, 2); - - ByteArrayOutputStream chunks = new ByteArrayOutputStream(); - chunks.write(Utf8Helper.getBytes("fmt ")); - byte[] subChunk1DataBytes = subChunk1Data.toByteArray(); - writeLE(chunks, subChunk1DataBytes.length, 4); - chunks.write(subChunk1DataBytes); - - chunks.write(Utf8Helper.getBytes("data")); - writeLE(chunks, data.length, 4); - chunks.write(data); - - fos.write(Utf8Helper.getBytes("RIFF")); - byte[] chunkBytes = chunks.toByteArray(); - writeLE(fos, 4 + chunkBytes.length, 4); - fos.write(Utf8Helper.getBytes("WAVE")); - fos.write(chunkBytes); - } - - public static String getTypePrefix(CharacterTag c) { - if (c instanceof ShapeTag) { - return "shape"; - } - if (c instanceof MorphShapeTag) { - return "morphshape"; - } - if (c instanceof DefineSpriteTag) { - return "sprite"; - } - if (c instanceof TextTag) { - return "text"; - } - if (c instanceof ButtonTag) { - return "button"; - } - if (c instanceof FontTag) { - return "font"; - } - if (c instanceof ImageTag) { - return "image"; - } - return "character"; - } - - public static void writeLibrary(SWF fswf, Set library, OutputStream fos) throws IOException { - for (int c : library) { - CharacterTag ch = fswf.getCharacter(c); - if (ch instanceof FontTag) { - fos.write(Utf8Helper.getBytes("function " + getTypePrefix(ch) + c + "(ctx,ch,textColor){\r\n")); - fos.write(Utf8Helper.getBytes(((FontTag) ch).toHtmlCanvas(1))); - fos.write(Utf8Helper.getBytes("}\r\n\r\n")); - } else { - if (ch instanceof ImageTag) { - ImageTag image = (ImageTag) ch; - String format = image.getImageFormat(); - InputStream imageStream = image.getImageData(); - byte[] imageData; - if (imageStream != null) { - imageData = Helper.readStream(image.getImageData()); - } else { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ImageHelper.write(image.getImage().getBufferedImage(), format.toUpperCase(Locale.ENGLISH), baos); - imageData = baos.toByteArray(); - } - String base64ImgData = Helper.byteArrayToBase64String(imageData); - fos.write(Utf8Helper.getBytes("var imageObj" + c + " = document.createElement(\"img\");\r\nimageObj" + c + ".src=\"data:image/" + format + ";base64," + base64ImgData + "\";\r\n")); - } - fos.write(Utf8Helper.getBytes("function " + getTypePrefix(ch) + c + "(ctx,ctrans,frame,ratio,time){\r\n")); - if (ch instanceof DrawableTag) { - fos.write(Utf8Helper.getBytes(((DrawableTag) ch).toHtmlCanvas(1))); - } - fos.write(Utf8Helper.getBytes("}\r\n\r\n")); - } - } - } - - private static void getVariables(ConstantPool constantPool, BaseLocalData localData, TranslateStack stack, List output, ActionGraphSource code, int ip, List> variables, List functions, HashMap strings, List visited, HashMap usageTypes, String path) throws InterruptedException { - boolean debugMode = false; - while ((ip > -1) && ip < code.size()) { - if (visited.contains(ip)) { - break; - } - GraphSourceItem ins = code.get(ip); - - if (debugMode) { - System.err.println("Visit " + ip + ": ofs" + Helper.formatAddress(((Action) ins).getAddress()) + ":" + ((Action) ins).getASMSource(new ActionList(), new HashSet(), ScriptExportMode.PCODE) + " stack:" + Helper.stackToString(stack, LocalData.create(new ConstantPool()))); - } - if (ins.isExit()) { - break; - } - if (ins.isIgnored()) { - ip++; - continue; - } - - String usageType = "name"; - GraphTargetItem name = null; - if ((ins instanceof ActionGetVariable) - || (ins instanceof ActionGetMember) - || (ins instanceof ActionDefineLocal2) - || (ins instanceof ActionNewMethod) - || (ins instanceof ActionNewObject) - || (ins instanceof ActionCallMethod) - || (ins instanceof ActionCallFunction)) { - if (stack.isEmpty()) { - break; - } - name = stack.peek(); - } - - if ((ins instanceof ActionGetVariable) || (ins instanceof ActionDefineLocal2)) { - usageType = "variable"; - } - if (ins instanceof ActionGetMember) { - usageType = "member"; - } - if ((ins instanceof ActionNewMethod) || (ins instanceof ActionNewObject)) { - usageType = "class"; - } - if (ins instanceof ActionCallMethod) { - usageType = "function"; // can there be method? - } - if (ins instanceof ActionCallFunction) { - usageType = "function"; - } - - if ((ins instanceof ActionDefineFunction) || (ins instanceof ActionDefineFunction2)) { - functions.add(ins); - } - - if (ins instanceof GraphSourceItemContainer) { - GraphSourceItemContainer cnt = (GraphSourceItemContainer) ins; - List cntSizes = cnt.getContainerSizes(); - long addr = code.pos2adr(ip + 1); - ip = code.adr2pos(addr); - String cntName = cnt.getName(); - for (Long size : cntSizes) { - if (size == 0) { - continue; - } - ip = code.adr2pos(addr); - addr += size; - int nextip = code.adr2pos(addr); - getVariables(variables, functions, strings, usageTypes, new ActionGraphSource(code.getActions().subList(ip, nextip), code.version, new HashMap(), new HashMap(), new HashMap()), 0, path + (cntName == null ? "" : "/" + cntName)); - ip = nextip; - } - List> r = new ArrayList<>(); - r.add(new ArrayList()); - r.add(new ArrayList()); - r.add(new ArrayList()); - try { - ((GraphSourceItemContainer) ins).translateContainer(r, stack, output, new HashMap(), new HashMap(), new HashMap()); - } catch (EmptyStackException ex) { - } - - continue; - } - - if ((ins instanceof ActionSetVariable) || (ins instanceof ActionSetMember) || (ins instanceof ActionDefineLocal)) { - if (stack.size() < 2) { - break; - } - name = stack.get(stack.size() - 2); - } - - if ((ins instanceof ActionSetVariable) || (ins instanceof ActionDefineLocal)) { - usageType = "variable"; - } - - if (ins instanceof ActionSetMember) { - usageType = "member"; - } - - if (name instanceof DirectValueActionItem) { - variables.add(new MyEntry<>((DirectValueActionItem) name, constantPool)); - usageTypes.put((DirectValueActionItem) name, usageType); - } - - // for..in return - if (((ins instanceof ActionEquals) || (ins instanceof ActionEquals2)) && (stack.size() == 1) && (stack.peek() instanceof DirectValueActionItem)) { - stack.push(new DirectValueActionItem(null, 0, new Null(), new ArrayList())); - } - - if (ins instanceof ActionConstantPool) { - constantPool = new ConstantPool(((ActionConstantPool) ins).constantPool); - } - int staticOperation = Graph.SOP_USE_STATIC; //(Boolean) Configuration.getConfig("autoDeobfuscate", true) ? Graph.SOP_SKIP_STATIC : Graph.SOP_USE_STATIC; - - try { - ins.translate(localData, stack, output, staticOperation, path); - } catch (EmptyStackException ex) { - // probably obfucated code, never executed branch - break; - } - if (ins.isExit()) { - break; - } - - if (ins instanceof ActionPush) { - if (!stack.isEmpty()) { - GraphTargetItem top = stack.peek(); - if (top instanceof DirectValueActionItem) { - DirectValueActionItem dvt = (DirectValueActionItem) top; - if ((dvt.value instanceof String) || (dvt.value instanceof ConstantIndex)) { - if (constantPool == null) { - constantPool = new ConstantPool(dvt.constants); - } - strings.put(dvt, constantPool); - } - } - } - } - - if (ins.isBranch() || ins.isJump()) { - if (ins instanceof ActionIf) { - if (stack.isEmpty()) { - break; - } - stack.pop(); - } - visited.add(ip); - List branches = ins.getBranches(code); - for (int b : branches) { - TranslateStack brStack = (TranslateStack) stack.clone(); - if (b >= 0) { - getVariables(constantPool, localData, brStack, output, code, b, variables, functions, strings, visited, usageTypes, path); - } else { - if (debugMode) { - System.out.println("Negative branch:" + b); - } - } - } - // } - break; - } - ip++; - }; - } - - private static void getVariables(List> variables, List functions, HashMap strings, HashMap usageTypes, ActionGraphSource code, int addr, String path) throws InterruptedException { - ActionLocalData localData = new ActionLocalData(); - getVariables(null, localData, new TranslateStack(), new ArrayList(), code, code.adr2pos(addr), variables, functions, strings, new ArrayList(), usageTypes, path); - } - - private List> getVariables(List> variables, HashMap actionsMap, List functions, HashMap strings, HashMap usageTypes, ASMSource src, String path) throws InterruptedException { - List> ret = new ArrayList<>(); - ActionList actions = src.getActions(); - actionsMap.put(src, actions); - getVariables(variables, functions, strings, usageTypes, new ActionGraphSource(actions, version, new HashMap(), new HashMap(), new HashMap()), 0, path); - return ret; - } - - private void getVariables(List tags, String path, List> variables, HashMap actionsMap, List functions, HashMap strings, HashMap usageTypes) throws InterruptedException { - List processed = new ArrayList<>(); - for (Tag t : tags) { - String subPath = path + "/" + t.toString(); - if (t instanceof ASMSource) { - addVariable((ASMSource) t, subPath, processed, variables, actionsMap, functions, strings, usageTypes); - } - if (t instanceof ASMSourceContainer) { - List processed2 = new ArrayList<>(); - for (ASMSource asm : ((ASMSourceContainer) t).getSubItems()) { - addVariable(asm, subPath + "/" + asm.toString(), processed2, variables, actionsMap, functions, strings, usageTypes); - } - } - if (t instanceof DefineSpriteTag) { - getVariables(((DefineSpriteTag) t).getSubTags(), path + "/" + t.toString(), variables, actionsMap, functions, strings, usageTypes); - } - } - } - - private void addVariable(ASMSource asm, String path, List processed, List> variables, HashMap actionsMap, List functions, HashMap strings, HashMap usageTypes) throws InterruptedException { - int pos = 1; - String infPath2 = path; - while (processed.contains(infPath2)) { - pos++; - infPath2 = path + "[" + pos + "]"; - } - processed.add(infPath2); - informListeners("getVariables", infPath2); - getVariables(variables, actionsMap, functions, strings, usageTypes, asm, path); - } - - public void fixAS3Code() { - for (ABCContainerTag abcTag : getAbcList()) { - ABC abc = abcTag.getABC(); - for (MethodBody body : abc.bodies) { - AVM2Code code = body.getCode(); - } - - ((Tag) abcTag).setModified(true); - } - } - - public int deobfuscateAS3Identifiers(RenameType renameType) { - for (Tag tag : tags) { - if (tag instanceof ABCContainerTag) { - ((ABCContainerTag) tag).getABC().deobfuscateIdentifiers(deobfuscated, renameType, true); - tag.setModified(true); - } - } - for (Tag tag : tags) { - if (tag instanceof ABCContainerTag) { - ((ABCContainerTag) tag).getABC().deobfuscateIdentifiers(deobfuscated, renameType, false); - tag.setModified(true); - } - } - for (Tag tag : tags) { - if (tag instanceof SymbolClassTag) { - SymbolClassTag sc = (SymbolClassTag) tag; - for (int i = 0; i < sc.names.size(); i++) { - String newname = deobfuscation.deobfuscateNameWithPackage(true, sc.names.get(i), deobfuscated, renameType, deobfuscated); - if (newname != null) { - sc.names.set(i, newname); - } - } - sc.setModified(true); - } - } - deobfuscation.deobfuscateInstanceNames(true, deobfuscated, renameType, tags, new HashMap()); - return deobfuscated.size(); - } - - public int deobfuscateIdentifiers(RenameType renameType) throws InterruptedException { - FileAttributesTag fileAttributes = getFileAttributes(); - if (fileAttributes == null) { - int cnt = 0; - cnt += deobfuscateAS2Identifiers(renameType); - cnt += deobfuscateAS3Identifiers(renameType); - return cnt; - } else { - if (fileAttributes.actionScript3) { - return deobfuscateAS3Identifiers(renameType); - } else { - return deobfuscateAS2Identifiers(renameType); - } - } - } - - public void renameAS2Identifier(String identifier, String newname) throws InterruptedException { - Map selected = new HashMap<>(); - selected.put(identifier, newname); - renameAS2Identifiers(null, selected); - } - - private int deobfuscateAS2Identifiers(RenameType renameType) throws InterruptedException { - return renameAS2Identifiers(renameType, null); - } - - private int renameAS2Identifiers(RenameType renameType, Map selected) throws InterruptedException { - HashMap actionsMap = new HashMap<>(); - List allFunctions = new ArrayList<>(); - List> allVariableNames = new ArrayList<>(); - HashMap allStrings = new HashMap<>(); - HashMap usageTypes = new HashMap<>(); - - int ret = 0; - getVariables(tags, "", allVariableNames, actionsMap, allFunctions, allStrings, usageTypes); - informListeners("rename", ""); - int fc = 0; - for (MyEntry it : allVariableNames) { - String name = it.getKey().toStringNoH(it.getValue()); - deobfuscation.allVariableNamesStr.add(name); - } - - informListeners("rename", "classes"); - int classCount = 0; - for (Tag t : tags) { - if (t instanceof DoInitActionTag) { - classCount++; - } - } - int cnt = 0; - for (Tag t : tags) { - if (t instanceof DoInitActionTag) { - cnt++; - informListeners("rename", "class " + cnt + "/" + classCount); - DoInitActionTag dia = (DoInitActionTag) t; - String exportName = getExportName(dia.spriteId); - exportName = exportName != null ? exportName : "_unk_"; - final String pkgPrefix = "__Packages."; - String[] classNameParts = null; - if (exportName.startsWith(pkgPrefix)) { - String className = exportName.substring(pkgPrefix.length()); - if (className.contains(".")) { - classNameParts = className.split("\\."); - } else { - classNameParts = new String[]{className}; - } - } - int staticOperation = Graph.SOP_USE_STATIC; //(Boolean) Configuration.getConfig("autoDeobfuscate", true) ? Graph.SOP_SKIP_STATIC : Graph.SOP_USE_STATIC; - List dec; - try { - dec = Action.actionsToTree(dia.getActions(), version, staticOperation, ""/*FIXME*/); - } catch (EmptyStackException ex) { - continue; - } - GraphTargetItem name = null; - for (GraphTargetItem it : dec) { - if (it instanceof ClassActionItem) { - ClassActionItem cti = (ClassActionItem) it; - List methods = new ArrayList<>(); - methods.addAll(cti.functions); - methods.addAll(cti.staticFunctions); - - for (GraphTargetItem gti : methods) { - if (gti instanceof FunctionActionItem) { - FunctionActionItem fun = (FunctionActionItem) gti; - if (fun.calculatedFunctionName instanceof DirectValueActionItem) { - DirectValueActionItem dvf = (DirectValueActionItem) fun.calculatedFunctionName; - String fname = dvf.toStringNoH(null); - String changed = deobfuscation.deobfuscateName(false, fname, false, "method", deobfuscated, renameType, selected); - if (changed != null) { - deobfuscated.put(fname, changed); - } - } - } - } - - List vars = new ArrayList<>(); - for (MyEntry item : cti.vars) { - vars.add(item.getKey()); - } - for (MyEntry item : cti.staticVars) { - vars.add(item.getKey()); - } - for (GraphTargetItem gti : vars) { - if (gti instanceof DirectValueActionItem) { - DirectValueActionItem dvf = (DirectValueActionItem) gti; - String vname = dvf.toStringNoH(null); - String changed = deobfuscation.deobfuscateName(false, vname, false, "attribute", deobfuscated, renameType, selected); - if (changed != null) { - deobfuscated.put(vname, changed); - } - } - } - - name = cti.className; - break; - } - if (it instanceof InterfaceActionItem) { - InterfaceActionItem ift = (InterfaceActionItem) it; - name = ift.name; - } - } - - if (name != null) { - int pos = 0; - while (name instanceof GetMemberActionItem) { - GetMemberActionItem mem = (GetMemberActionItem) name; - GraphTargetItem memberName = mem.memberName; - if (memberName instanceof DirectValueActionItem) { - DirectValueActionItem dvt = (DirectValueActionItem) memberName; - String nameStr = dvt.toStringNoH(null); - if (classNameParts != null) { - if (classNameParts.length - 1 - pos < 0) { - break; - } - } - String changedNameStr = nameStr; - if (classNameParts != null) { - changedNameStr = classNameParts[classNameParts.length - 1 - pos]; - } - String changedNameStr2 = deobfuscation.deobfuscateName(false, changedNameStr, pos == 0, pos == 0 ? "class" : "package", deobfuscated, renameType, selected); - if (changedNameStr2 != null) { - changedNameStr = changedNameStr2; - } - ret++; - deobfuscated.put(nameStr, changedNameStr); - pos++; - } - name = mem.object; - } - if (name instanceof GetVariableActionItem) { - GetVariableActionItem var = (GetVariableActionItem) name; - if (var.name instanceof DirectValueActionItem) { - DirectValueActionItem dvt = (DirectValueActionItem) var.name; - String nameStr = dvt.toStringNoH(null); - if (classNameParts != null) { - if (classNameParts.length - 1 - pos < 0) { - break; - } - } - String changedNameStr = nameStr; - if (classNameParts != null) { - changedNameStr = classNameParts[classNameParts.length - 1 - pos]; - } - String changedNameStr2 = deobfuscation.deobfuscateName(false, changedNameStr, pos == 0, pos == 0 ? "class" : "package", deobfuscated, renameType, selected); - if (changedNameStr2 != null) { - changedNameStr = changedNameStr2; - } - ret++; - deobfuscated.put(nameStr, changedNameStr); - pos++; - } - } - } - t.setModified(true); - } - } - - for (GraphSourceItem fun : allFunctions) { - fc++; - informListeners("rename", "function " + fc + "/" + allFunctions.size()); - if (fun instanceof ActionDefineFunction) { - ActionDefineFunction f = (ActionDefineFunction) fun; - if (f.functionName.isEmpty()) { // anonymous function, leave as is - continue; - } - String changed = deobfuscation.deobfuscateName(false, f.functionName, false, "function", deobfuscated, renameType, selected); - if (changed != null) { - f.replacedFunctionName = changed; - ret++; - } - } - if (fun instanceof ActionDefineFunction2) { - ActionDefineFunction2 f = (ActionDefineFunction2) fun; - if (f.functionName.isEmpty()) { // anonymous function, leave as is - continue; - } - String changed = deobfuscation.deobfuscateName(false, f.functionName, false, "function", deobfuscated, renameType, selected); - if (changed != null) { - f.replacedFunctionName = changed; - ret++; - } - } - } - - HashSet stringsNoVarH = new HashSet<>(); - List allVariableNamesDv = new ArrayList<>(); - for (MyEntry it : allVariableNames) { - allVariableNamesDv.add(it.getKey()); - } - for (DirectValueActionItem ti : allStrings.keySet()) { - if (!allVariableNamesDv.contains(ti)) { - stringsNoVarH.add(System.identityHashCode(allStrings.get(ti)) + "_" + ti.toStringNoH(allStrings.get(ti))); - } - } - - int vc = 0; - for (MyEntry it : allVariableNames) { - vc++; - String name = it.getKey().toStringNoH(it.getValue()); - String changed = deobfuscation.deobfuscateName(false, name, false, usageTypes.get(it.getKey()), deobfuscated, renameType, selected); - if (changed != null) { - boolean addNew = false; - String h = System.identityHashCode(it.getKey()) + "_" + name; - if (stringsNoVarH.contains(h)) { - addNew = true; - } - ActionPush pu = (ActionPush) it.getKey().src; - if (pu.replacement == null) { - pu.replacement = new ArrayList<>(); - pu.replacement.addAll(pu.values); - } - if (pu.replacement.get(it.getKey().pos) instanceof ConstantIndex) { - ConstantIndex ci = (ConstantIndex) pu.replacement.get(it.getKey().pos); - ConstantPool pool = it.getValue(); - if (pool == null) { - continue; - } - if (pool.constants == null) { - continue; - } - if (addNew) { - pool.constants.add(changed); - ci.index = pool.constants.size() - 1; - } else { - pool.constants.set(ci.index, changed); - } - } else { - pu.replacement.set(it.getKey().pos, changed); - } - ret++; - } - } - - for (ASMSource src : actionsMap.keySet()) { - actionsMap.get(src).removeNops(); - src.setActions(actionsMap.get(src)); - src.setModified(); - } - - deobfuscation.deobfuscateInstanceNames(false, deobfuscated, renameType, tags, selected); - return ret; - } - - public void exportFla(AbortRetryIgnoreHandler handler, String outfile, String swfName, String generator, String generatorVerName, String generatorVersion, boolean parallel, FLAVersion version) throws IOException { - XFLConverter.convertSWF(handler, this, swfName, outfile, true, generator, generatorVerName, generatorVersion, parallel, version); - clearAllCache(); - } - - public void exportXfl(AbortRetryIgnoreHandler handler, String outfile, String swfName, String generator, String generatorVerName, String generatorVersion, boolean parallel, FLAVersion version) throws IOException { - XFLConverter.convertSWF(handler, this, swfName, outfile, false, generator, generatorVerName, generatorVersion, parallel, version); - clearAllCache(); - } - - public static AffineTransform matrixToTransform(MATRIX mat) { - return new AffineTransform(mat.getScaleXFloat(), mat.getRotateSkew0Float(), - mat.getRotateSkew1Float(), mat.getScaleYFloat(), - mat.translateX, mat.translateY); - } - - public SerializableImage getFromCache(String key) { - if (frameCache.contains(key)) { - return frameCache.get(key); - } - return null; - } - - public void putToCache(String key, SerializableImage img) { - if (Configuration.useFrameCache.get()) { - frameCache.put(key, img); - } - } - - public void clearImageCache() { - frameCache.clear(); - DefineSpriteTag.clearCache(); - DefineButtonTag.clearCache(); - DefineButton2Tag.clearCache(); - for (Tag tag : tags) { - if (tag instanceof ImageTag) { - ((ImageTag) tag).clearCache(); - } - } - } - - public void clearScriptCache() { - as2Cache.clear(); - as3Cache.clear(); - } - - public void clearAllCache() { - characters = null; - abcList = null; - timeline = null; - clearImageCache(); - clearScriptCache(); - Cache.clearAll(); - Helper.clearShapeCache(); - System.gc(); - } - - public static void uncache(ASMSource src) { - if (src != null) { - src.getSwf().as2Cache.remove(src); - } - } - - public static void uncache(ScriptPack pack) { - if (pack != null) { - pack.getSwf().as3Cache.remove(pack); - } - } - - public static boolean isCached(ASMSource src) { - return src.getSwf().as2Cache.contains(src); - } - - public static boolean isCached(ScriptPack pack) { - return pack.getSwf().as3Cache.contains(pack); - } - - public static CachedScript getCached(ASMSource src, ActionList actions) throws InterruptedException { - SWF swf = src.getSwf(); - if (swf.as2Cache.contains(src)) { - return swf.as2Cache.get(src); - } - - if (actions == null) { - actions = src.getActions(); - } - - HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), true); - Action.actionsToSource(src, actions, src.toString()/*FIXME?*/, writer); - List hilights = writer.instructionHilights; - String srcNoHex = writer.toString(); - CachedScript res = new CachedScript(srcNoHex, hilights); - swf.as2Cache.put(src, res); - return res; - } - - public static CachedDecompilation getCached(ScriptPack pack) throws InterruptedException { - SWF swf = pack.getSwf(); - if (swf.as3Cache.contains(pack)) { - return swf.as3Cache.get(pack); - } - - int scriptIndex = pack.scriptIndex; - ScriptInfo script = null; - if (scriptIndex > -1) { - script = pack.abc.script_info.get(scriptIndex); - } - boolean parallel = Configuration.parallelSpeedUp.get(); - HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), true); - pack.toSource(writer, script.traits.traits, ScriptExportMode.AS, parallel); - HighlightedText hilightedCode = new HighlightedText(writer); - CachedDecompilation res = new CachedDecompilation(hilightedCode); - swf.as3Cache.put(pack, res); - - return res; - } - - public static RECT fixRect(RECT rect) { - RECT ret = new RECT(); - ret.Xmin = rect.Xmin; - ret.Xmax = rect.Xmax; - ret.Ymin = rect.Ymin; - ret.Ymax = rect.Ymax; - - if (ret.Xmax <= 0) { - ret.Xmax = ret.getWidth(); - ret.Xmin = 0; - } - if (ret.Ymax <= 0) { - ret.Ymax = ret.getHeight(); - ret.Ymin = 0; - } - if (ret.Xmin < 0) { - ret.Xmax += (-ret.Xmin); - ret.Xmin = 0; - } - if (ret.Ymin < 0) { - ret.Ymax += (-ret.Ymin); - ret.Ymin = 0; - } - - if (ret.getWidth() < 1 || ret.getHeight() < 1) { - ret.Xmin = 0; - ret.Ymin = 0; - ret.Xmax = 20; - ret.Ymax = 20; - } - return ret; - } - - public static void frameToSvg(Timeline timeline, int frame, int time, DepthState stateUnderCursor, int mouseButton, SVGExporter exporter, ColorTransform colorTransform, int level, double zoom) throws IOException { - if (timeline.getFrameCount() <= frame) { - return; - } - Frame frameObj = timeline.getFrame(frame); - List clips = new ArrayList<>(); - List prevClips = new ArrayList<>(); - - int maxDepth = timeline.getMaxDepth(); - for (int i = 1; i <= maxDepth; i++) { - for (int c = 0; c < clips.size(); c++) { - if (clips.get(c).depth == i) { - exporter.setClip(prevClips.get(c)); - prevClips.remove(c); - clips.remove(c); - } - } - if (!frameObj.layers.containsKey(i)) { - continue; - } - DepthState layer = frameObj.layers.get(i); - if (!timeline.swf.getCharacters().containsKey(layer.characterId)) { - continue; - } - if (!layer.isVisible) { - continue; - } - - CharacterTag character = timeline.swf.getCharacter(layer.characterId); - if (colorTransform == null) { - colorTransform = new ColorTransform(); - } - - ColorTransform clrTrans = colorTransform.clone(); - if (layer.colorTransForm != null && layer.blendMode <= 1) { // Normal blend mode - clrTrans = colorTransform.merge(layer.colorTransForm); - } - - if (character instanceof DrawableTag) { - DrawableTag drawable = (DrawableTag) character; - - String assetName; - Tag drawableTag = (Tag) drawable; - RECT boundRect = drawable.getRect(); - if (exporter.exportedTags.containsKey(drawableTag)) { - assetName = exporter.exportedTags.get(drawableTag); - } else { - assetName = getTagIdPrefix(drawableTag, exporter); - exporter.exportedTags.put(drawableTag, assetName); - exporter.createDefGroup(new ExportRectangle(boundRect), assetName); - drawable.toSVG(exporter, layer.ratio, clrTrans, level + 1, zoom); - exporter.endGroup(); - } - ExportRectangle rect = new ExportRectangle(boundRect); - - // TODO: if (layer.filters != null) - // TODO: if (layer.blendMode > 1) - if (layer.clipDepth > -1) { - String clipName = exporter.getUniqueId("clipPath"); - exporter.createClipPath(new Matrix(), clipName); - SvgClip clip = new SvgClip(clipName, layer.clipDepth); - clips.add(clip); - prevClips.add(exporter.getClip()); - Matrix mat = Matrix.getTranslateInstance(rect.xMin, rect.yMin).preConcatenate(new Matrix(layer.matrix)); - exporter.addUse(mat, boundRect, assetName); - exporter.setClip(clip.shape); - exporter.endGroup(); - } else { - Matrix mat = Matrix.getTranslateInstance(rect.xMin, rect.yMin).preConcatenate(new Matrix(layer.matrix)); - exporter.addUse(mat, boundRect, assetName); - } - } - } - } - - private static String getTagIdPrefix(Tag tag, SVGExporter exporter) { - if (tag instanceof ShapeTag) { - return exporter.getUniqueId("shape"); - } - if (tag instanceof MorphShapeTag) { - return exporter.getUniqueId("morphshape"); - } - if (tag instanceof DefineSpriteTag) { - return exporter.getUniqueId("sprite"); - } - if (tag instanceof TextTag) { - return exporter.getUniqueId("text"); - } - if (tag instanceof ButtonTag) { - return exporter.getUniqueId("button"); - } - return exporter.getUniqueId("tag"); - } - - public static SerializableImage frameToImageGet(Timeline timeline, int frame, int time, DepthState stateUnderCursor, int mouseButton, RECT displayRect, Matrix transformation, ColorTransform colorTransform, Color backGroundColor, boolean useCache, double zoom) { - SWF swf = timeline.swf; - String key = "frame_" + frame + "_" + timeline.id + "_" + swf.hashCode() + "_" + zoom; - SerializableImage image; - if (useCache) { - image = swf.getFromCache(key); - if (image != null) { - return image; - } - } - - if (timeline.getFrameCount() == 0) { - return new SerializableImage(1, 1, SerializableImage.TYPE_INT_ARGB); - } - - RECT rect = displayRect; - image = new SerializableImage((int) (rect.getWidth() * zoom / SWF.unitDivisor) + 1, - (int) (rect.getHeight() * zoom / SWF.unitDivisor) + 1, SerializableImage.TYPE_INT_ARGB); - if (backGroundColor == null) { - image.fillTransparent(); - } else { - Graphics2D g = (Graphics2D) image.getBufferedImage().getGraphics(); - g.setComposite(AlphaComposite.Src); - g.setColor(backGroundColor); - g.fill(new Rectangle(image.getWidth(), image.getHeight())); - } - - Matrix m = transformation.clone(); - m.translate(-rect.Xmin * zoom, -rect.Ymin * zoom); - m.scale(zoom); - RenderContext renderContext = new RenderContext(); - renderContext.stateUnderCursor = stateUnderCursor; - renderContext.mouseButton = mouseButton; - frameToImage(timeline, frame, time, renderContext, image, m, colorTransform); - if (useCache) { - swf.putToCache(key, image); - } - - return image; - } - - public static void framesToImage(Timeline timeline, List ret, int startFrame, int stopFrame, RenderContext renderContext, RECT displayRect, int totalFrameCount, Stack visited, Matrix transformation, ColorTransform colorTransform, double zoom) { - RECT rect = displayRect; - for (int f = 0; f < timeline.getFrameCount(); f++) { - SerializableImage image = new SerializableImage((int) (rect.getWidth() / SWF.unitDivisor) + 1, - (int) (rect.getHeight() / SWF.unitDivisor) + 1, SerializableImage.TYPE_INT_ARGB); - image.fillTransparent(); - Matrix m = new Matrix(); - m.translate(-rect.Xmin, -rect.Ymin); - frameToImage(timeline, f, 0, renderContext, image, m, colorTransform); - ret.add(image); - } - } - - public static void frameToImage(Timeline timeline, int frame, int time, RenderContext renderContext, SerializableImage image, Matrix transformation, ColorTransform colorTransform) { - double unzoom = SWF.unitDivisor; - if (timeline.getFrameCount() <= frame) { - return; - } - Frame frameObj = timeline.getFrame(frame); - Graphics2D g = (Graphics2D) image.getGraphics(); - g.setPaint(frameObj.backgroundColor.toColor()); - g.fill(new Rectangle(image.getWidth(), image.getHeight())); - g.setTransform(transformation.toTransform()); - List clips = new ArrayList<>(); - List prevClips = new ArrayList<>(); - - int maxDepth = timeline.getMaxDepth(); - for (int i = 1; i <= maxDepth; i++) { - for (int c = 0; c < clips.size(); c++) { - if (clips.get(c).depth == i) { - g.setClip(prevClips.get(c)); - prevClips.remove(c); - clips.remove(c); - } - } - if (!frameObj.layers.containsKey(i)) { - continue; - } - DepthState layer = frameObj.layers.get(i); - if (!timeline.swf.getCharacters().containsKey(layer.characterId)) { - continue; - } - if (!layer.isVisible) { - continue; - } - - CharacterTag character = timeline.swf.getCharacter(layer.characterId); - Matrix mat = new Matrix(layer.matrix); - mat = mat.preConcatenate(transformation); - - if (colorTransform == null) { - colorTransform = new ColorTransform(); - } - - ColorTransform clrTrans = colorTransform.clone(); - if (layer.colorTransForm != null && layer.blendMode <= 1) { // Normal blend mode - clrTrans = colorTransform.merge(layer.colorTransForm); - } - - boolean showPlaceholder = false; - if (character instanceof DrawableTag) { - DrawableTag drawable = (DrawableTag) character; - Matrix drawMatrix = new Matrix(); - int drawableFrameCount = drawable.getNumFrames(); - if (drawableFrameCount == 0) { - drawableFrameCount = 1; - } - - int dframe; - if (timeline.fontFrameNum != -1) { - dframe = timeline.fontFrameNum; - } else { - dframe = (time + layer.time) % drawableFrameCount; - } - - if (character instanceof ButtonTag) { - dframe = ButtonTag.FRAME_UP; - if (renderContext.stateUnderCursor == layer) { - if (renderContext.mouseButton > 0) { - dframe = ButtonTag.FRAME_DOWN; - } else { - dframe = ButtonTag.FRAME_OVER; - } - } - } - - RECT boundRect = drawable.getRect(); - ExportRectangle rect = new ExportRectangle(boundRect); - rect = mat.transform(rect); - Matrix m = mat.clone(); - if (layer.filters != null && layer.filters.size() > 0) { - // calculate size after applying the filters - double deltaXMax = 0; - double deltaYMax = 0; - for (FILTER filter : layer.filters) { - double x = filter.getDeltaX(); - double y = filter.getDeltaY(); - deltaXMax = Math.max(x, deltaXMax); - deltaYMax = Math.max(y, deltaYMax); - } - rect.xMin -= deltaXMax * unzoom; - rect.xMax += deltaXMax * unzoom; - rect.yMin -= deltaYMax * unzoom; - rect.yMax += deltaYMax * unzoom; - } - - rect.xMin -= 1 * unzoom; - rect.yMin -= 1 * unzoom; - rect.xMin = Math.max(0, rect.xMin); - rect.yMin = Math.max(0, rect.yMin); - - int newWidth = (int) (rect.getWidth() / unzoom); - int newHeight = (int) (rect.getHeight() / unzoom); - int deltaX = (int) (rect.xMin / unzoom); - int deltaY = (int) (rect.yMin / unzoom); - newWidth = Math.min(image.getWidth() - deltaX, newWidth) + 1; - newHeight = Math.min(image.getHeight() - deltaY, newHeight) + 1; - - if (newWidth <= 0 || newHeight <= 0) { - continue; - } - - m.translate(-rect.xMin, -rect.yMin); - drawMatrix.translate(rect.xMin, rect.yMin); - - SerializableImage img = null; - String cacheKey = null; - if (drawable instanceof ShapeTag) { - cacheKey = ((ShapeTag) drawable).getCharacterId() + m.toString() + clrTrans.toString(); - img = renderContext.shapeCache.get(cacheKey); - } - - if (img == null) { - img = new SerializableImage(newWidth, newHeight, SerializableImage.TYPE_INT_ARGB); - img.fillTransparent(); - - drawable.toImage(dframe, layer.time + time, layer.ratio, renderContext, img, m, clrTrans); - - if (cacheKey != null) { - renderContext.shapeCache.put(cacheKey, img); - } - } - - /*//if (renderContext.stateUnderCursor == layer) { - if (true) { - BufferedImage bi = img.getBufferedImage(); - ColorModel cm = bi.getColorModel(); - boolean isAlphaPremultiplied = cm.isAlphaPremultiplied(); - WritableRaster raster = bi.copyData(null); - img = new SerializableImage(new BufferedImage(cm, raster, isAlphaPremultiplied, null)); - Graphics2D gg = (Graphics2D) img.getGraphics(); - gg.setStroke(new BasicStroke(3)); - gg.setPaint(Color.red); - gg.setTransform(AffineTransform.getTranslateInstance(0, 0)); - gg.draw(SHAPERECORD.twipToPixelShape(drawable.getOutline(dframe, layer.time + time, layer.ratio, renderContext, m))); - }*/ - if (layer.filters != null) { - for (FILTER filter : layer.filters) { - img = filter.apply(img); - } - } - if (layer.blendMode > 1) { - if (layer.colorTransForm != null) { - img = layer.colorTransForm.apply(img); - } - } - - drawMatrix.translateX /= unzoom; - drawMatrix.translateY /= unzoom; - AffineTransform trans = drawMatrix.toTransform(); - - switch (layer.blendMode) { - case 0: - case 1: - g.setComposite(AlphaComposite.SrcOver); - break; - case 2: // Layer - g.setComposite(AlphaComposite.SrcOver); - break; - case 3: - g.setComposite(BlendComposite.Multiply); - break; - case 4: - g.setComposite(BlendComposite.Screen); - break; - case 5: - g.setComposite(BlendComposite.Lighten); - break; - case 6: - g.setComposite(BlendComposite.Darken); - break; - case 7: - g.setComposite(BlendComposite.Difference); - break; - case 8: - g.setComposite(BlendComposite.Add); - break; - case 9: - g.setComposite(BlendComposite.Subtract); - break; - case 10: - g.setComposite(BlendComposite.Invert); - break; - case 11: - g.setComposite(BlendComposite.Alpha); - break; - case 12: - g.setComposite(BlendComposite.Erase); - break; - case 13: - g.setComposite(BlendComposite.Overlay); - break; - case 14: - g.setComposite(BlendComposite.HardLight); - break; - default: // Not implemented - g.setComposite(AlphaComposite.SrcOver); - break; - } - - if (layer.clipDepth > -1) { - BufferedImage mask = new BufferedImage(image.getWidth(), image.getHeight(), image.getType()); - Graphics2D gm = (Graphics2D) mask.getGraphics(); - gm.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); - gm.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); - gm.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - gm.setComposite(AlphaComposite.Src); - gm.setColor(new Color(0, 0, 0, 0f)); - gm.fillRect(0, 0, image.getWidth(), image.getHeight()); - gm.setTransform(trans); - gm.drawImage(img.getBufferedImage(), 0, 0, null); - Clip clip = new Clip(Helper.imageToShape(mask), layer.clipDepth); // Maybe we can get current outline instead converting from image (?) - clips.add(clip); - prevClips.add(g.getClip()); - g.setTransform(AffineTransform.getTranslateInstance(0, 0)); - g.setClip(clip.shape); - } else { - g.setTransform(trans); - g.drawImage(img.getBufferedImage(), 0, 0, null); - } - } else if (character instanceof BoundedTag) { - showPlaceholder = true; - } - - if (showPlaceholder) { - mat.translateX /= unzoom; - mat.translateY /= unzoom; - AffineTransform trans = mat.toTransform(); - g.setTransform(trans); - BoundedTag b = (BoundedTag) character; - g.setPaint(new Color(255, 255, 255, 128)); - g.setComposite(BlendComposite.Invert); - RECT r = b.getRect(); - int div = (int) unzoom; - g.drawString(character.toString(), r.Xmin / div + 3, r.Ymin / div + 15); - g.draw(new Rectangle(r.Xmin / div, r.Ymin / div, r.getWidth() / div, r.getHeight() / div)); - g.drawLine(r.Xmin / div, r.Ymin / div, r.Xmax / div, r.Ymax / div); - g.drawLine(r.Xmax / div, r.Ymin / div, r.Xmin / div, r.Ymax / div); - g.setComposite(AlphaComposite.Dst); - } - } - - g.setTransform(AffineTransform.getScaleInstance(1, 1)); - } - - private void removeTagWithDependenciesFromTimeline(Tag toRemove, Timeline timeline) { - int characterId = 0; - if (toRemove instanceof CharacterTag) { - characterId = ((CharacterTag) toRemove).getCharacterId(); - } - Map stage = new HashMap<>(); - - Set dependingChars = new HashSet<>(); - if (characterId != 0) { - dependingChars.add(characterId); - for (int i = 0; i < timeline.tags.size(); i++) { - Tag t = timeline.tags.get(i); - if (t instanceof CharacterIdTag) { - CharacterIdTag c = (CharacterIdTag) t; - Set needed = new HashSet<>(); - t.getNeededCharacters(needed); - if (needed.contains(characterId)) { - dependingChars.add(c.getCharacterId()); - } - } - } - } - - for (int i = 0; i < timeline.tags.size(); i++) { - Tag t = timeline.tags.get(i); - if (t instanceof RemoveTag) { - RemoveTag rt = (RemoveTag) t; - int depth = rt.getDepth(); - if (stage.containsKey(depth)) { - int currentCharId = stage.get(depth); - stage.remove(depth); - if (dependingChars.contains(currentCharId)) { - timeline.tags.remove(i); - i--; - continue; - } - } - } - if (t instanceof PlaceObjectTypeTag) { - PlaceObjectTypeTag po = (PlaceObjectTypeTag) t; - int placeCharId = po.getCharacterId(); - int depth = po.getDepth(); - if (placeCharId != 0) { - stage.put(depth, placeCharId); - if (dependingChars.contains(placeCharId)) { - timeline.tags.remove(i); - i--; - continue; - } - } - } - if (t instanceof CharacterIdTag) { - CharacterIdTag c = (CharacterIdTag) t; - if (dependingChars.contains(c.getCharacterId())) { - timeline.tags.remove(i); - i--; - continue; - } - } - Set needed = new HashSet<>(); - t.getNeededCharacters(needed); - for (int dep : dependingChars) { - if (needed.contains(dep)) { - timeline.tags.remove(i); - i--; - continue; - } - } - if (t == toRemove) { - timeline.tags.remove(i); - i--; - continue; - } - if (t instanceof Timelined) { - removeTagWithDependenciesFromTimeline(toRemove, ((Timelined) t).getTimeline()); - } - } - } - - private boolean removeTagFromTimeline(Tag toRemove, Timeline timeline) { - boolean modified = false; - int characterId = -1; - if (toRemove instanceof CharacterTag) { - characterId = ((CharacterTag) toRemove).getCharacterId(); - modified = timeline.removeCharacter(characterId); - } - for (int i = 0; i < timeline.tags.size(); i++) { - Tag t = timeline.tags.get(i); - if (t == toRemove) { - timeline.tags.remove(t); - i--; - continue; - } - - if (toRemove instanceof CharacterTag) { - if (t.removeCharacter(characterId)) { - modified = true; - i = -1; - continue; - } - } - - if (t instanceof DefineSpriteTag) { - DefineSpriteTag spr = (DefineSpriteTag) t; - boolean sprModified = removeTagFromTimeline(toRemove, spr.getTimeline()); - if (sprModified) { - spr.setModified(true); - } - modified |= sprModified; - } - } - return modified; - } - - public void removeTags(Collection tags, boolean removeDependencies) { - Set timelineds = new HashSet<>(); - for (Tag tag : tags) { - Timelined timelined = tag.getTimelined(); - timelineds.add(timelined); - removeTagInternal(timelined, tag, removeDependencies); - } - - for (Timelined timelined : timelineds) { - resetTimelines(timelined); - } - - updateCharacters(); - clearImageCache(); - } - - public void removeTag(Tag tag, boolean removeDependencies) { - Timelined timelined = tag.getTimelined(); - removeTagInternal(timelined, tag, removeDependencies); - resetTimelines(timelined); - updateCharacters(); - clearImageCache(); - } - - private void removeTagInternal(Timelined timelined, Tag tag, boolean removeDependencies) { - if (tag instanceof ShowFrameTag || ShowFrameTag.isNestedTagType(tag.getId())) { - List tags; - if (timelined instanceof DefineSpriteTag) { - DefineSpriteTag sprite = (DefineSpriteTag) timelined; - tags = sprite.getSubTags(); - } else { - tags = this.tags; - } - tags.remove(tag); - if (timelined instanceof DefineSpriteTag) { - DefineSpriteTag sprite = (DefineSpriteTag) timelined; - sprite.setModified(true); - } - timelined.resetTimeline(); - } else { - // timeline should be always the swf here - if (removeDependencies) { - removeTagWithDependenciesFromTimeline(tag, timelined.getTimeline()); - if (timelined instanceof DefineSpriteTag) { - DefineSpriteTag sprite = (DefineSpriteTag) timelined; - sprite.setModified(true); - } - } else { - removeTagFromTimeline(tag, timeline); - } - } - } - - @Override - public String toString() { - return getShortFileName(); - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash; + +import SevenZip.Compression.LZMA.Decoder; +import SevenZip.Compression.LZMA.Encoder; +import com.jpexs.decompiler.flash.abc.ABC; +import com.jpexs.decompiler.flash.abc.CachedDecompilation; +import com.jpexs.decompiler.flash.abc.ClassPath; +import com.jpexs.decompiler.flash.abc.RenameType; +import com.jpexs.decompiler.flash.abc.ScriptPack; +import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; +import com.jpexs.decompiler.flash.abc.types.MethodBody; +import com.jpexs.decompiler.flash.abc.types.ScriptInfo; +import com.jpexs.decompiler.flash.action.Action; +import com.jpexs.decompiler.flash.action.ActionGraphSource; +import com.jpexs.decompiler.flash.action.ActionList; +import com.jpexs.decompiler.flash.action.ActionLocalData; +import com.jpexs.decompiler.flash.action.CachedScript; +import com.jpexs.decompiler.flash.action.model.ConstantPool; +import com.jpexs.decompiler.flash.action.model.DirectValueActionItem; +import com.jpexs.decompiler.flash.action.model.FunctionActionItem; +import com.jpexs.decompiler.flash.action.model.GetMemberActionItem; +import com.jpexs.decompiler.flash.action.model.GetVariableActionItem; +import com.jpexs.decompiler.flash.action.model.clauses.ClassActionItem; +import com.jpexs.decompiler.flash.action.model.clauses.InterfaceActionItem; +import com.jpexs.decompiler.flash.action.swf4.ActionEquals; +import com.jpexs.decompiler.flash.action.swf4.ActionGetVariable; +import com.jpexs.decompiler.flash.action.swf4.ActionIf; +import com.jpexs.decompiler.flash.action.swf4.ActionPush; +import com.jpexs.decompiler.flash.action.swf4.ActionSetVariable; +import com.jpexs.decompiler.flash.action.swf4.ConstantIndex; +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.ActionDefineFunction; +import com.jpexs.decompiler.flash.action.swf5.ActionDefineLocal; +import com.jpexs.decompiler.flash.action.swf5.ActionDefineLocal2; +import com.jpexs.decompiler.flash.action.swf5.ActionEquals2; +import com.jpexs.decompiler.flash.action.swf5.ActionGetMember; +import com.jpexs.decompiler.flash.action.swf5.ActionNewMethod; +import com.jpexs.decompiler.flash.action.swf5.ActionNewObject; +import com.jpexs.decompiler.flash.action.swf5.ActionSetMember; +import com.jpexs.decompiler.flash.action.swf7.ActionDefineFunction2; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.dumpview.DumpInfo; +import com.jpexs.decompiler.flash.dumpview.DumpInfoSwfNode; +import com.jpexs.decompiler.flash.ecma.Null; +import com.jpexs.decompiler.flash.exporters.commonshape.ExportRectangle; +import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; +import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; +import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; +import com.jpexs.decompiler.flash.exporters.script.AS2ScriptExporter; +import com.jpexs.decompiler.flash.exporters.script.AS3ScriptExporter; +import com.jpexs.decompiler.flash.exporters.settings.ScriptExportSettings; +import com.jpexs.decompiler.flash.helpers.HighlightedText; +import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter; +import com.jpexs.decompiler.flash.helpers.ImageHelper; +import com.jpexs.decompiler.flash.helpers.SWFDecompilerPlugin; +import com.jpexs.decompiler.flash.helpers.collections.MyEntry; +import com.jpexs.decompiler.flash.helpers.hilight.Highlighting; +import com.jpexs.decompiler.flash.tags.ABCContainerTag; +import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag; +import com.jpexs.decompiler.flash.tags.DefineButton2Tag; +import com.jpexs.decompiler.flash.tags.DefineButtonTag; +import com.jpexs.decompiler.flash.tags.DefineSpriteTag; +import com.jpexs.decompiler.flash.tags.DoInitActionTag; +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.JPEGTablesTag; +import com.jpexs.decompiler.flash.tags.ShowFrameTag; +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.VideoFrameTag; +import com.jpexs.decompiler.flash.tags.base.ASMSource; +import com.jpexs.decompiler.flash.tags.base.ASMSourceContainer; +import com.jpexs.decompiler.flash.tags.base.BoundedTag; +import com.jpexs.decompiler.flash.tags.base.ButtonTag; +import com.jpexs.decompiler.flash.tags.base.CharacterIdTag; +import com.jpexs.decompiler.flash.tags.base.CharacterTag; +import com.jpexs.decompiler.flash.tags.base.DrawableTag; +import com.jpexs.decompiler.flash.tags.base.Exportable; +import com.jpexs.decompiler.flash.tags.base.FontTag; +import com.jpexs.decompiler.flash.tags.base.ImageTag; +import com.jpexs.decompiler.flash.tags.base.MorphShapeTag; +import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag; +import com.jpexs.decompiler.flash.tags.base.RemoveTag; +import com.jpexs.decompiler.flash.tags.base.RenderContext; +import com.jpexs.decompiler.flash.tags.base.ShapeTag; +import com.jpexs.decompiler.flash.tags.base.TextTag; +import com.jpexs.decompiler.flash.tags.enums.ImageFormat; +import com.jpexs.decompiler.flash.timeline.AS2Package; +import com.jpexs.decompiler.flash.timeline.Clip; +import com.jpexs.decompiler.flash.timeline.DepthState; +import com.jpexs.decompiler.flash.timeline.Frame; +import com.jpexs.decompiler.flash.timeline.FrameScript; +import com.jpexs.decompiler.flash.timeline.SvgClip; +import com.jpexs.decompiler.flash.timeline.TagScript; +import com.jpexs.decompiler.flash.timeline.Timeline; +import com.jpexs.decompiler.flash.timeline.Timelined; +import com.jpexs.decompiler.flash.treeitems.SWFList; +import com.jpexs.decompiler.flash.treeitems.TreeItem; +import com.jpexs.decompiler.flash.types.ColorTransform; +import com.jpexs.decompiler.flash.types.MATRIX; +import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.decompiler.flash.types.annotations.Internal; +import com.jpexs.decompiler.flash.types.filters.BlendComposite; +import com.jpexs.decompiler.flash.types.filters.FILTER; +import com.jpexs.decompiler.flash.xfl.FLAVersion; +import com.jpexs.decompiler.flash.xfl.XFLConverter; +import com.jpexs.decompiler.graph.Graph; +import com.jpexs.decompiler.graph.GraphSourceItem; +import com.jpexs.decompiler.graph.GraphSourceItemContainer; +import com.jpexs.decompiler.graph.GraphTargetItem; +import com.jpexs.decompiler.graph.TranslateStack; +import com.jpexs.decompiler.graph.model.LocalData; +import com.jpexs.helpers.Cache; +import com.jpexs.helpers.Helper; +import com.jpexs.helpers.NulStream; +import com.jpexs.helpers.ProgressListener; +import com.jpexs.helpers.SerializableImage; +import com.jpexs.helpers.utf8.Utf8Helper; +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.EmptyStackException; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Stack; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.zip.DeflaterOutputStream; +import java.util.zip.InflaterInputStream; + +/** + * Class representing SWF file + * + * @author JPEXS + */ +public final class SWF implements SWFContainerItem, Timelined { + + // big object for testing cleanup + //BigObject bigObj = new BigObject(); + /** + * Default version of SWF file format + */ + public static final int DEFAULT_VERSION = 10; + + /** + * Maximum SWF file format version + * Needs to be fixed when SWF versions reaches this value + */ + public static final int MAX_VERSION = 30; + + /** + * Tags inside of file + */ + public List tags = new ArrayList<>(); + + @Internal + public boolean hasEndTag = true; + + /** + * ExportRectangle for the display + */ + public RECT displayRect; + + /** + * Movie frame rate + */ + public int frameRate; + + /** + * Number of frames in movie + */ + public int frameCount; + + /** + * Version of SWF + */ + public int version; + + /** + * Uncompressed size of the file + */ + @Internal + public long fileSize; + + /** + * Used compression mode + */ + public SWFCompression compression = SWFCompression.NONE; + + /** + * Compressed size of the file (LZMA) + */ + @Internal + public long compressedSize; + + /** + * LZMA Properties + */ + public byte[] lzmaProperties; + + @Internal + public byte[] uncompressedData; + + @Internal + public byte[] originalUncompressedData; + + /** + * ScaleForm GFx + */ + public boolean gfx = false; + + @Internal + public SWFList swfList; + + @Internal + private String file; + + @Internal + private String fileTitle; + + @Internal + private Map characters; + + @Internal + private List abcList; + + @Internal + private JPEGTablesTag jtt; + + @Internal + public Map sourceFontNamesMap = new HashMap<>(); + + public static final double unitDivisor = 20; + + private static final Logger logger = Logger.getLogger(SWF.class.getName()); + + @Internal + private Timeline timeline; + + @Internal + public DumpInfoSwfNode dumpInfo; + + @Internal + public DefineBinaryDataTag binaryData; + + @Internal + private final HashMap deobfuscated = new HashMap<>(); + + @Internal + private final IdentifiersDeobfuscation deobfuscation = new IdentifiersDeobfuscation(); + + @Internal + private Cache frameCache = Cache.getInstance(false, false, "frame"); + + @Internal + private final Cache as2Cache = Cache.getInstance(true, false, "as2"); + + @Internal + private final Cache as3Cache = Cache.getInstance(true, false, "as3"); + + public void updateCharacters() { + characters = null; + } + + public void clearTagSwfs() { + resetTimelines(this); + updateCharacters(); + + for (Tag tag : tags) { + if (tag instanceof DefineSpriteTag) { + DefineSpriteTag spriteTag = (DefineSpriteTag) tag; + for (Tag tag1 : spriteTag.subTags) { + tag1.setSwf(null); + } + + spriteTag.subTags.clear(); + } + + if (tag instanceof DefineBinaryDataTag) { + DefineBinaryDataTag binaryTag = (DefineBinaryDataTag) tag; + if (binaryTag.innerSwf != null) { + binaryTag.innerSwf.clearTagSwfs(); + } + } + + tag.setSwf(null); + } + + tags.clear(); + if (abcList != null) { + abcList.clear(); + } + + if (swfList != null) { + swfList.swfs.clear(); + } + + as2Cache.clear(); + as3Cache.clear(); + frameCache.clear(); + + timeline = null; + clearDumpInfo(dumpInfo); + dumpInfo = null; + jtt = null; + binaryData = null; + } + + private void clearDumpInfo(DumpInfo di) { + for (DumpInfo childInfo : di.getChildInfos()) { + clearDumpInfo(childInfo); + } + + di.getChildInfos().clear(); + } + + public Map getCharacters() { + if (characters == null) { + synchronized (this) { + if (characters == null) { + Map chars = new HashMap<>(); + parseCharacters(tags, chars); + characters = Collections.unmodifiableMap(chars); + } + } + } + + return characters; + } + + public CharacterTag getCharacter(int characterId) { + return getCharacters().get(characterId); + } + + public String getExportName(int characterId) { + CharacterTag characterTag = getCharacters().get(characterId); + String exportName = characterTag != null ? characterTag.getExportName() : null; + return exportName; + } + + public FontTag getFont(int fontId) { + CharacterTag characterTag = getCharacters().get(fontId); + if (characterTag instanceof FontTag) { + return (FontTag) characterTag; + } + + if (characterTag != null) { + logger.log(Level.SEVERE, "CharacterTag should be a FontTag. characterId: {0}", fontId); + } + + return null; + } + + public ImageTag getImage(int imageId) { + CharacterTag characterTag = getCharacters().get(imageId); + if (characterTag instanceof ImageTag) { + return (ImageTag) characterTag; + } + + if (characterTag != null) { + logger.log(Level.SEVERE, "CharacterTag should be an ImageTag. characterId: {0}", imageId); + } + + return null; + } + + public TextTag getText(int textId) { + CharacterTag characterTag = getCharacters().get(textId); + if (characterTag instanceof TextTag) { + return (TextTag) characterTag; + } + + if (characterTag != null) { + logger.log(Level.SEVERE, "CharacterTag should be a TextTag. characterId: {0}", textId); + } + + return null; + } + + public List getAbcList() { + if (abcList == null) { + synchronized (this) { + if (abcList == null) { + ArrayList newAbcList = new ArrayList<>(); + getAbcTags(tags, newAbcList); + abcList = newAbcList; + } + } + } + + return abcList; + } + + public boolean isAS3() { + FileAttributesTag fileAttributes = getFileAttributes(); + return (fileAttributes != null && fileAttributes.actionScript3) || (fileAttributes == null && !getAbcList().isEmpty()); + } + + public FileAttributesTag getFileAttributes() { + for (Tag t : tags) { + if (t instanceof FileAttributesTag) { + return (FileAttributesTag) t; + } + } + + return null; + } + + public int getNextCharacterId() { + int max = -1; + for (int characterId : getCharacters().keySet()) { + if (characterId > max) { + max = characterId; + } + } + + return max + 1; + } + + public synchronized JPEGTablesTag getJtt() { + if (jtt == null) { + synchronized (this) { + if (jtt == null) { + for (Tag t : tags) { + if (t instanceof JPEGTablesTag) { + jtt = (JPEGTablesTag) t; + break; + } + } + } + } + } + + return jtt; + } + + public String getDocumentClass() { + for (Tag t : tags) { + if (t instanceof SymbolClassTag) { + SymbolClassTag sc = (SymbolClassTag) t; + for (int i = 0; i < sc.tags.size(); i++) { + if (sc.tags.get(i) == 0) { + return sc.names.get(i); + } + } + } + } + + return null; + } + + public void fixCharactersOrder(boolean checkAll) { + Set addedCharacterIds = new HashSet<>(); + Set movedTags = new HashSet<>(); + for (int i = 0; i < tags.size(); i++) { + Tag tag = tags.get(i); + if (checkAll || tag.isModified()) { + Set needed = new HashSet<>(); + tag.getNeededCharacters(needed); + if (tag instanceof CharacterTag) { + CharacterTag characterTag = (CharacterTag) tag; + needed.remove(characterTag.getCharacterId()); + } + boolean moved = false; + for (Integer id : needed) { + if (!addedCharacterIds.contains(id)) { + CharacterTag neededCharacter = getCharacter(id); + if (neededCharacter == null) { + continue; + } + + if (movedTags.contains(neededCharacter)) { + logger.log(Level.SEVERE, "Fixing characters order failed, recursion detected."); + return; + } + + // move the needed character to the current position + tags.remove(neededCharacter); + tags.add(i, neededCharacter); + movedTags.add(neededCharacter); + moved = true; + } + } + + if (moved) { + i--; + continue; + } + } + if (tag instanceof CharacterTag) { + addedCharacterIds.add(((CharacterTag) tag).getCharacterId()); + } + } + } + + public void resetTimelines(Timelined timelined) { + timelined.resetTimeline(); + if (timelined instanceof SWF) { + for (Tag t : ((SWF) timelined).tags) { + if (t instanceof Timelined) { + resetTimelines((Timelined) t); + } + } + } + } + + private void parseCharacters(List list, Map characters) { + for (Tag t : list) { + if (t instanceof CharacterTag) { + int characterId = ((CharacterTag) t).getCharacterId(); + if (characters.containsKey(characterId)) { + logger.log(Level.SEVERE, "SWF already contains characterId={0}", characterId); + } + + if (characterId != 0) { + characters.put(characterId, (CharacterTag) t); + } + } + if (t instanceof DefineSpriteTag) { + parseCharacters(((DefineSpriteTag) t).getSubTags(), characters); + } + } + } + + /** + * Unresolve recursive sprites + */ + private void checkInvalidSprites() { + for (int i = 0; i < tags.size(); i++) { + Tag t = tags.get(i); + if (t instanceof DefineSpriteTag) { + if (!isSpriteValid((DefineSpriteTag) t, new ArrayList())) { + tags.set(i, new TagStub(this, t.getId(), "InvalidSprite", t.getOriginalRange(), null)); + } + } + } + } + + private boolean isSpriteValid(DefineSpriteTag sprite, List path) { + if (path.contains(sprite.spriteId)) { + return false; + } + path.add(sprite.spriteId); + for (Tag t : sprite.subTags) { + if (t instanceof DefineSpriteTag) { + if (!isSpriteValid((DefineSpriteTag) t, path)) { + return false; + } + } + } + path.remove((Integer) sprite.spriteId); + return true; + } + + @Override + public Timeline getTimeline() { + if (timeline == null) { + timeline = new Timeline(this); + } + return timeline; + } + + @Override + public void resetTimeline() { + if (timeline != null) { + timeline.reset(this); + } + } + + /** + * Gets all tags with specified id + * + * @param tagId Identificator of tag type + * @return List of tags + */ + public List getTagData(int tagId) { + List ret = new ArrayList<>(); + for (Tag tag : tags) { + if (tag.getId() == tagId) { + ret.add(tag); + } + } + return ret; + } + + /** + * Saves this SWF into new file + * + * @param os OutputStream to save SWF in + * @throws IOException + */ + public void saveTo(OutputStream os) throws IOException { + saveTo(os, compression); + } + + public String getHeaderBytes() { + return getHeaderBytes(compression, gfx); + } + + private String getHeaderBytes(SWFCompression compression, boolean gfx) { + if (compression == SWFCompression.LZMA_ABC) { + return "ABC"; + } + + String ret = ""; + if (compression == SWFCompression.LZMA) { + ret += 'Z'; + } else if (compression == SWFCompression.ZLIB) { + ret += 'C'; + } else { + if (gfx) { + ret += 'G'; + } else { + ret += 'F'; + } + } + if (gfx) { + ret += 'F'; + ret += 'X'; + } else { + ret += 'W'; + ret += 'S'; + } + return ret; + } + + /** + * Saves this SWF into new file + * + * @param os OutputStream to save SWF in + * @param compression + * @throws IOException + */ + public void saveTo(OutputStream os, SWFCompression compression) throws IOException { + try { + fixCharactersOrder(false); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + SWFOutputStream sos = new SWFOutputStream(baos, version); + sos.writeRECT(displayRect); + sos.writeUI8(0); + sos.writeUI8(frameRate); + sos.writeUI16(frameCount); + + sos.writeTags(tags); + if (hasEndTag) { + sos.writeUI16(0); + } + + sos.close(); + os.write(Utf8Helper.getBytes(getHeaderBytes(compression, gfx))); + os.write(version); + byte[] data = baos.toByteArray(); + sos = new SWFOutputStream(os, version); + sos.writeUI32(data.length + 8); + + if (compression == SWFCompression.LZMA || compression == SWFCompression.LZMA_ABC) { + long uncompressedLength = data.length; + Encoder enc = new Encoder(); + int val = lzmaProperties[0] & 0xFF; + int lc = val % 9; + int remainder = val / 9; + int lp = remainder % 5; + int pb = remainder / 5; + int dictionarySize = 0; + for (int i = 0; i < 4; i++) { + dictionarySize += ((int) (lzmaProperties[1 + i]) & 0xFF) << (i * 8); + } + if (Configuration.lzmaFastBytes.get() > 0) { + enc.SetNumFastBytes(Configuration.lzmaFastBytes.get()); + } + enc.SetDictionarySize(dictionarySize); + enc.SetLcLpPb(lc, lp, pb); + baos = new ByteArrayOutputStream(); + enc.SetEndMarkerMode(true); + enc.Code(new ByteArrayInputStream(data), baos, -1, -1, null); + data = baos.toByteArray(); + if (compression == SWFCompression.LZMA) { + byte[] udata = new byte[4]; + udata[0] = (byte) (data.length & 0xFF); + udata[1] = (byte) ((data.length >> 8) & 0xFF); + udata[2] = (byte) ((data.length >> 16) & 0xFF); + udata[3] = (byte) ((data.length >> 24) & 0xFF); + os.write(udata); + } + enc.WriteCoderProperties(os); + if (compression == SWFCompression.LZMA_ABC) { + byte[] udata = new byte[8]; + udata[0] = (byte) (uncompressedLength & 0xFF); + udata[1] = (byte) ((uncompressedLength >> 8) & 0xFF); + udata[2] = (byte) ((uncompressedLength >> 16) & 0xFF); + udata[3] = (byte) ((uncompressedLength >> 24) & 0xFF); + udata[4] = (byte) ((uncompressedLength >> 32) & 0xFF); + udata[5] = (byte) ((uncompressedLength >> 40) & 0xFF); + udata[6] = (byte) ((uncompressedLength >> 48) & 0xFF); + udata[7] = (byte) ((uncompressedLength >> 56) & 0xFF); + os.write(udata); + } + } else if (compression == SWFCompression.ZLIB) { + os = new DeflaterOutputStream(os); + } + + os.write(data); + } finally { + if (os != null) { + os.close(); + } + } + } + + public boolean isModified() { + for (Tag tag : tags) { + if (tag.isModified()) { + return true; + } + } + return false; + } + + public void clearModified() { + for (Tag tag : tags) { + if (tag.isModified()) { + tag.createOriginalData(); + tag.setModified(false); + } + } + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try { + saveTo(baos, SWFCompression.NONE); + byte[] swfData = baos.toByteArray(); + uncompressedData = swfData; + } catch (IOException ex) { + logger.log(Level.SEVERE, "Cannot save SWF", ex); + } + } + + /** + * Constructs an empty SWF + */ + public SWF() { + + } + + /** + * Construct SWF from stream + * + * @param is Stream to read SWF from + * @param parallelRead Use parallel threads? + * @throws IOException + * @throws java.lang.InterruptedException + */ + public SWF(InputStream is, boolean parallelRead) throws IOException, InterruptedException { + this(is, null, null, null, parallelRead, false, true); + } + + /** + * Construct SWF from stream + * + * @param is Stream to read SWF from + * @param parallelRead Use parallel threads? + * @param lazy + * @throws IOException + * @throws java.lang.InterruptedException + */ + public SWF(InputStream is, boolean parallelRead, boolean lazy) throws IOException, InterruptedException { + this(is, null, null, null, parallelRead, false, lazy); + } + + /** + * Construct SWF from stream + * + * @param is Stream to read SWF from + * @param file Path to the file + * @param fileTitle Title of the SWF + * @param parallelRead Use parallel threads? + * @throws IOException + * @throws java.lang.InterruptedException + */ + public SWF(InputStream is, String file, String fileTitle, boolean parallelRead) throws IOException, InterruptedException { + this(is, file, fileTitle, null, parallelRead, false, true); + } + + /** + * Construct SWF from stream + * + * @param is Stream to read SWF from + * @param listener + * @param parallelRead Use parallel threads? + * @throws IOException + * @throws java.lang.InterruptedException + */ + public SWF(InputStream is, ProgressListener listener, boolean parallelRead) throws IOException, InterruptedException { + this(is, null, null, listener, parallelRead, false, true); + } + + /** + * Construct SWF from stream + * + * @param is Stream to read SWF from + * @param file Path to the file + * @param fileTitle Title of the SWF + * @param listener + * @param parallelRead Use parallel threads? + * @throws IOException + * @throws java.lang.InterruptedException + */ + public SWF(InputStream is, String file, String fileTitle, ProgressListener listener, boolean parallelRead) throws IOException, InterruptedException { + this(is, file, fileTitle, listener, parallelRead, false, true); + } + + /** + * Faster constructor to check SWF only + * + * @param is + * @throws java.io.IOException + */ + public SWF(InputStream is) throws IOException { + decompress(is, new NulStream(), true); + } + + /** + * Construct SWF from stream + * + * @param is Stream to read SWF from + * @param file Path to the file + * @param fileTitle Title of the SWF + * @param listener + * @param parallelRead Use parallel threads? + * @param checkOnly Check only file validity + * @param lazy + * @throws IOException + * @throws java.lang.InterruptedException + */ + public SWF(InputStream is, String file, String fileTitle, ProgressListener listener, boolean parallelRead, boolean checkOnly, boolean lazy) throws IOException, InterruptedException { + this.file = file; + this.fileTitle = fileTitle; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + SWFHeader header = decompress(is, baos, true); + gfx = header.gfx; + compression = header.compression; + lzmaProperties = header.lzmaProperties; + uncompressedData = baos.toByteArray(); + originalUncompressedData = uncompressedData; + + SWFInputStream sis = new SWFInputStream(this, uncompressedData); + dumpInfo = new DumpInfoSwfNode(this, "rootswf", "", null, 0, 0); + sis.dumpInfo = dumpInfo; + sis.readBytesEx(3, "signature"); // skip siganture + version = sis.readUI8("version"); + fileSize = sis.readUI32("fileSize"); + dumpInfo.lengthBytes = fileSize; + if (listener != null) { + sis.addPercentListener(listener); + } + sis.setPercentMax(fileSize); + displayRect = sis.readRECT("displayRect"); + // FIXED8 (16 bit fixed point) frameRate + sis.readUI8("tmpFirstByetOfFrameRate"); // tmpFirstByetOfFrameRate + frameRate = sis.readUI8("frameRate"); + frameCount = sis.readUI16("frameCount"); + List tags = sis.readTagList(this, 0, parallelRead, true, !checkOnly, lazy); + if (tags.size() > 0 && tags.get(tags.size() - 1).getId() == EndTag.ID) { + tags.remove(tags.size() - 1); + } else { + hasEndTag = false; + } + this.tags = tags; + if (!checkOnly) { + checkInvalidSprites(); + updateCharacters(); + assignExportNamesToSymbols(); + assignClassesToSymbols(); + SWFDecompilerPlugin.fireSwfParsed(this); + } else { + boolean hasNonUnknownTag = false; + for (Tag tag : tags) { + if (tag.getOriginalDataLength() > 0 && Tag.getRequiredTags().contains(tag.getId())) { + hasNonUnknownTag = true; + } + } + if (!hasNonUnknownTag) { + throw new IOException("Invalid SWF file. No known tag found."); + } + } + + /*preload shape tags + for (Tag tag : tags) { + if (tag instanceof ShapeTag) { + ((ShapeTag) tag).getShapes(); + } + }*/ + } + + @Override + public SWF getSwf() { + return this; + } + + public SWF getRootSwf() { + SWF result = this; + while (result.binaryData != null) { + result = result.binaryData.getSwf(); + } + + return result; + } + + public String getFile() { + return file; + } + + /** + * Get title of the file + * + * @return file title + */ + public String getFileTitle() { + if (fileTitle != null) { + return fileTitle; + } + return file; + } + + public String getShortFileName() { + String title = getFileTitle(); + if (title == null) { + return ""; + } + return new File(title).getName(); + } + + public void setFile(String file) { + this.file = file; + fileTitle = null; + } + + private static void getAbcTags(List list, List actionScripts) { + for (Tag t : list) { + if (t instanceof DefineSpriteTag) { + getAbcTags(((DefineSpriteTag) t).getSubTags(), actionScripts); + } + if (t instanceof ABCContainerTag) { + actionScripts.add((ABCContainerTag) t); + } + } + } + + public void assignExportNamesToSymbols() { + HashMap exportNames = new HashMap<>(); + for (Tag t : tags) { + if (t instanceof ExportAssetsTag) { + ExportAssetsTag eat = (ExportAssetsTag) t; + for (int i = 0; i < eat.tags.size(); i++) { + Integer tagId = eat.tags.get(i); + String name = eat.names.get(i); + if ((!exportNames.containsKey(tagId)) && (!exportNames.containsValue(name))) { + exportNames.put(tagId, name); + } + } + } + } + for (Tag t : tags) { + if (t instanceof CharacterTag) { + CharacterTag ct = (CharacterTag) t; + if (exportNames.containsKey(ct.getCharacterId())) { + ct.setExportName(exportNames.get(ct.getCharacterId())); + } + } + } + } + + public void assignClassesToSymbols() { + HashMap classes = new HashMap<>(); + for (Tag t : tags) { + if (t instanceof SymbolClassTag) { + SymbolClassTag sct = (SymbolClassTag) t; + for (int i = 0; i < sct.tags.size(); i++) { + if ((!classes.containsKey(sct.tags.get(i))) && (!classes.containsValue(sct.names.get(i)))) { + classes.put(sct.tags.get(i), sct.names.get(i)); + } + } + } + } + for (Tag t : tags) { + if (t instanceof CharacterTag) { + CharacterTag ct = (CharacterTag) t; + if (classes.containsKey(ct.getCharacterId())) { + ct.setClassName(classes.get(ct.getCharacterId())); + } + } + } + } + + /** + * Compress SWF file + * + * @param fis Input stream + * @param fos Output stream + * @return True on success + */ + public static boolean fws2cws(InputStream fis, OutputStream fos) { + try { + byte[] swfHead = new byte[8]; + fis.read(swfHead); + + if (swfHead[0] != 'F') { + fis.close(); + return false; + } + swfHead[0] = 'C'; + fos.write(swfHead); + fos = new DeflaterOutputStream(fos); + int i; + while ((i = fis.read()) != -1) { + fos.write(i); + } + + fis.close(); + fos.close(); + } catch (IOException ex) { + return false; + } + return true; + } + + public static boolean decompress(InputStream fis, OutputStream fos) { + try { + decompress(fis, fos, false); + return true; + } catch (IOException ex) { + return false; + } + } + + private static void decodeLZMAStream(InputStream is, OutputStream os, byte[] lzmaProperties, long fileSize) throws IOException { + Decoder decoder = new Decoder(); + if (!decoder.SetDecoderProperties(lzmaProperties)) { + throw new IOException("LZMA:Incorrect stream properties"); + } + if (!decoder.Code(is, os, fileSize - 8)) { + throw new IOException("LZMA:Error in data stream"); + } + } + + private static SWFHeader decompress(InputStream is, OutputStream os, boolean allowUncompressed) throws IOException { + byte[] hdr = new byte[8]; + + // SWFheader: signature, version and fileSize + if (is.read(hdr) != 8) { + throw new IOException("SWF header is too short"); + } + + String signature = new String(hdr, 0, 3, Utf8Helper.charset); + if (!Arrays.asList( + "FWS", // Uncompressed Flash + "CWS", // ZLib compressed Flash + "ZWS", // LZMA compressed Flash + "GFX", // Uncompressed ScaleForm GFx + "CFX", // Compressed ScaleForm GFx + "ABC" // Non-standard LZMA compressed Flash + ).contains(signature)) { + throw new IOException("Invalid SWF file"); + } + + int version = hdr[3]; + SWFInputStream sis = new SWFInputStream(null, Arrays.copyOfRange(hdr, 4, 8), 4, 4); + long fileSize = sis.readUI32("fileSize"); + SWFHeader header = new SWFHeader(); + header.version = version; + header.fileSize = fileSize; + + if (hdr[1] == 'F' && hdr[2] == 'X') { + header.gfx = true; + } + + try (SWFOutputStream sos = new SWFOutputStream(os, version)) { + sos.write(Utf8Helper.getBytes(header.gfx ? "GFX" : "FWS")); + sos.writeUI8(version); + sos.writeUI32(fileSize); + + switch (hdr[0]) { + case 'C': { // CWS, CFX + Helper.copyStream(new InflaterInputStream(is), os, fileSize - 8); + header.compression = SWFCompression.ZLIB; + break; + } + case 'Z': { // ZWS + byte[] lzmaprop = new byte[9]; + is.read(lzmaprop); + sis = new SWFInputStream(null, lzmaprop); + sis.readUI32("LZMAsize"); // compressed LZMA data size = compressed SWF - 17 byte, + // where 17 = 8 byte header + this 4 byte + 5 bytes decoder properties + int propertiesSize = 5; + byte[] lzmaProperties = sis.readBytes(propertiesSize, "lzmaproperties"); + if (lzmaProperties.length != propertiesSize) { + throw new IOException("LZMA:input .lzma file is too short"); + } + + decodeLZMAStream(is, os, lzmaProperties, fileSize); + + header.compression = SWFCompression.LZMA; + header.lzmaProperties = lzmaProperties; + break; + } + case 'A': { // ABC + byte[] lzmaProperties = new byte[5]; + is.read(lzmaProperties); + byte[] uncompressedLength = new byte[8]; + is.read(uncompressedLength); + + decodeLZMAStream(is, os, lzmaProperties, fileSize); + + header.compression = SWFCompression.LZMA_ABC; + header.lzmaProperties = lzmaProperties; + break; + } + default: { // FWS, GFX + if (allowUncompressed) { + Helper.copyStream(is, os, fileSize - 8); + } else { + throw new IOException("SWF is not compressed"); + } + } + } + + return header; + } + } + + public static boolean renameInvalidIdentifiers(RenameType renameType, InputStream fis, OutputStream fos) { + try { + SWF swf = new SWF(fis, Configuration.parallelSpeedUp.get()); + int cnt = swf.deobfuscateIdentifiers(renameType); + swf.assignClassesToSymbols(); + System.out.println(cnt + " identifiers renamed."); + swf.saveTo(fos); + } catch (InterruptedException ex) { + return false; + } catch (IOException ex) { + return false; + } + return true; + } + + public boolean exportAS3Class(String className, String outdir, ScriptExportSettings exportSettings, boolean parallel, EventListener evl) throws Exception { + boolean exported = false; + + List abcList = getAbcList(); + for (int i = 0; i < abcList.size(); i++) { + ABC abc = abcList.get(i).getABC(); + List scrs = abc.findScriptPacksByPath(className); + for (int j = 0; j < scrs.size(); j++) { + ScriptPack scr = scrs.get(j); + String cnt = ""; + if (scrs.size() > 1) { + cnt = "script " + (j + 1) + "/" + scrs.size() + " "; + } + String eventData = cnt + scr.getPath() + " ..."; + evl.handleExportingEvent("tag", i + 1, abcList.size(), eventData); + scr.export(outdir, exportSettings, parallel); + evl.handleExportedEvent("tag", i + 1, abcList.size(), eventData); + exported = true; + } + } + return exported; + } + + private List uniqueAS3Packs(List packs) { + List ret = new ArrayList<>(); + Set classPaths = new HashSet<>(); + for (ScriptPack item : packs) { + ClassPath key = item.getClassPath(); + if (classPaths.contains(key)) { + logger.log(Level.SEVERE, "Duplicate pack path found (" + key + ")!"); + } else { + classPaths.add(key); + ret.add(item); + } + } + return ret; + } + + public List getAS3Packs() { + List packs = new ArrayList<>(); + for (ABCContainerTag abcTag : getAbcList()) { + packs.addAll(abcTag.getABC().getScriptPacks(null)); + } + return uniqueAS3Packs(packs); + } + + @Override + public RECT getRect() { + return displayRect; + } + + @Override + public RECT getRect(Set added) { + return displayRect; + } + + public EventListener getExportEventListener() { + EventListener evl = new EventListener() { + @Override + public void handleExportingEvent(String type, int index, int count, Object data) { + for (EventListener listener : listeners) { + listener.handleExportingEvent(type, index, count, data); + } + } + + @Override + public void handleExportedEvent(String type, int index, int count, Object data) { + for (EventListener listener : listeners) { + listener.handleExportedEvent(type, index, count, data); + } + } + + @Override + public void handleEvent(String event, Object data) { + informListeners(event, data); + } + }; + + return evl; + } + + public List exportActionScript(AbortRetryIgnoreHandler handler, String outdir, ScriptExportSettings exportSettings, boolean parallel, EventListener evl) throws IOException { + List ret = new ArrayList<>(); + + if (isAS3()) { + ret.addAll(new AS3ScriptExporter().exportActionScript3(this, handler, outdir, exportSettings, parallel, evl)); + } else { + ret.addAll(new AS2ScriptExporter().exportAS2ScriptsTimeout(handler, outdir, getASMs(true), exportSettings, evl)); + } + return ret; + } + + public Map getASMs(boolean exportFileNames) { + return getASMs(exportFileNames, new ArrayList(), true); + } + + public Map getASMs(boolean exportFileNames, List nodesToExport, boolean exportAll) { + Map asmsToExport = new HashMap<>(); + for (TreeItem treeItem : getFirstLevelASMNodes(null)) { + getASMs(exportFileNames, treeItem, nodesToExport, exportAll, asmsToExport, File.separator + getASMPath(exportFileNames, treeItem)); + } + + return asmsToExport; + } + + private void getASMs(boolean exportFileNames, TreeItem treeItem, List nodesToExport, boolean exportAll, Map asmsToExport, String path) { + boolean exportNode = nodesToExport.contains(treeItem); + TreeItem realItem = treeItem instanceof TagScript ? ((TagScript) treeItem).getTag() : treeItem; + if (realItem instanceof ASMSource && (exportAll || exportNode)) { + String npath = path; + int ppos = 1; + while (asmsToExport.containsKey(npath)) { + ppos++; + npath = path + (exportFileNames ? "[" + ppos + "]" : "_" + ppos); + } + asmsToExport.put(npath, (ASMSource) realItem); + } + + if (treeItem instanceof TagScript) { + TagScript tagScript = (TagScript) treeItem; + for (TreeItem subItem : tagScript.getFrames()) { + getASMs(exportFileNames, subItem, nodesToExport, exportAll, asmsToExport, path + File.separator + getASMPath(exportFileNames, subItem)); + } + } else if (treeItem instanceof FrameScript) { + FrameScript frameScript = (FrameScript) treeItem; + Frame parentFrame = frameScript.getFrame(); + for (TreeItem subItem : parentFrame.actionContainers) { + getASMs(exportFileNames, getASMWrapToTagScript(subItem), nodesToExport, exportAll || exportNode, asmsToExport, path + File.separator + getASMPath(exportFileNames, subItem)); + } + for (TreeItem subItem : parentFrame.actions) { + getASMs(exportFileNames, getASMWrapToTagScript(subItem), nodesToExport, exportAll || exportNode, asmsToExport, path + File.separator + getASMPath(exportFileNames, subItem)); + } + } else if (treeItem instanceof AS2Package) { + AS2Package as2Package = (AS2Package) treeItem; + for (TreeItem subItem : as2Package.subPackages.values()) { + getASMs(exportFileNames, subItem, nodesToExport, exportAll, asmsToExport, path + File.separator + getASMPath(exportFileNames, subItem)); + } + for (TreeItem subItem : as2Package.scripts.values()) { + getASMs(exportFileNames, subItem, nodesToExport, exportAll, asmsToExport, path + File.separator + getASMPath(exportFileNames, subItem)); + } + } + } + + private String getASMPath(boolean exportFileName, TreeItem treeItem) { + if (!exportFileName) { + return treeItem.toString(); + } + + String result; + if (treeItem instanceof Exportable) { + result = ((Exportable) treeItem).getExportFileName(); + } else { + result = treeItem.toString(); + } + + return Helper.makeFileName(result); + } + + private TreeItem getASMWrapToTagScript(TreeItem treeItem) { + if (treeItem instanceof Tag) { + Tag resultTag = (Tag) treeItem; + List subNodes = new ArrayList<>(); + if (treeItem instanceof ASMSourceContainer) { + for (ASMSource item : ((ASMSourceContainer) treeItem).getSubItems()) { + subNodes.add(item); + } + } + + TagScript tagScript = new TagScript(treeItem.getSwf(), resultTag, subNodes); + return tagScript; + } + + return treeItem; + } + + public List getFirstLevelASMNodes(Map tagScriptCache) { + Timeline timeline = getTimeline(); + List subNodes = new ArrayList<>(); + List subFrames = new ArrayList<>(); + subNodes.addAll(timeline.getAS2RootPackage().subPackages.values()); + subNodes.addAll(timeline.getAS2RootPackage().scripts.values()); + + for (Tag tag : timeline.otherTags) { + boolean hasInnerFrames = false; + List tagSubNodes = new ArrayList<>(); + if (tag instanceof Timelined) { + Timeline timeline2 = ((Timelined) tag).getTimeline(); + for (Frame frame : timeline2.getFrames()) { + if (!frame.actions.isEmpty() || !frame.actionContainers.isEmpty()) { + FrameScript frameScript = new FrameScript(this, frame); + tagSubNodes.add(frameScript); + hasInnerFrames = true; + } + } + } + + if (tag instanceof ASMSourceContainer) { + for (ASMSource asm : ((ASMSourceContainer) tag).getSubItems()) { + tagSubNodes.add(asm); + } + } + + if (!tagSubNodes.isEmpty()) { + TagScript ts = new TagScript(this, tag, tagSubNodes); + if (tagScriptCache != null) { + tagScriptCache.put(tag, ts); + } + if (hasInnerFrames) { + subFrames.add(ts); + } else { + subNodes.add(ts); + } + } + } + + subNodes.addAll(subFrames); + for (Frame frame : timeline.getFrames()) { + if (!frame.actions.isEmpty() || !frame.actionContainers.isEmpty()) { + FrameScript frameScript = new FrameScript(this, frame); + subNodes.add(frameScript); + } + } + + return subNodes; + } + + private final HashSet listeners = new HashSet<>(); + + public final void addEventListener(EventListener listener) { + listeners.add(listener); + for (Tag t : tags) { + if (t instanceof ABCContainerTag) { + (((ABCContainerTag) t).getABC()).addEventListener(listener); + } + } + } + + public final void removeEventListener(EventListener listener) { + listeners.remove(listener); + for (Tag t : tags) { + if (t instanceof ABCContainerTag) { + (((ABCContainerTag) t).getABC()).removeEventListener(listener); + } + } + } + + protected void informListeners(String event, Object data) { + for (EventListener listener : listeners) { + listener.handleEvent(event, data); + } + } + + public static void populateVideoFrames(int streamId, List tags, HashMap output) { + for (Tag t : tags) { + if (t instanceof VideoFrameTag) { + output.put(((VideoFrameTag) t).frameNum, (VideoFrameTag) t); + } + if (t instanceof DefineSpriteTag) { + populateVideoFrames(streamId, ((DefineSpriteTag) t).getSubTags(), output); + } + } + } + + private static void writeLE(OutputStream os, long val, int size) throws IOException { + for (int i = 0; i < size; i++) { + os.write((int) (val & 0xff)); + val >>= 8; + } + } + + public static void createWavFromPcmData(OutputStream fos, int soundRateHz, boolean soundSize, boolean soundType, byte[] data) throws IOException { + ByteArrayOutputStream subChunk1Data = new ByteArrayOutputStream(); + int audioFormat = 1; // PCM + writeLE(subChunk1Data, audioFormat, 2); + int numChannels = soundType ? 2 : 1; + writeLE(subChunk1Data, numChannels, 2); + int[] rateMap = {5512, 11025, 22050, 44100}; + int sampleRate = soundRateHz; // rateMap[soundRate]; + writeLE(subChunk1Data, sampleRate, 4); + int bitsPerSample = soundSize ? 16 : 8; + int byteRate = sampleRate * numChannels * bitsPerSample / 8; + writeLE(subChunk1Data, byteRate, 4); + int blockAlign = numChannels * bitsPerSample / 8; + writeLE(subChunk1Data, blockAlign, 2); + writeLE(subChunk1Data, bitsPerSample, 2); + + ByteArrayOutputStream chunks = new ByteArrayOutputStream(); + chunks.write(Utf8Helper.getBytes("fmt ")); + byte[] subChunk1DataBytes = subChunk1Data.toByteArray(); + writeLE(chunks, subChunk1DataBytes.length, 4); + chunks.write(subChunk1DataBytes); + + chunks.write(Utf8Helper.getBytes("data")); + writeLE(chunks, data.length, 4); + chunks.write(data); + + fos.write(Utf8Helper.getBytes("RIFF")); + byte[] chunkBytes = chunks.toByteArray(); + writeLE(fos, 4 + chunkBytes.length, 4); + fos.write(Utf8Helper.getBytes("WAVE")); + fos.write(chunkBytes); + } + + public static String getTypePrefix(CharacterTag c) { + if (c instanceof ShapeTag) { + return "shape"; + } + if (c instanceof MorphShapeTag) { + return "morphshape"; + } + if (c instanceof DefineSpriteTag) { + return "sprite"; + } + if (c instanceof TextTag) { + return "text"; + } + if (c instanceof ButtonTag) { + return "button"; + } + if (c instanceof FontTag) { + return "font"; + } + if (c instanceof ImageTag) { + return "image"; + } + return "character"; + } + + public static void writeLibrary(SWF fswf, Set library, OutputStream fos) throws IOException { + for (int c : library) { + CharacterTag ch = fswf.getCharacter(c); + if (ch instanceof FontTag) { + fos.write(Utf8Helper.getBytes("function " + getTypePrefix(ch) + c + "(ctx,ch,textColor){\r\n")); + fos.write(Utf8Helper.getBytes(((FontTag) ch).toHtmlCanvas(1))); + fos.write(Utf8Helper.getBytes("}\r\n\r\n")); + } else { + if (ch instanceof ImageTag) { + ImageTag image = (ImageTag) ch; + ImageFormat format = image.getImageFormat(); + InputStream imageStream = image.getImageData(); + byte[] imageData; + if (imageStream != null) { + imageData = Helper.readStream(image.getImageData()); + } else { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ImageHelper.write(image.getImage().getBufferedImage(), format, baos); + imageData = baos.toByteArray(); + } + String base64ImgData = Helper.byteArrayToBase64String(imageData); + fos.write(Utf8Helper.getBytes("var imageObj" + c + " = document.createElement(\"img\");\r\nimageObj" + c + ".src=\"data:image/" + format + ";base64," + base64ImgData + "\";\r\n")); + } + fos.write(Utf8Helper.getBytes("function " + getTypePrefix(ch) + c + "(ctx,ctrans,frame,ratio,time){\r\n")); + if (ch instanceof DrawableTag) { + fos.write(Utf8Helper.getBytes(((DrawableTag) ch).toHtmlCanvas(1))); + } + fos.write(Utf8Helper.getBytes("}\r\n\r\n")); + } + } + } + + private static void getVariables(ConstantPool constantPool, BaseLocalData localData, TranslateStack stack, List output, ActionGraphSource code, int ip, List> variables, List functions, HashMap strings, List visited, HashMap usageTypes, String path) throws InterruptedException { + boolean debugMode = false; + while ((ip > -1) && ip < code.size()) { + if (visited.contains(ip)) { + break; + } + GraphSourceItem ins = code.get(ip); + + if (debugMode) { + System.err.println("Visit " + ip + ": ofs" + Helper.formatAddress(((Action) ins).getAddress()) + ":" + ((Action) ins).getASMSource(new ActionList(), new HashSet(), ScriptExportMode.PCODE) + " stack:" + Helper.stackToString(stack, LocalData.create(new ConstantPool()))); + } + if (ins.isExit()) { + break; + } + if (ins.isIgnored()) { + ip++; + continue; + } + + String usageType = "name"; + GraphTargetItem name = null; + if ((ins instanceof ActionGetVariable) + || (ins instanceof ActionGetMember) + || (ins instanceof ActionDefineLocal2) + || (ins instanceof ActionNewMethod) + || (ins instanceof ActionNewObject) + || (ins instanceof ActionCallMethod) + || (ins instanceof ActionCallFunction)) { + if (stack.isEmpty()) { + break; + } + name = stack.peek(); + } + + if ((ins instanceof ActionGetVariable) || (ins instanceof ActionDefineLocal2)) { + usageType = "variable"; + } + if (ins instanceof ActionGetMember) { + usageType = "member"; + } + if ((ins instanceof ActionNewMethod) || (ins instanceof ActionNewObject)) { + usageType = "class"; + } + if (ins instanceof ActionCallMethod) { + usageType = "function"; // can there be method? + } + if (ins instanceof ActionCallFunction) { + usageType = "function"; + } + + if ((ins instanceof ActionDefineFunction) || (ins instanceof ActionDefineFunction2)) { + functions.add(ins); + } + + if (ins instanceof GraphSourceItemContainer) { + GraphSourceItemContainer cnt = (GraphSourceItemContainer) ins; + List cntSizes = cnt.getContainerSizes(); + long addr = code.pos2adr(ip + 1); + ip = code.adr2pos(addr); + String cntName = cnt.getName(); + for (Long size : cntSizes) { + if (size == 0) { + continue; + } + ip = code.adr2pos(addr); + addr += size; + int nextip = code.adr2pos(addr); + getVariables(variables, functions, strings, usageTypes, new ActionGraphSource(code.getActions().subList(ip, nextip), code.version, new HashMap(), new HashMap(), new HashMap()), 0, path + (cntName == null ? "" : "/" + cntName)); + ip = nextip; + } + List> r = new ArrayList<>(); + r.add(new ArrayList()); + r.add(new ArrayList()); + r.add(new ArrayList()); + try { + ((GraphSourceItemContainer) ins).translateContainer(r, stack, output, new HashMap(), new HashMap(), new HashMap()); + } catch (EmptyStackException ex) { + } + + continue; + } + + if ((ins instanceof ActionSetVariable) || (ins instanceof ActionSetMember) || (ins instanceof ActionDefineLocal)) { + if (stack.size() < 2) { + break; + } + name = stack.get(stack.size() - 2); + } + + if ((ins instanceof ActionSetVariable) || (ins instanceof ActionDefineLocal)) { + usageType = "variable"; + } + + if (ins instanceof ActionSetMember) { + usageType = "member"; + } + + if (name instanceof DirectValueActionItem) { + variables.add(new MyEntry<>((DirectValueActionItem) name, constantPool)); + usageTypes.put((DirectValueActionItem) name, usageType); + } + + // for..in return + if (((ins instanceof ActionEquals) || (ins instanceof ActionEquals2)) && (stack.size() == 1) && (stack.peek() instanceof DirectValueActionItem)) { + stack.push(new DirectValueActionItem(null, 0, new Null(), new ArrayList())); + } + + if (ins instanceof ActionConstantPool) { + constantPool = new ConstantPool(((ActionConstantPool) ins).constantPool); + } + int staticOperation = Graph.SOP_USE_STATIC; //(Boolean) Configuration.getConfig("autoDeobfuscate", true) ? Graph.SOP_SKIP_STATIC : Graph.SOP_USE_STATIC; + + try { + ins.translate(localData, stack, output, staticOperation, path); + } catch (EmptyStackException ex) { + // probably obfucated code, never executed branch + break; + } + if (ins.isExit()) { + break; + } + + if (ins instanceof ActionPush) { + if (!stack.isEmpty()) { + GraphTargetItem top = stack.peek(); + if (top instanceof DirectValueActionItem) { + DirectValueActionItem dvt = (DirectValueActionItem) top; + if ((dvt.value instanceof String) || (dvt.value instanceof ConstantIndex)) { + if (constantPool == null) { + constantPool = new ConstantPool(dvt.constants); + } + strings.put(dvt, constantPool); + } + } + } + } + + if (ins.isBranch() || ins.isJump()) { + if (ins instanceof ActionIf) { + if (stack.isEmpty()) { + break; + } + stack.pop(); + } + visited.add(ip); + List branches = ins.getBranches(code); + for (int b : branches) { + TranslateStack brStack = (TranslateStack) stack.clone(); + if (b >= 0) { + getVariables(constantPool, localData, brStack, output, code, b, variables, functions, strings, visited, usageTypes, path); + } else { + if (debugMode) { + System.out.println("Negative branch:" + b); + } + } + } + // } + break; + } + ip++; + }; + } + + private static void getVariables(List> variables, List functions, HashMap strings, HashMap usageTypes, ActionGraphSource code, int addr, String path) throws InterruptedException { + ActionLocalData localData = new ActionLocalData(); + getVariables(null, localData, new TranslateStack(), new ArrayList(), code, code.adr2pos(addr), variables, functions, strings, new ArrayList(), usageTypes, path); + } + + private List> getVariables(List> variables, HashMap actionsMap, List functions, HashMap strings, HashMap usageTypes, ASMSource src, String path) throws InterruptedException { + List> ret = new ArrayList<>(); + ActionList actions = src.getActions(); + actionsMap.put(src, actions); + getVariables(variables, functions, strings, usageTypes, new ActionGraphSource(actions, version, new HashMap(), new HashMap(), new HashMap()), 0, path); + return ret; + } + + private void getVariables(List tags, String path, List> variables, HashMap actionsMap, List functions, HashMap strings, HashMap usageTypes) throws InterruptedException { + List processed = new ArrayList<>(); + for (Tag t : tags) { + String subPath = path + "/" + t.toString(); + if (t instanceof ASMSource) { + addVariable((ASMSource) t, subPath, processed, variables, actionsMap, functions, strings, usageTypes); + } + if (t instanceof ASMSourceContainer) { + List processed2 = new ArrayList<>(); + for (ASMSource asm : ((ASMSourceContainer) t).getSubItems()) { + addVariable(asm, subPath + "/" + asm.toString(), processed2, variables, actionsMap, functions, strings, usageTypes); + } + } + if (t instanceof DefineSpriteTag) { + getVariables(((DefineSpriteTag) t).getSubTags(), path + "/" + t.toString(), variables, actionsMap, functions, strings, usageTypes); + } + } + } + + private void addVariable(ASMSource asm, String path, List processed, List> variables, HashMap actionsMap, List functions, HashMap strings, HashMap usageTypes) throws InterruptedException { + int pos = 1; + String infPath2 = path; + while (processed.contains(infPath2)) { + pos++; + infPath2 = path + "[" + pos + "]"; + } + processed.add(infPath2); + informListeners("getVariables", infPath2); + getVariables(variables, actionsMap, functions, strings, usageTypes, asm, path); + } + + public void fixAS3Code() { + for (ABCContainerTag abcTag : getAbcList()) { + ABC abc = abcTag.getABC(); + for (MethodBody body : abc.bodies) { + AVM2Code code = body.getCode(); + } + + ((Tag) abcTag).setModified(true); + } + } + + public int deobfuscateAS3Identifiers(RenameType renameType) { + for (Tag tag : tags) { + if (tag instanceof ABCContainerTag) { + ((ABCContainerTag) tag).getABC().deobfuscateIdentifiers(deobfuscated, renameType, true); + tag.setModified(true); + } + } + for (Tag tag : tags) { + if (tag instanceof ABCContainerTag) { + ((ABCContainerTag) tag).getABC().deobfuscateIdentifiers(deobfuscated, renameType, false); + tag.setModified(true); + } + } + for (Tag tag : tags) { + if (tag instanceof SymbolClassTag) { + SymbolClassTag sc = (SymbolClassTag) tag; + for (int i = 0; i < sc.names.size(); i++) { + String newname = deobfuscation.deobfuscateNameWithPackage(true, sc.names.get(i), deobfuscated, renameType, deobfuscated); + if (newname != null) { + sc.names.set(i, newname); + } + } + sc.setModified(true); + } + } + deobfuscation.deobfuscateInstanceNames(true, deobfuscated, renameType, tags, new HashMap()); + return deobfuscated.size(); + } + + public int deobfuscateIdentifiers(RenameType renameType) throws InterruptedException { + FileAttributesTag fileAttributes = getFileAttributes(); + if (fileAttributes == null) { + int cnt = 0; + cnt += deobfuscateAS2Identifiers(renameType); + cnt += deobfuscateAS3Identifiers(renameType); + return cnt; + } else { + if (fileAttributes.actionScript3) { + return deobfuscateAS3Identifiers(renameType); + } else { + return deobfuscateAS2Identifiers(renameType); + } + } + } + + public void renameAS2Identifier(String identifier, String newname) throws InterruptedException { + Map selected = new HashMap<>(); + selected.put(identifier, newname); + renameAS2Identifiers(null, selected); + } + + private int deobfuscateAS2Identifiers(RenameType renameType) throws InterruptedException { + return renameAS2Identifiers(renameType, null); + } + + private int renameAS2Identifiers(RenameType renameType, Map selected) throws InterruptedException { + HashMap actionsMap = new HashMap<>(); + List allFunctions = new ArrayList<>(); + List> allVariableNames = new ArrayList<>(); + HashMap allStrings = new HashMap<>(); + HashMap usageTypes = new HashMap<>(); + + int ret = 0; + getVariables(tags, "", allVariableNames, actionsMap, allFunctions, allStrings, usageTypes); + informListeners("rename", ""); + int fc = 0; + for (MyEntry it : allVariableNames) { + String name = it.getKey().toStringNoH(it.getValue()); + deobfuscation.allVariableNamesStr.add(name); + } + + informListeners("rename", "classes"); + int classCount = 0; + for (Tag t : tags) { + if (t instanceof DoInitActionTag) { + classCount++; + } + } + int cnt = 0; + for (Tag t : tags) { + if (t instanceof DoInitActionTag) { + cnt++; + informListeners("rename", "class " + cnt + "/" + classCount); + DoInitActionTag dia = (DoInitActionTag) t; + String exportName = getExportName(dia.spriteId); + exportName = exportName != null ? exportName : "_unk_"; + final String pkgPrefix = "__Packages."; + String[] classNameParts = null; + if (exportName.startsWith(pkgPrefix)) { + String className = exportName.substring(pkgPrefix.length()); + if (className.contains(".")) { + classNameParts = className.split("\\."); + } else { + classNameParts = new String[]{className}; + } + } + int staticOperation = Graph.SOP_USE_STATIC; //(Boolean) Configuration.getConfig("autoDeobfuscate", true) ? Graph.SOP_SKIP_STATIC : Graph.SOP_USE_STATIC; + List dec; + try { + dec = Action.actionsToTree(dia.getActions(), version, staticOperation, ""/*FIXME*/); + } catch (EmptyStackException ex) { + continue; + } + GraphTargetItem name = null; + for (GraphTargetItem it : dec) { + if (it instanceof ClassActionItem) { + ClassActionItem cti = (ClassActionItem) it; + List methods = new ArrayList<>(); + methods.addAll(cti.functions); + methods.addAll(cti.staticFunctions); + + for (GraphTargetItem gti : methods) { + if (gti instanceof FunctionActionItem) { + FunctionActionItem fun = (FunctionActionItem) gti; + if (fun.calculatedFunctionName instanceof DirectValueActionItem) { + DirectValueActionItem dvf = (DirectValueActionItem) fun.calculatedFunctionName; + String fname = dvf.toStringNoH(null); + String changed = deobfuscation.deobfuscateName(false, fname, false, "method", deobfuscated, renameType, selected); + if (changed != null) { + deobfuscated.put(fname, changed); + } + } + } + } + + List vars = new ArrayList<>(); + for (MyEntry item : cti.vars) { + vars.add(item.getKey()); + } + for (MyEntry item : cti.staticVars) { + vars.add(item.getKey()); + } + for (GraphTargetItem gti : vars) { + if (gti instanceof DirectValueActionItem) { + DirectValueActionItem dvf = (DirectValueActionItem) gti; + String vname = dvf.toStringNoH(null); + String changed = deobfuscation.deobfuscateName(false, vname, false, "attribute", deobfuscated, renameType, selected); + if (changed != null) { + deobfuscated.put(vname, changed); + } + } + } + + name = cti.className; + break; + } + if (it instanceof InterfaceActionItem) { + InterfaceActionItem ift = (InterfaceActionItem) it; + name = ift.name; + } + } + + if (name != null) { + int pos = 0; + while (name instanceof GetMemberActionItem) { + GetMemberActionItem mem = (GetMemberActionItem) name; + GraphTargetItem memberName = mem.memberName; + if (memberName instanceof DirectValueActionItem) { + DirectValueActionItem dvt = (DirectValueActionItem) memberName; + String nameStr = dvt.toStringNoH(null); + if (classNameParts != null) { + if (classNameParts.length - 1 - pos < 0) { + break; + } + } + String changedNameStr = nameStr; + if (classNameParts != null) { + changedNameStr = classNameParts[classNameParts.length - 1 - pos]; + } + String changedNameStr2 = deobfuscation.deobfuscateName(false, changedNameStr, pos == 0, pos == 0 ? "class" : "package", deobfuscated, renameType, selected); + if (changedNameStr2 != null) { + changedNameStr = changedNameStr2; + } + ret++; + deobfuscated.put(nameStr, changedNameStr); + pos++; + } + name = mem.object; + } + if (name instanceof GetVariableActionItem) { + GetVariableActionItem var = (GetVariableActionItem) name; + if (var.name instanceof DirectValueActionItem) { + DirectValueActionItem dvt = (DirectValueActionItem) var.name; + String nameStr = dvt.toStringNoH(null); + if (classNameParts != null) { + if (classNameParts.length - 1 - pos < 0) { + break; + } + } + String changedNameStr = nameStr; + if (classNameParts != null) { + changedNameStr = classNameParts[classNameParts.length - 1 - pos]; + } + String changedNameStr2 = deobfuscation.deobfuscateName(false, changedNameStr, pos == 0, pos == 0 ? "class" : "package", deobfuscated, renameType, selected); + if (changedNameStr2 != null) { + changedNameStr = changedNameStr2; + } + ret++; + deobfuscated.put(nameStr, changedNameStr); + pos++; + } + } + } + t.setModified(true); + } + } + + for (GraphSourceItem fun : allFunctions) { + fc++; + informListeners("rename", "function " + fc + "/" + allFunctions.size()); + if (fun instanceof ActionDefineFunction) { + ActionDefineFunction f = (ActionDefineFunction) fun; + if (f.functionName.isEmpty()) { // anonymous function, leave as is + continue; + } + String changed = deobfuscation.deobfuscateName(false, f.functionName, false, "function", deobfuscated, renameType, selected); + if (changed != null) { + f.replacedFunctionName = changed; + ret++; + } + } + if (fun instanceof ActionDefineFunction2) { + ActionDefineFunction2 f = (ActionDefineFunction2) fun; + if (f.functionName.isEmpty()) { // anonymous function, leave as is + continue; + } + String changed = deobfuscation.deobfuscateName(false, f.functionName, false, "function", deobfuscated, renameType, selected); + if (changed != null) { + f.replacedFunctionName = changed; + ret++; + } + } + } + + HashSet stringsNoVarH = new HashSet<>(); + List allVariableNamesDv = new ArrayList<>(); + for (MyEntry it : allVariableNames) { + allVariableNamesDv.add(it.getKey()); + } + for (DirectValueActionItem ti : allStrings.keySet()) { + if (!allVariableNamesDv.contains(ti)) { + stringsNoVarH.add(System.identityHashCode(allStrings.get(ti)) + "_" + ti.toStringNoH(allStrings.get(ti))); + } + } + + int vc = 0; + for (MyEntry it : allVariableNames) { + vc++; + String name = it.getKey().toStringNoH(it.getValue()); + String changed = deobfuscation.deobfuscateName(false, name, false, usageTypes.get(it.getKey()), deobfuscated, renameType, selected); + if (changed != null) { + boolean addNew = false; + String h = System.identityHashCode(it.getKey()) + "_" + name; + if (stringsNoVarH.contains(h)) { + addNew = true; + } + ActionPush pu = (ActionPush) it.getKey().src; + if (pu.replacement == null) { + pu.replacement = new ArrayList<>(); + pu.replacement.addAll(pu.values); + } + if (pu.replacement.get(it.getKey().pos) instanceof ConstantIndex) { + ConstantIndex ci = (ConstantIndex) pu.replacement.get(it.getKey().pos); + ConstantPool pool = it.getValue(); + if (pool == null) { + continue; + } + if (pool.constants == null) { + continue; + } + if (addNew) { + pool.constants.add(changed); + ci.index = pool.constants.size() - 1; + } else { + pool.constants.set(ci.index, changed); + } + } else { + pu.replacement.set(it.getKey().pos, changed); + } + ret++; + } + } + + for (ASMSource src : actionsMap.keySet()) { + actionsMap.get(src).removeNops(); + src.setActions(actionsMap.get(src)); + src.setModified(); + } + + deobfuscation.deobfuscateInstanceNames(false, deobfuscated, renameType, tags, selected); + return ret; + } + + public void exportFla(AbortRetryIgnoreHandler handler, String outfile, String swfName, String generator, String generatorVerName, String generatorVersion, boolean parallel, FLAVersion version) throws IOException { + XFLConverter.convertSWF(handler, this, swfName, outfile, true, generator, generatorVerName, generatorVersion, parallel, version); + clearAllCache(); + } + + public void exportXfl(AbortRetryIgnoreHandler handler, String outfile, String swfName, String generator, String generatorVerName, String generatorVersion, boolean parallel, FLAVersion version) throws IOException { + XFLConverter.convertSWF(handler, this, swfName, outfile, false, generator, generatorVerName, generatorVersion, parallel, version); + clearAllCache(); + } + + public static AffineTransform matrixToTransform(MATRIX mat) { + return new AffineTransform(mat.getScaleXFloat(), mat.getRotateSkew0Float(), + mat.getRotateSkew1Float(), mat.getScaleYFloat(), + mat.translateX, mat.translateY); + } + + public SerializableImage getFromCache(String key) { + if (frameCache.contains(key)) { + return frameCache.get(key); + } + return null; + } + + public void putToCache(String key, SerializableImage img) { + if (Configuration.useFrameCache.get()) { + frameCache.put(key, img); + } + } + + public void clearImageCache() { + frameCache.clear(); + DefineSpriteTag.clearCache(); + DefineButtonTag.clearCache(); + DefineButton2Tag.clearCache(); + for (Tag tag : tags) { + if (tag instanceof ImageTag) { + ((ImageTag) tag).clearCache(); + } + } + } + + public void clearScriptCache() { + as2Cache.clear(); + as3Cache.clear(); + } + + public void clearAllCache() { + characters = null; + abcList = null; + timeline = null; + clearImageCache(); + clearScriptCache(); + Cache.clearAll(); + Helper.clearShapeCache(); + System.gc(); + } + + public static void uncache(ASMSource src) { + if (src != null) { + src.getSwf().as2Cache.remove(src); + } + } + + public static void uncache(ScriptPack pack) { + if (pack != null) { + pack.getSwf().as3Cache.remove(pack); + } + } + + public static boolean isCached(ASMSource src) { + return src.getSwf().as2Cache.contains(src); + } + + public static boolean isCached(ScriptPack pack) { + return pack.getSwf().as3Cache.contains(pack); + } + + public static CachedScript getCached(ASMSource src, ActionList actions) throws InterruptedException { + SWF swf = src.getSwf(); + if (swf.as2Cache.contains(src)) { + return swf.as2Cache.get(src); + } + + if (actions == null) { + actions = src.getActions(); + } + + HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), true); + Action.actionsToSource(src, actions, src.toString()/*FIXME?*/, writer); + List hilights = writer.instructionHilights; + String srcNoHex = writer.toString(); + CachedScript res = new CachedScript(srcNoHex, hilights); + swf.as2Cache.put(src, res); + return res; + } + + public static CachedDecompilation getCached(ScriptPack pack) throws InterruptedException { + SWF swf = pack.getSwf(); + if (swf.as3Cache.contains(pack)) { + return swf.as3Cache.get(pack); + } + + int scriptIndex = pack.scriptIndex; + ScriptInfo script = null; + if (scriptIndex > -1) { + script = pack.abc.script_info.get(scriptIndex); + } + boolean parallel = Configuration.parallelSpeedUp.get(); + HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), true); + pack.toSource(writer, script.traits.traits, ScriptExportMode.AS, parallel); + HighlightedText hilightedCode = new HighlightedText(writer); + CachedDecompilation res = new CachedDecompilation(hilightedCode); + swf.as3Cache.put(pack, res); + + return res; + } + + public static RECT fixRect(RECT rect) { + RECT ret = new RECT(); + ret.Xmin = rect.Xmin; + ret.Xmax = rect.Xmax; + ret.Ymin = rect.Ymin; + ret.Ymax = rect.Ymax; + + if (ret.Xmax <= 0) { + ret.Xmax = ret.getWidth(); + ret.Xmin = 0; + } + if (ret.Ymax <= 0) { + ret.Ymax = ret.getHeight(); + ret.Ymin = 0; + } + if (ret.Xmin < 0) { + ret.Xmax += (-ret.Xmin); + ret.Xmin = 0; + } + if (ret.Ymin < 0) { + ret.Ymax += (-ret.Ymin); + ret.Ymin = 0; + } + + if (ret.getWidth() < 1 || ret.getHeight() < 1) { + ret.Xmin = 0; + ret.Ymin = 0; + ret.Xmax = 20; + ret.Ymax = 20; + } + return ret; + } + + public static void frameToSvg(Timeline timeline, int frame, int time, DepthState stateUnderCursor, int mouseButton, SVGExporter exporter, ColorTransform colorTransform, int level, double zoom) throws IOException { + if (timeline.getFrameCount() <= frame) { + return; + } + Frame frameObj = timeline.getFrame(frame); + List clips = new ArrayList<>(); + List prevClips = new ArrayList<>(); + + int maxDepth = timeline.getMaxDepth(); + for (int i = 1; i <= maxDepth; i++) { + for (int c = 0; c < clips.size(); c++) { + if (clips.get(c).depth == i) { + exporter.setClip(prevClips.get(c)); + prevClips.remove(c); + clips.remove(c); + } + } + if (!frameObj.layers.containsKey(i)) { + continue; + } + DepthState layer = frameObj.layers.get(i); + if (!timeline.swf.getCharacters().containsKey(layer.characterId)) { + continue; + } + if (!layer.isVisible) { + continue; + } + + CharacterTag character = timeline.swf.getCharacter(layer.characterId); + if (colorTransform == null) { + colorTransform = new ColorTransform(); + } + + ColorTransform clrTrans = colorTransform.clone(); + if (layer.colorTransForm != null && layer.blendMode <= 1) { // Normal blend mode + clrTrans = colorTransform.merge(layer.colorTransForm); + } + + if (character instanceof DrawableTag) { + DrawableTag drawable = (DrawableTag) character; + + String assetName; + Tag drawableTag = (Tag) drawable; + RECT boundRect = drawable.getRect(); + if (exporter.exportedTags.containsKey(drawableTag)) { + assetName = exporter.exportedTags.get(drawableTag); + } else { + assetName = getTagIdPrefix(drawableTag, exporter); + exporter.exportedTags.put(drawableTag, assetName); + exporter.createDefGroup(new ExportRectangle(boundRect), assetName); + drawable.toSVG(exporter, layer.ratio, clrTrans, level + 1, zoom); + exporter.endGroup(); + } + ExportRectangle rect = new ExportRectangle(boundRect); + + // TODO: if (layer.filters != null) + // TODO: if (layer.blendMode > 1) + if (layer.clipDepth > -1) { + String clipName = exporter.getUniqueId("clipPath"); + exporter.createClipPath(new Matrix(), clipName); + SvgClip clip = new SvgClip(clipName, layer.clipDepth); + clips.add(clip); + prevClips.add(exporter.getClip()); + Matrix mat = Matrix.getTranslateInstance(rect.xMin, rect.yMin).preConcatenate(new Matrix(layer.matrix)); + exporter.addUse(mat, boundRect, assetName); + exporter.setClip(clip.shape); + exporter.endGroup(); + } else { + Matrix mat = Matrix.getTranslateInstance(rect.xMin, rect.yMin).preConcatenate(new Matrix(layer.matrix)); + exporter.addUse(mat, boundRect, assetName); + } + } + } + } + + private static String getTagIdPrefix(Tag tag, SVGExporter exporter) { + if (tag instanceof ShapeTag) { + return exporter.getUniqueId("shape"); + } + if (tag instanceof MorphShapeTag) { + return exporter.getUniqueId("morphshape"); + } + if (tag instanceof DefineSpriteTag) { + return exporter.getUniqueId("sprite"); + } + if (tag instanceof TextTag) { + return exporter.getUniqueId("text"); + } + if (tag instanceof ButtonTag) { + return exporter.getUniqueId("button"); + } + return exporter.getUniqueId("tag"); + } + + public static SerializableImage frameToImageGet(Timeline timeline, int frame, int time, DepthState stateUnderCursor, int mouseButton, RECT displayRect, Matrix transformation, ColorTransform colorTransform, Color backGroundColor, boolean useCache, double zoom) { + SWF swf = timeline.swf; + String key = "frame_" + frame + "_" + timeline.id + "_" + swf.hashCode() + "_" + zoom; + SerializableImage image; + if (useCache) { + image = swf.getFromCache(key); + if (image != null) { + return image; + } + } + + if (timeline.getFrameCount() == 0) { + return new SerializableImage(1, 1, SerializableImage.TYPE_INT_ARGB); + } + + RECT rect = displayRect; + image = new SerializableImage((int) (rect.getWidth() * zoom / SWF.unitDivisor) + 1, + (int) (rect.getHeight() * zoom / SWF.unitDivisor) + 1, SerializableImage.TYPE_INT_ARGB); + if (backGroundColor == null) { + image.fillTransparent(); + } else { + Graphics2D g = (Graphics2D) image.getBufferedImage().getGraphics(); + g.setComposite(AlphaComposite.Src); + g.setColor(backGroundColor); + g.fill(new Rectangle(image.getWidth(), image.getHeight())); + } + + Matrix m = transformation.clone(); + m.translate(-rect.Xmin * zoom, -rect.Ymin * zoom); + m.scale(zoom); + RenderContext renderContext = new RenderContext(); + renderContext.stateUnderCursor = stateUnderCursor; + renderContext.mouseButton = mouseButton; + frameToImage(timeline, frame, time, renderContext, image, m, colorTransform); + if (useCache) { + swf.putToCache(key, image); + } + + return image; + } + + public static void framesToImage(Timeline timeline, List ret, int startFrame, int stopFrame, RenderContext renderContext, RECT displayRect, int totalFrameCount, Stack visited, Matrix transformation, ColorTransform colorTransform, double zoom) { + RECT rect = displayRect; + for (int f = 0; f < timeline.getFrameCount(); f++) { + SerializableImage image = new SerializableImage((int) (rect.getWidth() / SWF.unitDivisor) + 1, + (int) (rect.getHeight() / SWF.unitDivisor) + 1, SerializableImage.TYPE_INT_ARGB); + image.fillTransparent(); + Matrix m = new Matrix(); + m.translate(-rect.Xmin, -rect.Ymin); + frameToImage(timeline, f, 0, renderContext, image, m, colorTransform); + ret.add(image); + } + } + + public static void frameToImage(Timeline timeline, int frame, int time, RenderContext renderContext, SerializableImage image, Matrix transformation, ColorTransform colorTransform) { + double unzoom = SWF.unitDivisor; + if (timeline.getFrameCount() <= frame) { + return; + } + Frame frameObj = timeline.getFrame(frame); + Graphics2D g = (Graphics2D) image.getGraphics(); + g.setPaint(frameObj.backgroundColor.toColor()); + g.fill(new Rectangle(image.getWidth(), image.getHeight())); + g.setTransform(transformation.toTransform()); + List clips = new ArrayList<>(); + List prevClips = new ArrayList<>(); + + int maxDepth = timeline.getMaxDepth(); + for (int i = 1; i <= maxDepth; i++) { + for (int c = 0; c < clips.size(); c++) { + if (clips.get(c).depth == i) { + g.setClip(prevClips.get(c)); + prevClips.remove(c); + clips.remove(c); + } + } + if (!frameObj.layers.containsKey(i)) { + continue; + } + DepthState layer = frameObj.layers.get(i); + if (!timeline.swf.getCharacters().containsKey(layer.characterId)) { + continue; + } + if (!layer.isVisible) { + continue; + } + + CharacterTag character = timeline.swf.getCharacter(layer.characterId); + Matrix mat = new Matrix(layer.matrix); + mat = mat.preConcatenate(transformation); + + if (colorTransform == null) { + colorTransform = new ColorTransform(); + } + + ColorTransform clrTrans = colorTransform.clone(); + if (layer.colorTransForm != null && layer.blendMode <= 1) { // Normal blend mode + clrTrans = colorTransform.merge(layer.colorTransForm); + } + + boolean showPlaceholder = false; + if (character instanceof DrawableTag) { + DrawableTag drawable = (DrawableTag) character; + Matrix drawMatrix = new Matrix(); + int drawableFrameCount = drawable.getNumFrames(); + if (drawableFrameCount == 0) { + drawableFrameCount = 1; + } + + int dframe; + if (timeline.fontFrameNum != -1) { + dframe = timeline.fontFrameNum; + } else { + dframe = (time + layer.time) % drawableFrameCount; + } + + if (character instanceof ButtonTag) { + dframe = ButtonTag.FRAME_UP; + if (renderContext.stateUnderCursor == layer) { + if (renderContext.mouseButton > 0) { + dframe = ButtonTag.FRAME_DOWN; + } else { + dframe = ButtonTag.FRAME_OVER; + } + } + } + + RECT boundRect = drawable.getRect(); + ExportRectangle rect = new ExportRectangle(boundRect); + rect = mat.transform(rect); + Matrix m = mat.clone(); + if (layer.filters != null && layer.filters.size() > 0) { + // calculate size after applying the filters + double deltaXMax = 0; + double deltaYMax = 0; + for (FILTER filter : layer.filters) { + double x = filter.getDeltaX(); + double y = filter.getDeltaY(); + deltaXMax = Math.max(x, deltaXMax); + deltaYMax = Math.max(y, deltaYMax); + } + rect.xMin -= deltaXMax * unzoom; + rect.xMax += deltaXMax * unzoom; + rect.yMin -= deltaYMax * unzoom; + rect.yMax += deltaYMax * unzoom; + } + + rect.xMin -= 1 * unzoom; + rect.yMin -= 1 * unzoom; + rect.xMin = Math.max(0, rect.xMin); + rect.yMin = Math.max(0, rect.yMin); + + int newWidth = (int) (rect.getWidth() / unzoom); + int newHeight = (int) (rect.getHeight() / unzoom); + int deltaX = (int) (rect.xMin / unzoom); + int deltaY = (int) (rect.yMin / unzoom); + newWidth = Math.min(image.getWidth() - deltaX, newWidth) + 1; + newHeight = Math.min(image.getHeight() - deltaY, newHeight) + 1; + + if (newWidth <= 0 || newHeight <= 0) { + continue; + } + + m.translate(-rect.xMin, -rect.yMin); + drawMatrix.translate(rect.xMin, rect.yMin); + + SerializableImage img = null; + String cacheKey = null; + if (drawable instanceof ShapeTag) { + cacheKey = ((ShapeTag) drawable).getCharacterId() + m.toString() + clrTrans.toString(); + img = renderContext.shapeCache.get(cacheKey); + } + + if (img == null) { + img = new SerializableImage(newWidth, newHeight, SerializableImage.TYPE_INT_ARGB); + img.fillTransparent(); + + drawable.toImage(dframe, layer.time + time, layer.ratio, renderContext, img, m, clrTrans); + + if (cacheKey != null) { + renderContext.shapeCache.put(cacheKey, img); + } + } + + /*//if (renderContext.stateUnderCursor == layer) { + if (true) { + BufferedImage bi = img.getBufferedImage(); + ColorModel cm = bi.getColorModel(); + boolean isAlphaPremultiplied = cm.isAlphaPremultiplied(); + WritableRaster raster = bi.copyData(null); + img = new SerializableImage(new BufferedImage(cm, raster, isAlphaPremultiplied, null)); + Graphics2D gg = (Graphics2D) img.getGraphics(); + gg.setStroke(new BasicStroke(3)); + gg.setPaint(Color.red); + gg.setTransform(AffineTransform.getTranslateInstance(0, 0)); + gg.draw(SHAPERECORD.twipToPixelShape(drawable.getOutline(dframe, layer.time + time, layer.ratio, renderContext, m))); + }*/ + if (layer.filters != null) { + for (FILTER filter : layer.filters) { + img = filter.apply(img); + } + } + if (layer.blendMode > 1) { + if (layer.colorTransForm != null) { + img = layer.colorTransForm.apply(img); + } + } + + drawMatrix.translateX /= unzoom; + drawMatrix.translateY /= unzoom; + AffineTransform trans = drawMatrix.toTransform(); + + switch (layer.blendMode) { + case 0: + case 1: + g.setComposite(AlphaComposite.SrcOver); + break; + case 2: // Layer + g.setComposite(AlphaComposite.SrcOver); + break; + case 3: + g.setComposite(BlendComposite.Multiply); + break; + case 4: + g.setComposite(BlendComposite.Screen); + break; + case 5: + g.setComposite(BlendComposite.Lighten); + break; + case 6: + g.setComposite(BlendComposite.Darken); + break; + case 7: + g.setComposite(BlendComposite.Difference); + break; + case 8: + g.setComposite(BlendComposite.Add); + break; + case 9: + g.setComposite(BlendComposite.Subtract); + break; + case 10: + g.setComposite(BlendComposite.Invert); + break; + case 11: + g.setComposite(BlendComposite.Alpha); + break; + case 12: + g.setComposite(BlendComposite.Erase); + break; + case 13: + g.setComposite(BlendComposite.Overlay); + break; + case 14: + g.setComposite(BlendComposite.HardLight); + break; + default: // Not implemented + g.setComposite(AlphaComposite.SrcOver); + break; + } + + if (layer.clipDepth > -1) { + BufferedImage mask = new BufferedImage(image.getWidth(), image.getHeight(), image.getType()); + Graphics2D gm = (Graphics2D) mask.getGraphics(); + gm.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); + gm.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); + gm.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + gm.setComposite(AlphaComposite.Src); + gm.setColor(new Color(0, 0, 0, 0f)); + gm.fillRect(0, 0, image.getWidth(), image.getHeight()); + gm.setTransform(trans); + gm.drawImage(img.getBufferedImage(), 0, 0, null); + Clip clip = new Clip(Helper.imageToShape(mask), layer.clipDepth); // Maybe we can get current outline instead converting from image (?) + clips.add(clip); + prevClips.add(g.getClip()); + g.setTransform(AffineTransform.getTranslateInstance(0, 0)); + g.setClip(clip.shape); + } else { + g.setTransform(trans); + g.drawImage(img.getBufferedImage(), 0, 0, null); + } + } else if (character instanceof BoundedTag) { + showPlaceholder = true; + } + + if (showPlaceholder) { + mat.translateX /= unzoom; + mat.translateY /= unzoom; + AffineTransform trans = mat.toTransform(); + g.setTransform(trans); + BoundedTag b = (BoundedTag) character; + g.setPaint(new Color(255, 255, 255, 128)); + g.setComposite(BlendComposite.Invert); + RECT r = b.getRect(); + int div = (int) unzoom; + g.drawString(character.toString(), r.Xmin / div + 3, r.Ymin / div + 15); + g.draw(new Rectangle(r.Xmin / div, r.Ymin / div, r.getWidth() / div, r.getHeight() / div)); + g.drawLine(r.Xmin / div, r.Ymin / div, r.Xmax / div, r.Ymax / div); + g.drawLine(r.Xmax / div, r.Ymin / div, r.Xmin / div, r.Ymax / div); + g.setComposite(AlphaComposite.Dst); + } + } + + g.setTransform(AffineTransform.getScaleInstance(1, 1)); + } + + private void removeTagWithDependenciesFromTimeline(Tag toRemove, Timeline timeline) { + int characterId = 0; + if (toRemove instanceof CharacterTag) { + characterId = ((CharacterTag) toRemove).getCharacterId(); + } + Map stage = new HashMap<>(); + + Set dependingChars = new HashSet<>(); + if (characterId != 0) { + dependingChars.add(characterId); + for (int i = 0; i < timeline.tags.size(); i++) { + Tag t = timeline.tags.get(i); + if (t instanceof CharacterIdTag) { + CharacterIdTag c = (CharacterIdTag) t; + Set needed = new HashSet<>(); + t.getNeededCharacters(needed); + if (needed.contains(characterId)) { + dependingChars.add(c.getCharacterId()); + } + } + } + } + + for (int i = 0; i < timeline.tags.size(); i++) { + Tag t = timeline.tags.get(i); + if (t instanceof RemoveTag) { + RemoveTag rt = (RemoveTag) t; + int depth = rt.getDepth(); + if (stage.containsKey(depth)) { + int currentCharId = stage.get(depth); + stage.remove(depth); + if (dependingChars.contains(currentCharId)) { + timeline.tags.remove(i); + i--; + continue; + } + } + } + if (t instanceof PlaceObjectTypeTag) { + PlaceObjectTypeTag po = (PlaceObjectTypeTag) t; + int placeCharId = po.getCharacterId(); + int depth = po.getDepth(); + if (placeCharId != 0) { + stage.put(depth, placeCharId); + if (dependingChars.contains(placeCharId)) { + timeline.tags.remove(i); + i--; + continue; + } + } + } + if (t instanceof CharacterIdTag) { + CharacterIdTag c = (CharacterIdTag) t; + if (dependingChars.contains(c.getCharacterId())) { + timeline.tags.remove(i); + i--; + continue; + } + } + Set needed = new HashSet<>(); + t.getNeededCharacters(needed); + for (int dep : dependingChars) { + if (needed.contains(dep)) { + timeline.tags.remove(i); + i--; + continue; + } + } + if (t == toRemove) { + timeline.tags.remove(i); + i--; + continue; + } + if (t instanceof Timelined) { + removeTagWithDependenciesFromTimeline(toRemove, ((Timelined) t).getTimeline()); + } + } + } + + private boolean removeTagFromTimeline(Tag toRemove, Timeline timeline) { + boolean modified = false; + int characterId = -1; + if (toRemove instanceof CharacterTag) { + characterId = ((CharacterTag) toRemove).getCharacterId(); + modified = timeline.removeCharacter(characterId); + } + for (int i = 0; i < timeline.tags.size(); i++) { + Tag t = timeline.tags.get(i); + if (t == toRemove) { + timeline.tags.remove(t); + i--; + continue; + } + + if (toRemove instanceof CharacterTag) { + if (t.removeCharacter(characterId)) { + modified = true; + i = -1; + continue; + } + } + + if (t instanceof DefineSpriteTag) { + DefineSpriteTag spr = (DefineSpriteTag) t; + boolean sprModified = removeTagFromTimeline(toRemove, spr.getTimeline()); + if (sprModified) { + spr.setModified(true); + } + modified |= sprModified; + } + } + return modified; + } + + public void removeTags(Collection tags, boolean removeDependencies) { + Set timelineds = new HashSet<>(); + for (Tag tag : tags) { + Timelined timelined = tag.getTimelined(); + timelineds.add(timelined); + removeTagInternal(timelined, tag, removeDependencies); + } + + for (Timelined timelined : timelineds) { + resetTimelines(timelined); + } + + updateCharacters(); + clearImageCache(); + } + + public void removeTag(Tag tag, boolean removeDependencies) { + Timelined timelined = tag.getTimelined(); + removeTagInternal(timelined, tag, removeDependencies); + resetTimelines(timelined); + updateCharacters(); + clearImageCache(); + } + + private void removeTagInternal(Timelined timelined, Tag tag, boolean removeDependencies) { + if (tag instanceof ShowFrameTag || ShowFrameTag.isNestedTagType(tag.getId())) { + List tags; + if (timelined instanceof DefineSpriteTag) { + DefineSpriteTag sprite = (DefineSpriteTag) timelined; + tags = sprite.getSubTags(); + } else { + tags = this.tags; + } + tags.remove(tag); + if (timelined instanceof DefineSpriteTag) { + DefineSpriteTag sprite = (DefineSpriteTag) timelined; + sprite.setModified(true); + } + timelined.resetTimeline(); + } else { + // timeline should be always the swf here + if (removeDependencies) { + removeTagWithDependenciesFromTimeline(tag, timelined.getTimeline()); + if (timelined instanceof DefineSpriteTag) { + DefineSpriteTag sprite = (DefineSpriteTag) timelined; + sprite.setModified(true); + } + } else { + removeTagFromTimeline(tag, timeline); + } + } + } + + @Override + public String toString() { + return getShortFileName(); + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/FrameExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/FrameExporter.java index 08c49945a..05b7fa4b0 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/FrameExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/FrameExporter.java @@ -35,6 +35,7 @@ import com.jpexs.decompiler.flash.tags.DefineSpriteTag; import com.jpexs.decompiler.flash.tags.SetBackgroundColorTag; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.base.CharacterTag; +import com.jpexs.decompiler.flash.tags.enums.ImageFormat; import com.jpexs.decompiler.flash.timeline.DepthState; import com.jpexs.decompiler.flash.timeline.Frame; import com.jpexs.decompiler.flash.timeline.Timeline; @@ -355,7 +356,7 @@ public class FrameExporter { final int fi = i; new RetryTask(() -> { File file = new File(foutdir + File.separator + (fframes.get(fi) + 1) + ".png"); - ImageHelper.write(frameImages.next(), "PNG", file); + ImageHelper.write(frameImages.next(), ImageFormat.PNG, file); ret.add(file); }, handler).run(); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ImageExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ImageExporter.java index 69d673ada..be850277d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ImageExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ImageExporter.java @@ -25,13 +25,13 @@ import com.jpexs.decompiler.flash.helpers.BMPFile; import com.jpexs.decompiler.flash.helpers.ImageHelper; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.base.ImageTag; +import com.jpexs.decompiler.flash.tags.enums.ImageFormat; import com.jpexs.helpers.Helper; import com.jpexs.helpers.Path; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; -import java.util.Locale; /** * @@ -68,28 +68,28 @@ public class ImageExporter { final ImageTag imageTag = (ImageTag) t; - String fileFormat = imageTag.getImageFormat().toUpperCase(Locale.ENGLISH); + ImageFormat fileFormat = imageTag.getImageFormat(); if (settings.mode == ImageExportMode.PNG) { - fileFormat = "png"; + fileFormat = ImageFormat.PNG; } if (settings.mode == ImageExportMode.JPEG) { - fileFormat = "jpg"; + fileFormat = ImageFormat.JPEG; } if (settings.mode == ImageExportMode.BMP) { - fileFormat = "bmp"; + fileFormat = ImageFormat.BMP; } { final File file = new File(outdir + File.separator + Helper.makeFileName(imageTag.getCharacterExportFileName() + "." + fileFormat)); - final String ffileFormat = fileFormat; + final ImageFormat ffileFormat = fileFormat; new RetryTask(() -> { - if (ffileFormat.equals("bmp")) { + if (ffileFormat == ImageFormat.BMP) { BMPFile.saveBitmap(imageTag.getImage().getBufferedImage(), file); } else { - ImageHelper.write(imageTag.getImage().getBufferedImage(), ffileFormat.toUpperCase(Locale.ENGLISH), file); + ImageHelper.write(imageTag.getImage().getBufferedImage(), ffileFormat, file); } }, handler).run(); ret.add(file); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ShapeExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ShapeExporter.java index 58ac832b0..97c58468b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ShapeExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ShapeExporter.java @@ -32,6 +32,7 @@ import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.base.CharacterTag; import com.jpexs.decompiler.flash.tags.base.RenderContext; import com.jpexs.decompiler.flash.tags.base.ShapeTag; +import com.jpexs.decompiler.flash.tags.enums.ImageFormat; import com.jpexs.decompiler.flash.types.CXFORMWITHALPHA; import com.jpexs.decompiler.flash.types.RECT; import com.jpexs.decompiler.flash.types.SHAPE; @@ -126,7 +127,7 @@ public class ShapeExporter { m.scale(settings.zoom); st.toImage(0, 0, 0, new RenderContext(), img, m, new CXFORMWITHALPHA()); if (settings.mode == ShapeExportMode.PNG) { - ImageHelper.write(img.getBufferedImage(), "PNG", file); + ImageHelper.write(img.getBufferedImage(), ImageFormat.PNG, file); } else { BMPFile.saveBitmap(img.getBufferedImage(), file); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/SVGMorphShapeExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/SVGMorphShapeExporter.java index 7b7707f45..d8bf43904 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/SVGMorphShapeExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/SVGMorphShapeExporter.java @@ -21,6 +21,7 @@ import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; import com.jpexs.decompiler.flash.helpers.ImageHelper; import com.jpexs.decompiler.flash.tags.base.ImageTag; +import com.jpexs.decompiler.flash.tags.enums.ImageFormat; import com.jpexs.decompiler.flash.types.ColorTransform; import com.jpexs.decompiler.flash.types.FILLSTYLE; import com.jpexs.decompiler.flash.types.GRADIENT; @@ -34,7 +35,6 @@ import com.jpexs.helpers.SerializableImage; import java.awt.Color; import java.io.ByteArrayOutputStream; import java.io.InputStream; -import java.util.Locale; import org.w3c.dom.Element; /** @@ -115,14 +115,14 @@ public class SVGMorphShapeExporter extends DefaultSVGMorphShapeExporter { int height = img.getHeight(); lastPatternId++; String patternId = "PatternID_" + lastPatternId; - String format = image.getImageFormat(); + ImageFormat format = image.getImageFormat(); InputStream imageStream = image.getImageData(); byte[] imageData; if (imageStream != null) { imageData = Helper.readStream(image.getImageData()); } else { ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ImageHelper.write(img.getBufferedImage(), format.toUpperCase(Locale.ENGLISH), baos); + ImageHelper.write(img.getBufferedImage(), format, baos); imageData = baos.toByteArray(); } String base64ImgData = Helper.byteArrayToBase64String(imageData); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/shape/SVGShapeExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/shape/SVGShapeExporter.java index 0ece8a283..45f064077 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/shape/SVGShapeExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/shape/SVGShapeExporter.java @@ -21,6 +21,7 @@ import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; import com.jpexs.decompiler.flash.helpers.ImageHelper; import com.jpexs.decompiler.flash.tags.base.ImageTag; +import com.jpexs.decompiler.flash.tags.enums.ImageFormat; import com.jpexs.decompiler.flash.types.ColorTransform; import com.jpexs.decompiler.flash.types.FILLSTYLE; import com.jpexs.decompiler.flash.types.GRADIENT; @@ -34,7 +35,6 @@ import com.jpexs.helpers.SerializableImage; import java.awt.Color; import java.io.ByteArrayOutputStream; import java.io.InputStream; -import java.util.Locale; import org.w3c.dom.Element; /** @@ -113,14 +113,14 @@ public class SVGShapeExporter extends DefaultSVGShapeExporter { lastPatternId++; String patternId = "PatternID_"; patternId += lastPatternId; - String format = image.getImageFormat(); + ImageFormat format = image.getImageFormat(); InputStream imageStream = image.getImageData(); byte[] imageData; if (imageStream != null) { imageData = Helper.readStream(image.getImageData()); } else { ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ImageHelper.write(img.getBufferedImage(), format.toUpperCase(Locale.ENGLISH), baos); + ImageHelper.write(img.getBufferedImage(), format, baos); imageData = baos.toByteArray(); } String base64ImgData = Helper.byteArrayToBase64String(imageData); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/ImageHelper.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/ImageHelper.java index 657592a3a..0442c9a2b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/ImageHelper.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/ImageHelper.java @@ -16,6 +16,8 @@ */ package com.jpexs.decompiler.flash.helpers; +import com.jpexs.decompiler.flash.tags.base.ImageTag; +import com.jpexs.decompiler.flash.tags.enums.ImageFormat; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -23,6 +25,7 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.Locale; import java.util.logging.Level; import java.util.logging.Logger; import javax.imageio.ImageIO; @@ -57,19 +60,67 @@ public class ImageHelper { return in; } - public static void write(BufferedImage image, String formatName, File output) throws IOException { + public static void write(BufferedImage image, ImageFormat format, File output) throws IOException { + String formatName = getImageFormatString(format).toUpperCase(Locale.ENGLISH); + if (format == ImageFormat.JPEG) { + image = fixImageIOJpegBug(image); + } + ImageIO.write(image, formatName, output); } - public static void write(BufferedImage image, String formatName, OutputStream output) throws IOException { + public static void write(BufferedImage image, ImageFormat format, OutputStream output) throws IOException { + String formatName = getImageFormatString(format).toUpperCase(Locale.ENGLISH); + if (format == ImageFormat.JPEG) { + image = fixImageIOJpegBug(image); + } + ImageIO.write(image, formatName, output); } - public static void write(BufferedImage image, String formatName, ByteArrayOutputStream output) { + public static void write(BufferedImage image, ImageFormat format, ByteArrayOutputStream output) { + String formatName = getImageFormatString(format).toUpperCase(Locale.ENGLISH); + if (format == ImageFormat.JPEG) { + image = fixImageIOJpegBug(image); + } + try { ImageIO.write(image, formatName, output); } catch (IOException ex) { Logger.getLogger(ImageHelper.class.getName()).log(Level.SEVERE, null, ex); } } + + private static BufferedImage fixImageIOJpegBug(BufferedImage image) { + int type = image.getType(); + if (type != BufferedImage.TYPE_INT_RGB) { + // convert to RGB without alpha channel + int width = image.getWidth(); + int height = image.getHeight(); + int[] imgData = image.getRGB(0, 0, width, height, null, 0, width); + ImageTag.divideAlpha(imgData); + BufferedImage newImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + newImage.getRaster().setDataElements(0, 0, width, height, imgData); + return newImage; + } + + return image; + } + + public static String getImageFormatString(ImageFormat format) { + switch (format) { + case UNKNOWN: + return "unk"; + case JPEG: + return "jpg"; + case GIF: + return "gif"; + case PNG: + return "png"; + case BMP: + return "bmp"; + } + + throw new Error("Unsuported image format: " + format); + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/ImageImporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/ImageImporter.java index da0e1cb70..542b24a27 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/ImageImporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/ImageImporter.java @@ -19,9 +19,12 @@ package com.jpexs.decompiler.flash.importers; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.helpers.ImageHelper; 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.DefineBitsTag; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.base.ImageTag; +import com.jpexs.decompiler.flash.tags.enums.ImageFormat; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -37,7 +40,7 @@ public class ImageImporter extends TagImporter { if (newData[0] == 'B' && newData[1] == 'M') { BufferedImage b = ImageHelper.read(newData); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ImageHelper.write(b, "PNG", baos); + ImageHelper.write(b, ImageFormat.PNG, baos); newData = baos.toByteArray(); } @@ -53,4 +56,14 @@ public class ImageImporter extends TagImporter { } return null; } + + public Tag importImageAlpha(ImageTag it, byte[] newData) throws IOException { + + if (it instanceof DefineBitsJPEG3Tag) { + ((DefineBitsJPEG3Tag) it).setImageAlpha(newData); + } else if (it instanceof DefineBitsJPEG4Tag) { + ((DefineBitsJPEG4Tag) it).setImageAlpha(newData); + } + return null; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/ShapeImporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/ShapeImporter.java index 7523f2fe2..20ee6fac6 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/ShapeImporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/ShapeImporter.java @@ -21,6 +21,7 @@ import com.jpexs.decompiler.flash.helpers.ImageHelper; import com.jpexs.decompiler.flash.tags.DefineBitsJPEG2Tag; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.base.ShapeTag; +import com.jpexs.decompiler.flash.tags.enums.ImageFormat; import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; @@ -38,7 +39,7 @@ public class ShapeImporter { if (newData[0] == 'B' && newData[1] == 'M') { BufferedImage b = ImageHelper.read(newData); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ImageHelper.write(b, "PNG", baos); + ImageHelper.write(b, ImageFormat.PNG, baos); newData = baos.toByteArray(); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBinaryDataTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBinaryDataTag.java index 3a75e341a..5ff2f91b4 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBinaryDataTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBinaryDataTag.java @@ -56,26 +56,6 @@ public class DefineBinaryDataTag extends CharacterTag { @Internal public SWF innerSwf; - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(tag); - sos.writeUI32(reserved); - sos.write(binaryData); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - /** * Constructor * @@ -110,6 +90,26 @@ public class DefineBinaryDataTag extends CharacterTag { } } + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(tag); + sos.writeUI32(reserved); + sos.write(binaryData); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + @Override public int getCharacterId() { return tag; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG2Tag.java index 2b630492a..661b35d7c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG2Tag.java @@ -22,6 +22,7 @@ import com.jpexs.decompiler.flash.SWFOutputStream; import com.jpexs.decompiler.flash.helpers.ImageHelper; import com.jpexs.decompiler.flash.tags.base.AloneTag; import com.jpexs.decompiler.flash.tags.base.ImageTag; +import com.jpexs.decompiler.flash.tags.enums.ImageFormat; import com.jpexs.decompiler.flash.types.BasicType; import com.jpexs.decompiler.flash.types.annotations.SWFType; import com.jpexs.helpers.ByteArrayRange; @@ -92,7 +93,7 @@ public class DefineBitsJPEG2Tag extends ImageTag implements AloneTag { } @Override - public String getImageFormat() { + public ImageFormat getImageFormat() { return ImageTag.getImageFormat(imageData); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG3Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG3Tag.java index f1dcdc372..c8d5d8477 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG3Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG3Tag.java @@ -22,6 +22,7 @@ import com.jpexs.decompiler.flash.SWFOutputStream; import com.jpexs.decompiler.flash.helpers.ImageHelper; import com.jpexs.decompiler.flash.tags.base.AloneTag; import com.jpexs.decompiler.flash.tags.base.ImageTag; +import com.jpexs.decompiler.flash.tags.enums.ImageFormat; import com.jpexs.decompiler.flash.types.BasicType; import com.jpexs.decompiler.flash.types.annotations.SWFType; import com.jpexs.helpers.ByteArrayRange; @@ -109,14 +110,14 @@ public class DefineBitsJPEG3Tag extends ImageTag implements AloneTag { private byte[] createEmptyImage() { BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB); ByteArrayOutputStream bitmapDataOS = new ByteArrayOutputStream(); - ImageHelper.write(img, "JPG", bitmapDataOS); + ImageHelper.write(img, ImageFormat.JPEG, bitmapDataOS); return bitmapDataOS.toByteArray(); } @Override public void setImage(byte[] data) throws IOException { - if (ImageTag.getImageFormat(data).equals("jpg")) { - SerializableImage image = new SerializableImage(ImageHelper.read(data)); + if (ImageTag.getImageFormat(data) == ImageFormat.JPEG) { + BufferedImage image = ImageHelper.read(data); byte[] ba = new byte[image.getWidth() * image.getHeight()]; for (int i = 0; i < ba.length; i++) { ba[i] = (byte) 255; @@ -132,11 +133,27 @@ public class DefineBitsJPEG3Tag extends ImageTag implements AloneTag { setModified(true); } + public void setImageAlpha(byte[] data) throws IOException { + ImageFormat fmt = ImageTag.getImageFormat(imageData); + if (fmt != ImageFormat.JPEG) { + throw new IOException("Only Jpeg can have alpha channel."); + } + + SerializableImage image = getImage(); + if (data == null || data.length != image.getWidth() * image.getHeight()) { + throw new IOException("Data length must match the size of the image."); + } + + bitmapAlphaData = new ByteArrayRange(SWFOutputStream.compressByteArray(data)); + clearCache(); + setModified(true); + } + @Override - public String getImageFormat() { - String fmt = ImageTag.getImageFormat(imageData); - if (fmt.equals("jpg")) { - fmt = "png"; //transparency + public ImageFormat getImageFormat() { + ImageFormat fmt = ImageTag.getImageFormat(imageData); + if (fmt == ImageFormat.JPEG) { + fmt = ImageFormat.PNG; //transparency } return fmt; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG4Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG4Tag.java index 3b6aeb4f2..6c0ccc7b2 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG4Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsJPEG4Tag.java @@ -22,6 +22,7 @@ import com.jpexs.decompiler.flash.SWFOutputStream; import com.jpexs.decompiler.flash.helpers.ImageHelper; import com.jpexs.decompiler.flash.tags.base.AloneTag; import com.jpexs.decompiler.flash.tags.base.ImageTag; +import com.jpexs.decompiler.flash.tags.enums.ImageFormat; import com.jpexs.decompiler.flash.types.BasicType; import com.jpexs.decompiler.flash.types.annotations.SWFType; import com.jpexs.helpers.ByteArrayRange; @@ -114,14 +115,14 @@ public class DefineBitsJPEG4Tag extends ImageTag implements AloneTag { private byte[] createEmptyImage() { BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB); ByteArrayOutputStream bitmapDataOS = new ByteArrayOutputStream(); - ImageHelper.write(img, "JPG", bitmapDataOS); + ImageHelper.write(img, ImageFormat.JPEG, bitmapDataOS); return bitmapDataOS.toByteArray(); } @Override public void setImage(byte[] data) throws IOException { - if (ImageTag.getImageFormat(data).equals("jpg")) { - SerializableImage image = new SerializableImage(ImageHelper.read(data)); + if (ImageTag.getImageFormat(data) == ImageFormat.JPEG) { + BufferedImage image = ImageHelper.read(data); byte[] ba = new byte[image.getWidth() * image.getHeight()]; for (int i = 0; i < ba.length; i++) { ba[i] = (byte) 255; @@ -137,11 +138,27 @@ public class DefineBitsJPEG4Tag extends ImageTag implements AloneTag { setModified(true); } + public void setImageAlpha(byte[] data) throws IOException { + ImageFormat fmt = ImageTag.getImageFormat(imageData); + if (fmt != ImageFormat.JPEG) { + throw new IOException("Only Jpeg can have alpha channel."); + } + + SerializableImage image = getImage(); + if (data == null || data.length != image.getWidth() * image.getHeight()) { + throw new IOException("Data length must match the size of the image."); + } + + bitmapAlphaData = new ByteArrayRange(SWFOutputStream.compressByteArray(data)); + clearCache(); + setModified(true); + } + @Override - public String getImageFormat() { - String fmt = ImageTag.getImageFormat(imageData); - if (fmt.equals("jpg")) { - fmt = "png"; //transparency + public ImageFormat getImageFormat() { + ImageFormat fmt = ImageTag.getImageFormat(imageData); + if (fmt == ImageFormat.JPEG) { + fmt = ImageFormat.PNG; //transparency } return fmt; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsLossless2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsLossless2Tag.java index e54430950..663ff8885 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsLossless2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsLossless2Tag.java @@ -22,6 +22,7 @@ import com.jpexs.decompiler.flash.SWFOutputStream; import com.jpexs.decompiler.flash.helpers.ImageHelper; import com.jpexs.decompiler.flash.tags.base.AloneTag; import com.jpexs.decompiler.flash.tags.base.ImageTag; +import com.jpexs.decompiler.flash.tags.enums.ImageFormat; import com.jpexs.decompiler.flash.types.ALPHABITMAPDATA; import com.jpexs.decompiler.flash.types.ALPHACOLORMAPDATA; import com.jpexs.decompiler.flash.types.BasicType; @@ -221,8 +222,8 @@ public class DefineBitsLossless2Tag extends ImageTag implements AloneTag { } @Override - public String getImageFormat() { - return "png"; + public ImageFormat getImageFormat() { + return ImageFormat.PNG; } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsLosslessTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsLosslessTag.java index 05549c9db..c6830b256 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsLosslessTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsLosslessTag.java @@ -22,6 +22,7 @@ import com.jpexs.decompiler.flash.SWFOutputStream; import com.jpexs.decompiler.flash.helpers.ImageHelper; import com.jpexs.decompiler.flash.tags.base.AloneTag; import com.jpexs.decompiler.flash.tags.base.ImageTag; +import com.jpexs.decompiler.flash.tags.enums.ImageFormat; import com.jpexs.decompiler.flash.types.BITMAPDATA; import com.jpexs.decompiler.flash.types.BasicType; import com.jpexs.decompiler.flash.types.COLORMAPDATA; @@ -271,7 +272,7 @@ public class DefineBitsLosslessTag extends ImageTag implements AloneTag { } @Override - public String getImageFormat() { - return "png"; + public ImageFormat getImageFormat() { + return ImageFormat.PNG; } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsTag.java index ed9d8159e..06f5c10f5 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsTag.java @@ -21,6 +21,7 @@ import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; import com.jpexs.decompiler.flash.helpers.ImageHelper; import com.jpexs.decompiler.flash.tags.base.ImageTag; +import com.jpexs.decompiler.flash.tags.enums.ImageFormat; import com.jpexs.decompiler.flash.types.BasicType; import com.jpexs.decompiler.flash.types.annotations.SWFType; import com.jpexs.helpers.ByteArrayRange; @@ -46,17 +47,6 @@ public class DefineBitsTag extends ImageTag implements TagChangedListener { @SWFType(BasicType.UI8) public ByteArrayRange jpegData; - @Override - public void setImage(byte[] data) { - throw new UnsupportedOperationException("Set image is not supported for DefineBits"); - } - - @Override - public boolean importSupported() { - // importing a new image will replace the current DefineBitsTag with a new DefineBitsJPEG2Tag - return true; - } - /** * Constructor * @@ -99,6 +89,17 @@ public class DefineBitsTag extends ImageTag implements TagChangedListener { return baos.toByteArray(); } + @Override + public void setImage(byte[] data) { + throw new UnsupportedOperationException("Set image is not supported for DefineBits"); + } + + @Override + public boolean importSupported() { + // importing a new image will replace the current DefineBitsTag with a new DefineBitsJPEG2Tag + return true; + } + @Override public InputStream getImageData() { return null; @@ -137,8 +138,8 @@ public class DefineBitsTag extends ImageTag implements TagChangedListener { } @Override - public String getImageFormat() { - return "jpg"; + public ImageFormat getImageFormat() { + return ImageFormat.JPEG; } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java index b28f555c2..ff0989e6b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java @@ -90,21 +90,6 @@ public class DefineButton2Tag extends ButtonTag implements ASMSourceContainer { private static final Cache rectCache = Cache.getInstance(true, true, "rect_button2"); - @Override - public int getCharacterId() { - return buttonId; - } - - @Override - public void setCharacterId(int characterId) { - this.buttonId = characterId; - } - - @Override - public List getRecords() { - return characters; - } - /** * Constructor * @@ -178,6 +163,21 @@ public class DefineButton2Tag extends ButtonTag implements ASMSourceContainer { return baos.toByteArray(); } + @Override + public int getCharacterId() { + return buttonId; + } + + @Override + public void setCharacterId(int characterId) { + this.buttonId = characterId; + } + + @Override + public List getRecords() { + return characters; + } + /** * Returns all sub-items * diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonCxformTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonCxformTag.java index e32cae329..79f4117be 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonCxformTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonCxformTag.java @@ -43,25 +43,6 @@ public class DefineButtonCxformTag extends Tag implements CharacterIdTag { public CXFORM buttonColorTransform; - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(buttonId); - sos.writeCXFORM(buttonColorTransform); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - /** * Constructor * @@ -90,6 +71,25 @@ public class DefineButtonCxformTag extends Tag implements CharacterIdTag { buttonColorTransform = sis.readCXFORM("buttonColorTransform"); } + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(buttonId); + sos.writeCXFORM(buttonColorTransform); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + @Override public int getCharacterId() { return buttonId; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonSoundTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonSoundTag.java index 111013af8..c0b23938a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonSoundTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonSoundTag.java @@ -61,50 +61,6 @@ public class DefineButtonSoundTag extends Tag implements CharacterIdTag { public SOUNDINFO buttonSoundInfo3; - @Override - public int getCharacterId() { - return buttonId; - } - - @Override - public void setCharacterId(int characterId) { - this.buttonId = characterId; - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(buttonId); - sos.writeUI16(buttonSoundChar0); - if (buttonSoundChar0 != 0) { - sos.writeSOUNDINFO(buttonSoundInfo0); - } - sos.writeUI16(buttonSoundChar1); - if (buttonSoundChar1 != 0) { - sos.writeSOUNDINFO(buttonSoundInfo1); - } - sos.writeUI16(buttonSoundChar2); - if (buttonSoundChar2 != 0) { - sos.writeSOUNDINFO(buttonSoundInfo2); - } - sos.writeUI16(buttonSoundChar3); - if (buttonSoundChar3 != 0) { - sos.writeSOUNDINFO(buttonSoundInfo3); - } - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - /** * Constructor * @@ -146,4 +102,48 @@ public class DefineButtonSoundTag extends Tag implements CharacterIdTag { buttonSoundInfo3 = sis.readSOUNDINFO("buttonSoundInfo3"); } } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(buttonId); + sos.writeUI16(buttonSoundChar0); + if (buttonSoundChar0 != 0) { + sos.writeSOUNDINFO(buttonSoundInfo0); + } + sos.writeUI16(buttonSoundChar1); + if (buttonSoundChar1 != 0) { + sos.writeSOUNDINFO(buttonSoundInfo1); + } + sos.writeUI16(buttonSoundChar2); + if (buttonSoundChar2 != 0) { + sos.writeSOUNDINFO(buttonSoundInfo2); + } + sos.writeUI16(buttonSoundChar3); + if (buttonSoundChar3 != 0) { + sos.writeSOUNDINFO(buttonSoundInfo3); + } + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + @Override + public int getCharacterId() { + return buttonId; + } + + @Override + public void setCharacterId(int characterId) { + this.buttonId = characterId; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java index 690b63595..d58a91855 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java @@ -83,16 +83,6 @@ public class DefineButtonTag extends ButtonTag implements ASMSource { @HideInRawEdit public ByteArrayRange actionBytes; - @Override - public int getCharacterId() { - return buttonId; - } - - @Override - public void setCharacterId(int characterId) { - this.buttonId = characterId; - } - private Timeline timeline; private boolean isSingleFrameInitialized; @@ -101,11 +91,6 @@ public class DefineButtonTag extends ButtonTag implements ASMSource { private static final Cache rectCache = Cache.getInstance(true, true, "rect_button"); - @Override - public List getRecords() { - return characters; - } - /** * Constructor * @@ -162,6 +147,21 @@ public class DefineButtonTag extends ButtonTag implements ASMSource { return baos.toByteArray(); } + @Override + public int getCharacterId() { + return buttonId; + } + + @Override + public void setCharacterId(int characterId) { + this.buttonId = characterId; + } + + @Override + public List getRecords() { + return characters; + } + /** * Converts actions to ASM source * diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java index 64052703c..be5731774 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java @@ -1,1145 +1,1145 @@ -/* - * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3.0 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. - */ -package com.jpexs.decompiler.flash.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.decompiler.flash.exporters.commonshape.ExportRectangle; -import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; -import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; -import com.jpexs.decompiler.flash.helpers.HighlightedText; -import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter; -import com.jpexs.decompiler.flash.helpers.hilight.HighlightSpecialType; -import com.jpexs.decompiler.flash.tags.base.BoundedTag; -import com.jpexs.decompiler.flash.tags.base.FontTag; -import com.jpexs.decompiler.flash.tags.base.MissingCharacterHandler; -import com.jpexs.decompiler.flash.tags.base.RenderContext; -import com.jpexs.decompiler.flash.tags.base.TextTag; -import com.jpexs.decompiler.flash.tags.dynamictext.CharacterWithStyle; -import com.jpexs.decompiler.flash.tags.dynamictext.DynamicTextModel; -import com.jpexs.decompiler.flash.tags.dynamictext.GlyphCharacter; -import com.jpexs.decompiler.flash.tags.dynamictext.Paragraph; -import com.jpexs.decompiler.flash.tags.dynamictext.SameStyleTextRecord; -import com.jpexs.decompiler.flash.tags.dynamictext.TextStyle; -import com.jpexs.decompiler.flash.tags.dynamictext.Word; -import com.jpexs.decompiler.flash.tags.text.ParsedSymbol; -import com.jpexs.decompiler.flash.tags.text.TextAlign; -import com.jpexs.decompiler.flash.tags.text.TextLexer; -import com.jpexs.decompiler.flash.tags.text.TextParseException; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.ColorTransform; -import com.jpexs.decompiler.flash.types.DynamicTextGlyphEntry; -import com.jpexs.decompiler.flash.types.MATRIX; -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.TEXTRECORD; -import com.jpexs.decompiler.flash.types.annotations.Conditional; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.helpers.ByteArrayRange; -import com.jpexs.helpers.SerializableImage; -import com.jpexs.helpers.utf8.Utf8Helper; -import java.awt.Color; -import java.awt.Font; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.io.StringReader; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Set; -import java.util.Stack; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; -import org.xml.sax.Attributes; -import org.xml.sax.SAXException; -import org.xml.sax.helpers.DefaultHandler; - -/** - * - * @author JPEXS - */ -public class DefineEditTextTag extends TextTag { - - public static final int ID = 37; - - public static final String NAME = "DefineEditText"; - - @SWFType(BasicType.UI16) - public int characterID; - - public RECT bounds; - - public boolean hasText; - - public boolean wordWrap; - - public boolean multiline; - - public boolean password; - - public boolean readOnly; - - public boolean hasTextColor; - - public boolean hasMaxLength; - - public boolean hasFont; - - public boolean hasFontClass; - - public boolean autoSize; - - public boolean hasLayout; - - public boolean noSelect; - - public boolean border; - - public boolean wasStatic; - - public boolean html; - - public boolean useOutlines; - - @SWFType(BasicType.UI16) - @Conditional("hasFont") - public int fontId; - - @Conditional("hasFontClass") - public String fontClass; - - @SWFType(BasicType.UI16) - @Conditional("hasFont") - public int fontHeight; - - @Conditional("hasTextColor") - public RGBA textColor; - - @SWFType(BasicType.UI16) - @Conditional("hasMaxLength") - public int maxLength; - - @SWFType(BasicType.UI8) - @Conditional("hasLayout") - public int align; - - @SWFType(BasicType.UI16) - @Conditional("hasLayout") - public int leftMargin; - - @SWFType(BasicType.UI16) - @Conditional("hasLayout") - public int rightMargin; - - @SWFType(BasicType.UI16) - @Conditional("hasLayout") - public int indent; - - @SWFType(BasicType.SI16) - @Conditional("hasLayout") - public int leading; - - public String variableName; - - @Conditional("hasText") - public String initialText; - - @Override - public RECT getBounds() { - return bounds; - } - - @Override - public MATRIX getTextMatrix() { - MATRIX matrix = new MATRIX(); - matrix.translateX = bounds.Xmin; - matrix.translateY = bounds.Ymin; - return matrix; - } - - @Override - public void setBounds(RECT r) { - bounds = r; - } - - private String stripTags(String inp) { - boolean intag = false; - String outp = ""; - inp = inp.replaceAll("
", "\r\n"); - for (int i = 0; i < inp.length(); ++i) { - if (!intag && inp.charAt(i) == '<') { - intag = true; - continue; - } - if (intag && inp.charAt(i) == '>') { - intag = false; - continue; - } - if (!intag) { - outp += inp.charAt(i); - } - } - return outp; - } - - private String entitiesReplace(String s) { - s = s.replace("<", "<"); - s = s.replace(">", ">"); - s = s.replace("&", "&"); - s = s.replace(""", "\""); - return s; - } - - @Override - public List getTexts() { - String ret = ""; - if (hasText) { - ret = initialText; - } - if (html) { - ret = stripTags(ret); - ret = entitiesReplace(ret); - } - return Arrays.asList(ret); - } - - private List getTextWithStyle() { - String str = ""; - TextStyle style = new TextStyle(); - style.font = swf.getFont(fontId); - style.fontHeight = fontHeight; - style.fontLeading = leading; - if (hasTextColor) { - style.textColor = textColor; - } - if (hasText) { - str = initialText; - } - final List ret = new ArrayList<>(); - if (html) { - SAXParserFactory factory = SAXParserFactory.newInstance(); - SAXParser saxParser; - final Stack styles = new Stack<>(); - styles.add(style); - try { - saxParser = factory.newSAXParser(); - DefaultHandler handler = new DefaultHandler() { - - @Override - public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { - TextStyle style = styles.peek(); - switch (qName) { - case "p": - // todo: parse the following attribute: - // align - break; - case "b": - style = style.clone(); - style.bold = true; - styles.add(style); - break; - case "i": - style = style.clone(); - style.italic = true; - styles.add(style); - break; - case "u": - style = style.clone(); - style.underlined = true; - styles.add(style); - break; - case "font": - style = style.clone(); - String color = attributes.getValue("color"); - if (color != null) { - if (color.startsWith("#")) { - style.textColor = new RGBA(Color.decode(color)); - } - } - String size = attributes.getValue("size"); - if (size != null && size.length() > 0) { - char firstChar = size.charAt(0); - if (firstChar != '+' && firstChar != '-') { - int fontSize = Integer.parseInt(size); - style.fontHeight = (int) Math.round(fontSize * (style.font == null ? 1 : style.font.getDivider())); - style.fontLeading = leading; - } else { - // todo: parse relative sizes - } - } - String face = attributes.getValue("face"); - { - if (face != null && face.length() > 0) { - style.fontFace = face; - } - } - // todo: parse the following attributes: letterSpacing, kerning - styles.add(style); - break; - case "br": - case "sbr": // what's this? - CharacterWithStyle cs = new CharacterWithStyle(); - cs.character = '\n'; - cs.style = style; - ret.add(cs); - break; - } - //ret = entitiesReplace(ret); - } - - @Override - public void endElement(String uri, String localName, String qName) throws SAXException { - switch (qName) { - case "b": - case "i": - case "u": - case "font": - styles.pop(); - break; - case "p": - TextStyle style = styles.peek(); - CharacterWithStyle cs = new CharacterWithStyle(); - cs.character = '\n'; - cs.style = style; - ret.add(cs); - break; - } - } - - @Override - public void characters(char[] ch, int start, int length) throws SAXException { - String txt = new String(ch, start, length); - TextStyle style = styles.peek(); - addCharacters(ret, txt, style); - } - }; - str = " \n" - + "]>" + str + ""; - saxParser.parse(new ByteArrayInputStream(str.getBytes(Utf8Helper.charset)), handler); - } catch (ParserConfigurationException | SAXException | IOException ex) { - Logger.getLogger(DefineEditTextTag.class.getName()).log(Level.SEVERE, null, ex); - } - } else { - addCharacters(ret, str, style); - } - return ret; - } - - private void addCharacters(List list, String str, TextStyle style) { - for (int i = 0; i < str.length(); i++) { - char ch = str.charAt(i); - CharacterWithStyle cs = new CharacterWithStyle(); - cs.character = ch; - cs.style = style; - list.add(cs); - } - } - - @Override - public List getFontIds() { - List ret = new ArrayList<>(); - ret.add(fontId); - return ret; - } - - @Override - public HighlightedText getFormattedText() { - HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), true); - writer.append("["); - String[] alignNames = {"left", "right", "center", "justify"}; - String alignment; - if (align < alignNames.length) { - alignment = alignNames[align]; - } else { - alignment = "unknown"; - } - writer.newLine(); - writer.append("xmin " + bounds.Xmin).newLine(); - writer.append("ymin " + bounds.Ymin).newLine(); - writer.append("xmax " + bounds.Xmax).newLine(); - writer.append("ymax " + bounds.Ymax).newLine(); - if (wordWrap) { - writer.append("wordwrap 1").newLine(); - } - if (multiline) { - writer.append("multiline 1").newLine(); - } - if (password) { - writer.append("password 1").newLine(); - } - if (readOnly) { - writer.append("readonly 1").newLine(); - } - if (autoSize) { - writer.append("autosize 1").newLine(); - } - if (noSelect) { - writer.append("noselect 1").newLine(); - } - if (border) { - writer.append("border 1").newLine(); - } - if (wasStatic) { - writer.append("wasstatic 1").newLine(); - } - if (html) { - writer.append("html 1").newLine(); - } - if (useOutlines) { - writer.append("useoutlines 1").newLine(); - } - if (hasFont) { - writer.append("font " + fontId).newLine(); - writer.append("height " + fontHeight).newLine(); - } - if (hasTextColor) { - writer.append("color " + textColor.toHexARGB()).newLine(); - } - if (hasFontClass) { - writer.append("fontclass " + fontClass).newLine(); - } - if (hasMaxLength) { - writer.append("maxlength " + maxLength).newLine(); - } - writer.append("align " + alignment).newLine(); - if (hasLayout) { - writer.append("leftmargin " + leftMargin).newLine(); - writer.append("rightmargin " + rightMargin).newLine(); - writer.append("indent " + indent).newLine(); - writer.append("leading " + leading).newLine(); - } - if (!variableName.isEmpty()) { - writer.append("variablename " + variableName).newLine(); - } - writer.append("]"); - if (hasText) { - String text = initialText.replace("\\", "\\\\").replace("[", "\\[").replace("]", "\\]"); - writer.hilightSpecial(text, HighlightSpecialType.TEXT); - } - return new HighlightedText(writer); - } - - @Override - public boolean setFormattedText(MissingCharacterHandler missingCharHandler, String formattedText, String[] texts) throws TextParseException { - try { - TextLexer lexer = new TextLexer(new StringReader(formattedText)); - ParsedSymbol s = null; - formattedText = ""; - RECT bounds = new RECT(this.bounds); - boolean wordWrap = false; - boolean multiline = false; - boolean password = false; - boolean readOnly = false; - boolean autoSize = false; - boolean noSelect = false; - boolean border = false; - boolean wasStatic = false; - boolean html = false; - boolean useOutlines = false; - int fontId = -1; - int fontHeight = -1; - String fontClass = null; - RGBA textColor = null; - int maxLength = -1; - int align = -1; - int leftMargin = -1; - int rightMargin = -1; - int indent = -1; - int leading = -1; - String variableName = null; - - int textIdx = 0; - while ((s = lexer.yylex()) != null) { - switch (s.type) { - case PARAMETER: - String paramName = (String) s.values[0]; - String paramValue = (String) s.values[1]; - switch (paramName) { - case "xmin": - try { - bounds.Xmin = Integer.parseInt(paramValue); - } catch (NumberFormatException nfe) { - throw new TextParseException("Invalid xmin value. Number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "ymin": - try { - bounds.Ymin = Integer.parseInt(paramValue); - } catch (NumberFormatException nfe) { - throw new TextParseException("Invalid ymin value. Number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "xmax": - try { - bounds.Xmax = Integer.parseInt(paramValue); - } catch (NumberFormatException nfe) { - throw new TextParseException("Invalid xmax value. Number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "ymax": - try { - bounds.Ymax = Integer.parseInt(paramValue); - } catch (NumberFormatException nfe) { - throw new TextParseException("Invalid ymax value. Number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "wordwrap": - if (paramValue.equals("1")) { - wordWrap = true; - } - break; - case "multiline": - if (paramValue.equals("1")) { - multiline = true; - } - break; - case "password": - if (paramValue.equals("1")) { - password = true; - } - break; - case "readonly": - if (paramValue.equals("1")) { - readOnly = true; - } - break; - case "autosize": - if (paramValue.equals("1")) { - autoSize = true; - } - break; - case "noselect": - if (paramValue.equals("1")) { - noSelect = true; - } - break; - case "border": - if (paramValue.equals("1")) { - border = true; - } - break; - case "wasstatic": - if (paramValue.equals("1")) { - wasStatic = true; - } - break; - case "html": - if (paramValue.equals("1")) { - html = true; - } - break; - case "useoutlines": - if (paramValue.equals("1")) { - useOutlines = true; - } - break; - case "font": - try { - fontId = Integer.parseInt(paramValue); - - FontTag ft = swf.getFont(fontId); - if (ft == null) { - throw new TextParseException("Font not found.", lexer.yyline()); - } - } catch (NumberFormatException ne) { - throw new TextParseException("Invalid font value. Number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "fontclass": - fontClass = paramValue; - break; - case "height": - try { - fontHeight = Integer.parseInt(paramValue); - } catch (NumberFormatException ne) { - throw new TextParseException("Invalid height value. Number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "color": - Matcher m = Pattern.compile("#([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])").matcher(paramValue); - if (m.matches()) { - textColor = new RGBA(Integer.parseInt(m.group(2), 16), Integer.parseInt(m.group(3), 16), Integer.parseInt(m.group(4), 16), Integer.parseInt(m.group(1), 16)); - } else { - throw new TextParseException("Invalid color. Valid format is #aarrggbb. Found: " + paramValue, lexer.yyline()); - } - break; - case "maxlength": - try { - maxLength = Integer.parseInt(paramValue); - } catch (NumberFormatException ne) { - throw new TextParseException("Invalid maxLength value. Number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "align": - switch (paramValue) { - case "left": - align = 0; - break; - case "right": - align = 1; - break; - case "center": - align = 2; - break; - case "justify": - align = 3; - break; - default: - throw new TextParseException("Invalid align value. Expected one of: left,right,center or justify. Found: " + paramValue, lexer.yyline()); - } - break; - case "leftmargin": - try { - leftMargin = Integer.parseInt(paramValue); - } catch (NumberFormatException ne) { - throw new TextParseException("Invalid leftmargin value. Number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "rightmargin": - try { - rightMargin = Integer.parseInt(paramValue); - } catch (NumberFormatException ne) { - throw new TextParseException("Invalid rightmargin value. Number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "indent": - try { - indent = Integer.parseInt(paramValue); - } catch (NumberFormatException ne) { - throw new TextParseException("Invalid indent value. Number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "leading": - try { - leading = Integer.parseInt(paramValue); - } catch (NumberFormatException ne) { - throw new TextParseException("Invalid leading value. Number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "variablename": - variableName = paramValue; - break; - default: - throw new TextParseException("Unrecognized parameter name: " + paramName, lexer.yyline()); - } - break; - case TEXT: - String s2 = (String) s.values[0]; - if (s2 == null) { - s2 = ""; - } - - formattedText += (texts == null || textIdx >= texts.length) ? s2 : texts[textIdx++]; - formattedText = formattedText.replace("\r\n", "\r"); - break; - } - } - - setModified(true); - this.bounds = bounds; - if (formattedText.length() > 0) { - initialText = formattedText; - this.hasText = true; - } else { - this.hasText = false; - } - this.wordWrap = wordWrap; - this.multiline = multiline; - this.password = password; - this.readOnly = readOnly; - this.noSelect = noSelect; - this.border = border; - this.wasStatic = wasStatic; - this.html = html; - this.useOutlines = useOutlines; - if (textColor != null) { - hasTextColor = true; - this.textColor = textColor; - } - if (maxLength > -1) { - this.maxLength = maxLength; - hasMaxLength = true; - } - if (fontId > -1) { - this.fontId = fontId; - } - if (fontHeight > -1) { - this.fontHeight = fontHeight; - } - if (fontClass != null) { - this.fontClass = fontClass; - hasFontClass = true; - } - this.autoSize = autoSize; - this.align = align; - if ((leftMargin > -1) - || (rightMargin > -1) - || (indent > -1) - || (leading > -1)) { - this.leftMargin = leftMargin; - this.rightMargin = rightMargin; - this.indent = indent; - this.leading = leading; - hasLayout = true; - } - if (variableName == null) { - variableName = ""; - } - this.variableName = variableName; - - } catch (IOException ex) { - Logger.getLogger(DefineEditTextTag.class.getName()).log(Level.SEVERE, null, ex); - return false; - } - - return true; - } - - @Override - public void updateTextBounds() { - } - - @Override - public boolean alignText(TextAlign textAlign) { - return true; - } - - @Override - public boolean translateText(int diff) { - return true; - } - - @Override - public RECT getRect(Set added) { - return bounds; - } - - @Override - public int getCharacterId() { - return characterID; - } - - @Override - public void setCharacterId(int characterId) { - this.characterID = characterId; - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(characterID); - sos.writeRECT(bounds); - sos.writeUB(1, hasText ? 1 : 0); - sos.writeUB(1, wordWrap ? 1 : 0); - sos.writeUB(1, multiline ? 1 : 0); - sos.writeUB(1, password ? 1 : 0); - sos.writeUB(1, readOnly ? 1 : 0); - sos.writeUB(1, hasTextColor ? 1 : 0); - sos.writeUB(1, hasMaxLength ? 1 : 0); - sos.writeUB(1, hasFont ? 1 : 0); - sos.writeUB(1, hasFontClass ? 1 : 0); - sos.writeUB(1, autoSize ? 1 : 0); - sos.writeUB(1, hasLayout ? 1 : 0); - sos.writeUB(1, noSelect ? 1 : 0); - sos.writeUB(1, border ? 1 : 0); - sos.writeUB(1, wasStatic ? 1 : 0); - sos.writeUB(1, html ? 1 : 0); - sos.writeUB(1, useOutlines ? 1 : 0); - if (hasFont) { - sos.writeUI16(fontId); - } - if (hasFontClass) { - sos.writeString(fontClass); - } - if (hasFont) { - sos.writeUI16(fontHeight); - } - if (hasTextColor) { - sos.writeRGBA(textColor); - } - if (hasMaxLength) { - sos.writeUI16(maxLength); - } - if (hasLayout) { - sos.writeUI8(align); - sos.writeUI16(leftMargin); - sos.writeUI16(rightMargin); - sos.writeUI16(indent); - sos.writeSI16(leading); - } - sos.writeString(variableName); - if (hasText) { - sos.writeString(initialText); - } - - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - - /** - * Constructor - * - * @param swf - */ - public DefineEditTextTag(SWF swf) { - super(swf, ID, NAME, null); - characterID = swf.getNextCharacterId(); - bounds = new RECT(); - variableName = ""; - } - - /** - * Constructor - * - * @param sis - * @param data - * @throws IOException - */ - public DefineEditTextTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, NAME, data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - characterID = sis.readUI16("characterID"); - bounds = sis.readRECT("bounds"); - hasText = sis.readUB(1, "hasText") == 1; - wordWrap = sis.readUB(1, "wordWrap") == 1; - multiline = sis.readUB(1, "multiline") == 1; - password = sis.readUB(1, "password") == 1; - readOnly = sis.readUB(1, "readOnly") == 1; - hasTextColor = sis.readUB(1, "hasTextColor") == 1; - hasMaxLength = sis.readUB(1, "hasMaxLength") == 1; - hasFont = sis.readUB(1, "hasFont") == 1; - hasFontClass = sis.readUB(1, "hasFontClass") == 1; - autoSize = sis.readUB(1, "autoSize") == 1; - hasLayout = sis.readUB(1, "hasLayout") == 1; - noSelect = sis.readUB(1, "noSelect") == 1; - border = sis.readUB(1, "border") == 1; - wasStatic = sis.readUB(1, "wasStatic") == 1; - html = sis.readUB(1, "html") == 1; - useOutlines = sis.readUB(1, "useOutlines") == 1; - if (hasFont) { - fontId = sis.readUI16("fontId"); - } - if (hasFontClass) { - fontClass = sis.readString("fontClass"); - } - if (hasFont) { - fontHeight = sis.readUI16("fontHeight"); - } - if (hasTextColor) { - textColor = sis.readRGBA("textColor"); - } - if (hasMaxLength) { - maxLength = sis.readUI16("maxLength"); - } - if (hasLayout) { - align = sis.readUI8("align"); //0 left, 1 right, 2 center, 3 justify - leftMargin = sis.readUI16("leftMargin"); - rightMargin = sis.readUI16("rightMargin"); - indent = sis.readUI16("indent"); - leading = sis.readSI16("leading"); - } - variableName = sis.readString("variableName"); - if (hasText) { - initialText = sis.readString("initialText"); - } - - } - - @Override - public void getNeededCharacters(Set needed) { - if (hasFont) { - needed.add(fontId); - } - } - - @Override - public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { - if (fontId == oldCharacterId) { - fontId = newCharacterId; - setModified(true); - return true; - } - return false; - } - - @Override - public boolean removeCharacter(int characterId) { - if (fontId == characterId) { - hasFont = false; - fontId = 0; - setModified(true); - return true; - } - return false; - } - - @Override - public int getUsedParameters() { - return 0; - } - - @Override - public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, Matrix transformation, ColorTransform colorTransform) { - render(false, image, transformation, colorTransform); - } - - @Override - public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, double zoom) { - // todo: implement - } - - @Override - public String toHtmlCanvas(double unitDivisor) { - return render(true, null, new Matrix(), new ColorTransform()); - } - - private String render(boolean canvas, SerializableImage image, Matrix transformation, ColorTransform colorTransform) { - if (border) { - // border is always black, fill color is always white? - RGB borderColor = new RGBA(Color.black); - RGB fillColor = new RGBA(Color.white); - if (!canvas) { - drawBorder(swf, image, borderColor, fillColor, getRect(), getTextMatrix(), transformation, colorTransform); - } else { - // TODO: draw border - } - } - if (hasText) { - DynamicTextModel textModel = new DynamicTextModel(); - List txt = getTextWithStyle(); - TextStyle lastStyle = null; - char prevChar = 0; - boolean lastWasWhiteSpace = false; - for (int i = 0; i < txt.size(); i++) { - CharacterWithStyle cs = txt.get(i); - char c = cs.character; - if (c != '\r' && c != '\n') { - // create new SameStyleTextRecord for all words and all diffrent style text parts - if (lastWasWhiteSpace && !Character.isWhitespace(c)) { - textModel.newWord(); - lastWasWhiteSpace = false; - } - if (cs.style != lastStyle) { - lastStyle = cs.style; - textModel.style = lastStyle; - textModel.newRecord(); - } - Character nextChar = null; - if (i + 1 < txt.size()) { - nextChar = txt.get(i + 1).character; - } - int advance; - FontTag font = lastStyle.font; - DynamicTextGlyphEntry ge = new DynamicTextGlyphEntry(); - ge.fontFace = lastStyle.fontFace; - ge.fontStyle = (lastStyle.bold ? Font.BOLD : 0) | (lastStyle.italic ? Font.ITALIC : 0); - ge.character = c; - ge.glyphIndex = font == null ? -1 : font.charToGlyph(c); - if (font != null && font.hasLayout()) { - int kerningAdjustment = 0; - if (nextChar != null) { - kerningAdjustment = font.getCharKerningAdjustment(c, nextChar); - kerningAdjustment /= font.getDivider(); - } - advance = (int) Math.round(Math.round((double) lastStyle.fontHeight * (font.getGlyphAdvance(ge.glyphIndex) + kerningAdjustment) / (font.getDivider() * 1024.0))); - } else { - String fontName = lastStyle.fontFace != null ? lastStyle.fontFace : FontTag.defaultFontName; - int fontStyle = font == null ? ge.fontStyle : font.getFontStyle(); - advance = (int) Math.round(SWF.unitDivisor * FontTag.getSystemFontAdvance(fontName, fontStyle, (int) (lastStyle.fontHeight / SWF.unitDivisor), c, nextChar)); - } - ge.glyphAdvance = advance; - textModel.addGlyph(c, ge); - if (Character.isWhitespace(c)) { - lastWasWhiteSpace = true; - } - } else { - if (multiline) { - textModel.newParagraph(); - } - } - prevChar = c; - } - - textModel.calculateTextWidths(); - List> lines; - if (multiline && wordWrap) { - lines = new ArrayList<>(); - for (Paragraph paragraph : textModel.paragraphs) { - List line = new ArrayList<>(); - int lineLength = 0; - for (Word word : paragraph.words) { - if (lineLength + word.width <= bounds.getWidth()) { - line.addAll(word.records); - lineLength += word.width; - } else { - lines.add(line); - line = new ArrayList<>(); - line.addAll(word.records); - lineLength = 0; - } - } - if (!line.isEmpty()) { - lines.add(line); - } - } - } else { - lines = new ArrayList<>(); - for (Paragraph paragraph : textModel.paragraphs) { - List line = new ArrayList<>(); - for (Word word : paragraph.words) { - for (SameStyleTextRecord tr : word.records) { - line.add(tr); - } - } - lines.add(line); - } - } - - // remove spaces after last word - for (List line : lines) { - boolean removed = true; - while (removed) { - removed = false; - while (line.size() > 0 && line.get(line.size() - 1).glyphEntries.isEmpty()) { - line.remove(line.size() - 1); - removed = true; - } - if (line.size() > 0) { - SameStyleTextRecord lastRecord = line.get(line.size() - 1); - while (lastRecord.glyphEntries.size() > 0 - && Character.isWhitespace(lastRecord.glyphEntries.get(lastRecord.glyphEntries.size() - 1).character)) { - lastRecord.glyphEntries.remove(lastRecord.glyphEntries.size() - 1); - removed = true; - } - } - } - } - - textModel.calculateTextWidths(); - - List allTextRecords = new ArrayList<>(); - int lastHeight = 0; - int yOffset = 0; - for (List line : lines) { - int width = 0; - int currentOffset = 0; - if (line.isEmpty()) { - currentOffset = lastHeight; - } else { - for (SameStyleTextRecord tr : line) { - width += tr.width; - int lineHeight = tr.style.fontHeight + tr.style.fontLeading; - lastHeight = lineHeight; - if (lineHeight > currentOffset) { - currentOffset = lineHeight; - } - } - } - yOffset += currentOffset; - int alignOffset = 0; - switch (align) { - case 0: // left - alignOffset = 0; - break; - case 1: // right - alignOffset = bounds.getWidth() - width; - break; - case 2: // center - alignOffset = (bounds.getWidth() - width) / 2; - break; - case 3: // justify - // todo; - break; - } - for (SameStyleTextRecord tr : line) { - tr.xOffset = alignOffset; - alignOffset += tr.width; - } - for (SameStyleTextRecord tr : line) { - TEXTRECORD tr2 = new TEXTRECORD(); - tr2.styleFlagsHasFont = fontId != 0; - tr2.fontId = fontId; - tr2.textHeight = tr.style.fontHeight; - if (tr.style.textColor != null) { - tr2.styleFlagsHasColor = true; - tr2.textColorA = tr.style.textColor; - } - // always add xOffset, because no xOffset and 0 xOffset is diffrent in text rendering - tr2.styleFlagsHasXOffset = true; - tr2.xOffset = tr.xOffset; - if (yOffset != 0) { - tr2.styleFlagsHasYOffset = true; - tr2.yOffset = yOffset; - } - tr2.glyphEntries = new ArrayList<>(tr.glyphEntries.size()); - for (GlyphCharacter ge : tr.glyphEntries) { - tr2.glyphEntries.add(ge.glyphEntry); - } - allTextRecords.add(tr2); - } - } - - if (canvas) { - return staticTextToHtmlCanvas(1, swf, allTextRecords, 2, getBounds(), getTextMatrix(), colorTransform); - } else { - staticTextToImage(swf, allTextRecords, 2, image, getTextMatrix(), transformation, colorTransform); - } - } - - return ""; - } - - @Override - public ExportRectangle calculateTextBounds() { - return null; - } - - @Override - public int getNumFrames() { - return 1; - } - - @Override - public boolean isSingleFrame() { - return true; - } -} +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.exporters.commonshape.ExportRectangle; +import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; +import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; +import com.jpexs.decompiler.flash.helpers.HighlightedText; +import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter; +import com.jpexs.decompiler.flash.helpers.hilight.HighlightSpecialType; +import com.jpexs.decompiler.flash.tags.base.BoundedTag; +import com.jpexs.decompiler.flash.tags.base.FontTag; +import com.jpexs.decompiler.flash.tags.base.MissingCharacterHandler; +import com.jpexs.decompiler.flash.tags.base.RenderContext; +import com.jpexs.decompiler.flash.tags.base.TextTag; +import com.jpexs.decompiler.flash.tags.dynamictext.CharacterWithStyle; +import com.jpexs.decompiler.flash.tags.dynamictext.DynamicTextModel; +import com.jpexs.decompiler.flash.tags.dynamictext.GlyphCharacter; +import com.jpexs.decompiler.flash.tags.dynamictext.Paragraph; +import com.jpexs.decompiler.flash.tags.dynamictext.SameStyleTextRecord; +import com.jpexs.decompiler.flash.tags.dynamictext.TextStyle; +import com.jpexs.decompiler.flash.tags.dynamictext.Word; +import com.jpexs.decompiler.flash.tags.text.ParsedSymbol; +import com.jpexs.decompiler.flash.tags.text.TextAlign; +import com.jpexs.decompiler.flash.tags.text.TextLexer; +import com.jpexs.decompiler.flash.tags.text.TextParseException; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.ColorTransform; +import com.jpexs.decompiler.flash.types.DynamicTextGlyphEntry; +import com.jpexs.decompiler.flash.types.MATRIX; +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.TEXTRECORD; +import com.jpexs.decompiler.flash.types.annotations.Conditional; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.helpers.ByteArrayRange; +import com.jpexs.helpers.SerializableImage; +import com.jpexs.helpers.utf8.Utf8Helper; +import java.awt.Color; +import java.awt.Font; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import java.util.Stack; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +/** + * + * @author JPEXS + */ +public class DefineEditTextTag extends TextTag { + + public static final int ID = 37; + + public static final String NAME = "DefineEditText"; + + @SWFType(BasicType.UI16) + public int characterID; + + public RECT bounds; + + public boolean hasText; + + public boolean wordWrap; + + public boolean multiline; + + public boolean password; + + public boolean readOnly; + + public boolean hasTextColor; + + public boolean hasMaxLength; + + public boolean hasFont; + + public boolean hasFontClass; + + public boolean autoSize; + + public boolean hasLayout; + + public boolean noSelect; + + public boolean border; + + public boolean wasStatic; + + public boolean html; + + public boolean useOutlines; + + @SWFType(BasicType.UI16) + @Conditional("hasFont") + public int fontId; + + @Conditional("hasFontClass") + public String fontClass; + + @SWFType(BasicType.UI16) + @Conditional("hasFont") + public int fontHeight; + + @Conditional("hasTextColor") + public RGBA textColor; + + @SWFType(BasicType.UI16) + @Conditional("hasMaxLength") + public int maxLength; + + @SWFType(BasicType.UI8) + @Conditional("hasLayout") + public int align; + + @SWFType(BasicType.UI16) + @Conditional("hasLayout") + public int leftMargin; + + @SWFType(BasicType.UI16) + @Conditional("hasLayout") + public int rightMargin; + + @SWFType(BasicType.UI16) + @Conditional("hasLayout") + public int indent; + + @SWFType(BasicType.SI16) + @Conditional("hasLayout") + public int leading; + + public String variableName; + + @Conditional("hasText") + public String initialText; + + /** + * Constructor + * + * @param swf + */ + public DefineEditTextTag(SWF swf) { + super(swf, ID, NAME, null); + characterID = swf.getNextCharacterId(); + bounds = new RECT(); + variableName = ""; + } + + /** + * Constructor + * + * @param sis + * @param data + * @throws IOException + */ + public DefineEditTextTag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + characterID = sis.readUI16("characterID"); + bounds = sis.readRECT("bounds"); + hasText = sis.readUB(1, "hasText") == 1; + wordWrap = sis.readUB(1, "wordWrap") == 1; + multiline = sis.readUB(1, "multiline") == 1; + password = sis.readUB(1, "password") == 1; + readOnly = sis.readUB(1, "readOnly") == 1; + hasTextColor = sis.readUB(1, "hasTextColor") == 1; + hasMaxLength = sis.readUB(1, "hasMaxLength") == 1; + hasFont = sis.readUB(1, "hasFont") == 1; + hasFontClass = sis.readUB(1, "hasFontClass") == 1; + autoSize = sis.readUB(1, "autoSize") == 1; + hasLayout = sis.readUB(1, "hasLayout") == 1; + noSelect = sis.readUB(1, "noSelect") == 1; + border = sis.readUB(1, "border") == 1; + wasStatic = sis.readUB(1, "wasStatic") == 1; + html = sis.readUB(1, "html") == 1; + useOutlines = sis.readUB(1, "useOutlines") == 1; + if (hasFont) { + fontId = sis.readUI16("fontId"); + } + if (hasFontClass) { + fontClass = sis.readString("fontClass"); + } + if (hasFont) { + fontHeight = sis.readUI16("fontHeight"); + } + if (hasTextColor) { + textColor = sis.readRGBA("textColor"); + } + if (hasMaxLength) { + maxLength = sis.readUI16("maxLength"); + } + if (hasLayout) { + align = sis.readUI8("align"); //0 left, 1 right, 2 center, 3 justify + leftMargin = sis.readUI16("leftMargin"); + rightMargin = sis.readUI16("rightMargin"); + indent = sis.readUI16("indent"); + leading = sis.readSI16("leading"); + } + variableName = sis.readString("variableName"); + if (hasText) { + initialText = sis.readString("initialText"); + } + + } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(characterID); + sos.writeRECT(bounds); + sos.writeUB(1, hasText ? 1 : 0); + sos.writeUB(1, wordWrap ? 1 : 0); + sos.writeUB(1, multiline ? 1 : 0); + sos.writeUB(1, password ? 1 : 0); + sos.writeUB(1, readOnly ? 1 : 0); + sos.writeUB(1, hasTextColor ? 1 : 0); + sos.writeUB(1, hasMaxLength ? 1 : 0); + sos.writeUB(1, hasFont ? 1 : 0); + sos.writeUB(1, hasFontClass ? 1 : 0); + sos.writeUB(1, autoSize ? 1 : 0); + sos.writeUB(1, hasLayout ? 1 : 0); + sos.writeUB(1, noSelect ? 1 : 0); + sos.writeUB(1, border ? 1 : 0); + sos.writeUB(1, wasStatic ? 1 : 0); + sos.writeUB(1, html ? 1 : 0); + sos.writeUB(1, useOutlines ? 1 : 0); + if (hasFont) { + sos.writeUI16(fontId); + } + if (hasFontClass) { + sos.writeString(fontClass); + } + if (hasFont) { + sos.writeUI16(fontHeight); + } + if (hasTextColor) { + sos.writeRGBA(textColor); + } + if (hasMaxLength) { + sos.writeUI16(maxLength); + } + if (hasLayout) { + sos.writeUI8(align); + sos.writeUI16(leftMargin); + sos.writeUI16(rightMargin); + sos.writeUI16(indent); + sos.writeSI16(leading); + } + sos.writeString(variableName); + if (hasText) { + sos.writeString(initialText); + } + + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + @Override + public RECT getBounds() { + return bounds; + } + + @Override + public MATRIX getTextMatrix() { + MATRIX matrix = new MATRIX(); + matrix.translateX = bounds.Xmin; + matrix.translateY = bounds.Ymin; + return matrix; + } + + @Override + public void setBounds(RECT r) { + bounds = r; + } + + private String stripTags(String inp) { + boolean intag = false; + String outp = ""; + inp = inp.replaceAll("
", "\r\n"); + for (int i = 0; i < inp.length(); ++i) { + if (!intag && inp.charAt(i) == '<') { + intag = true; + continue; + } + if (intag && inp.charAt(i) == '>') { + intag = false; + continue; + } + if (!intag) { + outp += inp.charAt(i); + } + } + return outp; + } + + private String entitiesReplace(String s) { + s = s.replace("<", "<"); + s = s.replace(">", ">"); + s = s.replace("&", "&"); + s = s.replace(""", "\""); + return s; + } + + @Override + public List getTexts() { + String ret = ""; + if (hasText) { + ret = initialText; + } + if (html) { + ret = stripTags(ret); + ret = entitiesReplace(ret); + } + return Arrays.asList(ret); + } + + private List getTextWithStyle() { + String str = ""; + TextStyle style = new TextStyle(); + style.font = swf.getFont(fontId); + style.fontHeight = fontHeight; + style.fontLeading = leading; + if (hasTextColor) { + style.textColor = textColor; + } + if (hasText) { + str = initialText; + } + final List ret = new ArrayList<>(); + if (html) { + SAXParserFactory factory = SAXParserFactory.newInstance(); + SAXParser saxParser; + final Stack styles = new Stack<>(); + styles.add(style); + try { + saxParser = factory.newSAXParser(); + DefaultHandler handler = new DefaultHandler() { + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { + TextStyle style = styles.peek(); + switch (qName) { + case "p": + // todo: parse the following attribute: + // align + break; + case "b": + style = style.clone(); + style.bold = true; + styles.add(style); + break; + case "i": + style = style.clone(); + style.italic = true; + styles.add(style); + break; + case "u": + style = style.clone(); + style.underlined = true; + styles.add(style); + break; + case "font": + style = style.clone(); + String color = attributes.getValue("color"); + if (color != null) { + if (color.startsWith("#")) { + style.textColor = new RGBA(Color.decode(color)); + } + } + String size = attributes.getValue("size"); + if (size != null && size.length() > 0) { + char firstChar = size.charAt(0); + if (firstChar != '+' && firstChar != '-') { + int fontSize = Integer.parseInt(size); + style.fontHeight = (int) Math.round(fontSize * (style.font == null ? 1 : style.font.getDivider())); + style.fontLeading = leading; + } else { + // todo: parse relative sizes + } + } + String face = attributes.getValue("face"); + { + if (face != null && face.length() > 0) { + style.fontFace = face; + } + } + // todo: parse the following attributes: letterSpacing, kerning + styles.add(style); + break; + case "br": + case "sbr": // what's this? + CharacterWithStyle cs = new CharacterWithStyle(); + cs.character = '\n'; + cs.style = style; + ret.add(cs); + break; + } + //ret = entitiesReplace(ret); + } + + @Override + public void endElement(String uri, String localName, String qName) throws SAXException { + switch (qName) { + case "b": + case "i": + case "u": + case "font": + styles.pop(); + break; + case "p": + TextStyle style = styles.peek(); + CharacterWithStyle cs = new CharacterWithStyle(); + cs.character = '\n'; + cs.style = style; + ret.add(cs); + break; + } + } + + @Override + public void characters(char[] ch, int start, int length) throws SAXException { + String txt = new String(ch, start, length); + TextStyle style = styles.peek(); + addCharacters(ret, txt, style); + } + }; + str = " \n" + + "]>" + str + ""; + saxParser.parse(new ByteArrayInputStream(str.getBytes(Utf8Helper.charset)), handler); + } catch (ParserConfigurationException | SAXException | IOException ex) { + Logger.getLogger(DefineEditTextTag.class.getName()).log(Level.SEVERE, null, ex); + } + } else { + addCharacters(ret, str, style); + } + return ret; + } + + private void addCharacters(List list, String str, TextStyle style) { + for (int i = 0; i < str.length(); i++) { + char ch = str.charAt(i); + CharacterWithStyle cs = new CharacterWithStyle(); + cs.character = ch; + cs.style = style; + list.add(cs); + } + } + + @Override + public List getFontIds() { + List ret = new ArrayList<>(); + ret.add(fontId); + return ret; + } + + @Override + public HighlightedText getFormattedText() { + HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), true); + writer.append("["); + String[] alignNames = {"left", "right", "center", "justify"}; + String alignment; + if (align < alignNames.length) { + alignment = alignNames[align]; + } else { + alignment = "unknown"; + } + writer.newLine(); + writer.append("xmin " + bounds.Xmin).newLine(); + writer.append("ymin " + bounds.Ymin).newLine(); + writer.append("xmax " + bounds.Xmax).newLine(); + writer.append("ymax " + bounds.Ymax).newLine(); + if (wordWrap) { + writer.append("wordwrap 1").newLine(); + } + if (multiline) { + writer.append("multiline 1").newLine(); + } + if (password) { + writer.append("password 1").newLine(); + } + if (readOnly) { + writer.append("readonly 1").newLine(); + } + if (autoSize) { + writer.append("autosize 1").newLine(); + } + if (noSelect) { + writer.append("noselect 1").newLine(); + } + if (border) { + writer.append("border 1").newLine(); + } + if (wasStatic) { + writer.append("wasstatic 1").newLine(); + } + if (html) { + writer.append("html 1").newLine(); + } + if (useOutlines) { + writer.append("useoutlines 1").newLine(); + } + if (hasFont) { + writer.append("font " + fontId).newLine(); + writer.append("height " + fontHeight).newLine(); + } + if (hasTextColor) { + writer.append("color " + textColor.toHexARGB()).newLine(); + } + if (hasFontClass) { + writer.append("fontclass " + fontClass).newLine(); + } + if (hasMaxLength) { + writer.append("maxlength " + maxLength).newLine(); + } + writer.append("align " + alignment).newLine(); + if (hasLayout) { + writer.append("leftmargin " + leftMargin).newLine(); + writer.append("rightmargin " + rightMargin).newLine(); + writer.append("indent " + indent).newLine(); + writer.append("leading " + leading).newLine(); + } + if (!variableName.isEmpty()) { + writer.append("variablename " + variableName).newLine(); + } + writer.append("]"); + if (hasText) { + String text = initialText.replace("\\", "\\\\").replace("[", "\\[").replace("]", "\\]"); + writer.hilightSpecial(text, HighlightSpecialType.TEXT); + } + return new HighlightedText(writer); + } + + @Override + public boolean setFormattedText(MissingCharacterHandler missingCharHandler, String formattedText, String[] texts) throws TextParseException { + try { + TextLexer lexer = new TextLexer(new StringReader(formattedText)); + ParsedSymbol s = null; + formattedText = ""; + RECT bounds = new RECT(this.bounds); + boolean wordWrap = false; + boolean multiline = false; + boolean password = false; + boolean readOnly = false; + boolean autoSize = false; + boolean noSelect = false; + boolean border = false; + boolean wasStatic = false; + boolean html = false; + boolean useOutlines = false; + int fontId = -1; + int fontHeight = -1; + String fontClass = null; + RGBA textColor = null; + int maxLength = -1; + int align = -1; + int leftMargin = -1; + int rightMargin = -1; + int indent = -1; + int leading = -1; + String variableName = null; + + int textIdx = 0; + while ((s = lexer.yylex()) != null) { + switch (s.type) { + case PARAMETER: + String paramName = (String) s.values[0]; + String paramValue = (String) s.values[1]; + switch (paramName) { + case "xmin": + try { + bounds.Xmin = Integer.parseInt(paramValue); + } catch (NumberFormatException nfe) { + throw new TextParseException("Invalid xmin value. Number expected. Found: " + paramValue, lexer.yyline()); + } + break; + case "ymin": + try { + bounds.Ymin = Integer.parseInt(paramValue); + } catch (NumberFormatException nfe) { + throw new TextParseException("Invalid ymin value. Number expected. Found: " + paramValue, lexer.yyline()); + } + break; + case "xmax": + try { + bounds.Xmax = Integer.parseInt(paramValue); + } catch (NumberFormatException nfe) { + throw new TextParseException("Invalid xmax value. Number expected. Found: " + paramValue, lexer.yyline()); + } + break; + case "ymax": + try { + bounds.Ymax = Integer.parseInt(paramValue); + } catch (NumberFormatException nfe) { + throw new TextParseException("Invalid ymax value. Number expected. Found: " + paramValue, lexer.yyline()); + } + break; + case "wordwrap": + if (paramValue.equals("1")) { + wordWrap = true; + } + break; + case "multiline": + if (paramValue.equals("1")) { + multiline = true; + } + break; + case "password": + if (paramValue.equals("1")) { + password = true; + } + break; + case "readonly": + if (paramValue.equals("1")) { + readOnly = true; + } + break; + case "autosize": + if (paramValue.equals("1")) { + autoSize = true; + } + break; + case "noselect": + if (paramValue.equals("1")) { + noSelect = true; + } + break; + case "border": + if (paramValue.equals("1")) { + border = true; + } + break; + case "wasstatic": + if (paramValue.equals("1")) { + wasStatic = true; + } + break; + case "html": + if (paramValue.equals("1")) { + html = true; + } + break; + case "useoutlines": + if (paramValue.equals("1")) { + useOutlines = true; + } + break; + case "font": + try { + fontId = Integer.parseInt(paramValue); + + FontTag ft = swf.getFont(fontId); + if (ft == null) { + throw new TextParseException("Font not found.", lexer.yyline()); + } + } catch (NumberFormatException ne) { + throw new TextParseException("Invalid font value. Number expected. Found: " + paramValue, lexer.yyline()); + } + break; + case "fontclass": + fontClass = paramValue; + break; + case "height": + try { + fontHeight = Integer.parseInt(paramValue); + } catch (NumberFormatException ne) { + throw new TextParseException("Invalid height value. Number expected. Found: " + paramValue, lexer.yyline()); + } + break; + case "color": + Matcher m = Pattern.compile("#([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])").matcher(paramValue); + if (m.matches()) { + textColor = new RGBA(Integer.parseInt(m.group(2), 16), Integer.parseInt(m.group(3), 16), Integer.parseInt(m.group(4), 16), Integer.parseInt(m.group(1), 16)); + } else { + throw new TextParseException("Invalid color. Valid format is #aarrggbb. Found: " + paramValue, lexer.yyline()); + } + break; + case "maxlength": + try { + maxLength = Integer.parseInt(paramValue); + } catch (NumberFormatException ne) { + throw new TextParseException("Invalid maxLength value. Number expected. Found: " + paramValue, lexer.yyline()); + } + break; + case "align": + switch (paramValue) { + case "left": + align = 0; + break; + case "right": + align = 1; + break; + case "center": + align = 2; + break; + case "justify": + align = 3; + break; + default: + throw new TextParseException("Invalid align value. Expected one of: left,right,center or justify. Found: " + paramValue, lexer.yyline()); + } + break; + case "leftmargin": + try { + leftMargin = Integer.parseInt(paramValue); + } catch (NumberFormatException ne) { + throw new TextParseException("Invalid leftmargin value. Number expected. Found: " + paramValue, lexer.yyline()); + } + break; + case "rightmargin": + try { + rightMargin = Integer.parseInt(paramValue); + } catch (NumberFormatException ne) { + throw new TextParseException("Invalid rightmargin value. Number expected. Found: " + paramValue, lexer.yyline()); + } + break; + case "indent": + try { + indent = Integer.parseInt(paramValue); + } catch (NumberFormatException ne) { + throw new TextParseException("Invalid indent value. Number expected. Found: " + paramValue, lexer.yyline()); + } + break; + case "leading": + try { + leading = Integer.parseInt(paramValue); + } catch (NumberFormatException ne) { + throw new TextParseException("Invalid leading value. Number expected. Found: " + paramValue, lexer.yyline()); + } + break; + case "variablename": + variableName = paramValue; + break; + default: + throw new TextParseException("Unrecognized parameter name: " + paramName, lexer.yyline()); + } + break; + case TEXT: + String s2 = (String) s.values[0]; + if (s2 == null) { + s2 = ""; + } + + formattedText += (texts == null || textIdx >= texts.length) ? s2 : texts[textIdx++]; + formattedText = formattedText.replace("\r\n", "\r"); + break; + } + } + + setModified(true); + this.bounds = bounds; + if (formattedText.length() > 0) { + initialText = formattedText; + this.hasText = true; + } else { + this.hasText = false; + } + this.wordWrap = wordWrap; + this.multiline = multiline; + this.password = password; + this.readOnly = readOnly; + this.noSelect = noSelect; + this.border = border; + this.wasStatic = wasStatic; + this.html = html; + this.useOutlines = useOutlines; + if (textColor != null) { + hasTextColor = true; + this.textColor = textColor; + } + if (maxLength > -1) { + this.maxLength = maxLength; + hasMaxLength = true; + } + if (fontId > -1) { + this.fontId = fontId; + } + if (fontHeight > -1) { + this.fontHeight = fontHeight; + } + if (fontClass != null) { + this.fontClass = fontClass; + hasFontClass = true; + } + this.autoSize = autoSize; + this.align = align; + if ((leftMargin > -1) + || (rightMargin > -1) + || (indent > -1) + || (leading > -1)) { + this.leftMargin = leftMargin; + this.rightMargin = rightMargin; + this.indent = indent; + this.leading = leading; + hasLayout = true; + } + if (variableName == null) { + variableName = ""; + } + this.variableName = variableName; + + } catch (IOException ex) { + Logger.getLogger(DefineEditTextTag.class.getName()).log(Level.SEVERE, null, ex); + return false; + } + + return true; + } + + @Override + public void updateTextBounds() { + } + + @Override + public boolean alignText(TextAlign textAlign) { + return true; + } + + @Override + public boolean translateText(int diff) { + return true; + } + + @Override + public RECT getRect(Set added) { + return bounds; + } + + @Override + public int getCharacterId() { + return characterID; + } + + @Override + public void setCharacterId(int characterId) { + this.characterID = characterId; + } + + @Override + public void getNeededCharacters(Set needed) { + if (hasFont) { + needed.add(fontId); + } + } + + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + if (fontId == oldCharacterId) { + fontId = newCharacterId; + setModified(true); + return true; + } + return false; + } + + @Override + public boolean removeCharacter(int characterId) { + if (fontId == characterId) { + hasFont = false; + fontId = 0; + setModified(true); + return true; + } + return false; + } + + @Override + public int getUsedParameters() { + return 0; + } + + @Override + public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, Matrix transformation, ColorTransform colorTransform) { + render(false, image, transformation, colorTransform); + } + + @Override + public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, double zoom) { + // todo: implement + } + + @Override + public String toHtmlCanvas(double unitDivisor) { + return render(true, null, new Matrix(), new ColorTransform()); + } + + private String render(boolean canvas, SerializableImage image, Matrix transformation, ColorTransform colorTransform) { + if (border) { + // border is always black, fill color is always white? + RGB borderColor = new RGBA(Color.black); + RGB fillColor = new RGBA(Color.white); + if (!canvas) { + drawBorder(swf, image, borderColor, fillColor, getRect(), getTextMatrix(), transformation, colorTransform); + } else { + // TODO: draw border + } + } + if (hasText) { + DynamicTextModel textModel = new DynamicTextModel(); + List txt = getTextWithStyle(); + TextStyle lastStyle = null; + char prevChar = 0; + boolean lastWasWhiteSpace = false; + for (int i = 0; i < txt.size(); i++) { + CharacterWithStyle cs = txt.get(i); + char c = cs.character; + if (c != '\r' && c != '\n') { + // create new SameStyleTextRecord for all words and all diffrent style text parts + if (lastWasWhiteSpace && !Character.isWhitespace(c)) { + textModel.newWord(); + lastWasWhiteSpace = false; + } + if (cs.style != lastStyle) { + lastStyle = cs.style; + textModel.style = lastStyle; + textModel.newRecord(); + } + Character nextChar = null; + if (i + 1 < txt.size()) { + nextChar = txt.get(i + 1).character; + } + int advance; + FontTag font = lastStyle.font; + DynamicTextGlyphEntry ge = new DynamicTextGlyphEntry(); + ge.fontFace = lastStyle.fontFace; + ge.fontStyle = (lastStyle.bold ? Font.BOLD : 0) | (lastStyle.italic ? Font.ITALIC : 0); + ge.character = c; + ge.glyphIndex = font == null ? -1 : font.charToGlyph(c); + if (font != null && font.hasLayout()) { + int kerningAdjustment = 0; + if (nextChar != null) { + kerningAdjustment = font.getCharKerningAdjustment(c, nextChar); + kerningAdjustment /= font.getDivider(); + } + advance = (int) Math.round(Math.round((double) lastStyle.fontHeight * (font.getGlyphAdvance(ge.glyphIndex) + kerningAdjustment) / (font.getDivider() * 1024.0))); + } else { + String fontName = lastStyle.fontFace != null ? lastStyle.fontFace : FontTag.defaultFontName; + int fontStyle = font == null ? ge.fontStyle : font.getFontStyle(); + advance = (int) Math.round(SWF.unitDivisor * FontTag.getSystemFontAdvance(fontName, fontStyle, (int) (lastStyle.fontHeight / SWF.unitDivisor), c, nextChar)); + } + ge.glyphAdvance = advance; + textModel.addGlyph(c, ge); + if (Character.isWhitespace(c)) { + lastWasWhiteSpace = true; + } + } else { + if (multiline) { + textModel.newParagraph(); + } + } + prevChar = c; + } + + textModel.calculateTextWidths(); + List> lines; + if (multiline && wordWrap) { + lines = new ArrayList<>(); + for (Paragraph paragraph : textModel.paragraphs) { + List line = new ArrayList<>(); + int lineLength = 0; + for (Word word : paragraph.words) { + if (lineLength + word.width <= bounds.getWidth()) { + line.addAll(word.records); + lineLength += word.width; + } else { + lines.add(line); + line = new ArrayList<>(); + line.addAll(word.records); + lineLength = 0; + } + } + if (!line.isEmpty()) { + lines.add(line); + } + } + } else { + lines = new ArrayList<>(); + for (Paragraph paragraph : textModel.paragraphs) { + List line = new ArrayList<>(); + for (Word word : paragraph.words) { + for (SameStyleTextRecord tr : word.records) { + line.add(tr); + } + } + lines.add(line); + } + } + + // remove spaces after last word + for (List line : lines) { + boolean removed = true; + while (removed) { + removed = false; + while (line.size() > 0 && line.get(line.size() - 1).glyphEntries.isEmpty()) { + line.remove(line.size() - 1); + removed = true; + } + if (line.size() > 0) { + SameStyleTextRecord lastRecord = line.get(line.size() - 1); + while (lastRecord.glyphEntries.size() > 0 + && Character.isWhitespace(lastRecord.glyphEntries.get(lastRecord.glyphEntries.size() - 1).character)) { + lastRecord.glyphEntries.remove(lastRecord.glyphEntries.size() - 1); + removed = true; + } + } + } + } + + textModel.calculateTextWidths(); + + List allTextRecords = new ArrayList<>(); + int lastHeight = 0; + int yOffset = 0; + for (List line : lines) { + int width = 0; + int currentOffset = 0; + if (line.isEmpty()) { + currentOffset = lastHeight; + } else { + for (SameStyleTextRecord tr : line) { + width += tr.width; + int lineHeight = tr.style.fontHeight + tr.style.fontLeading; + lastHeight = lineHeight; + if (lineHeight > currentOffset) { + currentOffset = lineHeight; + } + } + } + yOffset += currentOffset; + int alignOffset = 0; + switch (align) { + case 0: // left + alignOffset = 0; + break; + case 1: // right + alignOffset = bounds.getWidth() - width; + break; + case 2: // center + alignOffset = (bounds.getWidth() - width) / 2; + break; + case 3: // justify + // todo; + break; + } + for (SameStyleTextRecord tr : line) { + tr.xOffset = alignOffset; + alignOffset += tr.width; + } + for (SameStyleTextRecord tr : line) { + TEXTRECORD tr2 = new TEXTRECORD(); + tr2.styleFlagsHasFont = fontId != 0; + tr2.fontId = fontId; + tr2.textHeight = tr.style.fontHeight; + if (tr.style.textColor != null) { + tr2.styleFlagsHasColor = true; + tr2.textColorA = tr.style.textColor; + } + // always add xOffset, because no xOffset and 0 xOffset is diffrent in text rendering + tr2.styleFlagsHasXOffset = true; + tr2.xOffset = tr.xOffset; + if (yOffset != 0) { + tr2.styleFlagsHasYOffset = true; + tr2.yOffset = yOffset; + } + tr2.glyphEntries = new ArrayList<>(tr.glyphEntries.size()); + for (GlyphCharacter ge : tr.glyphEntries) { + tr2.glyphEntries.add(ge.glyphEntry); + } + allTextRecords.add(tr2); + } + } + + if (canvas) { + return staticTextToHtmlCanvas(1, swf, allTextRecords, 2, getBounds(), getTextMatrix(), colorTransform); + } else { + staticTextToImage(swf, allTextRecords, 2, image, getTextMatrix(), transformation, colorTransform); + } + } + + return ""; + } + + @Override + public ExportRectangle calculateTextBounds() { + return null; + } + + @Override + public int getNumFrames() { + return 1; + } + + @Override + public boolean isSingleFrame() { + return true; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont2Tag.java index 064c14acb..bd6034f7e 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont2Tag.java @@ -97,114 +97,6 @@ public class DefineFont2Tag extends FontTag { @Conditional("fontFlagsHasLayout") public List fontKerningTable; - @Override - public boolean isSmall() { - return fontFlagsSmallText; - } - - @Override - public int getGlyphWidth(int glyphIndex) { - return glyphShapeTable.get(glyphIndex).getBounds().getWidth(); - } - - @Override - public RECT getGlyphBounds(int glyphIndex) { - if (fontFlagsHasLayout) { - return fontBoundsTable.get(glyphIndex); - } - return super.getGlyphBounds(glyphIndex); - } - - @Override - public double getGlyphAdvance(int glyphIndex) { - if (fontFlagsHasLayout) { - return fontAdvanceTable.get(glyphIndex); - } else { - return -1; - } - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - SWFOutputStream sos = new SWFOutputStream(baos, getVersion()); - try { - sos.writeUI16(fontId); - sos.writeUB(1, fontFlagsHasLayout ? 1 : 0); - sos.writeUB(1, fontFlagsShiftJIS ? 1 : 0); - sos.writeUB(1, fontFlagsSmallText ? 1 : 0); - sos.writeUB(1, fontFlagsANSI ? 1 : 0); - sos.writeUB(1, fontFlagsWideOffsets ? 1 : 0); - sos.writeUB(1, fontFlagsWideCodes ? 1 : 0); - sos.writeUB(1, fontFlagsItalic ? 1 : 0); - sos.writeUB(1, fontFlagsBold ? 1 : 0); - sos.writeLANGCODE(languageCode); - byte[] fontNameBytes = Utf8Helper.getBytes(fontName); - sos.writeUI8(fontNameBytes.length); - sos.write(fontNameBytes); - int numGlyphs = glyphShapeTable.size(); - sos.writeUI16(numGlyphs); - - List offsetTable = new ArrayList<>(); - ByteArrayOutputStream baosGlyphShapes = new ByteArrayOutputStream(); - - SWFOutputStream sos3 = new SWFOutputStream(baosGlyphShapes, getVersion()); - for (int i = 0; i < numGlyphs; i++) { - offsetTable.add((glyphShapeTable.size() + 1/*CodeTableOffset*/) * (fontFlagsWideOffsets ? 4 : 2) + sos3.getPos()); - sos3.writeSHAPE(glyphShapeTable.get(i), 1); - } - byte[] baGlyphShapes = baosGlyphShapes.toByteArray(); - for (Long offset : offsetTable) { - if (fontFlagsWideOffsets) { - sos.writeUI32(offset); - } else { - sos.writeUI16((int) (long) offset); - } - } - if (numGlyphs > 0) { - long offset = (glyphShapeTable.size() + 1/*CodeTableOffset*/) * (fontFlagsWideOffsets ? 4 : 2) + baGlyphShapes.length; - if (fontFlagsWideOffsets) { - sos.writeUI32(offset); - } else { - sos.writeUI16((int) offset); - } - sos.write(baGlyphShapes); - - for (int i = 0; i < numGlyphs; i++) { - if (fontFlagsWideCodes) { - sos.writeUI16(codeTable.get(i)); - } else { - sos.writeUI8(codeTable.get(i)); - } - } - } - if (fontFlagsHasLayout) { - sos.writeSI16(fontAscent); - sos.writeSI16(fontDescent); - sos.writeSI16(fontLeading); - for (int i = 0; i < numGlyphs; i++) { - sos.writeSI16(fontAdvanceTable.get(i)); - } - for (int i = 0; i < numGlyphs; i++) { - sos.writeRECT(fontBoundsTable.get(i)); - } - sos.writeUI16(fontKerningTable.size()); - for (int k = 0; k < fontKerningTable.size(); k++) { - sos.writeKERNINGRECORD(fontKerningTable.get(k), fontFlagsWideCodes); - } - } - - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - /** * Constructor * @@ -302,9 +194,112 @@ public class DefineFont2Tag extends FontTag { } } + /** + * Gets data bytes + * + * @return Bytes of data + */ @Override - public int getFontId() { - return fontId; + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + SWFOutputStream sos = new SWFOutputStream(baos, getVersion()); + try { + sos.writeUI16(fontId); + sos.writeUB(1, fontFlagsHasLayout ? 1 : 0); + sos.writeUB(1, fontFlagsShiftJIS ? 1 : 0); + sos.writeUB(1, fontFlagsSmallText ? 1 : 0); + sos.writeUB(1, fontFlagsANSI ? 1 : 0); + sos.writeUB(1, fontFlagsWideOffsets ? 1 : 0); + sos.writeUB(1, fontFlagsWideCodes ? 1 : 0); + sos.writeUB(1, fontFlagsItalic ? 1 : 0); + sos.writeUB(1, fontFlagsBold ? 1 : 0); + sos.writeLANGCODE(languageCode); + byte[] fontNameBytes = Utf8Helper.getBytes(fontName); + sos.writeUI8(fontNameBytes.length); + sos.write(fontNameBytes); + int numGlyphs = glyphShapeTable.size(); + sos.writeUI16(numGlyphs); + + List offsetTable = new ArrayList<>(); + ByteArrayOutputStream baosGlyphShapes = new ByteArrayOutputStream(); + + SWFOutputStream sos3 = new SWFOutputStream(baosGlyphShapes, getVersion()); + for (int i = 0; i < numGlyphs; i++) { + offsetTable.add((glyphShapeTable.size() + 1/*CodeTableOffset*/) * (fontFlagsWideOffsets ? 4 : 2) + sos3.getPos()); + sos3.writeSHAPE(glyphShapeTable.get(i), 1); + } + byte[] baGlyphShapes = baosGlyphShapes.toByteArray(); + for (Long offset : offsetTable) { + if (fontFlagsWideOffsets) { + sos.writeUI32(offset); + } else { + sos.writeUI16((int) (long) offset); + } + } + if (numGlyphs > 0) { + long offset = (glyphShapeTable.size() + 1/*CodeTableOffset*/) * (fontFlagsWideOffsets ? 4 : 2) + baGlyphShapes.length; + if (fontFlagsWideOffsets) { + sos.writeUI32(offset); + } else { + sos.writeUI16((int) offset); + } + sos.write(baGlyphShapes); + + for (int i = 0; i < numGlyphs; i++) { + if (fontFlagsWideCodes) { + sos.writeUI16(codeTable.get(i)); + } else { + sos.writeUI8(codeTable.get(i)); + } + } + } + if (fontFlagsHasLayout) { + sos.writeSI16(fontAscent); + sos.writeSI16(fontDescent); + sos.writeSI16(fontLeading); + for (int i = 0; i < numGlyphs; i++) { + sos.writeSI16(fontAdvanceTable.get(i)); + } + for (int i = 0; i < numGlyphs; i++) { + sos.writeRECT(fontBoundsTable.get(i)); + } + sos.writeUI16(fontKerningTable.size()); + for (int k = 0; k < fontKerningTable.size(); k++) { + sos.writeKERNINGRECORD(fontKerningTable.get(k), fontFlagsWideCodes); + } + } + + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + @Override + public boolean isSmall() { + return fontFlagsSmallText; + } + + @Override + public int getGlyphWidth(int glyphIndex) { + return glyphShapeTable.get(glyphIndex).getBounds().getWidth(); + } + + @Override + public RECT getGlyphBounds(int glyphIndex) { + if (fontFlagsHasLayout) { + return fontBoundsTable.get(glyphIndex); + } + return super.getGlyphBounds(glyphIndex); + } + + @Override + public double getGlyphAdvance(int glyphIndex) { + if (fontFlagsHasLayout) { + return fontAdvanceTable.get(glyphIndex); + } else { + return -1; + } } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont3Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont3Tag.java index 53123037a..b6d5c0008 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont3Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont3Tag.java @@ -101,35 +101,6 @@ public class DefineFont3Tag extends FontTag { @Conditional("fontFlagsHasLayout") public List fontKerningTable; - @Override - public boolean isSmall() { - return fontFlagsSmallText; - } - - @Override - public int getGlyphWidth(int glyphIndex) { - return glyphShapeTable.get(glyphIndex).getBounds().getWidth(); - } - - @Override - public double getGlyphAdvance(int glyphIndex) { - if (fontFlagsHasLayout && glyphIndex != -1) { - return fontAdvanceTable.get(glyphIndex); - } else { - return -1; - } - } - - @Override - public char glyphToChar(int glyphIndex) { - return (char) (int) codeTable.get(glyphIndex); - } - - @Override - public int charToGlyph(char c) { - return codeTable.indexOf((int) c); - } - /** * Constructor * @@ -312,8 +283,32 @@ public class DefineFont3Tag extends FontTag { } @Override - public int getFontId() { - return fontId; + public boolean isSmall() { + return fontFlagsSmallText; + } + + @Override + public int getGlyphWidth(int glyphIndex) { + return glyphShapeTable.get(glyphIndex).getBounds().getWidth(); + } + + @Override + public double getGlyphAdvance(int glyphIndex) { + if (fontFlagsHasLayout && glyphIndex != -1) { + return fontAdvanceTable.get(glyphIndex); + } else { + return -1; + } + } + + @Override + public char glyphToChar(int glyphIndex) { + return (char) (int) codeTable.get(glyphIndex); + } + + @Override + public int charToGlyph(char c) { + return codeTable.indexOf((int) c); } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont4Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont4Tag.java index 20c5eaee3..0dbccd3ea 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont4Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont4Tag.java @@ -55,16 +55,6 @@ public class DefineFont4Tag extends CharacterTag { public byte[] fontData; - @Override - public int getCharacterId() { - return fontID; - } - - @Override - public void setCharacterId(int characterId) { - this.fontID = characterId; - } - /** * Constructor * @@ -116,4 +106,14 @@ public class DefineFont4Tag extends CharacterTag { } return baos.toByteArray(); } + + @Override + public int getCharacterId() { + return fontID; + } + + @Override + public void setCharacterId(int characterId) { + this.fontID = characterId; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfo2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfo2Tag.java index ccd01aacd..b66b054a8 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfo2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfo2Tag.java @@ -68,38 +68,6 @@ public class DefineFontInfo2Tag extends Tag implements CharacterIdTag { @SWFType(BasicType.UI16) public List codeTable; - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(fontID); - byte[] fontNameBytes = Utf8Helper.getBytes(fontName); - sos.writeUI8(fontNameBytes.length); - sos.write(fontNameBytes); - sos.writeUB(2, reserved); - sos.writeUB(1, fontFlagsSmallText ? 1 : 0); - sos.writeUB(1, fontFlagsShiftJIS ? 1 : 0); - sos.writeUB(1, fontFlagsANSI ? 1 : 0); - sos.writeUB(1, fontFlagsItalic ? 1 : 0); - sos.writeUB(1, fontFlagsBold ? 1 : 0); - sos.writeUB(1, fontFlagsWideCodes ? 1 : 0); - sos.writeLANGCODE(languageCode); - for (int c : codeTable) { - sos.writeUI16(c); - } - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - /** * Constructor * @@ -148,6 +116,38 @@ public class DefineFontInfo2Tag extends Tag implements CharacterIdTag { } } + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(fontID); + byte[] fontNameBytes = Utf8Helper.getBytes(fontName); + sos.writeUI8(fontNameBytes.length); + sos.write(fontNameBytes); + sos.writeUB(2, reserved); + sos.writeUB(1, fontFlagsSmallText ? 1 : 0); + sos.writeUB(1, fontFlagsShiftJIS ? 1 : 0); + sos.writeUB(1, fontFlagsANSI ? 1 : 0); + sos.writeUB(1, fontFlagsItalic ? 1 : 0); + sos.writeUB(1, fontFlagsBold ? 1 : 0); + sos.writeUB(1, fontFlagsWideCodes ? 1 : 0); + sos.writeLANGCODE(languageCode); + for (int c : codeTable) { + sos.writeUI16(c); + } + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + @Override public int getCharacterId() { return fontID; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfoTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfoTag.java index f36524440..ff717ca80 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfoTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfoTag.java @@ -65,41 +65,6 @@ public class DefineFontInfoTag extends Tag implements CharacterIdTag { @SWFType(value = BasicType.UI8, alternateValue = BasicType.UI16, alternateCondition = "fontFlagsWideCodes") public List codeTable; - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(fontId); - byte[] fontNameBytes = Utf8Helper.getBytes(fontName); - sos.writeUI8(fontNameBytes.length); - sos.write(fontNameBytes); - sos.writeUB(2, reserved); - sos.writeUB(1, fontFlagsSmallText ? 1 : 0); - sos.writeUB(1, fontFlagsShiftJIS ? 1 : 0); - sos.writeUB(1, fontFlagsANSI ? 1 : 0); - sos.writeUB(1, fontFlagsItalic ? 1 : 0); - sos.writeUB(1, fontFlagsBold ? 1 : 0); - sos.writeUB(1, fontFlagsWideCodes ? 1 : 0); - for (int code : codeTable) { - if (fontFlagsWideCodes) { - sos.writeUI16(code); - } else { - sos.writeUI8(code); - } - } - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - /** * Constructor * @@ -149,6 +114,41 @@ public class DefineFontInfoTag extends Tag implements CharacterIdTag { } } + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(fontId); + byte[] fontNameBytes = Utf8Helper.getBytes(fontName); + sos.writeUI8(fontNameBytes.length); + sos.write(fontNameBytes); + sos.writeUB(2, reserved); + sos.writeUB(1, fontFlagsSmallText ? 1 : 0); + sos.writeUB(1, fontFlagsShiftJIS ? 1 : 0); + sos.writeUB(1, fontFlagsANSI ? 1 : 0); + sos.writeUB(1, fontFlagsItalic ? 1 : 0); + sos.writeUB(1, fontFlagsBold ? 1 : 0); + sos.writeUB(1, fontFlagsWideCodes ? 1 : 0); + for (int code : codeTable) { + if (fontFlagsWideCodes) { + sos.writeUI16(code); + } else { + sos.writeUI8(code); + } + } + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + @Override public int getCharacterId() { return fontId; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontTag.java index 392bbe879..4bfdad339 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontTag.java @@ -54,6 +54,80 @@ public class DefineFontTag extends FontTag { @Internal private DefineFontInfo2Tag fontInfo2Tag = null; + /** + * Constructor + * + * @param swf + */ + public DefineFontTag(SWF swf) { + super(swf, ID, NAME, null); + fontId = swf.getNextCharacterId(); + glyphShapeTable = new ArrayList<>(); + } + + /** + * Constructor + * + * @param sis + * @param data + * @throws IOException + */ + public DefineFontTag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + fontId = sis.readUI16("fontId"); + glyphShapeTable = new ArrayList<>(); + + if (sis.available() > 0) { + long pos = sis.getPos(); + int firstOffset = sis.readUI16("firstOffset"); + int nGlyphs = firstOffset / 2; + + long[] offsetTable = new long[nGlyphs]; + offsetTable[0] = firstOffset; + for (int i = 1; i < nGlyphs; i++) { + offsetTable[i] = sis.readUI16("offset"); + } + for (int i = 0; i < nGlyphs; i++) { + sis.seek(pos + offsetTable[i]); + glyphShapeTable.add(sis.readSHAPE(1, false, "shape")); + } + } + } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(fontId); + ByteArrayOutputStream baos2 = new ByteArrayOutputStream(); + List offsetTable = new ArrayList<>(); + SWFOutputStream sos2 = new SWFOutputStream(baos2, getVersion()); + for (SHAPE shape : glyphShapeTable) { + offsetTable.add(glyphShapeTable.size() * 2 + (int) sos2.getPos()); + sos2.writeSHAPE(shape, 1); + } + for (int offset : offsetTable) { + sos.writeUI16(offset); + } + sos.write(baos2.toByteArray()); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + @Override public boolean isSmall() { return false; @@ -112,85 +186,6 @@ public class DefineFontTag extends FontTag { } - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(fontId); - ByteArrayOutputStream baos2 = new ByteArrayOutputStream(); - List offsetTable = new ArrayList<>(); - SWFOutputStream sos2 = new SWFOutputStream(baos2, getVersion()); - for (SHAPE shape : glyphShapeTable) { - offsetTable.add(glyphShapeTable.size() * 2 + (int) sos2.getPos()); - sos2.writeSHAPE(shape, 1); - } - for (int offset : offsetTable) { - sos.writeUI16(offset); - } - sos.write(baos2.toByteArray()); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - - /** - * Constructor - * - * @param swf - */ - public DefineFontTag(SWF swf) { - super(swf, ID, NAME, null); - fontId = swf.getNextCharacterId(); - glyphShapeTable = new ArrayList<>(); - } - - /** - * Constructor - * - * @param sis - * @param data - * @throws IOException - */ - public DefineFontTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, NAME, data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - fontId = sis.readUI16("fontId"); - glyphShapeTable = new ArrayList<>(); - - if (sis.available() > 0) { - long pos = sis.getPos(); - int firstOffset = sis.readUI16("firstOffset"); - int nGlyphs = firstOffset / 2; - - long[] offsetTable = new long[nGlyphs]; - offsetTable[0] = firstOffset; - for (int i = 1; i < nGlyphs; i++) { - offsetTable[i] = sis.readUI16("offset"); - } - for (int i = 0; i < nGlyphs; i++) { - sis.seek(pos + offsetTable[i]); - glyphShapeTable.add(sis.readSHAPE(1, false, "shape")); - } - } - } - - @Override - public int getFontId() { - return fontId; - } - @Override public List getGlyphShapeTable() { return glyphShapeTable; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java index 76965a9bf..835ce8491 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java @@ -56,40 +56,6 @@ public class DefineMorphShape2Tag extends MorphShapeTag { public boolean usesScalingStrokes; - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(characterId); - sos.writeRECT(startBounds); - sos.writeRECT(endBounds); - sos.writeRECT(startEdgeBounds); - sos.writeRECT(endEdgeBounds); - sos.writeUB(6, reserved); - sos.writeUB(1, usesNonScalingStrokes ? 1 : 0); - sos.writeUB(1, usesScalingStrokes ? 1 : 0); - ByteArrayOutputStream baos2 = new ByteArrayOutputStream(); - SWFOutputStream sos2 = new SWFOutputStream(baos2, getVersion()); - sos2.writeMORPHFILLSTYLEARRAY(morphFillStyles, 2); - sos2.writeMORPHLINESTYLEARRAY(morphLineStyles, 2); - sos2.writeSHAPE(startEdges, 2); - byte[] ba2 = baos2.toByteArray(); - sos.writeUI32(ba2.length); - sos.write(ba2); - sos.writeSHAPE(endEdges, 2); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - /** * Constructor * @@ -139,6 +105,40 @@ public class DefineMorphShape2Tag extends MorphShapeTag { endEdges = sis.readSHAPE(2, true, "endEdges"); } + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(characterId); + sos.writeRECT(startBounds); + sos.writeRECT(endBounds); + sos.writeRECT(startEdgeBounds); + sos.writeRECT(endEdgeBounds); + sos.writeUB(6, reserved); + sos.writeUB(1, usesNonScalingStrokes ? 1 : 0); + sos.writeUB(1, usesScalingStrokes ? 1 : 0); + ByteArrayOutputStream baos2 = new ByteArrayOutputStream(); + SWFOutputStream sos2 = new SWFOutputStream(baos2, getVersion()); + sos2.writeMORPHFILLSTYLEARRAY(morphFillStyles, 2); + sos2.writeMORPHLINESTYLEARRAY(morphLineStyles, 2); + sos2.writeSHAPE(startEdges, 2); + byte[] ba2 = baos2.toByteArray(); + sos.writeUI32(ba2.length); + sos.write(ba2); + sos.writeSHAPE(endEdges, 2); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + @Override public int getShapeNum() { return 2; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShapeTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShapeTag.java index 53c1fe614..d4945a3ba 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShapeTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShapeTag.java @@ -41,35 +41,6 @@ public class DefineMorphShapeTag extends MorphShapeTag { public static final String NAME = "DefineMorphShape"; - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(characterId); - sos.writeRECT(startBounds); - sos.writeRECT(endBounds); - ByteArrayOutputStream baos2 = new ByteArrayOutputStream(); - SWFOutputStream sos2 = new SWFOutputStream(baos2, getVersion()); - sos2.writeMORPHFILLSTYLEARRAY(morphFillStyles, 1); - sos2.writeMORPHLINESTYLEARRAY(morphLineStyles, 1); - sos2.writeSHAPE(startEdges, 1); - byte[] ba2 = baos2.toByteArray(); - sos.writeUI32(ba2.length); - sos.write(ba2); - sos.writeSHAPE(endEdges, 1); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - /** * Constructor * @@ -112,6 +83,35 @@ public class DefineMorphShapeTag extends MorphShapeTag { endEdges = sis.readSHAPE(1, true, "endEdges"); } + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(characterId); + sos.writeRECT(startBounds); + sos.writeRECT(endBounds); + ByteArrayOutputStream baos2 = new ByteArrayOutputStream(); + SWFOutputStream sos2 = new SWFOutputStream(baos2, getVersion()); + sos2.writeMORPHFILLSTYLEARRAY(morphFillStyles, 1); + sos2.writeMORPHLINESTYLEARRAY(morphLineStyles, 1); + sos2.writeSHAPE(startEdges, 1); + byte[] ba2 = baos2.toByteArray(); + sos.writeUI32(ba2.length); + sos.write(ba2); + sos.writeSHAPE(endEdges, 1); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + @Override public int getShapeNum() { return 1; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSceneAndFrameLabelDataTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSceneAndFrameLabelDataTag.java index e66b8b5d5..70adcbd83 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSceneAndFrameLabelDataTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSceneAndFrameLabelDataTag.java @@ -51,35 +51,6 @@ public class DefineSceneAndFrameLabelDataTag extends Tag { @SWFArray(countField = "frameLabelCount") public String[] frameNames; - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - int sceneCount = sceneOffsets.length; - sos.writeEncodedU32(sceneCount); - for (int i = 0; i < sceneCount; i++) { - sos.writeEncodedU32(sceneOffsets[i]); - sos.writeString(sceneNames[i]); - } - int frameLabelCount = frameNums.length; - sos.writeEncodedU32(frameLabelCount); - for (int i = 0; i < frameLabelCount; i++) { - sos.writeEncodedU32(frameNums[i]); - sos.writeString(frameNames[i]); - } - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - /** * Constructor * @@ -123,4 +94,33 @@ public class DefineSceneAndFrameLabelDataTag extends Tag { } } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + int sceneCount = sceneOffsets.length; + sos.writeEncodedU32(sceneCount); + for (int i = 0; i < sceneCount; i++) { + sos.writeEncodedU32(sceneOffsets[i]); + sos.writeString(sceneNames[i]); + } + int frameLabelCount = frameNums.length; + sos.writeEncodedU32(frameLabelCount); + for (int i = 0; i < frameLabelCount; i++) { + sos.writeEncodedU32(frameNums[i]); + sos.writeString(frameNames[i]); + } + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSoundTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSoundTag.java index 3d61c0f76..61f49485d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSoundTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSoundTag.java @@ -69,41 +69,6 @@ public class DefineSoundTag extends CharacterTag implements SoundTag { public ByteArrayRange soundData; - @Override - public int getCharacterId() { - return soundId; - } - - @Override - public void setCharacterId(int characterId) { - this.soundId = characterId; - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(soundId); - sos.writeUB(4, soundFormat); - sos.writeUB(2, soundRate); - sos.writeUB(1, soundSize ? 1 : 0); - sos.writeUB(1, soundType ? 1 : 0); - sos.writeUI32(soundSampleCount); - sos.write(soundData); - - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - /** * Constructor * @@ -138,6 +103,41 @@ public class DefineSoundTag extends CharacterTag implements SoundTag { soundData = sis.readByteRangeEx(sis.available(), "soundData"); } + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(soundId); + sos.writeUB(4, soundFormat); + sos.writeUB(2, soundRate); + sos.writeUB(1, soundSize ? 1 : 0); + sos.writeUB(1, soundType ? 1 : 0); + sos.writeUI32(soundSampleCount); + sos.write(soundData); + + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + @Override + public int getCharacterId() { + return soundId; + } + + @Override + public void setCharacterId(int characterId) { + this.soundId = characterId; + } + @Override public String getExportFormat() { if (soundFormat == SoundFormat.FORMAT_MP3) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java index 64d82dd46..c68b750dd 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java @@ -89,6 +89,72 @@ public class DefineSpriteTag extends CharacterTag implements DrawableTag, Timeli private static final Cache rectCache = Cache.getInstance(true, true, "rect_sprite"); + /** + * Constructor + * + * @param swf + */ + public DefineSpriteTag(SWF swf) { + super(swf, ID, NAME, null); + spriteId = swf.getNextCharacterId(); + subTags = new ArrayList<>(); + } + + /** + * Constructor + * + * @param sis + * @param data + * @param level + * @param parallel + * @param skipUnusualTags + * @throws IOException + * @throws java.lang.InterruptedException + */ + public DefineSpriteTag(SWFInputStream sis, int level, ByteArrayRange data, boolean parallel, boolean skipUnusualTags) throws IOException, InterruptedException { + super(sis.getSwf(), ID, NAME, data); + readData(sis, data, level, parallel, skipUnusualTags, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException, InterruptedException { + spriteId = sis.readUI16("spriteId"); + frameCount = sis.readUI16("frameCount"); + List subTags = sis.readTagList(this, level + 1, parallel, skipUnusualTags, true, lazy); + if (subTags.size() > 0 && subTags.get(subTags.size() - 1).getId() == EndTag.ID) { + hasEndTag = true; + subTags.remove(subTags.size() - 1); + } + this.subTags = subTags; + } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + if (Configuration.debugCopy.get()) { + os = new CopyOutputStream(os, new ByteArrayInputStream(getOriginalData())); + } + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(spriteId); + sos.writeUI16(frameCount); + sos.writeTags(subTags); + if (hasEndTag) { + sos.writeUI16(0); + } + sos.close(); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + @Override public Timeline getTimeline() { if (timeline == null) { @@ -210,72 +276,6 @@ public class DefineSpriteTag extends CharacterTag implements DrawableTag, Timeli return ret; } - /** - * Constructor - * - * @param swf - */ - public DefineSpriteTag(SWF swf) { - super(swf, ID, NAME, null); - spriteId = swf.getNextCharacterId(); - subTags = new ArrayList<>(); - } - - /** - * Constructor - * - * @param sis - * @param data - * @param level - * @param parallel - * @param skipUnusualTags - * @throws IOException - * @throws java.lang.InterruptedException - */ - public DefineSpriteTag(SWFInputStream sis, int level, ByteArrayRange data, boolean parallel, boolean skipUnusualTags) throws IOException, InterruptedException { - super(sis.getSwf(), ID, NAME, data); - readData(sis, data, level, parallel, skipUnusualTags, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException, InterruptedException { - spriteId = sis.readUI16("spriteId"); - frameCount = sis.readUI16("frameCount"); - List subTags = sis.readTagList(this, level + 1, parallel, skipUnusualTags, true, lazy); - if (subTags.size() > 0 && subTags.get(subTags.size() - 1).getId() == EndTag.ID) { - hasEndTag = true; - subTags.remove(subTags.size() - 1); - } - this.subTags = subTags; - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - if (Configuration.debugCopy.get()) { - os = new CopyOutputStream(os, new ByteArrayInputStream(getOriginalData())); - } - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(spriteId); - sos.writeUI16(frameCount); - sos.writeTags(subTags); - if (hasEndTag) { - sos.writeUI16(0); - } - sos.close(); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - public List getSubTags() { return subTags; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/FontTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/FontTag.java index 41e2c4a1b..91333d03a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/FontTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/FontTag.java @@ -57,8 +57,6 @@ public abstract class FontTag extends CharacterTag implements AloneTag, Drawable super(swf, id, name, data); } - public abstract int getFontId(); - public abstract List getGlyphShapeTable(); public abstract void addCharacter(char character, Font font); @@ -131,6 +129,10 @@ public abstract class FontTag extends CharacterTag implements AloneTag, Drawable reload(); } + public int getFontId() { + return getCharacterId(); + } + public boolean hasLayout() { return false; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ImageTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ImageTag.java index 487038dbd..ba4374f34 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ImageTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ImageTag.java @@ -22,6 +22,7 @@ import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; import com.jpexs.decompiler.flash.exporters.shape.BitmapExporter; import com.jpexs.decompiler.flash.exporters.shape.CanvasShapeExporter; import com.jpexs.decompiler.flash.exporters.shape.SVGShapeExporter; +import com.jpexs.decompiler.flash.tags.enums.ImageFormat; import com.jpexs.decompiler.flash.types.BasicType; import com.jpexs.decompiler.flash.types.ColorTransform; import com.jpexs.decompiler.flash.types.FILLSTYLE; @@ -65,34 +66,34 @@ public abstract class ImageTag extends CharacterTag implements DrawableTag { public abstract void setImage(byte[] data) throws IOException; - public abstract String getImageFormat(); + public abstract ImageFormat getImageFormat(); public boolean importSupported() { return true; } - public static String getImageFormat(byte[] data) { + public static ImageFormat getImageFormat(byte[] data) { return getImageFormat(new ByteArrayRange(data)); } - public static String getImageFormat(ByteArrayRange data) { + public static ImageFormat getImageFormat(ByteArrayRange data) { if (hasErrorHeader(data)) { - return "jpg"; + return ImageFormat.JPEG; } if (data.getLength() > 2 && ((data.get(0) & 0xff) == 0xff) && ((data.get(1) & 0xff) == 0xd8)) { - return "jpg"; + return ImageFormat.JPEG; } if (data.getLength() > 6 && ((data.get(0) & 0xff) == 0x47) && ((data.get(1) & 0xff) == 0x49) && ((data.get(2) & 0xff) == 0x46) && ((data.get(3) & 0xff) == 0x38) && ((data.get(4) & 0xff) == 0x39) && ((data.get(5) & 0xff) == 0x61)) { - return "gif"; + return ImageFormat.GIF; } if (data.getLength() > 8 && ((data.get(0) & 0xff) == 0x89) && ((data.get(1) & 0xff) == 0x50) && ((data.get(2) & 0xff) == 0x4e) && ((data.get(3) & 0xff) == 0x47) && ((data.get(4) & 0xff) == 0x0d) && ((data.get(5) & 0xff) == 0x0a) && ((data.get(6) & 0xff) == 0x1a) && ((data.get(7) & 0xff) == 0x0a)) { - return "png"; + return ImageFormat.PNG; } - return "unk"; + return ImageFormat.UNKNOWN; } public static boolean hasErrorHeader(byte[] data) { @@ -128,6 +129,24 @@ public abstract class ImageTag extends CharacterTag implements DrawableTag { return RGBA.toInt(r, g, b, a); } + public static void divideAlpha(int[] pixels) { + for (int i = 0; i < pixels.length; i++) { + pixels[i] = divideAlpha(pixels[i]) & 0xffffff; + } + } + + protected static int divideAlpha(int value) { + int a = (value >> 24) & 0xFF; + int r = (value >> 16) & 0xFF; + int g = (value >> 8) & 0xFF; + int b = value & 0xFF; + float multiplier = a / 255.0f; + r = max255(r * multiplier); + g = max255(g * multiplier); + b = max255(b * multiplier); + return RGBA.toInt(r, g, b, a); + } + private SHAPEWITHSTYLE getShape() { RECT rect = getRect(); return getShape(rect, false); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/StaticTextTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/StaticTextTag.java index 896245017..29763508e 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/StaticTextTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/StaticTextTag.java @@ -78,6 +78,61 @@ public abstract class StaticTextTag extends TextTag { super(swf, id, name, data); } + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + characterID = sis.readUI16("characterID"); + textBounds = sis.readRECT("textBounds"); + textMatrix = sis.readMatrix("textMatrix"); + glyphBits = sis.readUI8("glyphBits"); + advanceBits = sis.readUI8("advanceBits"); + textRecords = new ArrayList<>(); + TEXTRECORD tr; + while ((tr = sis.readTEXTRECORD(getTextNum(), glyphBits, advanceBits, "record")) != null) { + textRecords.add(tr); + } + } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(characterID); + sos.writeRECT(textBounds); + sos.writeMatrix(textMatrix); + + int glyphBits = 0; + int advanceBits = 0; + for (TEXTRECORD tr : textRecords) { + for (GLYPHENTRY ge : tr.glyphEntries) { + glyphBits = SWFOutputStream.enlargeBitCountU(glyphBits, ge.glyphIndex); + advanceBits = SWFOutputStream.enlargeBitCountS(advanceBits, ge.glyphAdvance); + } + } + + if (Configuration.debugCopy.get()) { + glyphBits = Math.max(glyphBits, this.glyphBits); + advanceBits = Math.max(advanceBits, this.advanceBits); + } + + sos.writeUI8(glyphBits); + sos.writeUI8(advanceBits); + for (TEXTRECORD tr : textRecords) { + sos.writeTEXTRECORD(tr, getTextNum(), glyphBits, advanceBits); + } + sos.writeUI8(0); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + @Override public RECT getBounds() { return textBounds; @@ -522,61 +577,6 @@ public abstract class StaticTextTag extends TextTag { return true; } - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(characterID); - sos.writeRECT(textBounds); - sos.writeMatrix(textMatrix); - - int glyphBits = 0; - int advanceBits = 0; - for (TEXTRECORD tr : textRecords) { - for (GLYPHENTRY ge : tr.glyphEntries) { - glyphBits = SWFOutputStream.enlargeBitCountU(glyphBits, ge.glyphIndex); - advanceBits = SWFOutputStream.enlargeBitCountS(advanceBits, ge.glyphAdvance); - } - } - - if (Configuration.debugCopy.get()) { - glyphBits = Math.max(glyphBits, this.glyphBits); - advanceBits = Math.max(advanceBits, this.advanceBits); - } - - sos.writeUI8(glyphBits); - sos.writeUI8(advanceBits); - for (TEXTRECORD tr : textRecords) { - sos.writeTEXTRECORD(tr, getTextNum(), glyphBits, advanceBits); - } - sos.writeUI8(0); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - characterID = sis.readUI16("characterID"); - textBounds = sis.readRECT("textBounds"); - textMatrix = sis.readMatrix("textMatrix"); - glyphBits = sis.readUI8("glyphBits"); - advanceBits = sis.readUI8("advanceBits"); - textRecords = new ArrayList<>(); - TEXTRECORD tr; - while ((tr = sis.readTEXTRECORD(getTextNum(), glyphBits, advanceBits, "record")) != null) { - textRecords.add(tr); - } - } - @Override public void getNeededCharacters(Set needed) { for (TEXTRECORD tr : textRecords) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/enums/ImageFormat.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/enums/ImageFormat.java new file mode 100644 index 000000000..39c6a7c58 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/enums/ImageFormat.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags.enums; + +/** + * + * @author JPEXS + */ +public enum ImageFormat { + + UNKNOWN, JPEG, GIF, PNG, BMP +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineCompactedFont.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineCompactedFont.java index 402bb91ab..33ae27a56 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineCompactedFont.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineCompactedFont.java @@ -154,11 +154,6 @@ public final class DefineCompactedFont extends FontTag { this.fontId = characterId; } - @Override - public int getFontId() { - return fontId; - } - @Override public List getGlyphShapeTable() { return shapeCache; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java index f87eafbf2..b4f8d020e 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java @@ -66,6 +66,7 @@ import com.jpexs.decompiler.flash.tags.base.ShapeTag; import com.jpexs.decompiler.flash.tags.base.SoundStreamHeadTypeTag; import com.jpexs.decompiler.flash.tags.base.SoundTag; import com.jpexs.decompiler.flash.tags.base.TextTag; +import com.jpexs.decompiler.flash.tags.enums.ImageFormat; import com.jpexs.decompiler.flash.tags.font.CharacterRanges; import com.jpexs.decompiler.flash.types.BUTTONCONDACTION; import com.jpexs.decompiler.flash.types.BUTTONRECORD; @@ -1357,17 +1358,17 @@ public class XFLConverter { SerializableImage image = imageTag.getImage(); // do not store the image in cache during xfl conversion imageTag.clearCache(); - String format = imageTag.getImageFormat(); - ImageHelper.write(image.getBufferedImage(), format.toUpperCase(), baos); + ImageFormat format = imageTag.getImageFormat(); + ImageHelper.write(image.getBufferedImage(), format, baos); String symbolFile = "bitmap" + symbol.getCharacterId() + "." + imageTag.getImageFormat(); files.put(symbolFile, baos.toByteArray()); String mediaLinkStr = ". - -menu.file = File -menu.file.open = Open... -menu.file.save = Save -menu.file.saveas = Save as... -menu.file.export.fla = Export to FLA -menu.file.export.all = Export all parts -menu.file.export.selection = Export selection -menu.file.exit = Exit - -menu.tools = Tools -menu.tools.searchas = Search All ActionScript... -menu.tools.proxy = Proxy -menu.tools.deobfuscation = Deobfuscation -menu.tools.deobfuscation.pcode = P-code deobfuscation... -menu.tools.deobfuscation.globalrename = Globally rename identifier -menu.tools.deobfuscation.renameinvalid = Rename invalid identifiers -menu.tools.gotodocumentclass = Go to document class - -menu.settings = Settings -menu.settings.autodeobfuscation = Automatic deobfuscation -menu.settings.internalflashviewer = Use own Flash viewer -menu.settings.parallelspeedup = Parallel SpeedUp -menu.settings.disabledecompilation = Disable decompilation (Disassemble only) -menu.settings.addtocontextmenu = Add FFDec to SWF files context menu -menu.settings.language = Change language -menu.settings.cacheOnDisk = Use caching on disk -menu.settings.gotoMainClassOnStartup = Highlight document class on startup - -menu.help = Help -menu.help.checkupdates = Check for updates... -menu.help.helpus = Help us! -menu.help.homepage = Visit homepage -menu.help.about = About... - -contextmenu.remove = Remove - -button.save = Save -button.edit = Edit -button.cancel = Cancel -button.replace = Replace... - -notavailonthisplatform = Preview of this object is not available on this platform (Windows only). - -swfpreview = SWF preview -swfpreview.internal = SWF preview (Internal viewer) - -parameters = Parameters - -rename.enternew = Enter new name: - -rename.finished.identifier = Identifier renamed. -rename.finished.multiname = %count% multiname(s) renamed. - -node.texts = texts -node.images = images -node.movies = movies -node.sounds = sounds -node.binaryData = binaryData -node.fonts = fonts -node.sprites = sprites -node.shapes = shapes -node.morphshapes = morphshapes -node.buttons = buttons -node.frames = frames -node.scripts = scripts - -message.warning = Warning -message.confirm.experimental = Following procedure can damage SWF file which can be then unplayable.\r\nUSE IT ON YOUR OWN RISK. Do you want to continue? -message.confirm.parallel = Parallelism can speed up loading and decompilation but uses more memory. -message.confirm.on = Do you want to turn this ON? -message.confirm.off = Do you want to turn this OFF? -message.confirm = Confirm - -message.confirm.autodeobfuscate = Automatic deobfuscation is a way to decompile obfuscated code.\r\nDeobfuscation leads to slower decompilation and some of the dead code may be eliminated.\r\nIf the code is not obfuscated, it's better to turn autodeobfuscation off. - -message.parallel = Parallelism -message.trait.saved = Trait successfully saved - -message.constant.new.string = String "%value%" is not present in constants table. Do you want to add it? -message.constant.new.string.title = Add String -message.constant.new.integer = Integer value "%value%" is not present in constants table. Do you want to add it? -message.constant.new.integer.title = Add Integer -message.constant.new.unsignedinteger = Unsigned integer value "%value%" is not present in constants table. Do you want to add it? -message.constant.new.unsignedinteger.title = Add Unsigned integer -message.constant.new.double = Double value "%value%" is not present in constants table. Do you want to add it? -message.constant.new.double.title = Add Double - -work.buffering = Buffering -work.waitingfordissasembly = Waiting for disassembly -work.gettinghilights = Getting highlights -work.disassembling = Disassembling -work.exporting = Exporting -work.searching = Searching -work.renaming = Renaming -work.exporting.fla = Exporting FLA -work.renaming.identifiers = Renaming identifiers -work.deobfuscating = Deobfuscating -work.decompiling = Decompiling -work.gettingvariables = Getting variables -work.reading.swf = Reading SWF -work.creatingwindow = Creating window -work.buildingscripttree = Building script tree - -work.deobfuscating.complete = Deobfuscation complete - -message.search.notfound = String "%searchtext%" not found. -message.search.notfound.title = Not found - -message.rename.notfound.multiname = No multiname found under cursor -message.rename.notfound.identifier = No identifier found under cursor -message.rename.notfound.title = Not found -message.rename.renamed = Identifiers renamed: %count% - -filter.images = Images (*.jpg,*.gif,*.png,*.bmp) -filter.fla = %version% Document (*.fla) -filter.xfl = %version% Uncompressed Document (*.xfl) -filter.swf = SWF files (*.swf) - -error = Error -error.image.invalid = Invalid image. - -error.text.invalid = Invalid text: %text% on line %line% -error.file.save = Cannot save file -error.file.write = Cannot write to the file -error.export = Error during export - -export.select.directory = Select directory to export -export.finishedin = Exported in %time% - -update.check.title = Update check -update.check.nonewversion = No new version available. - -message.helpus = Please visit\r\n%url%\r\nfor details. -message.homepage = Visit homepage at: \r\n%url% - -proxy = Proxy -proxy.start = Start proxy -proxy.stop = Stop proxy -proxy.show = Show proxy -exit = Exit - -panel.disassembled = P-code source -panel.decompiled = ActionScript source - -search.info = Search for "%text%": -search.script = Script - -constants = Constants -traits = Traits - -pleasewait = Please wait - -abc.detail.methodtrait = Method/Getter/Setter Trait -abc.detail.unsupported = - -abc.detail.slotconsttrait = Slot/Const Trait -abc.detail.traitname = Name: - -abc.detail.body.params.maxstack = Max stack: -abc.detail.body.params.localregcount = Local registers count: -abc.detail.body.params.minscope = Minimum scope depth: -abc.detail.body.params.maxscope = Maximum scope depth: -abc.detail.body.params.autofill = Auto fill on code save (GLOBAL SETTING) -abc.detail.body.params.autofill.experimental = ...EXPERIMENTAL - -abc.detail.methodinfo.methodindex = Method Index: -abc.detail.methodinfo.parameters = Parameters: -abc.detail.methodinfo.returnvalue = Return value type: - -error.methodinfo.params = MethodInfo Params Error -error.methodinfo.returnvalue = MethodInfo Return value type Error - -abc.detail.methodinfo = MethodInfo -abc.detail.body.code = MethodBody Code -abc.detail.body.params = MethodBody params - -abc.detail.slotconst.typevalue = Type and Value: - -error.slotconst.typevalue = SlotConst type value Error - -message.autofill.failed = Cannot get code stats for automatic body params.\r\nUncheck autofill to avoid this message. -info.selecttrait = Select class and click a trait in Actionscript source to edit it. - -button.viewgraph = View Graph -button.viewhex = View Hex - -abc.traitslist.instanceinitializer = instance initializer -abc.traitslist.classinitializer = class initializer - -action.edit.experimental = (Experimental) - -message.action.saved = Code successfully saved - -error.action.save = %error% on line %line% - -message.confirm.remove = Are you sure you want to remove %item%\n and all objects which depend on it? - -#after version 1.6.5u1: - -button.ok = OK -button.cancel = Cancel - -font.name = Font name: -font.isbold = Is bold: -font.isitalic = Is italic: -font.ascent = Ascent: -font.descent = Descent: -font.leading = Leading: -font.characters = Characters: -font.characters.add = Add characters: -value.unknown = ? - -yes = yes -no = no - -errors.present = There are ERRORS in the log. Click to view. -errors.none = There are no errors in the log. - -#after version 1.6.6: - -dialog.message.title = Message -dialog.select.title = Select an Option - -button.yes = Yes -button.no = No - -FileChooser.openButtonText = Open -FileChooser.openButtonToolTipText = Open -FileChooser.lookInLabelText = Look in: -FileChooser.acceptAllFileFilterText = All Files -FileChooser.filesOfTypeLabelText = Files of type: -FileChooser.fileNameLabelText = File name: -FileChooser.listViewButtonToolTipText = List -FileChooser.listViewButtonAccessibleName = List -FileChooser.detailsViewButtonToolTipText = Details -FileChooser.detailsViewButtonAccessibleName = Details -FileChooser.upFolderToolTipText = Up One Level -FileChooser.upFolderAccessibleName = Up One Level -FileChooser.homeFolderToolTipText = Home -FileChooser.homeFolderAccessibleName = Home -FileChooser.fileNameHeaderText = Name -FileChooser.fileSizeHeaderText = Size -FileChooser.fileTypeHeaderText = Type -FileChooser.fileDateHeaderText = Date -FileChooser.fileAttrHeaderText = Attributes -FileChooser.openDialogTitleText = Open -FileChooser.directoryDescriptionText = Directory -FileChooser.directoryOpenButtonText = Open -FileChooser.directoryOpenButtonToolTipText = Open selected directory -FileChooser.fileDescriptionText = Generic File -FileChooser.helpButtonText = Help -FileChooser.helpButtonToolTipText = FileChooser help -FileChooser.newFolderAccessibleName = New Folder -FileChooser.newFolderErrorText = Error creating new folder -FileChooser.newFolderToolTipText = Create New Folder -FileChooser.other.newFolder = NewFolder -FileChooser.other.newFolder.subsequent = NewFolder.{0} -FileChooser.win32.newFolder = New Folder -FileChooser.win32.newFolder.subsequent = New Folder ({0}) -FileChooser.saveButtonText = Save -FileChooser.saveButtonToolTipText = Save selected file -FileChooser.saveDialogTitleText = Save -FileChooser.saveInLabelText = Save in: -FileChooser.updateButtonText = Update -FileChooser.updateButtonToolTipText = Update directory listing - -#after version 1.6.6u2: - -FileChooser.detailsViewActionLabel.textAndMnemonic = Details -FileChooser.detailsViewButtonToolTip.textAndMnemonic = Details -FileChooser.fileAttrHeader.textAndMnemonic = Attributes -FileChooser.fileDateHeader.textAndMnemonic = Modified -FileChooser.fileNameHeader.textAndMnemonic = Name -FileChooser.fileNameLabel.textAndMnemonic = File name: -FileChooser.fileSizeHeader.textAndMnemonic = Size -FileChooser.fileTypeHeader.textAndMnemonic = Type -FileChooser.filesOfTypeLabel.textAndMnemonic = Files of type: -FileChooser.folderNameLabel.textAndMnemonic = Folder name: -FileChooser.homeFolderToolTip.textAndMnemonic = Home -FileChooser.listViewActionLabel.textAndMnemonic = List -FileChooser.listViewButtonToolTip.textAndMnemonic = List -FileChooser.lookInLabel.textAndMnemonic = Look in: -FileChooser.newFolderActionLabel.textAndMnemonic = New Folder -FileChooser.newFolderToolTip.textAndMnemonic = Create New Folder -FileChooser.refreshActionLabel.textAndMnemonic = Refresh -FileChooser.saveInLabel.textAndMnemonic = Save in: -FileChooser.upFolderToolTip.textAndMnemonic = Up One Level -FileChooser.viewMenuButtonAccessibleName = View Menu -FileChooser.viewMenuButtonToolTipText = View Menu -FileChooser.viewMenuLabel.textAndMnemonic = View -FileChooser.newFolderActionLabelText = New Folder -FileChooser.listViewActionLabelText = List -FileChooser.detailsViewActionLabelText = Details -FileChooser.refreshActionLabelText = Refresh -FileChooser.sortMenuLabelText = Arrange Icons By -FileChooser.viewMenuLabelText = View -FileChooser.fileSizeKiloBytes = {0} KB -FileChooser.fileSizeMegaBytes = {0} MB -FileChooser.fileSizeGigaBytes = {0} GB -FileChooser.folderNameLabelText = Folder name: - -error.occured = Error occurred: %error% -button.abort = Abort -button.retry = Retry -button.ignore = Ignore - -font.source = Source Font: - -#after version 1.6.7: - -menu.export = Export -menu.general = General -menu.language = Language - -startup.welcometo = Welcome to -startup.selectopen = Click Open icon on the top panel or drag SWF file to this window to start. - -error.font.nocharacter = Selected source font does not contain character "%char%". - -warning.initializers = Static fields and consts are often initialized in initializers.\nEditing value here is usually not enough! - -#after version 1.7.0u1: - -menu.tools.searchmemory = Search SWFs in memory -menu.file.reload = Reload -message.confirm.reload = This action cancels all unsaved changes and reloads the SWF file again.\nDo you want to continue? - -dialog.selectbkcolor.title = Select background color for SWF display -button.selectbkcolor.hint = Select background color - -ColorChooser.okText = OK -ColorChooser.cancelText = Cancel -ColorChooser.resetText = Reset -ColorChooser.previewText = Preview -ColorChooser.swatchesNameText = Swatches -ColorChooser.swatchesRecentText = Recent: -ColorChooser.sampleText=Sample Text Sample Text - -#after version 1.7.1: - -preview.play = Play -preview.pause = Pause -preview.stop = Stop - -message.confirm.removemultiple = Are you sure you want to remove %count% items\n and all objects which depend on it? - -menu.tools.searchcache = Search browsers cache - -#after version 1.7.2u2 - -error.trait.exists = Trait with name "%name%" already exists. -button.addtrait = Add trait -button.font.embed = Embed... -button.yes.all = Yes to all -button.no.all = No to all -message.font.add.exists = Character %char% already exists in the font tag.\nDo you want to replace it? - -filter.gfx = ScaleForm GFx files (*.gfx) -filter.supported = All supported filetypes -work.canceled = Canceled -work.restoringControlFlow = Restoring control flow -menu.advancedsettings.advancedsettings = Advanced Settings -menu.recentFiles = Recent files - -#after version 1.7.4 -work.restoringControlFlow.complete = Control flow restored -message.confirm.recentFileNotFound = File not found. Do you want to remove it from the recent file list? -contextmenu.closeSwf = Close SWF -menu.settings.autoRenameIdentifiers = Auto rename identifiers -menu.file.saveasexe = Save as Exe... -filter.exe = Executable files (*.exe) - -#after version 1.8.0 -font.updateTexts = Update texts - -#after version 1.8.0u1 -menu.file.close = Close -menu.file.closeAll = Close all -menu.tools.otherTools = Other -menu.tools.otherTools.clearRecentFiles = Clear recent files -fontName.name = Font display name: -fontName.copyright = Font copyright: -button.preview = Preview -button.reset = Reset -errors.info = There are INFORMATIONS in the log. Click to view. -errors.warning = There are WARNINGS in the log. Click to view. - -decompilationError = Decompilation error - -disassemblingProgress.toString = toString -disassemblingProgress.reading = Reading -disassemblingProgress.deobfuscating = Deobfuscating - -contextmenu.moveTag = Move tag to - -filter.swc = SWC component files (*.swc) -filter.zip = ZIP compressed files (*.zip) -filter.binary = Binary search - all files (*.*) - -open.error = Error -open.error.fileNotFound = File not found -open.error.cannotOpen = Cannot open file - -node.others = others - -#after version 1.8.1 -menu.tools.search = Text Search - -#after version 1.8.1u1 -menu.tools.timeline = Timeline - -dialog.selectcolor.title = Select color -button.selectcolor.hint = Click to select color - -#default item name, will be used in following sentences -generictag.array.item = item -generictag.array.insertbeginning = Insert %item% at the beginning -generictag.array.insertbefore = Insert %item% before -generictag.array.remove = Remove %item% -generictag.array.insertafter = Insert %item% after -generictag.array.insertend = Insert %item% at the end - -#after version 2.0.0 -contextmenu.expandAll = Expand all - -filter.sounds = Supported sound formats (*.wav, *.mp3) -filter.sounds.wav = Wave file format (*.wav) -filter.sounds.mp3 = MP3 compressed format (*.mp3) - -error.sound.invalid = Invalid sound. - -button.prev = Previous -button.next = Next - -#after version 2.1.0 -message.action.playerglobal.title = PlayerGlobal library needed -message.action.playerglobal.needed = For ActionScript 3 direct editation, a library called "PlayerGlobal.swc" needs to be downloaded from Adobe homepage.\r\n%adobehomepage%\r\nPress OK to go to the download page. -message.action.playerglobal.place = Download the library called PlayerGlobal(.swc), and place it to directory\r\n%libpath%\r\n Press OK to continue. - -message.confirm.experimental.function = This function is EXPERIMENTAL. It means that you should not trust the results and the SWF file can be disfunctional after saving. -message.confirm.donotshowagain = Do not show again - -menu.import = Import -menu.file.import.text = Import text -import.select.directory = Select directory to import -error.text.import = Error during text import. Do you want to continue? - -#after version 2.1.1 -contextmenu.removeWithDependencies = Remove with dependencies - -abc.action.find-usages = Find usages -abc.action.find-declaration = Find declaration - -contextmenu.rawEdit = Raw edit -contextmenu.jumpToCharacter = Jump to character - -menu.settings.dumpView = Dump view - -menu.view = View -menu.file.view.resources = Resources -menu.file.view.hex = Hex dump - -node.header = header - -header.signature = Signature: -header.compression = Compression: -header.compression.lzma = LZMA -header.compression.zlib = ZLIB -header.compression.none = No compression -header.version = SWF Version: -header.gfx = GFX: -header.filesize = File size: -header.framerate = Frame rate: -header.framecount = Frame count: -header.displayrect = Display rect: -header.displayrect.value.twips = %xmin%,%ymin% => %xmax%,%ymax% twips -header.displayrect.value.pixels = %xmin%,%ymin% => %xmax%,%ymax% pixels - -#after version 2.1.2 -contextmenu.saveToFile = Save to File -contextmenu.parseActions = Parse actions -contextmenu.parseABC = Parse ABC -contextmenu.parseInstructions = Parse AVM2 Instructions - -#after version 2.1.3 -menu.deobfuscation = AS1/2 Deobfuscation -menu.file.deobfuscation.old = Old style -menu.file.deobfuscation.new = New style - -#after version 2.1.4 -contextmenu.openswfinside = Open SWF inside -binarydata.swfInside = It looks like there is SWF inside this binary data tag. Click here to load it as subtree. - -#after version 3.0.0 -button.zoomin.hint = Zoom in -button.zoomout.hint = Zoom out -button.zoomfit.hint = Zoom to fit -button.zoomnone.hint = Zoom to 1:1 -button.snapshot.hint = Take snapshot into clipboard - -editorTruncateWarning = Text truncated at position %chars% in debug mode. - -#Font name which is presented in the SWF Font tag -font.name.intag = Font name in tag: - -menu.debugger = Debugger -menu.debugger.switch = Debugger -menu.debugger.replacetrace = Replace trace calls -menu.debugger.showlog = Show Log - -message.debugger = This SWF Debugger can only be used to print messages to log window, browser console or alerts.\r\nIt is NOT designed for features like step code, breakpoints etc. - -contextmenu.addTag = Add tag - -deobfuscation.comment.tryenable = Tip: You can try enabling "Automatic deobfuscation" in Settings -deobfuscation.comment.failed = Deobfuscation is activated but decompilation still failed. If the file is NOT obfuscated, disable "Automatic deobfuscation" for better results. - -#after version 4.0.2 -preview.nextframe = Next frame -preview.prevframe = Previous frame -preview.gotoframe = Goto frame... - -preview.gotoframe.dialog.title = Goto frame -preview.gotoframe.dialog.message = Enter frame number (%min% - %max%) -preview.gotoframe.dialog.frame.error = Invalid frame number. It must be number between %min% and %max%. - -error.text.invalid.continue = Invalid text: %text% on line %line%. Do you want to continue? - -#after version 4.0.5 -contextmenu.copyTag = Copy tag to -fit = fit -button.setAdvanceValues = Set advance values - -menu.tools.replace = Text Replace - -message.confirm.close = There are unsaved changes. Do you really want to close {swfName}? -message.confirm.closeAll = There are unsaved changes. Do you really want to close all SWFs? - -contextmenu.exportJavaSource = Export Java Source -contextmenu.exportSwfXml = Export SWF as XML -contextmenu.importSwfXml = Import SWF XML - -filter.xml = XML - -#after version 4.1.0 -contextmenu.undo = Undo - -text.align.left = Left align -text.align.right = Right align -text.align.center = Center align -text.align.justify = Justify align - -text.undo = Undo changes - -menu.file.import.xml = Import SWF XML -menu.file.export.xml = Export SWF XML - -#after version 4.1.1 -text.align.translatex.decrease = Decrease TranslateX -text.align.translatex.increase = Increase TranslateX -selectPreviousTag = Select previous tag -selectNextTag = Select next tag -button.ignoreAll = Ignore All -menu.file.import.symbolClass = Import Symbol-Class -text.toggleCase = Toggle case - -#after version 5.0.2 -preview.loop = Loop -menu.file.import.script = Import script -contextmenu.copyTagWithDependencies = Copy tag with dependencies to -button.replaceWithTag = Replace with other character tag -button.resolveConstants = Resolve constants -button.viewConstants = View Constants -work.exported = Exported +# Copyright (C) 2010-2015 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 . + +menu.file = File +menu.file.open = Open... +menu.file.save = Save +menu.file.saveas = Save as... +menu.file.export.fla = Export to FLA +menu.file.export.all = Export all parts +menu.file.export.selection = Export selection +menu.file.exit = Exit + +menu.tools = Tools +menu.tools.searchas = Search All ActionScript... +menu.tools.proxy = Proxy +menu.tools.deobfuscation = Deobfuscation +menu.tools.deobfuscation.pcode = P-code deobfuscation... +menu.tools.deobfuscation.globalrename = Globally rename identifier +menu.tools.deobfuscation.renameinvalid = Rename invalid identifiers +menu.tools.gotodocumentclass = Go to document class + +menu.settings = Settings +menu.settings.autodeobfuscation = Automatic deobfuscation +menu.settings.internalflashviewer = Use own Flash viewer +menu.settings.parallelspeedup = Parallel SpeedUp +menu.settings.disabledecompilation = Disable decompilation (Disassemble only) +menu.settings.addtocontextmenu = Add FFDec to SWF files context menu +menu.settings.language = Change language +menu.settings.cacheOnDisk = Use caching on disk +menu.settings.gotoMainClassOnStartup = Highlight document class on startup + +menu.help = Help +menu.help.checkupdates = Check for updates... +menu.help.helpus = Help us! +menu.help.homepage = Visit homepage +menu.help.about = About... + +contextmenu.remove = Remove + +button.save = Save +button.edit = Edit +button.cancel = Cancel +button.replace = Replace... + +notavailonthisplatform = Preview of this object is not available on this platform (Windows only). + +swfpreview = SWF preview +swfpreview.internal = SWF preview (Internal viewer) + +parameters = Parameters + +rename.enternew = Enter new name: + +rename.finished.identifier = Identifier renamed. +rename.finished.multiname = %count% multiname(s) renamed. + +node.texts = texts +node.images = images +node.movies = movies +node.sounds = sounds +node.binaryData = binaryData +node.fonts = fonts +node.sprites = sprites +node.shapes = shapes +node.morphshapes = morphshapes +node.buttons = buttons +node.frames = frames +node.scripts = scripts + +message.warning = Warning +message.confirm.experimental = Following procedure can damage SWF file which can be then unplayable.\r\nUSE IT ON YOUR OWN RISK. Do you want to continue? +message.confirm.parallel = Parallelism can speed up loading and decompilation but uses more memory. +message.confirm.on = Do you want to turn this ON? +message.confirm.off = Do you want to turn this OFF? +message.confirm = Confirm + +message.confirm.autodeobfuscate = Automatic deobfuscation is a way to decompile obfuscated code.\r\nDeobfuscation leads to slower decompilation and some of the dead code may be eliminated.\r\nIf the code is not obfuscated, it's better to turn autodeobfuscation off. + +message.parallel = Parallelism +message.trait.saved = Trait successfully saved + +message.constant.new.string = String "%value%" is not present in constants table. Do you want to add it? +message.constant.new.string.title = Add String +message.constant.new.integer = Integer value "%value%" is not present in constants table. Do you want to add it? +message.constant.new.integer.title = Add Integer +message.constant.new.unsignedinteger = Unsigned integer value "%value%" is not present in constants table. Do you want to add it? +message.constant.new.unsignedinteger.title = Add Unsigned integer +message.constant.new.double = Double value "%value%" is not present in constants table. Do you want to add it? +message.constant.new.double.title = Add Double + +work.buffering = Buffering +work.waitingfordissasembly = Waiting for disassembly +work.gettinghilights = Getting highlights +work.disassembling = Disassembling +work.exporting = Exporting +work.searching = Searching +work.renaming = Renaming +work.exporting.fla = Exporting FLA +work.renaming.identifiers = Renaming identifiers +work.deobfuscating = Deobfuscating +work.decompiling = Decompiling +work.gettingvariables = Getting variables +work.reading.swf = Reading SWF +work.creatingwindow = Creating window +work.buildingscripttree = Building script tree + +work.deobfuscating.complete = Deobfuscation complete + +message.search.notfound = String "%searchtext%" not found. +message.search.notfound.title = Not found + +message.rename.notfound.multiname = No multiname found under cursor +message.rename.notfound.identifier = No identifier found under cursor +message.rename.notfound.title = Not found +message.rename.renamed = Identifiers renamed: %count% + +filter.images = Images (*.jpg,*.gif,*.png,*.bmp) +filter.fla = %version% Document (*.fla) +filter.xfl = %version% Uncompressed Document (*.xfl) +filter.swf = SWF files (*.swf) + +error = Error +error.image.invalid = Invalid image. + +error.text.invalid = Invalid text: %text% on line %line% +error.file.save = Cannot save file +error.file.write = Cannot write to the file +error.export = Error during export + +export.select.directory = Select directory to export +export.finishedin = Exported in %time% + +update.check.title = Update check +update.check.nonewversion = No new version available. + +message.helpus = Please visit\r\n%url%\r\nfor details. +message.homepage = Visit homepage at: \r\n%url% + +proxy = Proxy +proxy.start = Start proxy +proxy.stop = Stop proxy +proxy.show = Show proxy +exit = Exit + +panel.disassembled = P-code source +panel.decompiled = ActionScript source + +search.info = Search for "%text%": +search.script = Script + +constants = Constants +traits = Traits + +pleasewait = Please wait + +abc.detail.methodtrait = Method/Getter/Setter Trait +abc.detail.unsupported = - +abc.detail.slotconsttrait = Slot/Const Trait +abc.detail.traitname = Name: + +abc.detail.body.params.maxstack = Max stack: +abc.detail.body.params.localregcount = Local registers count: +abc.detail.body.params.minscope = Minimum scope depth: +abc.detail.body.params.maxscope = Maximum scope depth: +abc.detail.body.params.autofill = Auto fill on code save (GLOBAL SETTING) +abc.detail.body.params.autofill.experimental = ...EXPERIMENTAL + +abc.detail.methodinfo.methodindex = Method Index: +abc.detail.methodinfo.parameters = Parameters: +abc.detail.methodinfo.returnvalue = Return value type: + +error.methodinfo.params = MethodInfo Params Error +error.methodinfo.returnvalue = MethodInfo Return value type Error + +abc.detail.methodinfo = MethodInfo +abc.detail.body.code = MethodBody Code +abc.detail.body.params = MethodBody params + +abc.detail.slotconst.typevalue = Type and Value: + +error.slotconst.typevalue = SlotConst type value Error + +message.autofill.failed = Cannot get code stats for automatic body params.\r\nUncheck autofill to avoid this message. +info.selecttrait = Select class and click a trait in Actionscript source to edit it. + +button.viewgraph = View Graph +button.viewhex = View Hex + +abc.traitslist.instanceinitializer = instance initializer +abc.traitslist.classinitializer = class initializer + +action.edit.experimental = (Experimental) + +message.action.saved = Code successfully saved + +error.action.save = %error% on line %line% + +message.confirm.remove = Are you sure you want to remove %item%\n and all objects which depend on it? + +#after version 1.6.5u1: + +button.ok = OK +button.cancel = Cancel + +font.name = Font name: +font.isbold = Is bold: +font.isitalic = Is italic: +font.ascent = Ascent: +font.descent = Descent: +font.leading = Leading: +font.characters = Characters: +font.characters.add = Add characters: +value.unknown = ? + +yes = yes +no = no + +errors.present = There are ERRORS in the log. Click to view. +errors.none = There are no errors in the log. + +#after version 1.6.6: + +dialog.message.title = Message +dialog.select.title = Select an Option + +button.yes = Yes +button.no = No + +FileChooser.openButtonText = Open +FileChooser.openButtonToolTipText = Open +FileChooser.lookInLabelText = Look in: +FileChooser.acceptAllFileFilterText = All Files +FileChooser.filesOfTypeLabelText = Files of type: +FileChooser.fileNameLabelText = File name: +FileChooser.listViewButtonToolTipText = List +FileChooser.listViewButtonAccessibleName = List +FileChooser.detailsViewButtonToolTipText = Details +FileChooser.detailsViewButtonAccessibleName = Details +FileChooser.upFolderToolTipText = Up One Level +FileChooser.upFolderAccessibleName = Up One Level +FileChooser.homeFolderToolTipText = Home +FileChooser.homeFolderAccessibleName = Home +FileChooser.fileNameHeaderText = Name +FileChooser.fileSizeHeaderText = Size +FileChooser.fileTypeHeaderText = Type +FileChooser.fileDateHeaderText = Date +FileChooser.fileAttrHeaderText = Attributes +FileChooser.openDialogTitleText = Open +FileChooser.directoryDescriptionText = Directory +FileChooser.directoryOpenButtonText = Open +FileChooser.directoryOpenButtonToolTipText = Open selected directory +FileChooser.fileDescriptionText = Generic File +FileChooser.helpButtonText = Help +FileChooser.helpButtonToolTipText = FileChooser help +FileChooser.newFolderAccessibleName = New Folder +FileChooser.newFolderErrorText = Error creating new folder +FileChooser.newFolderToolTipText = Create New Folder +FileChooser.other.newFolder = NewFolder +FileChooser.other.newFolder.subsequent = NewFolder.{0} +FileChooser.win32.newFolder = New Folder +FileChooser.win32.newFolder.subsequent = New Folder ({0}) +FileChooser.saveButtonText = Save +FileChooser.saveButtonToolTipText = Save selected file +FileChooser.saveDialogTitleText = Save +FileChooser.saveInLabelText = Save in: +FileChooser.updateButtonText = Update +FileChooser.updateButtonToolTipText = Update directory listing + +#after version 1.6.6u2: + +FileChooser.detailsViewActionLabel.textAndMnemonic = Details +FileChooser.detailsViewButtonToolTip.textAndMnemonic = Details +FileChooser.fileAttrHeader.textAndMnemonic = Attributes +FileChooser.fileDateHeader.textAndMnemonic = Modified +FileChooser.fileNameHeader.textAndMnemonic = Name +FileChooser.fileNameLabel.textAndMnemonic = File name: +FileChooser.fileSizeHeader.textAndMnemonic = Size +FileChooser.fileTypeHeader.textAndMnemonic = Type +FileChooser.filesOfTypeLabel.textAndMnemonic = Files of type: +FileChooser.folderNameLabel.textAndMnemonic = Folder name: +FileChooser.homeFolderToolTip.textAndMnemonic = Home +FileChooser.listViewActionLabel.textAndMnemonic = List +FileChooser.listViewButtonToolTip.textAndMnemonic = List +FileChooser.lookInLabel.textAndMnemonic = Look in: +FileChooser.newFolderActionLabel.textAndMnemonic = New Folder +FileChooser.newFolderToolTip.textAndMnemonic = Create New Folder +FileChooser.refreshActionLabel.textAndMnemonic = Refresh +FileChooser.saveInLabel.textAndMnemonic = Save in: +FileChooser.upFolderToolTip.textAndMnemonic = Up One Level +FileChooser.viewMenuButtonAccessibleName = View Menu +FileChooser.viewMenuButtonToolTipText = View Menu +FileChooser.viewMenuLabel.textAndMnemonic = View +FileChooser.newFolderActionLabelText = New Folder +FileChooser.listViewActionLabelText = List +FileChooser.detailsViewActionLabelText = Details +FileChooser.refreshActionLabelText = Refresh +FileChooser.sortMenuLabelText = Arrange Icons By +FileChooser.viewMenuLabelText = View +FileChooser.fileSizeKiloBytes = {0} KB +FileChooser.fileSizeMegaBytes = {0} MB +FileChooser.fileSizeGigaBytes = {0} GB +FileChooser.folderNameLabelText = Folder name: + +error.occured = Error occurred: %error% +button.abort = Abort +button.retry = Retry +button.ignore = Ignore + +font.source = Source Font: + +#after version 1.6.7: + +menu.export = Export +menu.general = General +menu.language = Language + +startup.welcometo = Welcome to +startup.selectopen = Click Open icon on the top panel or drag SWF file to this window to start. + +error.font.nocharacter = Selected source font does not contain character "%char%". + +warning.initializers = Static fields and consts are often initialized in initializers.\nEditing value here is usually not enough! + +#after version 1.7.0u1: + +menu.tools.searchmemory = Search SWFs in memory +menu.file.reload = Reload +message.confirm.reload = This action cancels all unsaved changes and reloads the SWF file again.\nDo you want to continue? + +dialog.selectbkcolor.title = Select background color for SWF display +button.selectbkcolor.hint = Select background color + +ColorChooser.okText = OK +ColorChooser.cancelText = Cancel +ColorChooser.resetText = Reset +ColorChooser.previewText = Preview +ColorChooser.swatchesNameText = Swatches +ColorChooser.swatchesRecentText = Recent: +ColorChooser.sampleText=Sample Text Sample Text + +#after version 1.7.1: + +preview.play = Play +preview.pause = Pause +preview.stop = Stop + +message.confirm.removemultiple = Are you sure you want to remove %count% items\n and all objects which depend on it? + +menu.tools.searchcache = Search browsers cache + +#after version 1.7.2u2 + +error.trait.exists = Trait with name "%name%" already exists. +button.addtrait = Add trait +button.font.embed = Embed... +button.yes.all = Yes to all +button.no.all = No to all +message.font.add.exists = Character %char% already exists in the font tag.\nDo you want to replace it? + +filter.gfx = ScaleForm GFx files (*.gfx) +filter.supported = All supported filetypes +work.canceled = Canceled +work.restoringControlFlow = Restoring control flow +menu.advancedsettings.advancedsettings = Advanced Settings +menu.recentFiles = Recent files + +#after version 1.7.4 +work.restoringControlFlow.complete = Control flow restored +message.confirm.recentFileNotFound = File not found. Do you want to remove it from the recent file list? +contextmenu.closeSwf = Close SWF +menu.settings.autoRenameIdentifiers = Auto rename identifiers +menu.file.saveasexe = Save as Exe... +filter.exe = Executable files (*.exe) + +#after version 1.8.0 +font.updateTexts = Update texts + +#after version 1.8.0u1 +menu.file.close = Close +menu.file.closeAll = Close all +menu.tools.otherTools = Other +menu.tools.otherTools.clearRecentFiles = Clear recent files +fontName.name = Font display name: +fontName.copyright = Font copyright: +button.preview = Preview +button.reset = Reset +errors.info = There are INFORMATIONS in the log. Click to view. +errors.warning = There are WARNINGS in the log. Click to view. + +decompilationError = Decompilation error + +disassemblingProgress.toString = toString +disassemblingProgress.reading = Reading +disassemblingProgress.deobfuscating = Deobfuscating + +contextmenu.moveTag = Move tag to + +filter.swc = SWC component files (*.swc) +filter.zip = ZIP compressed files (*.zip) +filter.binary = Binary search - all files (*.*) + +open.error = Error +open.error.fileNotFound = File not found +open.error.cannotOpen = Cannot open file + +node.others = others + +#after version 1.8.1 +menu.tools.search = Text Search + +#after version 1.8.1u1 +menu.tools.timeline = Timeline + +dialog.selectcolor.title = Select color +button.selectcolor.hint = Click to select color + +#default item name, will be used in following sentences +generictag.array.item = item +generictag.array.insertbeginning = Insert %item% at the beginning +generictag.array.insertbefore = Insert %item% before +generictag.array.remove = Remove %item% +generictag.array.insertafter = Insert %item% after +generictag.array.insertend = Insert %item% at the end + +#after version 2.0.0 +contextmenu.expandAll = Expand all + +filter.sounds = Supported sound formats (*.wav, *.mp3) +filter.sounds.wav = Wave file format (*.wav) +filter.sounds.mp3 = MP3 compressed format (*.mp3) + +error.sound.invalid = Invalid sound. + +button.prev = Previous +button.next = Next + +#after version 2.1.0 +message.action.playerglobal.title = PlayerGlobal library needed +message.action.playerglobal.needed = For ActionScript 3 direct editation, a library called "PlayerGlobal.swc" needs to be downloaded from Adobe homepage.\r\n%adobehomepage%\r\nPress OK to go to the download page. +message.action.playerglobal.place = Download the library called PlayerGlobal(.swc), and place it to directory\r\n%libpath%\r\n Press OK to continue. + +message.confirm.experimental.function = This function is EXPERIMENTAL. It means that you should not trust the results and the SWF file can be disfunctional after saving. +message.confirm.donotshowagain = Do not show again + +menu.import = Import +menu.file.import.text = Import text +import.select.directory = Select directory to import +error.text.import = Error during text import. Do you want to continue? + +#after version 2.1.1 +contextmenu.removeWithDependencies = Remove with dependencies + +abc.action.find-usages = Find usages +abc.action.find-declaration = Find declaration + +contextmenu.rawEdit = Raw edit +contextmenu.jumpToCharacter = Jump to character + +menu.settings.dumpView = Dump view + +menu.view = View +menu.file.view.resources = Resources +menu.file.view.hex = Hex dump + +node.header = header + +header.signature = Signature: +header.compression = Compression: +header.compression.lzma = LZMA +header.compression.zlib = ZLIB +header.compression.none = No compression +header.version = SWF Version: +header.gfx = GFX: +header.filesize = File size: +header.framerate = Frame rate: +header.framecount = Frame count: +header.displayrect = Display rect: +header.displayrect.value.twips = %xmin%,%ymin% => %xmax%,%ymax% twips +header.displayrect.value.pixels = %xmin%,%ymin% => %xmax%,%ymax% pixels + +#after version 2.1.2 +contextmenu.saveToFile = Save to File +contextmenu.parseActions = Parse actions +contextmenu.parseABC = Parse ABC +contextmenu.parseInstructions = Parse AVM2 Instructions + +#after version 2.1.3 +menu.deobfuscation = AS1/2 Deobfuscation +menu.file.deobfuscation.old = Old style +menu.file.deobfuscation.new = New style + +#after version 2.1.4 +contextmenu.openswfinside = Open SWF inside +binarydata.swfInside = It looks like there is SWF inside this binary data tag. Click here to load it as subtree. + +#after version 3.0.0 +button.zoomin.hint = Zoom in +button.zoomout.hint = Zoom out +button.zoomfit.hint = Zoom to fit +button.zoomnone.hint = Zoom to 1:1 +button.snapshot.hint = Take snapshot into clipboard + +editorTruncateWarning = Text truncated at position %chars% in debug mode. + +#Font name which is presented in the SWF Font tag +font.name.intag = Font name in tag: + +menu.debugger = Debugger +menu.debugger.switch = Debugger +menu.debugger.replacetrace = Replace trace calls +menu.debugger.showlog = Show Log + +message.debugger = This SWF Debugger can only be used to print messages to log window, browser console or alerts.\r\nIt is NOT designed for features like step code, breakpoints etc. + +contextmenu.addTag = Add tag + +deobfuscation.comment.tryenable = Tip: You can try enabling "Automatic deobfuscation" in Settings +deobfuscation.comment.failed = Deobfuscation is activated but decompilation still failed. If the file is NOT obfuscated, disable "Automatic deobfuscation" for better results. + +#after version 4.0.2 +preview.nextframe = Next frame +preview.prevframe = Previous frame +preview.gotoframe = Goto frame... + +preview.gotoframe.dialog.title = Goto frame +preview.gotoframe.dialog.message = Enter frame number (%min% - %max%) +preview.gotoframe.dialog.frame.error = Invalid frame number. It must be number between %min% and %max%. + +error.text.invalid.continue = Invalid text: %text% on line %line%. Do you want to continue? + +#after version 4.0.5 +contextmenu.copyTag = Copy tag to +fit = fit +button.setAdvanceValues = Set advance values + +menu.tools.replace = Text Replace + +message.confirm.close = There are unsaved changes. Do you really want to close {swfName}? +message.confirm.closeAll = There are unsaved changes. Do you really want to close all SWFs? + +contextmenu.exportJavaSource = Export Java Source +contextmenu.exportSwfXml = Export SWF as XML +contextmenu.importSwfXml = Import SWF XML + +filter.xml = XML + +#after version 4.1.0 +contextmenu.undo = Undo + +text.align.left = Left align +text.align.right = Right align +text.align.center = Center align +text.align.justify = Justify align + +text.undo = Undo changes + +menu.file.import.xml = Import SWF XML +menu.file.export.xml = Export SWF XML + +#after version 4.1.1 +text.align.translatex.decrease = Decrease TranslateX +text.align.translatex.increase = Increase TranslateX +selectPreviousTag = Select previous tag +selectNextTag = Select next tag +button.ignoreAll = Ignore All +menu.file.import.symbolClass = Import Symbol-Class +text.toggleCase = Toggle case + +#after version 5.0.2 +preview.loop = Loop +menu.file.import.script = Import script +contextmenu.copyTagWithDependencies = Copy tag with dependencies to +button.replaceWithTag = Replace with other character tag +button.resolveConstants = Resolve constants + +#after version 5.1.0 +button.viewConstants = View Constants +work.exported = Exported +button.replaceAlphaChannel = Replace alpha channel... diff --git a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_hu.properties b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_hu.properties index 8260c602d..aef58e927 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_hu.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_hu.properties @@ -1,587 +1,590 @@ -# Copyright (C) 2010-2015 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 . - -menu.file = F\u00e1jl -menu.file.open = Megnyit\u00e1s... -menu.file.save = Ment\u00e9s -menu.file.saveas = Ment\u00e9s m\u00e1sk\u00e9nt... -menu.file.export.fla = Export\u00e1l\u00e1s FLA-ba -menu.file.export.all = Minden r\u00e9sz export\u00e1l\u00e1sa -menu.file.export.selection = Kijel\u00f6ltek export\u00e1l\u00e1sa -menu.file.exit = Kil\u00e9p\u00e9s - -menu.tools = Eszk\u00f6z\u00f6k -menu.tools.searchas = Keres\u00e9s az \u00f6sszes ActionScriptben... -menu.tools.proxy = Proxy -menu.tools.deobfuscation = Deobfuszk\u00e1l\u00e1s -menu.tools.deobfuscation.pcode = PCode deobfuszk\u00e1l\u00e1s... -menu.tools.deobfuscation.globalrename = Azonos\u00edt\u00f3k glob\u00e1lis \u00e1tnevez\u00e9se -menu.tools.deobfuscation.renameinvalid = \u00c9rv\u00e9nytelen azonos\u00edt\u00f3k \u00e1tnevez\u00e9se -menu.tools.gotodocumentclass = Dokumentum oszt\u00e1lyhoz ugr\u00e1s - -menu.settings = Be\u00e1ll\u00edt\u00e1sok -menu.settings.autodeobfuscation = Automatikus deobfuszk\u00e1l\u00e1s -menu.settings.internalflashviewer = Saj\u00e1t Flash-n\u00e9z\u0151ke haszn\u00e1lata -menu.settings.parallelspeedup = P\u00e1rhuzamos gyors\u00edt\u00e1s -menu.settings.disabledecompilation = Visszaford\u00edt\u00e1s letilt\u00e1sa (csak disassembl\u00e1l\u00e1s) -menu.settings.addtocontextmenu = FFDec hozz\u00e1rendel\u00e9se SWF f\u00e1jlokhoz a helyi men\u00fcben -menu.settings.language = Nyelv v\u00e1lt\u00e1sa -menu.settings.cacheOnDisk = Lemez gyors\u00edt\u00f3t\u00e1r haszn\u00e1lata -menu.settings.gotoMainClassOnStartup = Dokumentum oszt\u00e1ly kiemel\u00e9se ind\u00edt\u00e1skor - -menu.help = S\u00fag\u00f3 -menu.help.checkupdates = Friss\u00edt\u00e9sek keres\u00e9se... -menu.help.helpus = Seg\u00edts nek\u00fcnk! -menu.help.homepage = Honlap megnyit\u00e1sa -menu.help.about = N\u00e9vjegy... - -contextmenu.remove = Elt\u00e1vol\u00edt\u00e1s - -button.save = Ment\u00e9s -button.edit = Szerkeszt\u00e9s -button.cancel = M\u00e9gsem -button.replace = Csere... - -notavailonthisplatform = Ennek az objektumnak az el\u0151n\u00e9zete nem el\u00e9rhet\u0151 ezen a platformon. (Csak Windowson) - -swfpreview = SWF el\u0151n\u00e9zet -swfpreview.internal = SWF el\u0151n\u00e9zet (Be\u00e9p\u00edtett n\u00e9z\u0151ke) - -parameters = Param\u00e9terek - -rename.enternew = \u00cdrja be az \u00faj nevet: - -rename.finished.identifier = Azonos\u00edt\u00f3 \u00e1tnevezve. -rename.finished.multiname = %count% multiname \u00e1tnevezve. - -node.texts = sz\u00f6vegek -node.images = k\u00e9pek -node.movies = mozg\u00f3k\u00e9pek -node.sounds = hangok -node.binaryData = bin\u00e1ris adatok -node.fonts = bet\u0171t\u00edpusok -node.sprites = szpr\u00e1jtok -node.shapes = alakzatok -node.morphshapes = morph alakzatok -node.buttons = gombok -node.frames = keretek -node.scripts = szkriptek - -message.warning = Figyelmeztet\u00e9s -message.confirm.experimental = A k\u00f6vetkez\u0151 m\u0171velet k\u00e1ros\u00edthatja az SWF f\u00e1jlt, ami ezut\u00e1n lej\u00e1tszhatatlan lesz.\r\nCSAK SAJ\u00c1T FELEL\u0150SS\u00c9GRE HASZN\u00c1LJA. Szeretn\u00e9 folytatni? -message.confirm.parallel = P\u00e1rhuzamos\u00edt\u00e1s felgyors\u00edthatja a bet\u00f6lt\u00e9st \u00e9s visszaford\u00edt\u00e1st, de t\u00f6bb mem\u00f3ri\u00e1t haszn\u00e1l. -message.confirm.on = BE szeretn\u00e9 kapcsolni? -message.confirm.off = KI szeretn\u00e9 kapcsolni? -message.confirm = Meger\u0151s\u00edt\u00e9s - -message.confirm.autodeobfuscate = Automatikus deobfuszk\u00e1l\u00e1s egy m\u00f3d az obfuszk\u00e1lt k\u00f3d visszaford\u00edt\u00e1s\u00e1ra.\r\nDeobfuszk\u00e1l\u00e1s lassabb visszaford\u00edt\u00e1st eredm\u00e9nyez, \u00e9s n\u00e9h\u00e1ny halott k\u00f3dr\u00e9szlet elt\u00e1vol\u00edt\u00e1sra ker\u00fclhet.\r\nHa a k\u00f3d nincs obfuszk\u00e1lva jobb kikapcsolni az automatikus deobfuszk\u00e1l\u00e1st. - -message.parallel = P\u00e1rhuzamos\u00edt\u00e1s -message.trait.saved = Jellemz\u0151 sikeresen lementve - -message.constant.new.string = Karakterl\u00e1nc "%value%" nem tal\u00e1lhat\u00f3 a konstans t\u00e1bl\u00e1ban. Szeretn\u00e9 hozz\u00e1adni? -message.constant.new.string.title = Karakterl\u00e1nc hozz\u00e1ad\u00e1sa -message.constant.new.integer = Eg\u00e9sz \u00e9rt\u00e9k "%value%" nem tal\u00e1lhat\u00f3 a konstans t\u00e1bl\u00e1ban. Szeretn\u00e9 hozz\u00e1adni? -message.constant.new.integer.title = Eg\u00e9sz hozz\u00e1ad\u00e1sa -message.constant.new.unsignedinteger = El\u0151jel n\u00e9lk\u00fcli eg\u00e9sz \u00e9rt\u00e9k "%value%" nem tal\u00e1lhat\u00f3 a konstans t\u00e1bl\u00e1ban. Szeretn\u00e9 hozz\u00e1adni? -message.constant.new.unsignedinteger.title = El\u0151jel n\u00e9lk\u00fcli eg\u00e9sz hozz\u00e1ad\u00e1sa -message.constant.new.double = Lebeg\u0151pontos \u00e9rt\u00e9k "%value%" nem tal\u00e1lhat\u00f3 a konstans t\u00e1bl\u00e1ban. Szeretn\u00e9 hozz\u00e1adni? -message.constant.new.double.title = Lebeg\u0151pontos \u00e9rt\u00e9k hozz\u00e1ad\u00e1sa - -work.buffering = Pufferel\u00e9s -work.waitingfordissasembly = V\u00e1rakoz\u00e1s a visszafejt\u00e9sre -work.gettinghilights = Kiemel\u00e9sek elk\u00e9sz\u00edt\u00e9se -work.disassembling = Visszafejt\u00e9s -work.exporting = Export\u00e1l\u00e1s -work.searching = Keres\u00e9s -work.renaming = \u00c1tnevez\u00e9s -work.exporting.fla = Export\u00e1l\u00e1s FLA-ba -work.renaming.identifiers = Azonos\u00edt\u00f3k \u00e1tnevez\u00e9se -work.deobfuscating = Deobfuszk\u00e1l\u00e1s -work.decompiling = Visszaford\u00edt\u00e1s -work.gettingvariables = V\u00e1ltoz\u00f3k kinyer\u00e9se -work.reading.swf = SWF olvas\u00e1sa -work.creatingwindow = Ablak elk\u00e9sz\u00edt\u00e9se -work.buildingscripttree = Szkript fa \u00e9p\u00edt\u00e9se - -work.deobfuscating.complete = Deobfuszk\u00e1l\u00e1s k\u00e9sz - -message.search.notfound = Karakterl\u00e1nc "%searchtext%" nem tal\u00e1lhat\u00f3. -message.search.notfound.title = Nem tal\u00e1lhat\u00f3 - -message.rename.notfound.multiname = Multiname nem tal\u00e1lkat\u00f3 a kurzor alatt -message.rename.notfound.identifier = Azonos\u00edt\u00f3 nem tal\u00e1lhat\u00f3 a kurzor alatt -message.rename.notfound.title = Nem tal\u00e1lhat\u00f3 -message.rename.renamed = %count% azonos\u00edt\u00f3 \u00e1tnevezve - -filter.images = K\u00e9pek (*.jpg,*.gif,*.png,*.bmp) -filter.fla = %version% Dokumentum (*.fla) -filter.xfl = %version% T\u00f6m\u00f6r\u00edtetlen dokumentum (*.xfl) -filter.swf = SWF f\u00e1ljok (*.swf) - -error = Hiba -error.image.invalid = \u00c9rv\u00e9nytelen k\u00e9p. - -error.text.invalid = \u00c9rv\u00e9nytelen sz\u00f6veg: %text% a %line%. sorban -error.file.save = A f\u00e1jl nem menthet\u0151 -error.file.write = A f\u00e1lj nem \u00edrhat\u00f3 -error.export = Hiba export\u00e1l\u00e1s k\u00f6zben - -export.select.directory = V\u00e1lassza ki a mapp\u00e1t az export\u00e1l\u00e1shoz -export.finishedin = %time% alatt export\u00e1lva - -update.check.title = Friss\u00edt\u00e9s ellen\u0151rz\u00e9se -update.check.nonewversion = \u00dajabb verzi\u00f3 nem el\u00e9rhet\u0151. - -message.helpus = Tov\u00e1bbi r\u00e9szletek\u00e9rt k\u00e9rem l\u00e1togassa meg a(z)\r\n%url%\r\nweboldalt. -message.homepage = L\u00e1togassa meg a honlapot a k\u00f6vetkez\u0151 c\u00edmen: \r\n%url% - -proxy = Proxy -proxy.start = Proxy elind\u00edt\u00e1sa -proxy.stop = Proxy le\u00e1ll\u00edt\u00e1sa -proxy.show = Proxy megjelen\u00edt\u00e9se -exit = Kil\u00e9p\u00e9s - -panel.disassembled = P-code forr\u00e1s -panel.decompiled = ActionScript forr\u00e1s - -search.info = "%text%" sz\u00f6veg keres\u00e9se: -search.script = Szkript - -constants = Konstansok -traits = Jellemz\u0151k - -pleasewait = K\u00e9rem v\u00e1rjon - -abc.detail.methodtrait = Met\u00f3dus/Getter/Setter Jellemz\u0151 -abc.detail.unsupported = - -abc.detail.slotconsttrait = Slot/Konstans Jellemz\u0151 -abc.detail.traitname = N\u00e9v: - -abc.detail.body.params.maxstack = Maximum stack: -abc.detail.body.params.localregcount = Lok\u00e1lis regiszterek sz\u00e1ma: -abc.detail.body.params.minscope = \u00c9rv\u00e9nyess\u00e9gi k\u00f6r minimum m\u00e9lys\u00e9ge: -abc.detail.body.params.maxscope = \u00c9rv\u00e9nyess\u00e9gi k\u00f6r maximum m\u00e9lys\u00e9ge: -abc.detail.body.params.autofill = Automatikus kit\u00f6lt\u00e9s k\u00f3d ment\u00e9sekor (GLOB\u00c1LIS BE\u00c1LL\u00cdT\u00c1S) -abc.detail.body.params.autofill.experimental = ...K\u00cdS\u00c9RLETI - -abc.detail.methodinfo.methodindex = Met\u00f3dus Index: -abc.detail.methodinfo.parameters = Param\u00e9terek: -abc.detail.methodinfo.returnvalue = Visszat\u00e9r\u00e9si \u00e9rt\u00e9k t\u00edpusa: - -error.methodinfo.params = MethodInfo Param\u00e9ter Hiba -error.methodinfo.returnvalue = MethodInfo Visszat\u00e9r\u00e9si \u00e9rt\u00e9k Hiba - -abc.detail.methodinfo = MethodInfo -abc.detail.body.code = MethodBody K\u00f3d -abc.detail.body.params = MethodBody param\u00e9terek - -abc.detail.slotconst.typevalue = T\u00edpus \u00e9s \u00c9rt\u00e9k: - -error.slotconst.typevalue = SlotConst t\u00edpus\u00e9rt\u00e9k Hiba - -message.autofill.failed = K\u00f3d statisztika nem el\u00e9rhet\u0151 az automatikus t\u00f6rzs param\u00e9terekhez.\r\nVegye ki a pip\u00e1t az az automatikus kit\u00f6lt\u00e9s mell\u0151l ennek az \u00fczenetnek az elket\u00fcl\u00e9s\u00e9hez. -info.selecttrait = V\u00e1lasszon ki egy oszt\u00e1lyt \u00e9s kattintson egy jellemz\u0151re az ActionScript forr\u00e1sban a szerkeszt\u00e9shez. - -button.viewgraph = Gr\u00e1f mutat\u00e1sa -button.viewhex = Hexa mutat\u00e1sa - -abc.traitslist.instanceinitializer = p\u00e9ld\u00e1ny inicializ\u00e1l\u00f3 -abc.traitslist.classinitializer = oszt\u00e1ly inicializ\u00e1l\u00f3 - -action.edit.experimental = (K\u00eds\u00e9rleti) - -message.action.saved = K\u00f3d sikeresen lementve - -error.action.save = %error% a %line%. sorban - -message.confirm.remove = Biztos benne, hogy t\u00f6r\u00f6lni k\u00edv\u00e1nja a %item%-t \n \u00e9s az \u00f6sszes t\u0151le f\u00fcgg\u0151 objektumot ? - -#after version 1.6.5u1: - -button.ok = OK -button.cancel = M\u00e9gse - -font.name = Bet\u0171t\u00edpus neve: -font.isbold = F\u00e9lk\u00f6v\u00e9r: -font.isitalic = D\u0151lt: -font.ascent = Fels\u0151 index: -font.descent = Als\u00f3 index: -font.leading = Sork\u00f6z: -font.characters = Karakterek: -font.characters.add = Karakter hozz\u00e1ad\u00e1sa: -value.unknown = ? - -yes = igen -no = nem - -errors.present = HIB\u00c1K vannak a napl\u00f3ban. Kattintson ide a megjelen\u00edt\u00e9shez. -errors.none = Nincsenek hib\u00e1k a napl\u00f3ban - -#after version 1.6.6: - -dialog.message.title = \u00dczenet -dialog.select.title = V\u00e1lasszon egy lehet\u0151s\u00e9get - -button.yes = Igen -button.no = Nem - -FileChooser.openButtonText = Megnyit\u00e1s -FileChooser.openButtonToolTipText = Megnyit\u00e1s -FileChooser.lookInLabelText = Keres\u00e9s ebben: -FileChooser.acceptAllFileFilterText = Minden f\u00e1jlt\u00edpus -FileChooser.filesOfTypeLabelText = A k\u00f6vetkez\u0151 t\u00edpus\u00fa f\u00e1jlok: -FileChooser.fileNameLabelText = F\u00e1jln\u00e9v: -FileChooser.listViewButtonToolTipText = Lista -FileChooser.listViewButtonAccessibleName = Lista -FileChooser.detailsViewButtonToolTipText = R\u00e9szletek -FileChooser.detailsViewButtonAccessibleName = R\u00e9szletek -FileChooser.upFolderToolTipText = Egy szinttel feljebb -FileChooser.upFolderAccessibleName = Egy szinttel feljebb -FileChooser.homeFolderToolTipText = Otthon -FileChooser.homeFolderAccessibleName = Otthon -FileChooser.fileNameHeaderText = N\u00e9v -FileChooser.fileSizeHeaderText = M\u00e9ret -FileChooser.fileTypeHeaderText = T\u00edpus -FileChooser.fileDateHeaderText = D\u00e1tum -FileChooser.fileAttrHeaderText = Tulajdons\u00e1gok -FileChooser.openDialogTitleText = Megnyit\u00e1s -FileChooser.directoryDescriptionText = K\u00f6nyvt\u00e1r -FileChooser.directoryOpenButtonText = Megnyit\u00e1s -FileChooser.directoryOpenButtonToolTipText = A kiv\u00e1lasztott k\u00f6nyvt\u00e1r megnyit\u00e1sa -FileChooser.fileDescriptionText = \u00c1ltal\u00e1nos f\u00e1jl -FileChooser.helpButtonText = S\u00fag\u00f3 -FileChooser.helpButtonToolTipText = FileChooser s\u00fag\u00f3 -FileChooser.newFolderAccessibleName = \u00daj mappa -FileChooser.newFolderErrorText = Hiba az \u00faj mappa l\u00e9trehoz\u00e1sakor -FileChooser.newFolderToolTipText = \u00daj mappa l\u00e9trehoz\u00e1sa -FileChooser.other.newFolder = \u00dajMappa -FileChooser.other.newFolder.subsequent = \u00dajMappa.{0} -FileChooser.win32.newFolder = \u00daj mappa -FileChooser.win32.newFolder.subsequent = \u00daj Mappa ({0}) -FileChooser.saveButtonText = Ment\u00e9s -FileChooser.saveButtonToolTipText = Kijel\u00f6lt f\u00e1jl ment\u00e9se -FileChooser.saveDialogTitleText = Ment\u00e9s -FileChooser.saveInLabelText = Ment\u00e9s ide: -FileChooser.updateButtonText = Friss\u00edt\u00e9s -FileChooser.updateButtonToolTipText = K\u00f6nyvt\u00e1r lista friss\u00edt\u00e9se - -#after version 1.6.6u2: - -FileChooser.detailsViewActionLabel.textAndMnemonic = R\u00e9szletek -FileChooser.detailsViewButtonToolTip.textAndMnemonic = R\u00e9szletek -FileChooser.fileAttrHeader.textAndMnemonic = Attrib\u00fatumok -FileChooser.fileDateHeader.textAndMnemonic = M\u00f3dos\u00edtva -FileChooser.fileNameHeader.textAndMnemonic = N\u00e9v -FileChooser.fileNameLabel.textAndMnemonic = F\u00e1jln\u00e9v: -FileChooser.fileSizeHeader.textAndMnemonic = M\u00e9ret -FileChooser.fileTypeHeader.textAndMnemonic = T\u00edpus -FileChooser.filesOfTypeLabel.textAndMnemonic = A k\u00f6vetkez\u0151 t\u00edpus\u00fa f\u00e1jlok: -FileChooser.folderNameLabel.textAndMnemonic = Mappa neve: -FileChooser.homeFolderToolTip.textAndMnemonic = Otthon -FileChooser.listViewActionLabel.textAndMnemonic = Lista -FileChooser.listViewButtonToolTip.textAndMnemonic = Lista -FileChooser.lookInLabel.textAndMnemonic = Keres\u00e9s ebben: -FileChooser.newFolderActionLabel.textAndMnemonic = \u00daj mappa -FileChooser.newFolderToolTip.textAndMnemonic = \u00daj mappa l\u00e9trehoz\u00e1sa -FileChooser.refreshActionLabel.textAndMnemonic = Friss\u00edt\u00e9s -FileChooser.saveInLabel.textAndMnemonic = Ment\u00e9s ide: -FileChooser.upFolderToolTip.textAndMnemonic = Egy szinttel feljebb -FileChooser.viewMenuButtonAccessibleName = N\u00e9zet men\u00fc -FileChooser.viewMenuButtonToolTipText = N\u00e9zet men\u00fc -FileChooser.viewMenuLabel.textAndMnemonic = N\u00e9zet -FileChooser.newFolderActionLabelText = \u00daj mappa -FileChooser.listViewActionLabelText = Lista -FileChooser.detailsViewActionLabelText = R\u00e9szletek -FileChooser.refreshActionLabelText = Friss\u00edt\u00e9s -FileChooser.sortMenuLabelText = Ikonok sorbarendez\u00e9se a k\u00f6vetkez\u0151 alapj\u00e1n: -FileChooser.viewMenuLabelText = N\u00e9zet -FileChooser.fileSizeKiloBytes = {0} KB -FileChooser.fileSizeMegaBytes = {0} MB -FileChooser.fileSizeGigaBytes = {0} GB -FileChooser.folderNameLabelText = Mappa neve: - -error.occured = Hiba t\u00f6rt\u00e9nt : %error% -button.abort = Megszak\u00edt -button.retry = Ism\u00e9t -button.ignore = Mell\u0151z - -font.source = Forr\u00e1s bet\u0171t\u00edpus: - -#after version 1.6.7: - -menu.export = Export\u00e1l\u00e1s -menu.general = \u00c1ltal\u00e1nos -menu.language = Nyelv - -startup.welcometo = \u00dcdv\u00f6zli a -startup.selectopen = A kezd\u00e9shez kattintson a megnyit\u00e1s ikonra a fels\u0151 panelen, vagy h\u00fazzon egy SWF f\u00e1jlt ebbe az ablakba. - -error.font.nocharacter = A kiv\u00e1lasztott forr\u00e1s bet\u0171t\u00edpus nem tartalmazza a "%char%" karaktert. - -warning.initializers = A statikus mez\u0151k \u00e9s konstansok gyakran az initializerekben vannak inicializ\u00e1lva.\nAz \u00e9rt\u00e9k szerkeszt\u00e9se csak itt \u00e1ltal\u00e1ban nem elegend\u0151! - -#after version 1.7.0u1: - -menu.tools.searchmemory = SWF-ek keres\u00e9se a mem\u00f3ri\u00e1ban -menu.file.reload = \u00dajrat\u00f6lt\u00e9s -message.confirm.reload = Ez a m\u0171velet visszavonja az \u00f6sszes nem mentett v\u00e1ltoz\u00e1st, \u00e9s \u00fajrat\u00f6lti az SWF f\u00e1jlt.\nSzeretn\u00e9 folytatni? - -dialog.selectbkcolor.title = V\u00e1lassza ki a h\u00e1tt\u00e9rsz\u00ednt az SWF megjelen\u00edt\u00e9s\u00e9hez -button.selectbkcolor.hint = H\u00e1tt\u00e9rsz\u00edn kiv\u00e1laszt\u00e1sa - -ColorChooser.okText = OK -ColorChooser.cancelText = M\u00e9gsem -ColorChooser.resetText = Alaphelyzet -ColorChooser.previewText = El\u0151n\u00e9zet -ColorChooser.swatchesNameText = Mint\u00e1k -ColorChooser.swatchesRecentText = El\u0151zm\u00e9nyek: -ColorChooser.sampleText=Minta Sz\u00f6veg Minta Sz\u00f6veg - -#after version 1.7.1: - -preview.play = Lej\u00e1tsz\u00e1s -preview.pause = Sz\u00fcnet -preview.stop = Meg\u00e1ll\u00edt\u00e1s - -message.confirm.removemultiple = Biztos benne, hogy t\u00f6r\u00f6lni k\u00edv\u00e1nja a %count% elemet\n \u00e9s az \u00f6sszes t\u0151le f\u00fcgg\u0151 objektumot ? - -menu.tools.searchcache = Keres\u00e9s a b\u00f6ng\u00e9sz\u0151 gyors\u00edt\u00f3t\u00e1r\u00e1ban - -#after version 1.7.2u2 - -error.trait.exists = "%name%" nev\u0171 jellemz\u0151 m\u00e1r l\u00e9tezik. -button.addtrait = Jellemz\u0151 hozz\u00e1ad\u00e1sa -button.font.embed = Be\u00e1gyaz... -button.yes.all = Mind -button.no.all = Egyik sem -message.font.add.exists = %char% karakter m\u00e1r l\u00e9tezik a bet\u0171t\u00edpus tagben.\nSzeretn\u00e9 lecser\u00e9lni? - -filter.gfx = ScaleForm GFx f\u00e1jlok (*.gfx) -filter.supported = Minden t\u00e1mogatott f\u00e1jlt\u00edpus -work.canceled = Megszak\u00edtva -work.restoringControlFlow = Vez\u00e9rl\u00e9si-folyam helyre\u00e1ll\u00edt\u00e1s -menu.advancedsettings.advancedsettings = Halad\u00f3 be\u00e1ll\u00edt\u00e1sok -menu.recentFiles = El\u0151zm\u00e9nyek - -#after version 1.7.4 -work.restoringControlFlow.complete = Vez\u00e9rl\u00e9si-folyam helyre\u00e1ll\u00edt\u00e1s befejez\u0151d\u00f6tt -message.confirm.recentFileNotFound = F\u00e1jl nem tal\u00e1lhat\u00f3. Szeretn\u00e9 elt\u00e1vol\u00edtani az el\u0151zm\u00e9nyek k\u00f6z\u00fcl? -contextmenu.closeSwf = SWF bez\u00e1r\u00e1sa -menu.settings.autoRenameIdentifiers = Azonos\u00edt\u00f3k automatikus \u00e1tnevez\u00e9se -menu.file.saveasexe = Ment\u00e9s Exe-k\u00e9nt... -filter.exe = Futtathat\u00f3 f\u00e1jlok (*.exe) - -#after version 1.8.0 -font.updateTexts = Sz\u00f6vegek friss\u00edt\u00e9se - -#after version 1.8.0u1 -menu.file.close = Bez\u00e1r\u00e1s -menu.file.closeAll = Minden bez\u00e1r\u00e1sa -menu.tools.otherTools = Egy\u00e9b -menu.tools.otherTools.clearRecentFiles = El\u0151zm\u00e9nyek t\u00f6rl\u00e9se -fontName.name = Bet\u0171t\u00edpus megjelen\u00edtett neve: -fontName.copyright = Bet\u0171t\u00edpus szerz\u0151i jog: -button.preview = El\u0151n\u00e9zet -button.reset = Alaphelyzetbe \u00e1ll\u00edt -errors.info = INFORM\u00c1CI\u00d3K vannak a napl\u00f3ban. Kattintson ide a megjelen\u00edt\u00e9shez. -errors.warning = FIGYELMEZTET\u00c9SEK vannak a napl\u00f3ban. Kattintson ide a megjelen\u00edt\u00e9shez. - -decompilationError = Visszaford\u00edt\u00e1si hiba - -disassemblingProgress.toString = Karakterl\u00e1ncc\u00e1 alak\u00edt\u00e1s -disassemblingProgress.reading = Olvas\u00e1s -disassemblingProgress.deobfuscating = Deobfuszk\u00e1l\u00e1s - -contextmenu.moveTag = \u00c1thelyez\u00e9s ide - -filter.swc = SWC komponens f\u00e1jlok (*.swc) -filter.zip = ZIP t\u00f6m\u00f6t\u00edtett f\u00e1jlok (*.zip) -filter.binary = Bin\u00e1ris keres\u00e9s - minden f\u00e1jl (*.*) - -open.error = Hiba -open.error.fileNotFound = F\u00e1jl nem tal\u00e1lhat\u00f3 -open.error.cannotOpen = Nem lehet megnyitni a f\u00e1jlt - -node.others = egyebek - -#after version 1.8.1 -menu.tools.search = Sz\u00f6veg keres\u00e9s - -#after version 1.8.1u1 -menu.tools.timeline = Id\u0151vonal - -dialog.selectcolor.title = Sz\u00edn kiv\u00e1laszt\u00e1sa -button.selectcolor.hint = Kattintson a sz\u00edn kiv\u00e1laszt\u00e1s\u00e1hoz - -#default item name, will be used in following sentences -generictag.array.item = Elem -generictag.array.insertbeginning = %item% besz\u00far\u00e1sa az elej\u00e9re -generictag.array.insertbefore = %item% besz\u00far\u00e1sa el\u00e9 -generictag.array.remove = %item% t\u00f6rl\u00e9se -generictag.array.insertafter = %item% besz\u00far\u00e1sa m\u00f6g\u00e9 -generictag.array.insertend = %item% besz\u00far\u00e1sa a v\u00e9g\u00e9re - -#after version 2.0.0 -contextmenu.expandAll = Mindent kinyit - -filter.sounds = T\u00e1mogatott hang form\u00e1tumok (*.wav, *.mp3) -filter.sounds.wav = Hanghull\u00e1m form\u00e1tum (*.wav) -filter.sounds.mp3 = MP3 t\u00f6m\u00f6r\u00edtett form\u00e1tum (*.mp3) - -error.sound.invalid = \u00c9rv\u00e9nytelen hang. - -button.prev = El\u0151z\u0151 -button.next = K\u00f6vetkez\u0151 - -#after version 2.1.0 -message.action.playerglobal.title = PlayerGlobal k\u00f6nyvt\u00e1r sz\u00fcks\u00e9ges -message.action.playerglobal.needed = Az ActionScript 3 k\u00f6zvetlen szerkeszt\u00e9s\u00e9hez a "PlayerGlobal.swc" nev\u0171 k\u00f6nyvt\u00e1rra van sz\u00fcks\u00e9g, melyet az Adobe honlapj\u00e1r\u00f3l lehet let\u00f6lteni.\r\n%adobehomepage%\r\nNyomjon OK-t a let\u00f6lt\u00e9si oldal megnyit\u00e1s\u00e1hoz. -message.action.playerglobal.place = T\u00f6ltse le a PlayerGlobal(.swc) nev\u0171 k\u00f6nyvt\u00e1rat \u00e9s helyezze el a k\u00f6vetkez\u0151 mapp\u00e1ban:\r\n%libpath%\r\n Nyomjon OK-t a folytat\u00e1shoz. - -message.confirm.experimental.function = Ez egy K\u00cdS\u00c9RLETI funkci\u00f3. Ez azt jelenti, hogy nem szabad megb\u00edzni az eredm\u00e9ny\u00e9ben \u00e9s az SWF file m\u0171k\u00f6d\u00e9sk\u00e9ptelen lehet a ment\u00e9s ut\u00e1n. -message.confirm.donotshowagain = Ne mutassa \u00fajra - -menu.import = Import\u00e1l\u00e1s -menu.file.import.text = Sz\u00f6veg import\u00e1l\u00e1sa -import.select.directory = V\u00e1lassza ki a mapp\u00e1t az import\u00e1l\u00e1shoz -error.text.import = Hiba sz\u00f6veg import\u00e1l\u00e1s k\u00f6zben. Folytatja? - -#after version 2.1.1 -contextmenu.removeWithDependencies = Elt\u00e1vol\u00edt\u00e1s a f\u00fcgg\u0151s\u00e9gekkel egy\u00fctt - -abc.action.find-usages = Haszn\u00e1l\u00f3k keres\u00e9se -abc.action.find-declaration = Deklar\u00e1ci\u00f3 keres\u00e9se - -contextmenu.rawEdit = Nyers szerkeszt\u00e9s -contextmenu.jumpToCharacter = Ugr\u00e1s a karakterhez - -menu.settings.dumpView = Dump n\u00e9zet - -menu.view = N\u00e9zet -menu.file.view.resources = Er\u0151forr\u00e1sok -menu.file.view.hex = Hexa dump - -node.header = fejl\u00e9c - -header.signature = Al\u00e1\u00edr\u00e1s: -header.compression = T\u00f6m\u00f6r\u00edt\u00e9s: -header.compression.lzma = LZMA -header.compression.zlib = ZLIB -header.compression.none = Nincs t\u00f6m\u00f6t\u00edtve -header.version = SWF Verzi\u00f3: -header.gfx = GFX: -header.filesize = F\u00e1jl m\u00e9ret: -header.framerate = K\u00e9pfriss\u00edt\u00e9s: -header.framecount = Keret sz\u00e1m: -header.displayrect = Megjelen\u00edt\u00e9si t\u00e9glalap: -header.displayrect.value.twips = %xmin%,%ymin% => %xmax%,%ymax% twip -header.displayrect.value.pixels = %xmin%,%ymin% => %xmax%,%ymax% k\u00e9ppont - -#after version 2.1.2 -contextmenu.saveToFile = Ment\u00e9s f\u00e1jlba -contextmenu.parseActions = Action-\u00f6k elemz\u00e9se -contextmenu.parseABC = ABC elemz\u00e9se -contextmenu.parseInstructions = AVM2 utas\u00edt\u00e1sok elemz\u00e9se - -#after version 2.1.3 -menu.deobfuscation = AS1/2 Deobfuszk\u00e1l\u00e1s -menu.file.deobfuscation.old = R\u00e9gi -menu.file.deobfuscation.new = \u00daj - -#after version 2.1.4 -contextmenu.openswfinside = Bels\u0151 SWF megnyit\u00e1sa -binarydata.swfInside = \u00dagy n\u00e9z ki, hogy egy SWF van ebben a bin\u00e1ris adat tagben. Kattintson ide az al-f\u00e1ba val\u00f3 bet\u00f6lt\u00e9shez. - -#after version 3.0.0 -button.zoomin.hint = Nagy\u00edt\u00e1s -button.zoomout.hint = Kicsiny\u00edt\u00e1s -button.zoomfit.hint = Kit\u00f6lt\u00e9s -button.zoomnone.hint = Eredeti m\u00e9ret -button.snapshot.hint = Pillanatk\u00e9p k\u00e9sz\u00edt\u00e9se a v\u00e1g\u00f3lapra - -editorTruncateWarning = A sz\u00f6veg le lett v\u00e1gva a %chars%. karaktern\u00e9l hibakeres\u00e9si m\u00f3dban. - -font.name.intag = Bet\u0171t\u00edpus n\u00e9v a tag-ben: - -menu.debugger = Hibakeres\u0151 -menu.debugger.switch = Hibakeres\u0151 -menu.debugger.replacetrace = "Trace" h\u00edv\u00e1sok cser\u00e9je -menu.debugger.showlog = Napl\u00f3 mutat\u00e1sa - -message.debugger = Ez az SWF Hibakeres\u0151 arra haszn\u00e1lhat\u00f3, hogy \u00fczeneteket jelen\u00edtsen meg a hibanapl\u00f3 ablakban, b\u00f6ng\u00e9s\u0151 konzolban vagy felugr\u00f3 ablakban.\r\nNem arra lett tervezve, hogy l\u00e9p\u00e9senk\u00e9nti k\u00f3dv\u00e9grehajt\u00e1st vagy t\u00f6r\u00e9spontokat lehessen l\u00e9trehozni, stb. - -contextmenu.addTag = Tag hozz\u00e1ad\u00e1sa - -deobfuscation.comment.tryenable = Tipp: Megpr\u00f3b\u00e1lhatja bekapcsolni az "Automatikus deobfuszk\u00e1l\u00e1st" a Be\u00e1ll\u00edt\u00e1sokban -deobfuscation.comment.failed = Deobfuszk\u00e1l\u00e1s be van kapcsolva, de a visszaford\u00edt\u00e1s meghi\u00fasult. Ha a f\u00e1jl NEM obfuszk\u00e1lt kapcsolja ki az "Automatikus deobfuszk\u00e1l\u00e1st" jobb eredm\u00e9nyek el\u00e9r\u00e9se \u00e9rdek\u00e9ben. - -#after version 4.0.2 -preview.nextframe = K\u00f6vetkez\u0151 keret -preview.prevframe = El\u0151z\u0151 keret -preview.gotoframe = Keretre ugr\u00e1s... - -preview.gotoframe.dialog.title = Keretre ugr\u00e1s -preview.gotoframe.dialog.message = \u00cdrja be a keret sz\u00e1m\u00e1t (%min% - %max%) -preview.gotoframe.dialog.frame.error = Hib\u00e1s keret sz\u00e1m. A k\u00f6vetkez\u0151 \u00e9rt\u00e9kek k\u00f6z\u00f6tt kell lennie: %min% \u00e9s %max%. - -error.text.invalid.continue = Hib\u00e1s sz\u00f6veg: %text% a %line%. sorban. Folytatja? - -#after version 4.0.5 -contextmenu.copyTag = M\u00e1sol\u00e1s ide -fit = kit\u00f6lt -button.setAdvanceValues = Halad\u00e1si \u00e9rt\u00e9kek be\u00e1ll\u00edt\u00e1sa - -menu.tools.replace = Sz\u00f6veg csere - -message.confirm.close = Mentetlen v\u00e1ltoz\u00e1sok vannak. Szeretm\u00e9 m\u00e9gis bez\u00e9rni a k\u00f6vetkez\u0151t: {swfName}? -message.confirm.closeAll = Mentetlen v\u00e1ltoz\u00e1sok vannak. Szeretn\u00e9 bez\u00e1rni az \u00f6sszes SWF-t ? - -contextmenu.exportJavaSource = Java k\u00f3d export\u00e1l\u00e1s -contextmenu.exportSwfXml = SWF export\u00e1l\u00e1sa XML-k\u00e9nt -contextmenu.importSwfXml = SWF XML import\u00e1l\u00e1s - -filter.xml = XML - -#after version 4.1.0 -contextmenu.undo = Visszavon\u00e1s - -text.align.left = Balra igaz\u00edt\u00e1s -text.align.right = Jobbra igaz\u00edt\u00e1s -text.align.center = K\u00f6z\u00e9pre igaz\u00edt\u00e1s -text.align.justify = Sorkiz\u00e1t - -text.undo = M\u00f3dos\u00edt\u00e1sok visszavon\u00e1sa - -menu.file.import.xml = SWF XML import\u00e1l\u00e1s -menu.file.export.xml = SWF XML export\u00e1l\u00e1s - -#after version 4.1.1 -text.align.translatex.decrease = TranslateX cs\u00f6kkent\u00e9se -text.align.translatex.increase = TranslateX n\u00f6vel\u00e9se -selectPreviousTag = El\u0151z\u0151 tag kiv\u00e1laszt\u00e1sa -selectNextTag = K\u00f6vetkez\u0151 tag kiv\u00e1laszt\u00e1sa -button.ignoreAll = Mell\u0151z mindet -menu.file.import.symbolClass = Szimb\u00f3lum oszt\u00e1ly import\u00e1l\u00e1s -text.toggleCase = Kis- nagybet\u0171 v\u00e1ltoztat\u00e1s - -#after version 5.0.2 -preview.loop = Ism\u00e9tl\u00e9s -menu.file.import.script = Szkript import\u00e1l\u00e1sa -contextmenu.copyTagWithDependencies = M\u00e1sol\u00e1s ide f\u00fcgg\u0151s\u00e9gekkel -button.replaceWithTag = Csere m\u00e1sik karakter tagre -button.resolveConstants = Konstansok felold\u00e1sa -button.viewConstants = Konstansok mutat\u00e1sa -work.exporting = Export\u00e1lva +# Copyright (C) 2010-2015 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 . + +menu.file = F\u00e1jl +menu.file.open = Megnyit\u00e1s... +menu.file.save = Ment\u00e9s +menu.file.saveas = Ment\u00e9s m\u00e1sk\u00e9nt... +menu.file.export.fla = Export\u00e1l\u00e1s FLA-ba +menu.file.export.all = Minden r\u00e9sz export\u00e1l\u00e1sa +menu.file.export.selection = Kijel\u00f6ltek export\u00e1l\u00e1sa +menu.file.exit = Kil\u00e9p\u00e9s + +menu.tools = Eszk\u00f6z\u00f6k +menu.tools.searchas = Keres\u00e9s az \u00f6sszes ActionScriptben... +menu.tools.proxy = Proxy +menu.tools.deobfuscation = Deobfuszk\u00e1l\u00e1s +menu.tools.deobfuscation.pcode = PCode deobfuszk\u00e1l\u00e1s... +menu.tools.deobfuscation.globalrename = Azonos\u00edt\u00f3k glob\u00e1lis \u00e1tnevez\u00e9se +menu.tools.deobfuscation.renameinvalid = \u00c9rv\u00e9nytelen azonos\u00edt\u00f3k \u00e1tnevez\u00e9se +menu.tools.gotodocumentclass = Dokumentum oszt\u00e1lyhoz ugr\u00e1s + +menu.settings = Be\u00e1ll\u00edt\u00e1sok +menu.settings.autodeobfuscation = Automatikus deobfuszk\u00e1l\u00e1s +menu.settings.internalflashviewer = Saj\u00e1t Flash-n\u00e9z\u0151ke haszn\u00e1lata +menu.settings.parallelspeedup = P\u00e1rhuzamos gyors\u00edt\u00e1s +menu.settings.disabledecompilation = Visszaford\u00edt\u00e1s letilt\u00e1sa (csak disassembl\u00e1l\u00e1s) +menu.settings.addtocontextmenu = FFDec hozz\u00e1rendel\u00e9se SWF f\u00e1jlokhoz a helyi men\u00fcben +menu.settings.language = Nyelv v\u00e1lt\u00e1sa +menu.settings.cacheOnDisk = Lemez gyors\u00edt\u00f3t\u00e1r haszn\u00e1lata +menu.settings.gotoMainClassOnStartup = Dokumentum oszt\u00e1ly kiemel\u00e9se ind\u00edt\u00e1skor + +menu.help = S\u00fag\u00f3 +menu.help.checkupdates = Friss\u00edt\u00e9sek keres\u00e9se... +menu.help.helpus = Seg\u00edts nek\u00fcnk! +menu.help.homepage = Honlap megnyit\u00e1sa +menu.help.about = N\u00e9vjegy... + +contextmenu.remove = Elt\u00e1vol\u00edt\u00e1s + +button.save = Ment\u00e9s +button.edit = Szerkeszt\u00e9s +button.cancel = M\u00e9gsem +button.replace = Csere... + +notavailonthisplatform = Ennek az objektumnak az el\u0151n\u00e9zete nem el\u00e9rhet\u0151 ezen a platformon. (Csak Windowson) + +swfpreview = SWF el\u0151n\u00e9zet +swfpreview.internal = SWF el\u0151n\u00e9zet (Be\u00e9p\u00edtett n\u00e9z\u0151ke) + +parameters = Param\u00e9terek + +rename.enternew = \u00cdrja be az \u00faj nevet: + +rename.finished.identifier = Azonos\u00edt\u00f3 \u00e1tnevezve. +rename.finished.multiname = %count% multiname \u00e1tnevezve. + +node.texts = sz\u00f6vegek +node.images = k\u00e9pek +node.movies = mozg\u00f3k\u00e9pek +node.sounds = hangok +node.binaryData = bin\u00e1ris adatok +node.fonts = bet\u0171t\u00edpusok +node.sprites = szpr\u00e1jtok +node.shapes = alakzatok +node.morphshapes = morph alakzatok +node.buttons = gombok +node.frames = keretek +node.scripts = szkriptek + +message.warning = Figyelmeztet\u00e9s +message.confirm.experimental = A k\u00f6vetkez\u0151 m\u0171velet k\u00e1ros\u00edthatja az SWF f\u00e1jlt, ami ezut\u00e1n lej\u00e1tszhatatlan lesz.\r\nCSAK SAJ\u00c1T FELEL\u0150SS\u00c9GRE HASZN\u00c1LJA. Szeretn\u00e9 folytatni? +message.confirm.parallel = P\u00e1rhuzamos\u00edt\u00e1s felgyors\u00edthatja a bet\u00f6lt\u00e9st \u00e9s visszaford\u00edt\u00e1st, de t\u00f6bb mem\u00f3ri\u00e1t haszn\u00e1l. +message.confirm.on = BE szeretn\u00e9 kapcsolni? +message.confirm.off = KI szeretn\u00e9 kapcsolni? +message.confirm = Meger\u0151s\u00edt\u00e9s + +message.confirm.autodeobfuscate = Automatikus deobfuszk\u00e1l\u00e1s egy m\u00f3d az obfuszk\u00e1lt k\u00f3d visszaford\u00edt\u00e1s\u00e1ra.\r\nDeobfuszk\u00e1l\u00e1s lassabb visszaford\u00edt\u00e1st eredm\u00e9nyez, \u00e9s n\u00e9h\u00e1ny halott k\u00f3dr\u00e9szlet elt\u00e1vol\u00edt\u00e1sra ker\u00fclhet.\r\nHa a k\u00f3d nincs obfuszk\u00e1lva jobb kikapcsolni az automatikus deobfuszk\u00e1l\u00e1st. + +message.parallel = P\u00e1rhuzamos\u00edt\u00e1s +message.trait.saved = Jellemz\u0151 sikeresen lementve + +message.constant.new.string = Karakterl\u00e1nc "%value%" nem tal\u00e1lhat\u00f3 a konstans t\u00e1bl\u00e1ban. Szeretn\u00e9 hozz\u00e1adni? +message.constant.new.string.title = Karakterl\u00e1nc hozz\u00e1ad\u00e1sa +message.constant.new.integer = Eg\u00e9sz \u00e9rt\u00e9k "%value%" nem tal\u00e1lhat\u00f3 a konstans t\u00e1bl\u00e1ban. Szeretn\u00e9 hozz\u00e1adni? +message.constant.new.integer.title = Eg\u00e9sz hozz\u00e1ad\u00e1sa +message.constant.new.unsignedinteger = El\u0151jel n\u00e9lk\u00fcli eg\u00e9sz \u00e9rt\u00e9k "%value%" nem tal\u00e1lhat\u00f3 a konstans t\u00e1bl\u00e1ban. Szeretn\u00e9 hozz\u00e1adni? +message.constant.new.unsignedinteger.title = El\u0151jel n\u00e9lk\u00fcli eg\u00e9sz hozz\u00e1ad\u00e1sa +message.constant.new.double = Lebeg\u0151pontos \u00e9rt\u00e9k "%value%" nem tal\u00e1lhat\u00f3 a konstans t\u00e1bl\u00e1ban. Szeretn\u00e9 hozz\u00e1adni? +message.constant.new.double.title = Lebeg\u0151pontos \u00e9rt\u00e9k hozz\u00e1ad\u00e1sa + +work.buffering = Pufferel\u00e9s +work.waitingfordissasembly = V\u00e1rakoz\u00e1s a visszafejt\u00e9sre +work.gettinghilights = Kiemel\u00e9sek elk\u00e9sz\u00edt\u00e9se +work.disassembling = Visszafejt\u00e9s +work.exporting = Export\u00e1l\u00e1s +work.searching = Keres\u00e9s +work.renaming = \u00c1tnevez\u00e9s +work.exporting.fla = Export\u00e1l\u00e1s FLA-ba +work.renaming.identifiers = Azonos\u00edt\u00f3k \u00e1tnevez\u00e9se +work.deobfuscating = Deobfuszk\u00e1l\u00e1s +work.decompiling = Visszaford\u00edt\u00e1s +work.gettingvariables = V\u00e1ltoz\u00f3k kinyer\u00e9se +work.reading.swf = SWF olvas\u00e1sa +work.creatingwindow = Ablak elk\u00e9sz\u00edt\u00e9se +work.buildingscripttree = Szkript fa \u00e9p\u00edt\u00e9se + +work.deobfuscating.complete = Deobfuszk\u00e1l\u00e1s k\u00e9sz + +message.search.notfound = Karakterl\u00e1nc "%searchtext%" nem tal\u00e1lhat\u00f3. +message.search.notfound.title = Nem tal\u00e1lhat\u00f3 + +message.rename.notfound.multiname = Multiname nem tal\u00e1lkat\u00f3 a kurzor alatt +message.rename.notfound.identifier = Azonos\u00edt\u00f3 nem tal\u00e1lhat\u00f3 a kurzor alatt +message.rename.notfound.title = Nem tal\u00e1lhat\u00f3 +message.rename.renamed = %count% azonos\u00edt\u00f3 \u00e1tnevezve + +filter.images = K\u00e9pek (*.jpg,*.gif,*.png,*.bmp) +filter.fla = %version% Dokumentum (*.fla) +filter.xfl = %version% T\u00f6m\u00f6r\u00edtetlen dokumentum (*.xfl) +filter.swf = SWF f\u00e1ljok (*.swf) + +error = Hiba +error.image.invalid = \u00c9rv\u00e9nytelen k\u00e9p. + +error.text.invalid = \u00c9rv\u00e9nytelen sz\u00f6veg: %text% a %line%. sorban +error.file.save = A f\u00e1jl nem menthet\u0151 +error.file.write = A f\u00e1lj nem \u00edrhat\u00f3 +error.export = Hiba export\u00e1l\u00e1s k\u00f6zben + +export.select.directory = V\u00e1lassza ki a mapp\u00e1t az export\u00e1l\u00e1shoz +export.finishedin = %time% alatt export\u00e1lva + +update.check.title = Friss\u00edt\u00e9s ellen\u0151rz\u00e9se +update.check.nonewversion = \u00dajabb verzi\u00f3 nem el\u00e9rhet\u0151. + +message.helpus = Tov\u00e1bbi r\u00e9szletek\u00e9rt k\u00e9rem l\u00e1togassa meg a(z)\r\n%url%\r\nweboldalt. +message.homepage = L\u00e1togassa meg a honlapot a k\u00f6vetkez\u0151 c\u00edmen: \r\n%url% + +proxy = Proxy +proxy.start = Proxy elind\u00edt\u00e1sa +proxy.stop = Proxy le\u00e1ll\u00edt\u00e1sa +proxy.show = Proxy megjelen\u00edt\u00e9se +exit = Kil\u00e9p\u00e9s + +panel.disassembled = P-code forr\u00e1s +panel.decompiled = ActionScript forr\u00e1s + +search.info = "%text%" sz\u00f6veg keres\u00e9se: +search.script = Szkript + +constants = Konstansok +traits = Jellemz\u0151k + +pleasewait = K\u00e9rem v\u00e1rjon + +abc.detail.methodtrait = Met\u00f3dus/Getter/Setter Jellemz\u0151 +abc.detail.unsupported = - +abc.detail.slotconsttrait = Slot/Konstans Jellemz\u0151 +abc.detail.traitname = N\u00e9v: + +abc.detail.body.params.maxstack = Maximum stack: +abc.detail.body.params.localregcount = Lok\u00e1lis regiszterek sz\u00e1ma: +abc.detail.body.params.minscope = \u00c9rv\u00e9nyess\u00e9gi k\u00f6r minimum m\u00e9lys\u00e9ge: +abc.detail.body.params.maxscope = \u00c9rv\u00e9nyess\u00e9gi k\u00f6r maximum m\u00e9lys\u00e9ge: +abc.detail.body.params.autofill = Automatikus kit\u00f6lt\u00e9s k\u00f3d ment\u00e9sekor (GLOB\u00c1LIS BE\u00c1LL\u00cdT\u00c1S) +abc.detail.body.params.autofill.experimental = ...K\u00cdS\u00c9RLETI + +abc.detail.methodinfo.methodindex = Met\u00f3dus Index: +abc.detail.methodinfo.parameters = Param\u00e9terek: +abc.detail.methodinfo.returnvalue = Visszat\u00e9r\u00e9si \u00e9rt\u00e9k t\u00edpusa: + +error.methodinfo.params = MethodInfo Param\u00e9ter Hiba +error.methodinfo.returnvalue = MethodInfo Visszat\u00e9r\u00e9si \u00e9rt\u00e9k Hiba + +abc.detail.methodinfo = MethodInfo +abc.detail.body.code = MethodBody K\u00f3d +abc.detail.body.params = MethodBody param\u00e9terek + +abc.detail.slotconst.typevalue = T\u00edpus \u00e9s \u00c9rt\u00e9k: + +error.slotconst.typevalue = SlotConst t\u00edpus\u00e9rt\u00e9k Hiba + +message.autofill.failed = K\u00f3d statisztika nem el\u00e9rhet\u0151 az automatikus t\u00f6rzs param\u00e9terekhez.\r\nVegye ki a pip\u00e1t az az automatikus kit\u00f6lt\u00e9s mell\u0151l ennek az \u00fczenetnek az elket\u00fcl\u00e9s\u00e9hez. +info.selecttrait = V\u00e1lasszon ki egy oszt\u00e1lyt \u00e9s kattintson egy jellemz\u0151re az ActionScript forr\u00e1sban a szerkeszt\u00e9shez. + +button.viewgraph = Gr\u00e1f mutat\u00e1sa +button.viewhex = Hexa mutat\u00e1sa + +abc.traitslist.instanceinitializer = p\u00e9ld\u00e1ny inicializ\u00e1l\u00f3 +abc.traitslist.classinitializer = oszt\u00e1ly inicializ\u00e1l\u00f3 + +action.edit.experimental = (K\u00eds\u00e9rleti) + +message.action.saved = K\u00f3d sikeresen lementve + +error.action.save = %error% a %line%. sorban + +message.confirm.remove = Biztos benne, hogy t\u00f6r\u00f6lni k\u00edv\u00e1nja a %item%-t \n \u00e9s az \u00f6sszes t\u0151le f\u00fcgg\u0151 objektumot ? + +#after version 1.6.5u1: + +button.ok = OK +button.cancel = M\u00e9gse + +font.name = Bet\u0171t\u00edpus neve: +font.isbold = F\u00e9lk\u00f6v\u00e9r: +font.isitalic = D\u0151lt: +font.ascent = Fels\u0151 index: +font.descent = Als\u00f3 index: +font.leading = Sork\u00f6z: +font.characters = Karakterek: +font.characters.add = Karakter hozz\u00e1ad\u00e1sa: +value.unknown = ? + +yes = igen +no = nem + +errors.present = HIB\u00c1K vannak a napl\u00f3ban. Kattintson ide a megjelen\u00edt\u00e9shez. +errors.none = Nincsenek hib\u00e1k a napl\u00f3ban + +#after version 1.6.6: + +dialog.message.title = \u00dczenet +dialog.select.title = V\u00e1lasszon egy lehet\u0151s\u00e9get + +button.yes = Igen +button.no = Nem + +FileChooser.openButtonText = Megnyit\u00e1s +FileChooser.openButtonToolTipText = Megnyit\u00e1s +FileChooser.lookInLabelText = Keres\u00e9s ebben: +FileChooser.acceptAllFileFilterText = Minden f\u00e1jlt\u00edpus +FileChooser.filesOfTypeLabelText = A k\u00f6vetkez\u0151 t\u00edpus\u00fa f\u00e1jlok: +FileChooser.fileNameLabelText = F\u00e1jln\u00e9v: +FileChooser.listViewButtonToolTipText = Lista +FileChooser.listViewButtonAccessibleName = Lista +FileChooser.detailsViewButtonToolTipText = R\u00e9szletek +FileChooser.detailsViewButtonAccessibleName = R\u00e9szletek +FileChooser.upFolderToolTipText = Egy szinttel feljebb +FileChooser.upFolderAccessibleName = Egy szinttel feljebb +FileChooser.homeFolderToolTipText = Otthon +FileChooser.homeFolderAccessibleName = Otthon +FileChooser.fileNameHeaderText = N\u00e9v +FileChooser.fileSizeHeaderText = M\u00e9ret +FileChooser.fileTypeHeaderText = T\u00edpus +FileChooser.fileDateHeaderText = D\u00e1tum +FileChooser.fileAttrHeaderText = Tulajdons\u00e1gok +FileChooser.openDialogTitleText = Megnyit\u00e1s +FileChooser.directoryDescriptionText = K\u00f6nyvt\u00e1r +FileChooser.directoryOpenButtonText = Megnyit\u00e1s +FileChooser.directoryOpenButtonToolTipText = A kiv\u00e1lasztott k\u00f6nyvt\u00e1r megnyit\u00e1sa +FileChooser.fileDescriptionText = \u00c1ltal\u00e1nos f\u00e1jl +FileChooser.helpButtonText = S\u00fag\u00f3 +FileChooser.helpButtonToolTipText = FileChooser s\u00fag\u00f3 +FileChooser.newFolderAccessibleName = \u00daj mappa +FileChooser.newFolderErrorText = Hiba az \u00faj mappa l\u00e9trehoz\u00e1sakor +FileChooser.newFolderToolTipText = \u00daj mappa l\u00e9trehoz\u00e1sa +FileChooser.other.newFolder = \u00dajMappa +FileChooser.other.newFolder.subsequent = \u00dajMappa.{0} +FileChooser.win32.newFolder = \u00daj mappa +FileChooser.win32.newFolder.subsequent = \u00daj Mappa ({0}) +FileChooser.saveButtonText = Ment\u00e9s +FileChooser.saveButtonToolTipText = Kijel\u00f6lt f\u00e1jl ment\u00e9se +FileChooser.saveDialogTitleText = Ment\u00e9s +FileChooser.saveInLabelText = Ment\u00e9s ide: +FileChooser.updateButtonText = Friss\u00edt\u00e9s +FileChooser.updateButtonToolTipText = K\u00f6nyvt\u00e1r lista friss\u00edt\u00e9se + +#after version 1.6.6u2: + +FileChooser.detailsViewActionLabel.textAndMnemonic = R\u00e9szletek +FileChooser.detailsViewButtonToolTip.textAndMnemonic = R\u00e9szletek +FileChooser.fileAttrHeader.textAndMnemonic = Attrib\u00fatumok +FileChooser.fileDateHeader.textAndMnemonic = M\u00f3dos\u00edtva +FileChooser.fileNameHeader.textAndMnemonic = N\u00e9v +FileChooser.fileNameLabel.textAndMnemonic = F\u00e1jln\u00e9v: +FileChooser.fileSizeHeader.textAndMnemonic = M\u00e9ret +FileChooser.fileTypeHeader.textAndMnemonic = T\u00edpus +FileChooser.filesOfTypeLabel.textAndMnemonic = A k\u00f6vetkez\u0151 t\u00edpus\u00fa f\u00e1jlok: +FileChooser.folderNameLabel.textAndMnemonic = Mappa neve: +FileChooser.homeFolderToolTip.textAndMnemonic = Otthon +FileChooser.listViewActionLabel.textAndMnemonic = Lista +FileChooser.listViewButtonToolTip.textAndMnemonic = Lista +FileChooser.lookInLabel.textAndMnemonic = Keres\u00e9s ebben: +FileChooser.newFolderActionLabel.textAndMnemonic = \u00daj mappa +FileChooser.newFolderToolTip.textAndMnemonic = \u00daj mappa l\u00e9trehoz\u00e1sa +FileChooser.refreshActionLabel.textAndMnemonic = Friss\u00edt\u00e9s +FileChooser.saveInLabel.textAndMnemonic = Ment\u00e9s ide: +FileChooser.upFolderToolTip.textAndMnemonic = Egy szinttel feljebb +FileChooser.viewMenuButtonAccessibleName = N\u00e9zet men\u00fc +FileChooser.viewMenuButtonToolTipText = N\u00e9zet men\u00fc +FileChooser.viewMenuLabel.textAndMnemonic = N\u00e9zet +FileChooser.newFolderActionLabelText = \u00daj mappa +FileChooser.listViewActionLabelText = Lista +FileChooser.detailsViewActionLabelText = R\u00e9szletek +FileChooser.refreshActionLabelText = Friss\u00edt\u00e9s +FileChooser.sortMenuLabelText = Ikonok sorbarendez\u00e9se a k\u00f6vetkez\u0151 alapj\u00e1n: +FileChooser.viewMenuLabelText = N\u00e9zet +FileChooser.fileSizeKiloBytes = {0} KB +FileChooser.fileSizeMegaBytes = {0} MB +FileChooser.fileSizeGigaBytes = {0} GB +FileChooser.folderNameLabelText = Mappa neve: + +error.occured = Hiba t\u00f6rt\u00e9nt : %error% +button.abort = Megszak\u00edt +button.retry = Ism\u00e9t +button.ignore = Mell\u0151z + +font.source = Forr\u00e1s bet\u0171t\u00edpus: + +#after version 1.6.7: + +menu.export = Export\u00e1l\u00e1s +menu.general = \u00c1ltal\u00e1nos +menu.language = Nyelv + +startup.welcometo = \u00dcdv\u00f6zli a +startup.selectopen = A kezd\u00e9shez kattintson a megnyit\u00e1s ikonra a fels\u0151 panelen, vagy h\u00fazzon egy SWF f\u00e1jlt ebbe az ablakba. + +error.font.nocharacter = A kiv\u00e1lasztott forr\u00e1s bet\u0171t\u00edpus nem tartalmazza a "%char%" karaktert. + +warning.initializers = A statikus mez\u0151k \u00e9s konstansok gyakran az initializerekben vannak inicializ\u00e1lva.\nAz \u00e9rt\u00e9k szerkeszt\u00e9se csak itt \u00e1ltal\u00e1ban nem elegend\u0151! + +#after version 1.7.0u1: + +menu.tools.searchmemory = SWF-ek keres\u00e9se a mem\u00f3ri\u00e1ban +menu.file.reload = \u00dajrat\u00f6lt\u00e9s +message.confirm.reload = Ez a m\u0171velet visszavonja az \u00f6sszes nem mentett v\u00e1ltoz\u00e1st, \u00e9s \u00fajrat\u00f6lti az SWF f\u00e1jlt.\nSzeretn\u00e9 folytatni? + +dialog.selectbkcolor.title = V\u00e1lassza ki a h\u00e1tt\u00e9rsz\u00ednt az SWF megjelen\u00edt\u00e9s\u00e9hez +button.selectbkcolor.hint = H\u00e1tt\u00e9rsz\u00edn kiv\u00e1laszt\u00e1sa + +ColorChooser.okText = OK +ColorChooser.cancelText = M\u00e9gsem +ColorChooser.resetText = Alaphelyzet +ColorChooser.previewText = El\u0151n\u00e9zet +ColorChooser.swatchesNameText = Mint\u00e1k +ColorChooser.swatchesRecentText = El\u0151zm\u00e9nyek: +ColorChooser.sampleText=Minta Sz\u00f6veg Minta Sz\u00f6veg + +#after version 1.7.1: + +preview.play = Lej\u00e1tsz\u00e1s +preview.pause = Sz\u00fcnet +preview.stop = Meg\u00e1ll\u00edt\u00e1s + +message.confirm.removemultiple = Biztos benne, hogy t\u00f6r\u00f6lni k\u00edv\u00e1nja a %count% elemet\n \u00e9s az \u00f6sszes t\u0151le f\u00fcgg\u0151 objektumot ? + +menu.tools.searchcache = Keres\u00e9s a b\u00f6ng\u00e9sz\u0151 gyors\u00edt\u00f3t\u00e1r\u00e1ban + +#after version 1.7.2u2 + +error.trait.exists = "%name%" nev\u0171 jellemz\u0151 m\u00e1r l\u00e9tezik. +button.addtrait = Jellemz\u0151 hozz\u00e1ad\u00e1sa +button.font.embed = Be\u00e1gyaz... +button.yes.all = Mind +button.no.all = Egyik sem +message.font.add.exists = %char% karakter m\u00e1r l\u00e9tezik a bet\u0171t\u00edpus tagben.\nSzeretn\u00e9 lecser\u00e9lni? + +filter.gfx = ScaleForm GFx f\u00e1jlok (*.gfx) +filter.supported = Minden t\u00e1mogatott f\u00e1jlt\u00edpus +work.canceled = Megszak\u00edtva +work.restoringControlFlow = Vez\u00e9rl\u00e9si-folyam helyre\u00e1ll\u00edt\u00e1s +menu.advancedsettings.advancedsettings = Halad\u00f3 be\u00e1ll\u00edt\u00e1sok +menu.recentFiles = El\u0151zm\u00e9nyek + +#after version 1.7.4 +work.restoringControlFlow.complete = Vez\u00e9rl\u00e9si-folyam helyre\u00e1ll\u00edt\u00e1s befejez\u0151d\u00f6tt +message.confirm.recentFileNotFound = F\u00e1jl nem tal\u00e1lhat\u00f3. Szeretn\u00e9 elt\u00e1vol\u00edtani az el\u0151zm\u00e9nyek k\u00f6z\u00fcl? +contextmenu.closeSwf = SWF bez\u00e1r\u00e1sa +menu.settings.autoRenameIdentifiers = Azonos\u00edt\u00f3k automatikus \u00e1tnevez\u00e9se +menu.file.saveasexe = Ment\u00e9s Exe-k\u00e9nt... +filter.exe = Futtathat\u00f3 f\u00e1jlok (*.exe) + +#after version 1.8.0 +font.updateTexts = Sz\u00f6vegek friss\u00edt\u00e9se + +#after version 1.8.0u1 +menu.file.close = Bez\u00e1r\u00e1s +menu.file.closeAll = Minden bez\u00e1r\u00e1sa +menu.tools.otherTools = Egy\u00e9b +menu.tools.otherTools.clearRecentFiles = El\u0151zm\u00e9nyek t\u00f6rl\u00e9se +fontName.name = Bet\u0171t\u00edpus megjelen\u00edtett neve: +fontName.copyright = Bet\u0171t\u00edpus szerz\u0151i jog: +button.preview = El\u0151n\u00e9zet +button.reset = Alaphelyzetbe \u00e1ll\u00edt +errors.info = INFORM\u00c1CI\u00d3K vannak a napl\u00f3ban. Kattintson ide a megjelen\u00edt\u00e9shez. +errors.warning = FIGYELMEZTET\u00c9SEK vannak a napl\u00f3ban. Kattintson ide a megjelen\u00edt\u00e9shez. + +decompilationError = Visszaford\u00edt\u00e1si hiba + +disassemblingProgress.toString = Karakterl\u00e1ncc\u00e1 alak\u00edt\u00e1s +disassemblingProgress.reading = Olvas\u00e1s +disassemblingProgress.deobfuscating = Deobfuszk\u00e1l\u00e1s + +contextmenu.moveTag = \u00c1thelyez\u00e9s ide + +filter.swc = SWC komponens f\u00e1jlok (*.swc) +filter.zip = ZIP t\u00f6m\u00f6t\u00edtett f\u00e1jlok (*.zip) +filter.binary = Bin\u00e1ris keres\u00e9s - minden f\u00e1jl (*.*) + +open.error = Hiba +open.error.fileNotFound = F\u00e1jl nem tal\u00e1lhat\u00f3 +open.error.cannotOpen = Nem lehet megnyitni a f\u00e1jlt + +node.others = egyebek + +#after version 1.8.1 +menu.tools.search = Sz\u00f6veg keres\u00e9s + +#after version 1.8.1u1 +menu.tools.timeline = Id\u0151vonal + +dialog.selectcolor.title = Sz\u00edn kiv\u00e1laszt\u00e1sa +button.selectcolor.hint = Kattintson a sz\u00edn kiv\u00e1laszt\u00e1s\u00e1hoz + +#default item name, will be used in following sentences +generictag.array.item = Elem +generictag.array.insertbeginning = %item% besz\u00far\u00e1sa az elej\u00e9re +generictag.array.insertbefore = %item% besz\u00far\u00e1sa el\u00e9 +generictag.array.remove = %item% t\u00f6rl\u00e9se +generictag.array.insertafter = %item% besz\u00far\u00e1sa m\u00f6g\u00e9 +generictag.array.insertend = %item% besz\u00far\u00e1sa a v\u00e9g\u00e9re + +#after version 2.0.0 +contextmenu.expandAll = Mindent kinyit + +filter.sounds = T\u00e1mogatott hang form\u00e1tumok (*.wav, *.mp3) +filter.sounds.wav = Hanghull\u00e1m form\u00e1tum (*.wav) +filter.sounds.mp3 = MP3 t\u00f6m\u00f6r\u00edtett form\u00e1tum (*.mp3) + +error.sound.invalid = \u00c9rv\u00e9nytelen hang. + +button.prev = El\u0151z\u0151 +button.next = K\u00f6vetkez\u0151 + +#after version 2.1.0 +message.action.playerglobal.title = PlayerGlobal k\u00f6nyvt\u00e1r sz\u00fcks\u00e9ges +message.action.playerglobal.needed = Az ActionScript 3 k\u00f6zvetlen szerkeszt\u00e9s\u00e9hez a "PlayerGlobal.swc" nev\u0171 k\u00f6nyvt\u00e1rra van sz\u00fcks\u00e9g, melyet az Adobe honlapj\u00e1r\u00f3l lehet let\u00f6lteni.\r\n%adobehomepage%\r\nNyomjon OK-t a let\u00f6lt\u00e9si oldal megnyit\u00e1s\u00e1hoz. +message.action.playerglobal.place = T\u00f6ltse le a PlayerGlobal(.swc) nev\u0171 k\u00f6nyvt\u00e1rat \u00e9s helyezze el a k\u00f6vetkez\u0151 mapp\u00e1ban:\r\n%libpath%\r\n Nyomjon OK-t a folytat\u00e1shoz. + +message.confirm.experimental.function = Ez egy K\u00cdS\u00c9RLETI funkci\u00f3. Ez azt jelenti, hogy nem szabad megb\u00edzni az eredm\u00e9ny\u00e9ben \u00e9s az SWF file m\u0171k\u00f6d\u00e9sk\u00e9ptelen lehet a ment\u00e9s ut\u00e1n. +message.confirm.donotshowagain = Ne mutassa \u00fajra + +menu.import = Import\u00e1l\u00e1s +menu.file.import.text = Sz\u00f6veg import\u00e1l\u00e1sa +import.select.directory = V\u00e1lassza ki a mapp\u00e1t az import\u00e1l\u00e1shoz +error.text.import = Hiba sz\u00f6veg import\u00e1l\u00e1s k\u00f6zben. Folytatja? + +#after version 2.1.1 +contextmenu.removeWithDependencies = Elt\u00e1vol\u00edt\u00e1s a f\u00fcgg\u0151s\u00e9gekkel egy\u00fctt + +abc.action.find-usages = Haszn\u00e1l\u00f3k keres\u00e9se +abc.action.find-declaration = Deklar\u00e1ci\u00f3 keres\u00e9se + +contextmenu.rawEdit = Nyers szerkeszt\u00e9s +contextmenu.jumpToCharacter = Ugr\u00e1s a karakterhez + +menu.settings.dumpView = Dump n\u00e9zet + +menu.view = N\u00e9zet +menu.file.view.resources = Er\u0151forr\u00e1sok +menu.file.view.hex = Hexa dump + +node.header = fejl\u00e9c + +header.signature = Al\u00e1\u00edr\u00e1s: +header.compression = T\u00f6m\u00f6r\u00edt\u00e9s: +header.compression.lzma = LZMA +header.compression.zlib = ZLIB +header.compression.none = Nincs t\u00f6m\u00f6t\u00edtve +header.version = SWF Verzi\u00f3: +header.gfx = GFX: +header.filesize = F\u00e1jl m\u00e9ret: +header.framerate = K\u00e9pfriss\u00edt\u00e9s: +header.framecount = Keret sz\u00e1m: +header.displayrect = Megjelen\u00edt\u00e9si t\u00e9glalap: +header.displayrect.value.twips = %xmin%,%ymin% => %xmax%,%ymax% twip +header.displayrect.value.pixels = %xmin%,%ymin% => %xmax%,%ymax% k\u00e9ppont + +#after version 2.1.2 +contextmenu.saveToFile = Ment\u00e9s f\u00e1jlba +contextmenu.parseActions = Action-\u00f6k elemz\u00e9se +contextmenu.parseABC = ABC elemz\u00e9se +contextmenu.parseInstructions = AVM2 utas\u00edt\u00e1sok elemz\u00e9se + +#after version 2.1.3 +menu.deobfuscation = AS1/2 Deobfuszk\u00e1l\u00e1s +menu.file.deobfuscation.old = R\u00e9gi +menu.file.deobfuscation.new = \u00daj + +#after version 2.1.4 +contextmenu.openswfinside = Bels\u0151 SWF megnyit\u00e1sa +binarydata.swfInside = \u00dagy n\u00e9z ki, hogy egy SWF van ebben a bin\u00e1ris adat tagben. Kattintson ide az al-f\u00e1ba val\u00f3 bet\u00f6lt\u00e9shez. + +#after version 3.0.0 +button.zoomin.hint = Nagy\u00edt\u00e1s +button.zoomout.hint = Kicsiny\u00edt\u00e1s +button.zoomfit.hint = Kit\u00f6lt\u00e9s +button.zoomnone.hint = Eredeti m\u00e9ret +button.snapshot.hint = Pillanatk\u00e9p k\u00e9sz\u00edt\u00e9se a v\u00e1g\u00f3lapra + +editorTruncateWarning = A sz\u00f6veg le lett v\u00e1gva a %chars%. karaktern\u00e9l hibakeres\u00e9si m\u00f3dban. + +font.name.intag = Bet\u0171t\u00edpus n\u00e9v a tag-ben: + +menu.debugger = Hibakeres\u0151 +menu.debugger.switch = Hibakeres\u0151 +menu.debugger.replacetrace = "Trace" h\u00edv\u00e1sok cser\u00e9je +menu.debugger.showlog = Napl\u00f3 mutat\u00e1sa + +message.debugger = Ez az SWF Hibakeres\u0151 arra haszn\u00e1lhat\u00f3, hogy \u00fczeneteket jelen\u00edtsen meg a hibanapl\u00f3 ablakban, b\u00f6ng\u00e9s\u0151 konzolban vagy felugr\u00f3 ablakban.\r\nNem arra lett tervezve, hogy l\u00e9p\u00e9senk\u00e9nti k\u00f3dv\u00e9grehajt\u00e1st vagy t\u00f6r\u00e9spontokat lehessen l\u00e9trehozni, stb. + +contextmenu.addTag = Tag hozz\u00e1ad\u00e1sa + +deobfuscation.comment.tryenable = Tipp: Megpr\u00f3b\u00e1lhatja bekapcsolni az "Automatikus deobfuszk\u00e1l\u00e1st" a Be\u00e1ll\u00edt\u00e1sokban +deobfuscation.comment.failed = Deobfuszk\u00e1l\u00e1s be van kapcsolva, de a visszaford\u00edt\u00e1s meghi\u00fasult. Ha a f\u00e1jl NEM obfuszk\u00e1lt kapcsolja ki az "Automatikus deobfuszk\u00e1l\u00e1st" jobb eredm\u00e9nyek el\u00e9r\u00e9se \u00e9rdek\u00e9ben. + +#after version 4.0.2 +preview.nextframe = K\u00f6vetkez\u0151 keret +preview.prevframe = El\u0151z\u0151 keret +preview.gotoframe = Keretre ugr\u00e1s... + +preview.gotoframe.dialog.title = Keretre ugr\u00e1s +preview.gotoframe.dialog.message = \u00cdrja be a keret sz\u00e1m\u00e1t (%min% - %max%) +preview.gotoframe.dialog.frame.error = Hib\u00e1s keret sz\u00e1m. A k\u00f6vetkez\u0151 \u00e9rt\u00e9kek k\u00f6z\u00f6tt kell lennie: %min% \u00e9s %max%. + +error.text.invalid.continue = Hib\u00e1s sz\u00f6veg: %text% a %line%. sorban. Folytatja? + +#after version 4.0.5 +contextmenu.copyTag = M\u00e1sol\u00e1s ide +fit = kit\u00f6lt +button.setAdvanceValues = Halad\u00e1si \u00e9rt\u00e9kek be\u00e1ll\u00edt\u00e1sa + +menu.tools.replace = Sz\u00f6veg csere + +message.confirm.close = Mentetlen v\u00e1ltoz\u00e1sok vannak. Szeretm\u00e9 m\u00e9gis bez\u00e9rni a k\u00f6vetkez\u0151t: {swfName}? +message.confirm.closeAll = Mentetlen v\u00e1ltoz\u00e1sok vannak. Szeretn\u00e9 bez\u00e1rni az \u00f6sszes SWF-t ? + +contextmenu.exportJavaSource = Java k\u00f3d export\u00e1l\u00e1s +contextmenu.exportSwfXml = SWF export\u00e1l\u00e1sa XML-k\u00e9nt +contextmenu.importSwfXml = SWF XML import\u00e1l\u00e1s + +filter.xml = XML + +#after version 4.1.0 +contextmenu.undo = Visszavon\u00e1s + +text.align.left = Balra igaz\u00edt\u00e1s +text.align.right = Jobbra igaz\u00edt\u00e1s +text.align.center = K\u00f6z\u00e9pre igaz\u00edt\u00e1s +text.align.justify = Sorkiz\u00e1t + +text.undo = M\u00f3dos\u00edt\u00e1sok visszavon\u00e1sa + +menu.file.import.xml = SWF XML import\u00e1l\u00e1s +menu.file.export.xml = SWF XML export\u00e1l\u00e1s + +#after version 4.1.1 +text.align.translatex.decrease = TranslateX cs\u00f6kkent\u00e9se +text.align.translatex.increase = TranslateX n\u00f6vel\u00e9se +selectPreviousTag = El\u0151z\u0151 tag kiv\u00e1laszt\u00e1sa +selectNextTag = K\u00f6vetkez\u0151 tag kiv\u00e1laszt\u00e1sa +button.ignoreAll = Mell\u0151z mindet +menu.file.import.symbolClass = Szimb\u00f3lum oszt\u00e1ly import\u00e1l\u00e1s +text.toggleCase = Kis- nagybet\u0171 v\u00e1ltoztat\u00e1s + +#after version 5.0.2 +preview.loop = Ism\u00e9tl\u00e9s +menu.file.import.script = Szkript import\u00e1l\u00e1sa +contextmenu.copyTagWithDependencies = M\u00e1sol\u00e1s ide f\u00fcgg\u0151s\u00e9gekkel +button.replaceWithTag = Csere m\u00e1sik karakter tagre +button.resolveConstants = Konstansok felold\u00e1sa + +#after version 5.1.0 +button.viewConstants = Konstansok mutat\u00e1sa +work.exporting = Export\u00e1lva +button.replaceAlphaChannel = Alfa csarotna cser\u00e9je...