spanish translation + something with the line endings

This commit is contained in:
honfika@gmail.com
2016-06-03 15:43:13 +02:00
parent 8e6da8081f
commit ababe9010f
32 changed files with 9492 additions and 9490 deletions

View File

@@ -1,111 +1,111 @@
/*
* Copyright (C) 2010-2016 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 java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Properties;
/**
*
* @author JPEXS
*/
public class ApplicationInfo {
public static final String APPLICATION_NAME = "JPEXS Free Flash Decompiler";
public static final String SHORT_APPLICATION_NAME = "FFDec";
public static final String VENDOR = "JPEXS";
public static String version = "";
public static String revision = "";
public static int version_major = 4;
public static int version_minor = 0;
public static int version_release = 0;
public static int version_build = 0;
public static boolean nightly = false;
public static String applicationVerName;
public static String shortApplicationVerName;
public static final String PROJECT_PAGE = "https://www.free-decompiler.com/flash";
/**
* URL for checking new updates
*/
public static String updateCheckUrl = "https://www.free-decompiler.com/flash/update/check/?currentVersion=<version>&currentRevision=<revision>&currentVersionMajor=<version.major>&currentVersionMinor=<version.minor>&currentVersionRelease=<version.release>&currentVersionBuild=<version.build>&currentNightly=<nightly>";
/**
* URL for doing update
*/
public static String updateUrl = "https://www.free-decompiler.com/flash/update/update/?currentVersion=<version>&currentRevision=<revision>&currentVersionMajor=<version.major>&currentVersionMinor=<version.minor>&currentVersionRelease=<version.release>&currentVersionBuild=<version.build>&currentNightly=<nightly>";
static {
loadProperties();
}
private static void loadProperties() {
Properties prop = new Properties();
try {
prop.load(ApplicationInfo.class.getResourceAsStream("/project.properties"));
version = prop.getProperty("version");
revision = prop.getProperty("build");
version_major = Integer.parseInt(prop.getProperty("version.major"));
version_minor = Integer.parseInt(prop.getProperty("version.minor"));
version_release = Integer.parseInt(prop.getProperty("version.release"));
version_build = Integer.parseInt(prop.getProperty("version.build"));
nightly = prop.getProperty("nightly").equals("true");
if (nightly) {
version = version + " nightly build " + version_build;
}
} catch (IOException | NullPointerException | NumberFormatException ex) {
// ignore
version = "unknown";
}
try {
updateCheckUrl = updateCheckUrl
.replace("<revision>", URLEncoder.encode(revision, "UTF-8"))
.replace("<version>", URLEncoder.encode(version, "UTF-8"))
.replace("<version.major>", "" + version_major)
.replace("<version.minor>", "" + version_minor)
.replace("<version.release>", "" + version_release)
.replace("<version.build>", "" + version_build)
.replace("<nightly>", nightly ? "1" : "0");
updateUrl = updateUrl
.replace("<revision>", URLEncoder.encode(revision, "UTF-8"))
.replace("<version>", URLEncoder.encode(version, "UTF-8"))
.replace("<version.major>", "" + version_major)
.replace("<version.minor>", "" + version_minor)
.replace("<version.release>", "" + version_release)
.replace("<version.build>", "" + version_build)
.replace("<nightly>", nightly ? "1" : "0");
} catch (UnsupportedEncodingException e) {
}
applicationVerName = APPLICATION_NAME + " v." + version;
shortApplicationVerName = SHORT_APPLICATION_NAME + " v." + version;
}
}
/*
* Copyright (C) 2010-2016 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 java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Properties;
/**
*
* @author JPEXS
*/
public class ApplicationInfo {
public static final String APPLICATION_NAME = "JPEXS Free Flash Decompiler";
public static final String SHORT_APPLICATION_NAME = "FFDec";
public static final String VENDOR = "JPEXS";
public static String version = "";
public static String revision = "";
public static int version_major = 4;
public static int version_minor = 0;
public static int version_release = 0;
public static int version_build = 0;
public static boolean nightly = false;
public static String applicationVerName;
public static String shortApplicationVerName;
public static final String PROJECT_PAGE = "https://www.free-decompiler.com/flash";
/**
* URL for checking new updates
*/
public static String updateCheckUrl = "https://www.free-decompiler.com/flash/update/check/?currentVersion=<version>&currentRevision=<revision>&currentVersionMajor=<version.major>&currentVersionMinor=<version.minor>&currentVersionRelease=<version.release>&currentVersionBuild=<version.build>&currentNightly=<nightly>";
/**
* URL for doing update
*/
public static String updateUrl = "https://www.free-decompiler.com/flash/update/update/?currentVersion=<version>&currentRevision=<revision>&currentVersionMajor=<version.major>&currentVersionMinor=<version.minor>&currentVersionRelease=<version.release>&currentVersionBuild=<version.build>&currentNightly=<nightly>";
static {
loadProperties();
}
private static void loadProperties() {
Properties prop = new Properties();
try {
prop.load(ApplicationInfo.class.getResourceAsStream("/project.properties"));
version = prop.getProperty("version");
revision = prop.getProperty("build");
version_major = Integer.parseInt(prop.getProperty("version.major"));
version_minor = Integer.parseInt(prop.getProperty("version.minor"));
version_release = Integer.parseInt(prop.getProperty("version.release"));
version_build = Integer.parseInt(prop.getProperty("version.build"));
nightly = prop.getProperty("nightly").equals("true");
if (nightly) {
version = version + " nightly build " + version_build;
}
} catch (IOException | NullPointerException | NumberFormatException ex) {
// ignore
version = "unknown";
}
try {
updateCheckUrl = updateCheckUrl
.replace("<revision>", URLEncoder.encode(revision, "UTF-8"))
.replace("<version>", URLEncoder.encode(version, "UTF-8"))
.replace("<version.major>", "" + version_major)
.replace("<version.minor>", "" + version_minor)
.replace("<version.release>", "" + version_release)
.replace("<version.build>", "" + version_build)
.replace("<nightly>", nightly ? "1" : "0");
updateUrl = updateUrl
.replace("<revision>", URLEncoder.encode(revision, "UTF-8"))
.replace("<version>", URLEncoder.encode(version, "UTF-8"))
.replace("<version.major>", "" + version_major)
.replace("<version.minor>", "" + version_minor)
.replace("<version.release>", "" + version_release)
.replace("<version.build>", "" + version_build)
.replace("<nightly>", nightly ? "1" : "0");
} catch (UnsupportedEncodingException e) {
}
applicationVerName = APPLICATION_NAME + " v." + version;
shortApplicationVerName = SHORT_APPLICATION_NAME + " v." + version;
}
}

View File

@@ -1,62 +1,62 @@
/*
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
*/
package com.jpexs.decompiler.flash;
import com.jpexs.decompiler.flash.tags.Tag;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
*
* @author JPEXS
*/
public class ReadOnlyTagList implements Iterable<Tag> {
public static final ReadOnlyTagList EMPTY = new ReadOnlyTagList(new ArrayList<>());
private final List<Tag> list;
public ReadOnlyTagList(List<Tag> list) {
this.list = list;
}
@Override
public Iterator<Tag> iterator() {
return list.iterator();
}
public int size() {
return list.size();
}
public boolean isEmpty() {
return list.isEmpty();
}
public Tag get(int index) {
return list.get(index);
}
public int indexOf(Tag tag) {
return list.indexOf(tag);
}
public ArrayList<Tag> toArrayList() {
return new ArrayList<>(list);
}
}
/*
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
*/
package com.jpexs.decompiler.flash;
import com.jpexs.decompiler.flash.tags.Tag;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
*
* @author JPEXS
*/
public class ReadOnlyTagList implements Iterable<Tag> {
public static final ReadOnlyTagList EMPTY = new ReadOnlyTagList(new ArrayList<>());
private final List<Tag> list;
public ReadOnlyTagList(List<Tag> list) {
this.list = list;
}
@Override
public Iterator<Tag> iterator() {
return list.iterator();
}
public int size() {
return list.size();
}
public boolean isEmpty() {
return list.isEmpty();
}
public Tag get(int index) {
return list.get(index);
}
public int indexOf(Tag tag) {
return list.indexOf(tag);
}
public ArrayList<Tag> toArrayList() {
return new ArrayList<>(list);
}
}

View File

@@ -1,157 +1,157 @@
/*
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
*/
package com.jpexs.decompiler.flash;
import com.jpexs.helpers.Helper;
import com.jpexs.helpers.MemoryInputStream;
import com.jpexs.helpers.PosMarkedInputStream;
import com.jpexs.helpers.ProgressListener;
import com.jpexs.helpers.Searchable;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
*
* @author JPEXS
*/
public class SWFSearch {
protected Searchable s;
private final boolean noCheck;
private final SearchMode searchMode;
private boolean processed = false;
private final Set<ProgressListener> listeners = new HashSet<>();
private final Map<Long, MemoryInputStream> swfStreams = new HashMap<>();
public SWFSearch(Searchable s, boolean noCheck, SearchMode searchMode) {
this.s = s;
this.noCheck = noCheck;
this.searchMode = searchMode;
}
public void addProgressListener(ProgressListener l) {
listeners.add(l);
}
public void removeProgressListener(ProgressListener l) {
listeners.remove(l);
}
private void setProgress(int p) {
for (ProgressListener l : listeners) {
l.progress(p);
}
}
public void process() {
Map<Long, InputStream> ret;
ret = s.search(new ProgressListener() {
@Override
public void progress(int p) {
setProgress(p);
}
},
"FWS".getBytes(), // Uncompressed Flash
"CWS".getBytes(), // ZLib compressed Flash
"ZWS".getBytes(), // LZMA compressed Flash
"GFX".getBytes(), // Uncompressed ScaleForm GFx
"CFX".getBytes()); // Compressed ScaleForm GFx
int pos = 0;
long biggestSize = 0;
long smallestSize = Long.MAX_VALUE;
addressLoop:
for (Long addr : ret.keySet()) {
setProgress(pos * 100 / ret.size());
pos++;
try {
MemoryInputStream mis = (MemoryInputStream) ret.get(addr);
mis.reset();
PosMarkedInputStream pmi = new PosMarkedInputStream(mis);
SWF swf = noCheck ? new SWF(pmi) : new SWF(pmi, null, null, null, false, true, true);
boolean valid = swf.fileSize > 0
&& swf.version > 0
&& (!swf.getTags().isEmpty() || noCheck)
&& swf.version <= SWF.MAX_VERSION;
if (valid) {
long limit = pmi.getPos();
MemoryInputStream is = new MemoryInputStream(mis.getAllRead(), (int) (long) addr, (int) limit);
switch (searchMode) {
case ALL:
swfStreams.put(addr, is);
break;
case BIGGEST:
if (limit > biggestSize) {
biggestSize = limit;
swfStreams.clear();
swfStreams.put(addr, is);
}
break;
case SMALLEST:
if (limit < smallestSize) {
smallestSize = limit;
swfStreams.clear();
swfStreams.put(addr, is);
}
break;
case FIRST:
swfStreams.put(addr, is);
break addressLoop;
case LAST:
swfStreams.clear();
swfStreams.put(addr, is);
break;
}
}
} catch (OutOfMemoryError ome) {
Helper.freeMem();
} catch (Exception | Error ex) {
}
}
setProgress(100);
processed = true;
}
public MemoryInputStream get(ProgressListener listener, long address) throws IOException {
if (!processed) {
return null;
}
if (!swfStreams.containsKey(address)) {
return null;
}
return swfStreams.get(address);
}
public Set<Long> getAddresses() {
return swfStreams.keySet();
}
public int length() {
if (!processed) {
return 0;
}
return swfStreams.size();
}
}
/*
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
*/
package com.jpexs.decompiler.flash;
import com.jpexs.helpers.Helper;
import com.jpexs.helpers.MemoryInputStream;
import com.jpexs.helpers.PosMarkedInputStream;
import com.jpexs.helpers.ProgressListener;
import com.jpexs.helpers.Searchable;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
*
* @author JPEXS
*/
public class SWFSearch {
protected Searchable s;
private final boolean noCheck;
private final SearchMode searchMode;
private boolean processed = false;
private final Set<ProgressListener> listeners = new HashSet<>();
private final Map<Long, MemoryInputStream> swfStreams = new HashMap<>();
public SWFSearch(Searchable s, boolean noCheck, SearchMode searchMode) {
this.s = s;
this.noCheck = noCheck;
this.searchMode = searchMode;
}
public void addProgressListener(ProgressListener l) {
listeners.add(l);
}
public void removeProgressListener(ProgressListener l) {
listeners.remove(l);
}
private void setProgress(int p) {
for (ProgressListener l : listeners) {
l.progress(p);
}
}
public void process() {
Map<Long, InputStream> ret;
ret = s.search(new ProgressListener() {
@Override
public void progress(int p) {
setProgress(p);
}
},
"FWS".getBytes(), // Uncompressed Flash
"CWS".getBytes(), // ZLib compressed Flash
"ZWS".getBytes(), // LZMA compressed Flash
"GFX".getBytes(), // Uncompressed ScaleForm GFx
"CFX".getBytes()); // Compressed ScaleForm GFx
int pos = 0;
long biggestSize = 0;
long smallestSize = Long.MAX_VALUE;
addressLoop:
for (Long addr : ret.keySet()) {
setProgress(pos * 100 / ret.size());
pos++;
try {
MemoryInputStream mis = (MemoryInputStream) ret.get(addr);
mis.reset();
PosMarkedInputStream pmi = new PosMarkedInputStream(mis);
SWF swf = noCheck ? new SWF(pmi) : new SWF(pmi, null, null, null, false, true, true);
boolean valid = swf.fileSize > 0
&& swf.version > 0
&& (!swf.getTags().isEmpty() || noCheck)
&& swf.version <= SWF.MAX_VERSION;
if (valid) {
long limit = pmi.getPos();
MemoryInputStream is = new MemoryInputStream(mis.getAllRead(), (int) (long) addr, (int) limit);
switch (searchMode) {
case ALL:
swfStreams.put(addr, is);
break;
case BIGGEST:
if (limit > biggestSize) {
biggestSize = limit;
swfStreams.clear();
swfStreams.put(addr, is);
}
break;
case SMALLEST:
if (limit < smallestSize) {
smallestSize = limit;
swfStreams.clear();
swfStreams.put(addr, is);
}
break;
case FIRST:
swfStreams.put(addr, is);
break addressLoop;
case LAST:
swfStreams.clear();
swfStreams.put(addr, is);
break;
}
}
} catch (OutOfMemoryError ome) {
Helper.freeMem();
} catch (Exception | Error ex) {
}
}
setProgress(100);
processed = true;
}
public MemoryInputStream get(ProgressListener listener, long address) throws IOException {
if (!processed) {
return null;
}
if (!swfStreams.containsKey(address)) {
return null;
}
return swfStreams.get(address);
}
public Set<Long> getAddresses() {
return swfStreams.keySet();
}
public int length() {
if (!processed) {
return 0;
}
return swfStreams.size();
}
}

View File

@@ -1,61 +1,61 @@
/*
* Copyright (C) 2010-2016 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.abc.avm2.model;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
import com.jpexs.decompiler.graph.DottedChain;
import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.TypeItem;
import com.jpexs.decompiler.graph.model.LocalData;
import java.util.List;
/**
*
* @author JPEXS
*/
public class XMLAVM2Item extends AVM2Item {
public List<GraphTargetItem> parts;
public XMLAVM2Item(GraphSourceItem instruction, GraphSourceItem lineStartIns, List<GraphTargetItem> parts) {
super(instruction, lineStartIns, NOPRECEDENCE);
this.parts = parts;
}
@Override
public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException {
for (GraphTargetItem part : parts) {
if (part instanceof StringAVM2Item) {
writer.append(((StringAVM2Item) part).getValue());
} else {
part.toString(writer, localData);
}
}
return writer;
}
@Override
public GraphTargetItem returnType() {
return new TypeItem(DottedChain.XML);
}
@Override
public boolean hasReturnValue() {
return true;
}
}
/*
* Copyright (C) 2010-2016 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.abc.avm2.model;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
import com.jpexs.decompiler.graph.DottedChain;
import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.TypeItem;
import com.jpexs.decompiler.graph.model.LocalData;
import java.util.List;
/**
*
* @author JPEXS
*/
public class XMLAVM2Item extends AVM2Item {
public List<GraphTargetItem> parts;
public XMLAVM2Item(GraphSourceItem instruction, GraphSourceItem lineStartIns, List<GraphTargetItem> parts) {
super(instruction, lineStartIns, NOPRECEDENCE);
this.parts = parts;
}
@Override
public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException {
for (GraphTargetItem part : parts) {
if (part instanceof StringAVM2Item) {
writer.append(((StringAVM2Item) part).getValue());
} else {
part.toString(writer, localData);
}
}
return writer;
}
@Override
public GraphTargetItem returnType() {
return new TypeItem(DottedChain.XML);
}
@Override
public boolean hasReturnValue() {
return true;
}
}

View File

@@ -1,475 +1,475 @@
/*
* Copyright (C) 2010-2016 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.abc.types;
import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.ABCInputStream;
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
import com.jpexs.decompiler.flash.abc.avm2.CodeStats;
import com.jpexs.decompiler.flash.abc.avm2.UnknownInstructionCode;
import com.jpexs.decompiler.flash.abc.avm2.deobfuscation.DeobfuscationLevel;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
import com.jpexs.decompiler.flash.abc.types.traits.Traits;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter;
import com.jpexs.decompiler.flash.helpers.NulWriter;
import com.jpexs.decompiler.flash.tags.Tag;
import com.jpexs.decompiler.flash.types.annotations.Internal;
import com.jpexs.decompiler.flash.types.annotations.SWFField;
import com.jpexs.decompiler.graph.DottedChain;
import com.jpexs.decompiler.graph.Graph;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.ScopeStack;
import com.jpexs.decompiler.graph.model.LocalData;
import com.jpexs.helpers.CancellableWorker;
import com.jpexs.helpers.Helper;
import com.jpexs.helpers.MemoryInputStream;
import com.jpexs.helpers.stat.Statistics;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author JPEXS
*/
public final class MethodBody implements Cloneable {
private static final Logger logger = Logger.getLogger(MethodBody.class.getName());
private static final String DEBUG_FIXED = null;
@Internal
public boolean deleted;
@Internal
boolean debugMode = false;
public int method_info;
public int max_stack;
public int max_regs;
public int init_scope_depth;
public int max_scope_depth;
@SWFField
private byte[] codeBytes;
private AVM2Code code;
public ABCException[] exceptions;
public Traits traits;
@Internal
public transient List<GraphTargetItem> convertedItems;
@Internal
public transient Throwable convertException;
@Internal
private ABC abc;
public MethodBody() {
this.traits = new Traits();
this.codeBytes = SWFInputStream.BYTE_ARRAY_EMPTY;
this.exceptions = new ABCException[0];
this.abc = null;
}
public void setAbc(ABC abc) {
this.abc = abc;
}
public MethodBody(ABC abc, Traits traits, byte[] codeBytes, ABCException[] exceptions) {
this.traits = traits;
this.codeBytes = codeBytes;
this.exceptions = exceptions;
this.abc = abc;
}
public synchronized void setCodeBytes(byte codeBytes[]) {
this.codeBytes = codeBytes;
this.code = null;
}
public void setModified() {
this.codeBytes = null;
}
public synchronized byte[] getCodeBytes() {
if (codeBytes != null) {
return codeBytes;
} else {
return code.getBytes();
}
}
public synchronized AVM2Code getCode() {
if (code == null) {
AVM2Code avm2Code;
try {
ABCInputStream ais = new ABCInputStream(new MemoryInputStream(codeBytes));
avm2Code = new AVM2Code(ais, this);
avm2Code.removeWrongIndices(abc.constants);
} catch (UnknownInstructionCode | IOException ex) {
avm2Code = new AVM2Code();
logger.log(Level.SEVERE, null, ex);
}
avm2Code.compact();
code = avm2Code;
}
return code;
}
public void setCode(AVM2Code code) {
this.code = code;
this.codeBytes = null;
}
public List<Integer> getExceptionEntries() {
List<Integer> ret = new ArrayList<>();
AVM2Code code = getCode();
for (ABCException e : exceptions) {
ret.add(code.adr2pos(e.start, true));
ret.add(code.adr2pos(e.end, true));
ret.add(code.adr2pos(e.target));
}
return ret;
}
public void markOffsets() {
getCode().markOffsets();
}
@Override
public String toString() {
String s = "";
s += "method_info=" + method_info + " max_stack=" + max_stack + " max_regs=" + max_regs + " scope_depth=" + init_scope_depth + " max_scope=" + max_scope_depth;
s += "\r\nCode:\r\n" + getCode().toString();
return s;
}
public int removeDeadCode(AVM2ConstantPool constants, Trait trait, MethodInfo info) throws InterruptedException {
return getCode().removeDeadCode(this);
}
public int removeTraps(ABC abc, Trait trait, int scriptIndex, int classIndex, boolean isStatic, String path) throws InterruptedException {
return getCode().removeTraps(trait, method_info, this, abc, scriptIndex, classIndex, isStatic, path);
}
public void deobfuscate(DeobfuscationLevel level, Trait trait, int scriptIndex, int classIndex, boolean isStatic, String path) throws InterruptedException {
if (level == DeobfuscationLevel.LEVEL_REMOVE_DEAD_CODE) {
removeDeadCode(abc.constants, trait, abc.method_info.get(method_info));
} else if (level == DeobfuscationLevel.LEVEL_REMOVE_TRAPS) {
removeTraps(abc, trait, scriptIndex, classIndex, isStatic, path);
} else if (level == DeobfuscationLevel.LEVEL_RESTORE_CONTROL_FLOW) {
removeTraps(abc, trait, scriptIndex, classIndex, isStatic, path);
}
((Tag) abc.parentTag).setModified(true);
}
public void removeInstruction(int pos) {
getCode().removeInstruction(pos, this);
}
/**
* Replaces instruction by another. Properly handles offsets. Note: If
* newinstruction is jump, the offset operand must be handled properly by
* caller.
*
* @param pos
* @param instruction
*/
public void replaceInstruction(int pos, AVM2Instruction instruction) {
getCode().replaceInstruction(pos, instruction, this);
}
/**
* Inserts instruction at specified point. Handles offsets properly. Note:
* If newinstruction is jump, the offset operand must be handled properly by
* caller. All old jump offsets to pos are targeted before new instruction.
*
* @param pos Position in the list
* @param instruction Instruction False means before new instruction
*/
public void insertInstruction(int pos, AVM2Instruction instruction) {
getCode().insertInstruction(pos, instruction, this);
}
public void insertAll(int pos, List<AVM2Instruction> list) {
for (AVM2Instruction ins : list) {
insertInstruction(pos++, ins);
}
}
/**
* Inserts instruction at specified point. Handles offsets properly. Note:
* If newinstruction is jump, the offset operand must be handled properly by
* caller.
*
* @param pos Position in the list
* @param instruction Instruction
* @param mapOffsetsAfterIns Map all jumps to the pos after new instruction?
* False means before new instruction
*/
public void insertInstruction(int pos, AVM2Instruction instruction, boolean mapOffsetsAfterIns) {
getCode().insertInstruction(pos, instruction, mapOffsetsAfterIns, this);
}
public int getLocalReservedCount() {
MethodInfo methodInfo = abc.method_info.get(this.method_info);
int pos = methodInfo.param_types.length + 1;
if (methodInfo.flagNeed_arguments()) {
pos++;
}
if (methodInfo.flagNeed_rest()) {
pos++;
}
return pos;
}
public HashMap<Integer, String> getLocalRegNames(ABC abc) {
HashMap<Integer, String> ret = new HashMap<>();
for (int i = 1; i <= abc.method_info.get(this.method_info).param_types.length; i++) {
String paramName = "param" + i;
if (abc.method_info.get(this.method_info).flagHas_paramnames() && Configuration.paramNamesEnable.get()) {
paramName = abc.constants.getString(abc.method_info.get(this.method_info).paramNames[i - 1]);
}
ret.put(i, paramName);
}
int pos = abc.method_info.get(this.method_info).param_types.length + 1;
if (abc.method_info.get(this.method_info).flagNeed_arguments()) {
ret.put(pos, "arguments");
pos++;
}
if (abc.method_info.get(this.method_info).flagNeed_rest()) {
ret.put(pos, "rest");
pos++;
}
if (Configuration.getLocalNamesFromDebugInfo.get()) {
Map<Integer, String> debugRegNames = getCode().getLocalRegNamesFromDebug(abc);
for (int k : debugRegNames.keySet()) {
ret.put(k, debugRegNames.get(k));
}
}
return ret;
}
public void convert(final ConvertData convertData, final String path, ScriptExportMode exportMode, final boolean isStatic, final int methodIndex, final int scriptIndex, final int classIndex, final ABC abc, final Trait trait, final ScopeStack scopeStack, final int initializerType, final NulWriter writer, final List<DottedChain> fullyQualifiedNames, final List<Traits> initTraits, boolean firstLevel) throws InterruptedException {
if (debugMode) {
System.err.println("Decompiling " + path);
}
if (exportMode != ScriptExportMode.AS) {
getCode().toASMSource(abc.constants, trait, abc.method_info.get(this.method_info), this, exportMode, writer);
} else {
if ((DEBUG_FIXED != null && !path.endsWith(DEBUG_FIXED)) || (!Configuration.decompile.get())) {
writer.appendNoHilight(Helper.getDecompilationSkippedComment()).newLine();
return;
}
int timeout = Configuration.decompilationTimeoutSingleMethod.get();
convertException = null;
try {
Callable<Void> callable = new Callable<Void>() {
@Override
public Void call() throws InterruptedException {
try (Statistics s1 = new Statistics("MethodBody.convert")) {
MethodBody converted = convertMethodBody(convertData, path, isStatic, scriptIndex, classIndex, abc, trait, scopeStack, initializerType != GraphTextWriter.TRAIT_INSTANCE_INITIALIZER, fullyQualifiedNames, initTraits);
HashMap<Integer, String> localRegNames = getLocalRegNames(abc);
List<GraphTargetItem> convertedItems1;
try (Statistics s = new Statistics("AVM2Code.toGraphTargetItems")) {
convertedItems1 = converted.getCode().toGraphTargetItems(convertData.thisHasDefaultToPrimitive, convertData, path, methodIndex, isStatic, scriptIndex, classIndex, abc, converted, localRegNames, scopeStack, initializerType, fullyQualifiedNames, initTraits, Graph.SOP_USE_STATIC, new HashMap<>(), converted.getCode().visitCode(converted));
}
try (Statistics s = new Statistics("Graph.graphToString")) {
Graph.graphToString(convertedItems1, writer, LocalData.create(abc.constants, localRegNames, fullyQualifiedNames));
}
convertedItems = convertedItems1;
}
return null;
}
};
if (firstLevel) {
CancellableWorker.call(callable, timeout, TimeUnit.SECONDS);
} else {
callable.call();
}
} catch (InterruptedException ex) {
throw ex;
} catch (Exception | OutOfMemoryError | StackOverflowError ex) {
convertException = ex;
Throwable cause = ex.getCause();
if (ex instanceof ExecutionException && cause instanceof Exception) {
convertException = (Exception) cause;
}
if (convertException instanceof TimeoutException) {
logger.log(Level.SEVERE, "Decompilation timeout in: " + path, convertException);
} else {
logger.log(Level.SEVERE, "Decompilation error in: " + path, convertException);
}
}
}
}
public GraphTextWriter toString(final String path, ScriptExportMode exportMode, final ABC abc, final Trait trait, final GraphTextWriter writer, final List<DottedChain> fullyQualifiedNames) throws InterruptedException {
if (exportMode != ScriptExportMode.AS) {
getCode().toASMSource(abc.constants, trait, abc.method_info.get(this.method_info), this, exportMode, writer);
} else {
if ((DEBUG_FIXED != null && !path.endsWith(DEBUG_FIXED)) || (!Configuration.decompile.get())) {
//writer.startMethod(this.method_info);
writer.appendNoHilight(Helper.getDecompilationSkippedComment()).newLine();
//writer.endMethod();
return writer;
}
int timeout = Configuration.decompilationTimeoutSingleMethod.get();
try (Statistics s = new Statistics("MethodBody.toString")) {
if (convertException == null) {
HashMap<Integer, String> localRegNames = getLocalRegNames(abc);
//writer.startMethod(this.method_info);
if (Configuration.showMethodBodyId.get()) {
writer.appendNoHilight("// method body index: ");
writer.appendNoHilight(abc.findBodyIndex(this.method_info));
writer.appendNoHilight(" method index: ");
writer.appendNoHilight(this.method_info);
writer.newLine();
}
Graph.graphToString(convertedItems, writer, LocalData.create(abc.constants, localRegNames, fullyQualifiedNames));
//writer.endMethod();
} else if (convertException instanceof TimeoutException) {
// exception was logged in convert method
Helper.appendTimeoutCommentAs3(writer, timeout, getCode().code.size());
} else {
// exception was logged in convert method
Helper.appendErrorComment(writer, convertException);
}
}
}
return writer;
}
public MethodBody convertMethodBody(ConvertData convertData, String path, boolean isStatic, int scriptIndex, int classIndex, ABC abc, Trait trait, ScopeStack scopeStack, boolean isStaticInitializer, List<DottedChain> fullyQualifiedNames, List<Traits> initTraits) throws InterruptedException {
MethodBody body = clone();
AVM2Code code = body.getCode();
code.fixJumps(path, body);
if (convertData.deobfuscationMode != 0) {
try {
code.removeTraps(trait, method_info, body, abc, scriptIndex, classIndex, isStatic, path);
} catch (ThreadDeath | InterruptedException ex) {
throw ex;
} catch (Throwable ex) {
//ignore
logger.log(Level.SEVERE, "Deobfuscation failed in: " + path, ex);
body = clone();
code = body.getCode();
code.fixJumps(path, body);
return body;
}
}
return body;
}
public String toSource() {
ConvertData convertData = new ConvertData();
convertData.deobfuscationMode = 0;
try {
convert(convertData, "", ScriptExportMode.AS, false, method_info, 0, 0, abc, null, new ScopeStack(), 0, new NulWriter(), new ArrayList<>(), new ArrayList<>(), true);
HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), false);
writer.indent().indent().indent();
toString("", ScriptExportMode.AS, abc, null, writer, new ArrayList<>());
writer.unindent().unindent().unindent();
return writer.toString();
} catch (InterruptedException ex) {
logger.log(Level.SEVERE, null, ex);
}
return null;
}
@Override
public MethodBody clone() {
try {
MethodBody ret = (MethodBody) super.clone();
if (code != null) {
ret.code = code.clone();
}
if (exceptions != null) {
ret.exceptions = new ABCException[exceptions.length];
for (int i = 0; i < exceptions.length; i++) {
ret.exceptions[i] = exceptions[i].clone();
}
}
// maybe deep clone traits
/*if (traits != null) {
ret.traits = traits.clone();
}*/
ret.convertedItems = null;
ret.convertException = null;
return ret;
} catch (CloneNotSupportedException ex) {
throw new RuntimeException();
}
}
public boolean autoFillStats(ABC abc, int initScope, boolean hasThis) {
//System.out.println("--------------");
CodeStats stats = getCode().getStats(abc, this, initScope);
if (stats == null) {
return false;
}
if (stats.has_activation) {
initScope++;
}
max_stack = stats.maxstack;
max_scope_depth = stats.maxscope + (stats.has_activation ? 1 : 0);
max_regs = stats.maxlocal;
init_scope_depth = initScope;
abc.method_info.get(method_info).setFlagSetsdxns(stats.has_set_dxns);
abc.method_info.get(method_info).setFlagNeed_activation(stats.has_activation);
MethodInfo mi = abc.method_info.get(method_info);
int min_regs = mi.param_types.length + 1 + (mi.flagNeed_rest() ? 1 : 0);
if (max_regs < min_regs) {
max_regs = min_regs;
}
return true;
}
}
/*
* Copyright (C) 2010-2016 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.abc.types;
import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.ABCInputStream;
import com.jpexs.decompiler.flash.abc.avm2.AVM2Code;
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
import com.jpexs.decompiler.flash.abc.avm2.CodeStats;
import com.jpexs.decompiler.flash.abc.avm2.UnknownInstructionCode;
import com.jpexs.decompiler.flash.abc.avm2.deobfuscation.DeobfuscationLevel;
import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction;
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
import com.jpexs.decompiler.flash.abc.types.traits.Traits;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter;
import com.jpexs.decompiler.flash.helpers.NulWriter;
import com.jpexs.decompiler.flash.tags.Tag;
import com.jpexs.decompiler.flash.types.annotations.Internal;
import com.jpexs.decompiler.flash.types.annotations.SWFField;
import com.jpexs.decompiler.graph.DottedChain;
import com.jpexs.decompiler.graph.Graph;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.ScopeStack;
import com.jpexs.decompiler.graph.model.LocalData;
import com.jpexs.helpers.CancellableWorker;
import com.jpexs.helpers.Helper;
import com.jpexs.helpers.MemoryInputStream;
import com.jpexs.helpers.stat.Statistics;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author JPEXS
*/
public final class MethodBody implements Cloneable {
private static final Logger logger = Logger.getLogger(MethodBody.class.getName());
private static final String DEBUG_FIXED = null;
@Internal
public boolean deleted;
@Internal
boolean debugMode = false;
public int method_info;
public int max_stack;
public int max_regs;
public int init_scope_depth;
public int max_scope_depth;
@SWFField
private byte[] codeBytes;
private AVM2Code code;
public ABCException[] exceptions;
public Traits traits;
@Internal
public transient List<GraphTargetItem> convertedItems;
@Internal
public transient Throwable convertException;
@Internal
private ABC abc;
public MethodBody() {
this.traits = new Traits();
this.codeBytes = SWFInputStream.BYTE_ARRAY_EMPTY;
this.exceptions = new ABCException[0];
this.abc = null;
}
public void setAbc(ABC abc) {
this.abc = abc;
}
public MethodBody(ABC abc, Traits traits, byte[] codeBytes, ABCException[] exceptions) {
this.traits = traits;
this.codeBytes = codeBytes;
this.exceptions = exceptions;
this.abc = abc;
}
public synchronized void setCodeBytes(byte codeBytes[]) {
this.codeBytes = codeBytes;
this.code = null;
}
public void setModified() {
this.codeBytes = null;
}
public synchronized byte[] getCodeBytes() {
if (codeBytes != null) {
return codeBytes;
} else {
return code.getBytes();
}
}
public synchronized AVM2Code getCode() {
if (code == null) {
AVM2Code avm2Code;
try {
ABCInputStream ais = new ABCInputStream(new MemoryInputStream(codeBytes));
avm2Code = new AVM2Code(ais, this);
avm2Code.removeWrongIndices(abc.constants);
} catch (UnknownInstructionCode | IOException ex) {
avm2Code = new AVM2Code();
logger.log(Level.SEVERE, null, ex);
}
avm2Code.compact();
code = avm2Code;
}
return code;
}
public void setCode(AVM2Code code) {
this.code = code;
this.codeBytes = null;
}
public List<Integer> getExceptionEntries() {
List<Integer> ret = new ArrayList<>();
AVM2Code code = getCode();
for (ABCException e : exceptions) {
ret.add(code.adr2pos(e.start, true));
ret.add(code.adr2pos(e.end, true));
ret.add(code.adr2pos(e.target));
}
return ret;
}
public void markOffsets() {
getCode().markOffsets();
}
@Override
public String toString() {
String s = "";
s += "method_info=" + method_info + " max_stack=" + max_stack + " max_regs=" + max_regs + " scope_depth=" + init_scope_depth + " max_scope=" + max_scope_depth;
s += "\r\nCode:\r\n" + getCode().toString();
return s;
}
public int removeDeadCode(AVM2ConstantPool constants, Trait trait, MethodInfo info) throws InterruptedException {
return getCode().removeDeadCode(this);
}
public int removeTraps(ABC abc, Trait trait, int scriptIndex, int classIndex, boolean isStatic, String path) throws InterruptedException {
return getCode().removeTraps(trait, method_info, this, abc, scriptIndex, classIndex, isStatic, path);
}
public void deobfuscate(DeobfuscationLevel level, Trait trait, int scriptIndex, int classIndex, boolean isStatic, String path) throws InterruptedException {
if (level == DeobfuscationLevel.LEVEL_REMOVE_DEAD_CODE) {
removeDeadCode(abc.constants, trait, abc.method_info.get(method_info));
} else if (level == DeobfuscationLevel.LEVEL_REMOVE_TRAPS) {
removeTraps(abc, trait, scriptIndex, classIndex, isStatic, path);
} else if (level == DeobfuscationLevel.LEVEL_RESTORE_CONTROL_FLOW) {
removeTraps(abc, trait, scriptIndex, classIndex, isStatic, path);
}
((Tag) abc.parentTag).setModified(true);
}
public void removeInstruction(int pos) {
getCode().removeInstruction(pos, this);
}
/**
* Replaces instruction by another. Properly handles offsets. Note: If
* newinstruction is jump, the offset operand must be handled properly by
* caller.
*
* @param pos
* @param instruction
*/
public void replaceInstruction(int pos, AVM2Instruction instruction) {
getCode().replaceInstruction(pos, instruction, this);
}
/**
* Inserts instruction at specified point. Handles offsets properly. Note:
* If newinstruction is jump, the offset operand must be handled properly by
* caller. All old jump offsets to pos are targeted before new instruction.
*
* @param pos Position in the list
* @param instruction Instruction False means before new instruction
*/
public void insertInstruction(int pos, AVM2Instruction instruction) {
getCode().insertInstruction(pos, instruction, this);
}
public void insertAll(int pos, List<AVM2Instruction> list) {
for (AVM2Instruction ins : list) {
insertInstruction(pos++, ins);
}
}
/**
* Inserts instruction at specified point. Handles offsets properly. Note:
* If newinstruction is jump, the offset operand must be handled properly by
* caller.
*
* @param pos Position in the list
* @param instruction Instruction
* @param mapOffsetsAfterIns Map all jumps to the pos after new instruction?
* False means before new instruction
*/
public void insertInstruction(int pos, AVM2Instruction instruction, boolean mapOffsetsAfterIns) {
getCode().insertInstruction(pos, instruction, mapOffsetsAfterIns, this);
}
public int getLocalReservedCount() {
MethodInfo methodInfo = abc.method_info.get(this.method_info);
int pos = methodInfo.param_types.length + 1;
if (methodInfo.flagNeed_arguments()) {
pos++;
}
if (methodInfo.flagNeed_rest()) {
pos++;
}
return pos;
}
public HashMap<Integer, String> getLocalRegNames(ABC abc) {
HashMap<Integer, String> ret = new HashMap<>();
for (int i = 1; i <= abc.method_info.get(this.method_info).param_types.length; i++) {
String paramName = "param" + i;
if (abc.method_info.get(this.method_info).flagHas_paramnames() && Configuration.paramNamesEnable.get()) {
paramName = abc.constants.getString(abc.method_info.get(this.method_info).paramNames[i - 1]);
}
ret.put(i, paramName);
}
int pos = abc.method_info.get(this.method_info).param_types.length + 1;
if (abc.method_info.get(this.method_info).flagNeed_arguments()) {
ret.put(pos, "arguments");
pos++;
}
if (abc.method_info.get(this.method_info).flagNeed_rest()) {
ret.put(pos, "rest");
pos++;
}
if (Configuration.getLocalNamesFromDebugInfo.get()) {
Map<Integer, String> debugRegNames = getCode().getLocalRegNamesFromDebug(abc);
for (int k : debugRegNames.keySet()) {
ret.put(k, debugRegNames.get(k));
}
}
return ret;
}
public void convert(final ConvertData convertData, final String path, ScriptExportMode exportMode, final boolean isStatic, final int methodIndex, final int scriptIndex, final int classIndex, final ABC abc, final Trait trait, final ScopeStack scopeStack, final int initializerType, final NulWriter writer, final List<DottedChain> fullyQualifiedNames, final List<Traits> initTraits, boolean firstLevel) throws InterruptedException {
if (debugMode) {
System.err.println("Decompiling " + path);
}
if (exportMode != ScriptExportMode.AS) {
getCode().toASMSource(abc.constants, trait, abc.method_info.get(this.method_info), this, exportMode, writer);
} else {
if ((DEBUG_FIXED != null && !path.endsWith(DEBUG_FIXED)) || (!Configuration.decompile.get())) {
writer.appendNoHilight(Helper.getDecompilationSkippedComment()).newLine();
return;
}
int timeout = Configuration.decompilationTimeoutSingleMethod.get();
convertException = null;
try {
Callable<Void> callable = new Callable<Void>() {
@Override
public Void call() throws InterruptedException {
try (Statistics s1 = new Statistics("MethodBody.convert")) {
MethodBody converted = convertMethodBody(convertData, path, isStatic, scriptIndex, classIndex, abc, trait, scopeStack, initializerType != GraphTextWriter.TRAIT_INSTANCE_INITIALIZER, fullyQualifiedNames, initTraits);
HashMap<Integer, String> localRegNames = getLocalRegNames(abc);
List<GraphTargetItem> convertedItems1;
try (Statistics s = new Statistics("AVM2Code.toGraphTargetItems")) {
convertedItems1 = converted.getCode().toGraphTargetItems(convertData.thisHasDefaultToPrimitive, convertData, path, methodIndex, isStatic, scriptIndex, classIndex, abc, converted, localRegNames, scopeStack, initializerType, fullyQualifiedNames, initTraits, Graph.SOP_USE_STATIC, new HashMap<>(), converted.getCode().visitCode(converted));
}
try (Statistics s = new Statistics("Graph.graphToString")) {
Graph.graphToString(convertedItems1, writer, LocalData.create(abc.constants, localRegNames, fullyQualifiedNames));
}
convertedItems = convertedItems1;
}
return null;
}
};
if (firstLevel) {
CancellableWorker.call(callable, timeout, TimeUnit.SECONDS);
} else {
callable.call();
}
} catch (InterruptedException ex) {
throw ex;
} catch (Exception | OutOfMemoryError | StackOverflowError ex) {
convertException = ex;
Throwable cause = ex.getCause();
if (ex instanceof ExecutionException && cause instanceof Exception) {
convertException = (Exception) cause;
}
if (convertException instanceof TimeoutException) {
logger.log(Level.SEVERE, "Decompilation timeout in: " + path, convertException);
} else {
logger.log(Level.SEVERE, "Decompilation error in: " + path, convertException);
}
}
}
}
public GraphTextWriter toString(final String path, ScriptExportMode exportMode, final ABC abc, final Trait trait, final GraphTextWriter writer, final List<DottedChain> fullyQualifiedNames) throws InterruptedException {
if (exportMode != ScriptExportMode.AS) {
getCode().toASMSource(abc.constants, trait, abc.method_info.get(this.method_info), this, exportMode, writer);
} else {
if ((DEBUG_FIXED != null && !path.endsWith(DEBUG_FIXED)) || (!Configuration.decompile.get())) {
//writer.startMethod(this.method_info);
writer.appendNoHilight(Helper.getDecompilationSkippedComment()).newLine();
//writer.endMethod();
return writer;
}
int timeout = Configuration.decompilationTimeoutSingleMethod.get();
try (Statistics s = new Statistics("MethodBody.toString")) {
if (convertException == null) {
HashMap<Integer, String> localRegNames = getLocalRegNames(abc);
//writer.startMethod(this.method_info);
if (Configuration.showMethodBodyId.get()) {
writer.appendNoHilight("// method body index: ");
writer.appendNoHilight(abc.findBodyIndex(this.method_info));
writer.appendNoHilight(" method index: ");
writer.appendNoHilight(this.method_info);
writer.newLine();
}
Graph.graphToString(convertedItems, writer, LocalData.create(abc.constants, localRegNames, fullyQualifiedNames));
//writer.endMethod();
} else if (convertException instanceof TimeoutException) {
// exception was logged in convert method
Helper.appendTimeoutCommentAs3(writer, timeout, getCode().code.size());
} else {
// exception was logged in convert method
Helper.appendErrorComment(writer, convertException);
}
}
}
return writer;
}
public MethodBody convertMethodBody(ConvertData convertData, String path, boolean isStatic, int scriptIndex, int classIndex, ABC abc, Trait trait, ScopeStack scopeStack, boolean isStaticInitializer, List<DottedChain> fullyQualifiedNames, List<Traits> initTraits) throws InterruptedException {
MethodBody body = clone();
AVM2Code code = body.getCode();
code.fixJumps(path, body);
if (convertData.deobfuscationMode != 0) {
try {
code.removeTraps(trait, method_info, body, abc, scriptIndex, classIndex, isStatic, path);
} catch (ThreadDeath | InterruptedException ex) {
throw ex;
} catch (Throwable ex) {
//ignore
logger.log(Level.SEVERE, "Deobfuscation failed in: " + path, ex);
body = clone();
code = body.getCode();
code.fixJumps(path, body);
return body;
}
}
return body;
}
public String toSource() {
ConvertData convertData = new ConvertData();
convertData.deobfuscationMode = 0;
try {
convert(convertData, "", ScriptExportMode.AS, false, method_info, 0, 0, abc, null, new ScopeStack(), 0, new NulWriter(), new ArrayList<>(), new ArrayList<>(), true);
HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), false);
writer.indent().indent().indent();
toString("", ScriptExportMode.AS, abc, null, writer, new ArrayList<>());
writer.unindent().unindent().unindent();
return writer.toString();
} catch (InterruptedException ex) {
logger.log(Level.SEVERE, null, ex);
}
return null;
}
@Override
public MethodBody clone() {
try {
MethodBody ret = (MethodBody) super.clone();
if (code != null) {
ret.code = code.clone();
}
if (exceptions != null) {
ret.exceptions = new ABCException[exceptions.length];
for (int i = 0; i < exceptions.length; i++) {
ret.exceptions[i] = exceptions[i].clone();
}
}
// maybe deep clone traits
/*if (traits != null) {
ret.traits = traits.clone();
}*/
ret.convertedItems = null;
ret.convertException = null;
return ret;
} catch (CloneNotSupportedException ex) {
throw new RuntimeException();
}
}
public boolean autoFillStats(ABC abc, int initScope, boolean hasThis) {
//System.out.println("--------------");
CodeStats stats = getCode().getStats(abc, this, initScope);
if (stats == null) {
return false;
}
if (stats.has_activation) {
initScope++;
}
max_stack = stats.maxstack;
max_scope_depth = stats.maxscope + (stats.has_activation ? 1 : 0);
max_regs = stats.maxlocal;
init_scope_depth = initScope;
abc.method_info.get(method_info).setFlagSetsdxns(stats.has_set_dxns);
abc.method_info.get(method_info).setFlagNeed_activation(stats.has_activation);
MethodInfo mi = abc.method_info.get(method_info);
int min_regs = mi.param_types.length + 1 + (mi.flagNeed_rest() ? 1 : 0);
if (max_regs < min_regs) {
max_regs = min_regs;
}
return true;
}
}

View File

@@ -1,93 +1,93 @@
/*
* Copyright (C) 2010-2016 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.action;
import com.jpexs.decompiler.flash.ecma.EcmaScript;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
/**
*
* @author JPEXS
*/
public class LocalDataArea {
public List<String> constantPool;
public Stack<Object> stack = new Stack<>();
public List<ActionScriptFunction> functions = new ArrayList<>();
public Map<String, Object> localVariables = new HashMap<>();
public List<ActionScriptWith> withs = new ArrayList<>();
public Map<Integer, Object> localRegisters = new HashMap<>();
public Object target;
public Stage stage;
public Long jump;
public Object returnValue;
public String executionException;
public LocalDataArea(Stage stage) {
this.stage = stage;
this.target = this.stage;
}
public LocalDataArea(Stage stage, boolean preserveVariableOrder) {
this.stage = stage;
target = this.stage;
if (preserveVariableOrder) {
localVariables = new LinkedHashMap<>();
}
}
public void clear() {
constantPool = null;
stack.clear();
localVariables.clear();
localRegisters.clear();
withs.clear();
functions.clear();
stage.clear();
jump = null;
returnValue = null;
executionException = null;
target = stage;
}
public Object pop() {
return stack.pop();
}
public Double popAsNumber() {
return EcmaScript.toNumberAs2(stack.pop());
}
public String popAsString() {
return EcmaScript.toString(stack.pop());
}
}
/*
* Copyright (C) 2010-2016 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.action;
import com.jpexs.decompiler.flash.ecma.EcmaScript;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
/**
*
* @author JPEXS
*/
public class LocalDataArea {
public List<String> constantPool;
public Stack<Object> stack = new Stack<>();
public List<ActionScriptFunction> functions = new ArrayList<>();
public Map<String, Object> localVariables = new HashMap<>();
public List<ActionScriptWith> withs = new ArrayList<>();
public Map<Integer, Object> localRegisters = new HashMap<>();
public Object target;
public Stage stage;
public Long jump;
public Object returnValue;
public String executionException;
public LocalDataArea(Stage stage) {
this.stage = stage;
this.target = this.stage;
}
public LocalDataArea(Stage stage, boolean preserveVariableOrder) {
this.stage = stage;
target = this.stage;
if (preserveVariableOrder) {
localVariables = new LinkedHashMap<>();
}
}
public void clear() {
constantPool = null;
stack.clear();
localVariables.clear();
localRegisters.clear();
withs.clear();
functions.clear();
stage.clear();
jump = null;
returnValue = null;
executionException = null;
target = stage;
}
public Object pop() {
return stack.pop();
}
public Double popAsNumber() {
return EcmaScript.toNumberAs2(stack.pop());
}
public String popAsString() {
return EcmaScript.toString(stack.pop());
}
}

View File

@@ -1,51 +1,51 @@
/*
* Copyright (C) 2010-2016 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.action.special;
import com.jpexs.decompiler.flash.action.LocalDataArea;
import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.TranslateStack;
import com.jpexs.helpers.Helper;
import java.util.HashMap;
import java.util.List;
/**
*
* @author JPEXS
*/
public class ActionUnknown extends ActionNop {
public ActionUnknown(int actionCode, int actionLength) {
super(actionCode);
this.actionLength = actionLength;
}
@Override
public String toString() {
return "Unknown_" + Helper.byteToHex((byte) getActionCode());
}
@Override
public boolean execute(LocalDataArea lda) {
return true;
}
@Override
public void translate(GraphSourceItem lineStartItem, TranslateStack stack, List<GraphTargetItem> output, HashMap<Integer, String> regNames, HashMap<String, GraphTargetItem> variables, HashMap<String, GraphTargetItem> functions, int staticOperation, String path) {
}
}
/*
* Copyright (C) 2010-2016 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.action.special;
import com.jpexs.decompiler.flash.action.LocalDataArea;
import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.TranslateStack;
import com.jpexs.helpers.Helper;
import java.util.HashMap;
import java.util.List;
/**
*
* @author JPEXS
*/
public class ActionUnknown extends ActionNop {
public ActionUnknown(int actionCode, int actionLength) {
super(actionCode);
this.actionLength = actionLength;
}
@Override
public String toString() {
return "Unknown_" + Helper.byteToHex((byte) getActionCode());
}
@Override
public boolean execute(LocalDataArea lda) {
return true;
}
@Override
public void translate(GraphSourceItem lineStartItem, TranslateStack stack, List<GraphTargetItem> output, HashMap<Integer, String> regNames, HashMap<String, GraphTargetItem> variables, HashMap<String, GraphTargetItem> functions, int staticOperation, String path) {
}
}

View File

@@ -1,455 +1,455 @@
/*
* Copyright (C) 2010-2016 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.action.swf4;
import com.jpexs.decompiler.flash.BaseLocalData;
import com.jpexs.decompiler.flash.EndOfStreamException;
import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.SWFOutputStream;
import com.jpexs.decompiler.flash.action.Action;
import com.jpexs.decompiler.flash.action.ActionList;
import com.jpexs.decompiler.flash.action.LocalDataArea;
import com.jpexs.decompiler.flash.action.model.DirectValueActionItem;
import com.jpexs.decompiler.flash.action.model.TemporaryRegister;
import com.jpexs.decompiler.flash.action.parser.ActionParseException;
import com.jpexs.decompiler.flash.action.parser.pcode.ASMParsedSymbol;
import com.jpexs.decompiler.flash.action.parser.pcode.FlasmLexer;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.dumpview.DumpInfo;
import com.jpexs.decompiler.flash.ecma.Null;
import com.jpexs.decompiler.flash.ecma.Undefined;
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter;
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.TranslateStack;
import com.jpexs.decompiler.graph.model.FalseItem;
import com.jpexs.decompiler.graph.model.TrueItem;
import com.jpexs.helpers.Helper;
import com.jpexs.helpers.utf8.Utf8Helper;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
/**
*
* @author JPEXS
*/
@SWFVersion(from = 4)
public class ActionPush extends Action {
public List<Object> values;
public List<Object> replacement;
public List<String> constantPool;
public ActionPush(int actionLength, SWFInputStream sis, int version) throws IOException {
super(0x96, actionLength);
int type;
values = new ArrayList<>();
DumpInfo di = sis.dumpInfo;
sis = sis.getLimitedStream(actionLength);
sis.dumpInfo = di;
try {
while (sis.available() > 0) {
type = sis.readUI8("type");
switch (type) {
case 0:
values.add(sis.readString("string"));
break;
case 1:
values.add(sis.readFLOAT("float"));
break;
case 2:
values.add(Null.INSTANCE);
break;
case 3:
values.add(Undefined.INSTANCE);
break;
case 4:
values.add(new RegisterNumber(sis.readUI8("registerNumber")));
break;
case 5:
int b = sis.readUI8("boolean");
if (b == 0) {
values.add((Boolean) false);
} else {
values.add((Boolean) true);
}
break;
case 6:
values.add(sis.readDOUBLE("double"));
break;
case 7:
long el = sis.readSI32("integer");
values.add((Long) el);
break;
case 8:
values.add(new ConstantIndex(sis.readUI8("constantIndex")));
break;
case 9:
values.add(new ConstantIndex(sis.readUI16("constantIndex")));
break;
}
}
} catch (EndOfStreamException ex) {
}
}
@Override
protected void getContentBytes(SWFOutputStream sos) throws IOException {
for (Object o : values) {
if (o instanceof String) {
sos.writeUI8(0);
sos.writeString((String) o);
} else if (o instanceof Float) {
sos.writeUI8(1);
sos.writeFLOAT((Float) o);
} else if (o == Null.INSTANCE) {
sos.writeUI8(2);
} else if (o == Undefined.INSTANCE) {
sos.writeUI8(3);
} else if (o instanceof RegisterNumber) {
sos.writeUI8(4);
sos.writeUI8(((RegisterNumber) o).number);
} else if (o instanceof Boolean) {
sos.writeUI8(5);
sos.writeUI8((Boolean) o ? 1 : 0);
} else if (o instanceof Number) {
if (o instanceof Long) {
long l = (Long) o;
if (l < -0x80000000 || l > 0x7fffffff) {
o = (double) l;
}
}
if (o instanceof Double || o instanceof Float) {
sos.writeUI8(6);
sos.writeDOUBLE(((Number) o).doubleValue());
} else if (o instanceof Long || o instanceof Integer || o instanceof Short || o instanceof Byte) {
sos.writeUI8(7);
sos.writeSI32(((Number) o).longValue());
}
} else if (o instanceof ConstantIndex) {
int cIndex = ((ConstantIndex) o).index;
if (cIndex < 256) {
sos.writeUI8(8);
sos.writeUI8(cIndex);
} else {
sos.writeUI8(9);
sos.writeUI16(cIndex);
}
}
}
}
/**
* Gets the length of action converted to bytes
*
* @return Length
*/
@Override
protected int getContentBytesLength() {
int res = 0;
for (Object o : values) {
if (o instanceof String) {
res += Utf8Helper.getBytesLength((String) o) + 2;
} else if (o instanceof Float) {
res += 5;
} else if (o == Null.INSTANCE) {
res++;
} else if (o == Undefined.INSTANCE) {
res++;
} else if (o instanceof RegisterNumber) {
res += 2;
} else if (o instanceof Boolean) {
res += 2;
} else if (o instanceof Number) {
if (o instanceof Long) {
long l = (Long) o;
if (l < -0x80000000 || l > 0x7fffffff) {
o = (double) l;
}
}
if (o instanceof Double || o instanceof Float) {
res += 9;
} else if (o instanceof Long || o instanceof Integer || o instanceof Short || o instanceof Byte) {
res += 5;
}
} else if (o instanceof ConstantIndex) {
int cIndex = ((ConstantIndex) o).index;
if (cIndex < 256) {
res += 2;
} else {
res += 3;
}
}
}
return res;
}
public static boolean isValidValue(Object value) {
if (value instanceof String) {
for (char ch : ((String) value).toCharArray()) {
if (ch == 0) {
return false;
}
}
}
if (value instanceof Long) {
long l = (Long) value;
if (l < -0x80000000 || l > 0x7fffffff) {
return false;
}
}
return true;
}
public ActionPush(Object value) {
super(0x96, 0);
this.values = new ArrayList<>();
this.values.add(value);
updateLength();
}
public ActionPush(Object[] values) {
super(0x96, 0);
this.values = new ArrayList<>();
this.values.addAll(Arrays.asList(values));
updateLength();
}
public ActionPush(FlasmLexer lexer, List<String> constantPool) throws IOException, ActionParseException {
super(0x96, 0);
this.constantPool = constantPool;
values = new ArrayList<>();
int count = 0;
loop:
while (true) {
ASMParsedSymbol symb = lexer.yylex();
switch (symb.type) {
case ASMParsedSymbol.TYPE_STRING:
count++;
if (constantPool.contains((String) symb.value)) {
values.add(new ConstantIndex(constantPool.indexOf(symb.value)));
} else {
values.add(symb.value);
}
break;
case ASMParsedSymbol.TYPE_FLOAT:
case ASMParsedSymbol.TYPE_NULL:
case ASMParsedSymbol.TYPE_UNDEFINED:
case ASMParsedSymbol.TYPE_REGISTER:
case ASMParsedSymbol.TYPE_BOOLEAN:
case ASMParsedSymbol.TYPE_INTEGER:
case ASMParsedSymbol.TYPE_CONSTANT:
count++;
values.add(symb.value);
break;
case ASMParsedSymbol.TYPE_EOL:
case ASMParsedSymbol.TYPE_EOF:
if (count == 0) {
throw new ActionParseException("Arguments expected", lexer.yyline());
} else {
break loop;
}
case ASMParsedSymbol.TYPE_COMMENT:
break;
default:
throw new ActionParseException("Arguments expected, " + symb.type + " " + symb.value + " found", lexer.yyline());
}
}
}
@Override
public GraphTextWriter getASMSourceReplaced(ActionList container, Set<Long> knownAddreses, ScriptExportMode exportMode, GraphTextWriter writer) {
if (replacement == null || replacement.size() < values.size()) {
return toString(writer);
}
List<Object> oldVal = values;
values = replacement;
toString(writer);
values = oldVal;
return writer;
}
public GraphTextWriter paramsToStringReplaced(List<? extends GraphSourceItem> container, Set<Long> knownAddreses, ScriptExportMode exportMode, GraphTextWriter writer) {
if (replacement == null || replacement.size() < values.size()) {
return paramsToString(writer);
}
List<Object> oldVal = values;
values = replacement;
paramsToString(writer);
values = oldVal;
return writer;
}
public String toStringNoQ(int i) {
String ret;
Object value = values.get(i);
if (value instanceof ConstantIndex) {
ret = ((ConstantIndex) value).toStringNoQ(constantPool, Configuration.resolveConstants.get());
} else if (value instanceof String) {
ret = (String) value;
} else if (value instanceof RegisterNumber) {
ret = ((RegisterNumber) value).toStringNoName();
} else {
ret = value.toString();
}
return ret;
}
public String toString(int i) {
String ret;
Object value = values.get(i);
if (value instanceof ConstantIndex) {
ret = ((ConstantIndex) value).toString(constantPool, Configuration.resolveConstants.get());
} else if (value instanceof String) {
ret = "\"" + Helper.escapeActionScriptString((String) value) + "\"";
} else if (value instanceof RegisterNumber) {
ret = ((RegisterNumber) value).toStringNoName();
} else {
ret = value.toString();
}
return ret;
}
public GraphTextWriter paramsToString(GraphTextWriter writer) {
int pos = 0;
for (int i = 0; i < values.size(); i++) {
if (pos > 0) {
writer.appendNoHilight(" ");
}
writer.append(toString(i), getAddress() + pos + 1, getFileOffset());
pos++;
}
return writer;
}
@Override
public String toString() {
HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), false);
toString(writer);
return writer.toString();
}
public GraphTextWriter toString(GraphTextWriter writer) {
writer.appendNoHilight("Push ");
paramsToString(writer);
return writer;
}
@Override
public boolean execute(LocalDataArea lda) {
for (Object value : values) {
if (value instanceof ConstantIndex) {
ConstantIndex constantIndex = (ConstantIndex) value;
List<String> cPool = lda.constantPool != null ? lda.constantPool : constantPool;
lda.stack.push(constantIndex.toStringNoQ(cPool, true));
} else if (value instanceof RegisterNumber) {
int rn = ((RegisterNumber) value).number;
if (lda.localRegisters.containsKey(rn)) {
lda.stack.push(lda.localRegisters.get(rn));
} else {
lda.stack.push(Undefined.INSTANCE);
}
} else {
lda.stack.push(value);
}
}
return true;
}
@Override
public void translate(GraphSourceItem lineStartAction, TranslateStack stack, List<GraphTargetItem> output, HashMap<Integer, String> regNames, HashMap<String, GraphTargetItem> variables, HashMap<String, GraphTargetItem> functions, int staticOperation, String path) {
int pos = 0;
for (Object o : values) {
if (o instanceof ConstantIndex) {
if ((constantPool == null) || (((ConstantIndex) o).index >= constantPool.size())) {
o = "\u00A7\u00A7constant" + ((ConstantIndex) o).index;
} else {
o = constantPool.get(((ConstantIndex) o).index);
}
}
/*if (o instanceof RegisterNumber) {
if (regNames.containsKey(((RegisterNumber) o).number)) {
((RegisterNumber) o).name = regNames.get(((RegisterNumber) o).number);
} else if (output.size() >= 2) { //chained assignments:, ignore for class prototype assignment
GraphTargetItem last = output.get(output.size() - 1);
GraphTargetItem prev = output.get(output.size() - 2);
if (last instanceof SetTypeActionItem) {
if (prev instanceof StoreRegisterActionItem) {
StoreRegisterActionItem str = (StoreRegisterActionItem) prev;
if (str.register.number == ((RegisterNumber) o).number) {
SetTypeActionItem stt = (SetTypeActionItem) last;
stt.setTempRegister(((RegisterNumber) o).number);
if ((stt.getValue() instanceof IncrementActionItem) && (((IncrementActionItem) stt.getValue()).object.equals(stt.getObject()))) {
stack.push(new PreIncrementActionItem(this, lineStartAction, stt.getObject()));
} else if ((stt.getValue() instanceof DecrementActionItem) && (((DecrementActionItem) stt.getValue()).object.equals(stt.getObject()))) {
stack.push(new PreDecrementActionItem(this, lineStartAction, stt.getObject()));
} else {
//stack.push(last);
continue;
}
output.remove(output.size() - 1);
output.remove(output.size() - 1);
pos++;
continue;
}
}
}
}
}*/
if (o instanceof Boolean) {
Boolean b = (Boolean) o;
if (b) {
stack.push(new TrueItem(this, lineStartAction));
} else {
stack.push(new FalseItem(this, lineStartAction));
}
} else {
DirectValueActionItem dvt = new DirectValueActionItem(this, lineStartAction, pos, o, constantPool);
if (o instanceof RegisterNumber) {//TemporaryRegister
dvt.computedRegValue = variables.get("__register" + ((RegisterNumber) o).number);
if (regNames.containsKey(((RegisterNumber) o).number)) {
((RegisterNumber) o).name = regNames.get(((RegisterNumber) o).number);
}
}
if (dvt.computedRegValue instanceof TemporaryRegister) {
stack.push(new TemporaryRegister(((RegisterNumber) o).number, ((TemporaryRegister) dvt.computedRegValue).value));
} else {
stack.push(dvt);
}
}
pos++;
}
}
@Override
public int getStackPushCount(BaseLocalData localData, TranslateStack stack) {
return values.size();
}
}
/*
* Copyright (C) 2010-2016 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.action.swf4;
import com.jpexs.decompiler.flash.BaseLocalData;
import com.jpexs.decompiler.flash.EndOfStreamException;
import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.SWFOutputStream;
import com.jpexs.decompiler.flash.action.Action;
import com.jpexs.decompiler.flash.action.ActionList;
import com.jpexs.decompiler.flash.action.LocalDataArea;
import com.jpexs.decompiler.flash.action.model.DirectValueActionItem;
import com.jpexs.decompiler.flash.action.model.TemporaryRegister;
import com.jpexs.decompiler.flash.action.parser.ActionParseException;
import com.jpexs.decompiler.flash.action.parser.pcode.ASMParsedSymbol;
import com.jpexs.decompiler.flash.action.parser.pcode.FlasmLexer;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.dumpview.DumpInfo;
import com.jpexs.decompiler.flash.ecma.Null;
import com.jpexs.decompiler.flash.ecma.Undefined;
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter;
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.TranslateStack;
import com.jpexs.decompiler.graph.model.FalseItem;
import com.jpexs.decompiler.graph.model.TrueItem;
import com.jpexs.helpers.Helper;
import com.jpexs.helpers.utf8.Utf8Helper;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
/**
*
* @author JPEXS
*/
@SWFVersion(from = 4)
public class ActionPush extends Action {
public List<Object> values;
public List<Object> replacement;
public List<String> constantPool;
public ActionPush(int actionLength, SWFInputStream sis, int version) throws IOException {
super(0x96, actionLength);
int type;
values = new ArrayList<>();
DumpInfo di = sis.dumpInfo;
sis = sis.getLimitedStream(actionLength);
sis.dumpInfo = di;
try {
while (sis.available() > 0) {
type = sis.readUI8("type");
switch (type) {
case 0:
values.add(sis.readString("string"));
break;
case 1:
values.add(sis.readFLOAT("float"));
break;
case 2:
values.add(Null.INSTANCE);
break;
case 3:
values.add(Undefined.INSTANCE);
break;
case 4:
values.add(new RegisterNumber(sis.readUI8("registerNumber")));
break;
case 5:
int b = sis.readUI8("boolean");
if (b == 0) {
values.add((Boolean) false);
} else {
values.add((Boolean) true);
}
break;
case 6:
values.add(sis.readDOUBLE("double"));
break;
case 7:
long el = sis.readSI32("integer");
values.add((Long) el);
break;
case 8:
values.add(new ConstantIndex(sis.readUI8("constantIndex")));
break;
case 9:
values.add(new ConstantIndex(sis.readUI16("constantIndex")));
break;
}
}
} catch (EndOfStreamException ex) {
}
}
@Override
protected void getContentBytes(SWFOutputStream sos) throws IOException {
for (Object o : values) {
if (o instanceof String) {
sos.writeUI8(0);
sos.writeString((String) o);
} else if (o instanceof Float) {
sos.writeUI8(1);
sos.writeFLOAT((Float) o);
} else if (o == Null.INSTANCE) {
sos.writeUI8(2);
} else if (o == Undefined.INSTANCE) {
sos.writeUI8(3);
} else if (o instanceof RegisterNumber) {
sos.writeUI8(4);
sos.writeUI8(((RegisterNumber) o).number);
} else if (o instanceof Boolean) {
sos.writeUI8(5);
sos.writeUI8((Boolean) o ? 1 : 0);
} else if (o instanceof Number) {
if (o instanceof Long) {
long l = (Long) o;
if (l < -0x80000000 || l > 0x7fffffff) {
o = (double) l;
}
}
if (o instanceof Double || o instanceof Float) {
sos.writeUI8(6);
sos.writeDOUBLE(((Number) o).doubleValue());
} else if (o instanceof Long || o instanceof Integer || o instanceof Short || o instanceof Byte) {
sos.writeUI8(7);
sos.writeSI32(((Number) o).longValue());
}
} else if (o instanceof ConstantIndex) {
int cIndex = ((ConstantIndex) o).index;
if (cIndex < 256) {
sos.writeUI8(8);
sos.writeUI8(cIndex);
} else {
sos.writeUI8(9);
sos.writeUI16(cIndex);
}
}
}
}
/**
* Gets the length of action converted to bytes
*
* @return Length
*/
@Override
protected int getContentBytesLength() {
int res = 0;
for (Object o : values) {
if (o instanceof String) {
res += Utf8Helper.getBytesLength((String) o) + 2;
} else if (o instanceof Float) {
res += 5;
} else if (o == Null.INSTANCE) {
res++;
} else if (o == Undefined.INSTANCE) {
res++;
} else if (o instanceof RegisterNumber) {
res += 2;
} else if (o instanceof Boolean) {
res += 2;
} else if (o instanceof Number) {
if (o instanceof Long) {
long l = (Long) o;
if (l < -0x80000000 || l > 0x7fffffff) {
o = (double) l;
}
}
if (o instanceof Double || o instanceof Float) {
res += 9;
} else if (o instanceof Long || o instanceof Integer || o instanceof Short || o instanceof Byte) {
res += 5;
}
} else if (o instanceof ConstantIndex) {
int cIndex = ((ConstantIndex) o).index;
if (cIndex < 256) {
res += 2;
} else {
res += 3;
}
}
}
return res;
}
public static boolean isValidValue(Object value) {
if (value instanceof String) {
for (char ch : ((String) value).toCharArray()) {
if (ch == 0) {
return false;
}
}
}
if (value instanceof Long) {
long l = (Long) value;
if (l < -0x80000000 || l > 0x7fffffff) {
return false;
}
}
return true;
}
public ActionPush(Object value) {
super(0x96, 0);
this.values = new ArrayList<>();
this.values.add(value);
updateLength();
}
public ActionPush(Object[] values) {
super(0x96, 0);
this.values = new ArrayList<>();
this.values.addAll(Arrays.asList(values));
updateLength();
}
public ActionPush(FlasmLexer lexer, List<String> constantPool) throws IOException, ActionParseException {
super(0x96, 0);
this.constantPool = constantPool;
values = new ArrayList<>();
int count = 0;
loop:
while (true) {
ASMParsedSymbol symb = lexer.yylex();
switch (symb.type) {
case ASMParsedSymbol.TYPE_STRING:
count++;
if (constantPool.contains((String) symb.value)) {
values.add(new ConstantIndex(constantPool.indexOf(symb.value)));
} else {
values.add(symb.value);
}
break;
case ASMParsedSymbol.TYPE_FLOAT:
case ASMParsedSymbol.TYPE_NULL:
case ASMParsedSymbol.TYPE_UNDEFINED:
case ASMParsedSymbol.TYPE_REGISTER:
case ASMParsedSymbol.TYPE_BOOLEAN:
case ASMParsedSymbol.TYPE_INTEGER:
case ASMParsedSymbol.TYPE_CONSTANT:
count++;
values.add(symb.value);
break;
case ASMParsedSymbol.TYPE_EOL:
case ASMParsedSymbol.TYPE_EOF:
if (count == 0) {
throw new ActionParseException("Arguments expected", lexer.yyline());
} else {
break loop;
}
case ASMParsedSymbol.TYPE_COMMENT:
break;
default:
throw new ActionParseException("Arguments expected, " + symb.type + " " + symb.value + " found", lexer.yyline());
}
}
}
@Override
public GraphTextWriter getASMSourceReplaced(ActionList container, Set<Long> knownAddreses, ScriptExportMode exportMode, GraphTextWriter writer) {
if (replacement == null || replacement.size() < values.size()) {
return toString(writer);
}
List<Object> oldVal = values;
values = replacement;
toString(writer);
values = oldVal;
return writer;
}
public GraphTextWriter paramsToStringReplaced(List<? extends GraphSourceItem> container, Set<Long> knownAddreses, ScriptExportMode exportMode, GraphTextWriter writer) {
if (replacement == null || replacement.size() < values.size()) {
return paramsToString(writer);
}
List<Object> oldVal = values;
values = replacement;
paramsToString(writer);
values = oldVal;
return writer;
}
public String toStringNoQ(int i) {
String ret;
Object value = values.get(i);
if (value instanceof ConstantIndex) {
ret = ((ConstantIndex) value).toStringNoQ(constantPool, Configuration.resolveConstants.get());
} else if (value instanceof String) {
ret = (String) value;
} else if (value instanceof RegisterNumber) {
ret = ((RegisterNumber) value).toStringNoName();
} else {
ret = value.toString();
}
return ret;
}
public String toString(int i) {
String ret;
Object value = values.get(i);
if (value instanceof ConstantIndex) {
ret = ((ConstantIndex) value).toString(constantPool, Configuration.resolveConstants.get());
} else if (value instanceof String) {
ret = "\"" + Helper.escapeActionScriptString((String) value) + "\"";
} else if (value instanceof RegisterNumber) {
ret = ((RegisterNumber) value).toStringNoName();
} else {
ret = value.toString();
}
return ret;
}
public GraphTextWriter paramsToString(GraphTextWriter writer) {
int pos = 0;
for (int i = 0; i < values.size(); i++) {
if (pos > 0) {
writer.appendNoHilight(" ");
}
writer.append(toString(i), getAddress() + pos + 1, getFileOffset());
pos++;
}
return writer;
}
@Override
public String toString() {
HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), false);
toString(writer);
return writer.toString();
}
public GraphTextWriter toString(GraphTextWriter writer) {
writer.appendNoHilight("Push ");
paramsToString(writer);
return writer;
}
@Override
public boolean execute(LocalDataArea lda) {
for (Object value : values) {
if (value instanceof ConstantIndex) {
ConstantIndex constantIndex = (ConstantIndex) value;
List<String> cPool = lda.constantPool != null ? lda.constantPool : constantPool;
lda.stack.push(constantIndex.toStringNoQ(cPool, true));
} else if (value instanceof RegisterNumber) {
int rn = ((RegisterNumber) value).number;
if (lda.localRegisters.containsKey(rn)) {
lda.stack.push(lda.localRegisters.get(rn));
} else {
lda.stack.push(Undefined.INSTANCE);
}
} else {
lda.stack.push(value);
}
}
return true;
}
@Override
public void translate(GraphSourceItem lineStartAction, TranslateStack stack, List<GraphTargetItem> output, HashMap<Integer, String> regNames, HashMap<String, GraphTargetItem> variables, HashMap<String, GraphTargetItem> functions, int staticOperation, String path) {
int pos = 0;
for (Object o : values) {
if (o instanceof ConstantIndex) {
if ((constantPool == null) || (((ConstantIndex) o).index >= constantPool.size())) {
o = "\u00A7\u00A7constant" + ((ConstantIndex) o).index;
} else {
o = constantPool.get(((ConstantIndex) o).index);
}
}
/*if (o instanceof RegisterNumber) {
if (regNames.containsKey(((RegisterNumber) o).number)) {
((RegisterNumber) o).name = regNames.get(((RegisterNumber) o).number);
} else if (output.size() >= 2) { //chained assignments:, ignore for class prototype assignment
GraphTargetItem last = output.get(output.size() - 1);
GraphTargetItem prev = output.get(output.size() - 2);
if (last instanceof SetTypeActionItem) {
if (prev instanceof StoreRegisterActionItem) {
StoreRegisterActionItem str = (StoreRegisterActionItem) prev;
if (str.register.number == ((RegisterNumber) o).number) {
SetTypeActionItem stt = (SetTypeActionItem) last;
stt.setTempRegister(((RegisterNumber) o).number);
if ((stt.getValue() instanceof IncrementActionItem) && (((IncrementActionItem) stt.getValue()).object.equals(stt.getObject()))) {
stack.push(new PreIncrementActionItem(this, lineStartAction, stt.getObject()));
} else if ((stt.getValue() instanceof DecrementActionItem) && (((DecrementActionItem) stt.getValue()).object.equals(stt.getObject()))) {
stack.push(new PreDecrementActionItem(this, lineStartAction, stt.getObject()));
} else {
//stack.push(last);
continue;
}
output.remove(output.size() - 1);
output.remove(output.size() - 1);
pos++;
continue;
}
}
}
}
}*/
if (o instanceof Boolean) {
Boolean b = (Boolean) o;
if (b) {
stack.push(new TrueItem(this, lineStartAction));
} else {
stack.push(new FalseItem(this, lineStartAction));
}
} else {
DirectValueActionItem dvt = new DirectValueActionItem(this, lineStartAction, pos, o, constantPool);
if (o instanceof RegisterNumber) {//TemporaryRegister
dvt.computedRegValue = variables.get("__register" + ((RegisterNumber) o).number);
if (regNames.containsKey(((RegisterNumber) o).number)) {
((RegisterNumber) o).name = regNames.get(((RegisterNumber) o).number);
}
}
if (dvt.computedRegValue instanceof TemporaryRegister) {
stack.push(new TemporaryRegister(((RegisterNumber) o).number, ((TemporaryRegister) dvt.computedRegValue).value));
} else {
stack.push(dvt);
}
}
pos++;
}
}
@Override
public int getStackPushCount(BaseLocalData localData, TranslateStack stack) {
return values.size();
}
}

View File

@@ -1,32 +1,32 @@
/*
* Copyright (C) 2010-2016 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.configuration;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
/**
*
* @author JPEXS
*/
public class SwfSpecificConfiguration implements Serializable {
public Map<String, String> fontPairingMap = new HashMap<>();
public String lastSelectedPath = null;
}
/*
* Copyright (C) 2010-2016 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.configuration;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
/**
*
* @author JPEXS
*/
public class SwfSpecificConfiguration implements Serializable {
public Map<String, String> fontPairingMap = new HashMap<>();
public String lastSelectedPath = null;
}

View File

@@ -1,433 +1,433 @@
/*
* Copyright (C) 2010-2016 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.exporters.commonshape;
import com.jpexs.decompiler.flash.types.MATRIX;
import java.awt.geom.AffineTransform;
/**
*
* @author JPEXS
*/
public final class Matrix implements Cloneable {
public double scaleX = 1;
public double scaleY = 1;
public double rotateSkew0;
public double rotateSkew1;
public double translateX;
public double translateY;
public static Matrix getScaleInstance(double scale) {
Matrix mat = new Matrix();
mat.scale(scale);
return mat;
}
public static Matrix getTranslateInstance(double x, double y) {
Matrix mat = new Matrix();
mat.translate(x, y);
return mat;
}
public Matrix() {
scaleX = 1;
scaleY = 1;
}
public Matrix(MATRIX matrix) {
if (matrix == null) {
matrix = new MATRIX();
}
translateX = matrix.translateX;
translateY = matrix.translateY;
if (matrix.hasScale) {
scaleX = matrix.getScaleXFloat();
scaleY = matrix.getScaleYFloat();
} else {
scaleX = 1;
scaleY = 1;
}
if (matrix.hasRotate) {
rotateSkew0 = matrix.getRotateSkew0Float();
rotateSkew1 = matrix.getRotateSkew1Float();
}
}
public Matrix(AffineTransform transform) {
this();
if (transform != null) {
scaleX = transform.getScaleX();
rotateSkew1 = transform.getShearX();
translateX = transform.getTranslateX();
rotateSkew0 = transform.getShearY();
scaleY = transform.getScaleY();
translateY = transform.getTranslateY();
}
}
@Override
public Matrix clone() {
try {
Matrix mat = (Matrix) super.clone();
return mat;
} catch (CloneNotSupportedException ex) {
throw new RuntimeException();
}
}
public Point transform(double x, double y) {
Point result = new Point(
scaleX * x + rotateSkew1 * y + translateX,
rotateSkew0 * x + scaleY * y + translateY);
return result;
}
public Point transform(Point point) {
return transform(point.x, point.y);
}
public Point deltaTransform(double x, double y) {
Point result = new Point(
scaleX * x + rotateSkew1 * y,
rotateSkew0 * x + scaleY * y);
return result;
}
public Point deltaTransform(Point point) {
return deltaTransform(point.x, point.y);
}
public java.awt.Point deltaTransform(java.awt.Point point) {
Point p = deltaTransform(point.x, point.y);
return new java.awt.Point((int) p.x, (int) p.y);
}
public java.awt.Point transform(java.awt.Point point) {
Point p = transform(point.x, point.y);
return new java.awt.Point((int) p.x, (int) p.y);
}
public ExportRectangle transform(ExportRectangle rect) {
double minX = Double.MAX_VALUE;
double minY = Double.MAX_VALUE;
double maxX = Double.MIN_VALUE;
double maxY = Double.MIN_VALUE;
Point point;
point = transform(rect.xMin, rect.yMin);
if (point.x < minX) {
minX = point.x;
}
if (point.x > maxX) {
maxX = point.x;
}
if (point.y < minY) {
minY = point.y;
}
if (point.y > maxY) {
maxY = point.y;
}
point = transform(rect.xMax, rect.yMin);
if (point.x < minX) {
minX = point.x;
}
if (point.x > maxX) {
maxX = point.x;
}
if (point.y < minY) {
minY = point.y;
}
if (point.y > maxY) {
maxY = point.y;
}
point = transform(rect.xMin, rect.yMax);
if (point.x < minX) {
minX = point.x;
}
if (point.x > maxX) {
maxX = point.x;
}
if (point.y < minY) {
minY = point.y;
}
if (point.y > maxY) {
maxY = point.y;
}
point = transform(rect.xMax, rect.yMax);
if (point.x < minX) {
minX = point.x;
}
if (point.x > maxX) {
maxX = point.x;
}
if (point.y < minY) {
minY = point.y;
}
if (point.y > maxY) {
maxY = point.y;
}
return new ExportRectangle(minX, minY, maxX, maxY);
}
public void translate(double x, double y) {
translateX = scaleX * x + rotateSkew1 * y + translateX;
translateY = rotateSkew0 * x + scaleY * y + translateY;
}
public void scale(double factor) {
scaleX *= factor;
scaleY *= factor;
rotateSkew0 *= factor;
rotateSkew1 *= factor;
}
public Matrix concatenate(Matrix m) {
Matrix result = new Matrix();
result.scaleX = scaleX * m.scaleX + rotateSkew1 * m.rotateSkew0;
result.rotateSkew0 = rotateSkew0 * m.scaleX + scaleY * m.rotateSkew0;
result.rotateSkew1 = scaleX * m.rotateSkew1 + rotateSkew1 * m.scaleY;
result.scaleY = rotateSkew0 * m.rotateSkew1 + scaleY * m.scaleY;
result.translateX = scaleX * m.translateX + rotateSkew1 * m.translateY + translateX;
result.translateY = rotateSkew0 * m.translateX + scaleY * m.translateY + translateY;
return result;
}
public Matrix preConcatenate(Matrix m) {
Matrix result = new Matrix();
result.scaleX = m.scaleX * scaleX + m.rotateSkew1 * rotateSkew0;
result.rotateSkew0 = m.rotateSkew0 * scaleX + m.scaleY * rotateSkew0;
result.rotateSkew1 = m.scaleX * rotateSkew1 + m.rotateSkew1 * scaleY;
result.scaleY = m.rotateSkew0 * rotateSkew1 + m.scaleY * scaleY;
result.translateX = m.scaleX * translateX + m.rotateSkew1 * translateY + m.translateX;
result.translateY = m.rotateSkew0 * translateX + m.scaleY * translateY + m.translateY;
return result;
}
public AffineTransform toTransform() {
AffineTransform transform = new AffineTransform(scaleX, rotateSkew0,
rotateSkew1, scaleY,
translateX, translateY);
return transform;
}
public String getSvgTransformationString(double translateDivisor, double unitDivisor) {
double translateX = roundPixels400(this.translateX / translateDivisor);
double translateY = roundPixels400(this.translateY / translateDivisor);
double rotateSkew0 = roundPixels400(this.rotateSkew0 / unitDivisor);
double rotateSkew1 = roundPixels400(this.rotateSkew1 / unitDivisor);
double scaleX = roundPixels400(this.scaleX / unitDivisor);
double scaleY = roundPixels400(this.scaleY / unitDivisor);
return "matrix(" + scaleX + ", " + rotateSkew0 + ", "
+ rotateSkew1 + ", " + scaleY + ", " + translateX + ", " + translateY + ")";
}
public static String[] parseSvgNumberList(String params) {
while (params.contains(" ")) {
params = params.replaceAll(" ", " ");
}
params = params.trim();
params = params.replace(", ", ",");
params = params.replace(" ", ",");
String[] args = params.split(",");
return args;
}
public static Matrix parseSvgMatrix(String transformStr, double translateDivisor, double unitDivisor) {
Matrix ret = new Matrix();
while (transformStr != null && transformStr.length() > 0) {
String funcName = transformStr.split("\\(")[0];
transformStr = transformStr.substring(funcName.length() + 1);
String params = transformStr.split("\\)")[0];
transformStr = transformStr.substring(params.length() + 1).trim();
String[] args = parseSvgNumberList(params);
funcName = funcName.trim();
switch (funcName) {
case "matrix":
if (args.length == 6) {
double scaleX = Double.parseDouble(args[0].trim());
double rotateSkew0 = Double.parseDouble(args[1].trim());
double rotateSkew1 = Double.parseDouble(args[2].trim());
double scaleY = Double.parseDouble(args[3].trim());
double translateX = Double.parseDouble(args[4].trim());
double translateY = Double.parseDouble(args[5].trim());
Matrix result = new Matrix();
result.translateX = translateX;
result.translateY = translateY;
result.rotateSkew0 = rotateSkew0;
result.rotateSkew1 = rotateSkew1;
result.scaleX = scaleX;
result.scaleY = scaleY;
ret = ret.concatenate(result);
}
break;
case "translate":
if (args.length == 1 || args.length == 2) {
double translateX = Double.parseDouble(args[0].trim());
double translateY = 0;
if (args.length == 2) {
translateY = Double.parseDouble(args[1].trim());
}
Matrix result = new Matrix();
result.translateX = translateX;
result.translateY = translateY;
ret = ret.concatenate(result);
}
break;
case "scale":
if (args.length == 1 || args.length == 2) {
double scaleX = Double.parseDouble(args[0].trim());
double scaleY = scaleX;
if (args.length == 2) {
scaleY = Double.parseDouble(args[1].trim());
}
Matrix result = new Matrix();
result.scaleX = scaleX;
result.scaleY = scaleY;
ret = ret.concatenate(result);
}
break;
case "skewX":
if (args.length == 1) {
double angle = Double.parseDouble(args[0].trim()) * Math.PI / 180;
Matrix result = new Matrix();
result.rotateSkew1 = Math.tan(angle);
ret = ret.concatenate(result);
}
break;
case "skewY":
if (args.length == 1) {
double angle = Double.parseDouble(args[0].trim()) * Math.PI / 180;
Matrix result = new Matrix();
result.rotateSkew0 = Math.tan(angle);
ret = ret.concatenate(result);
}
break;
case "rotate":
if (args.length == 1 || args.length == 3) {
double rotateAngle = Double.parseDouble(args[0].trim());
double tx = 0;
double ty = 0;
if (args.length > 1) {
tx = Double.parseDouble(args[1].trim());
ty = Double.parseDouble(args[2].trim());
}
double angleRad = -rotateAngle * Math.PI / 180;
Matrix result = new Matrix();
result.rotateSkew0 = -Math.sin(angleRad);
result.rotateSkew1 = Math.sin(angleRad);
result.scaleX = Math.cos(angleRad);
result.scaleY = Math.cos(angleRad);
result = result.preConcatenate(getTranslateInstance(tx, ty))
.concatenate(getTranslateInstance(-tx, -ty));
ret = ret.concatenate(result);
}
break;
}
}
ret.translateX *= translateDivisor;
ret.translateY *= translateDivisor;
ret.rotateSkew0 *= unitDivisor;
ret.rotateSkew1 *= unitDivisor;
ret.scaleX *= unitDivisor;
ret.scaleY *= unitDivisor;
return ret;
}
private double roundPixels400(double pixels) {
return Math.round(pixels * 10000) / 10000.0;
}
@Override
public String toString() {
return "[Matrix scale:" + scaleX + "," + scaleY + ", rotate:" + rotateSkew0 + "," + rotateSkew1 + ", translate:" + translateX + "," + translateY + "]";
}
public Matrix inverse() {
double a = scaleX;
double b = rotateSkew1;
double tx = translateX;
double c = rotateSkew0;
double d = scaleY;
double ty = translateY;
double det = a * d - b * c;
double a2 = d / det;
double b2 = -b / det;
double tx2 = (b * ty - tx * d) / det;
double c2 = -c / det;
double d2 = a / det;
double ty2 = (tx * c - a * ty) / det;
Matrix ret = new Matrix();
ret.scaleX = a2;
ret.rotateSkew0 = c2;
ret.rotateSkew1 = b2;
ret.scaleY = d2;
ret.translateX = tx2;
ret.translateY = ty2;
return ret;
}
public double getTotalSkewAngleX() {
Point px = deltaTransform(new Point(0, 1));
return ((180 / Math.PI) * Math.atan2(px.y, px.x) - 90);
}
public double getTotalSkewAngleY() {
Point py = deltaTransform(new Point(1, 0));
return ((180 / Math.PI) * Math.atan2(py.y, py.x));
}
public double getTotalScaleX() {
return Math.sqrt(scaleX * scaleX + rotateSkew0 * rotateSkew0);
}
public double getTotalScaleY() {
return Math.sqrt(rotateSkew1 * rotateSkew1 + scaleY * scaleY);
}
private int fromFloat(double f) {
return (int) (f * (1 << 16));
}
public MATRIX toMATRIX() {
MATRIX result = new MATRIX();
result.translateX = (int) translateX;
result.translateY = (int) translateY;
result.hasRotate = true;
result.hasScale = true;
result.scaleX = fromFloat(scaleX);
result.scaleY = fromFloat(scaleY);
result.rotateSkew0 = fromFloat(rotateSkew0);
result.rotateSkew1 = fromFloat(rotateSkew1);
return result;
}
}
/*
* Copyright (C) 2010-2016 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.exporters.commonshape;
import com.jpexs.decompiler.flash.types.MATRIX;
import java.awt.geom.AffineTransform;
/**
*
* @author JPEXS
*/
public final class Matrix implements Cloneable {
public double scaleX = 1;
public double scaleY = 1;
public double rotateSkew0;
public double rotateSkew1;
public double translateX;
public double translateY;
public static Matrix getScaleInstance(double scale) {
Matrix mat = new Matrix();
mat.scale(scale);
return mat;
}
public static Matrix getTranslateInstance(double x, double y) {
Matrix mat = new Matrix();
mat.translate(x, y);
return mat;
}
public Matrix() {
scaleX = 1;
scaleY = 1;
}
public Matrix(MATRIX matrix) {
if (matrix == null) {
matrix = new MATRIX();
}
translateX = matrix.translateX;
translateY = matrix.translateY;
if (matrix.hasScale) {
scaleX = matrix.getScaleXFloat();
scaleY = matrix.getScaleYFloat();
} else {
scaleX = 1;
scaleY = 1;
}
if (matrix.hasRotate) {
rotateSkew0 = matrix.getRotateSkew0Float();
rotateSkew1 = matrix.getRotateSkew1Float();
}
}
public Matrix(AffineTransform transform) {
this();
if (transform != null) {
scaleX = transform.getScaleX();
rotateSkew1 = transform.getShearX();
translateX = transform.getTranslateX();
rotateSkew0 = transform.getShearY();
scaleY = transform.getScaleY();
translateY = transform.getTranslateY();
}
}
@Override
public Matrix clone() {
try {
Matrix mat = (Matrix) super.clone();
return mat;
} catch (CloneNotSupportedException ex) {
throw new RuntimeException();
}
}
public Point transform(double x, double y) {
Point result = new Point(
scaleX * x + rotateSkew1 * y + translateX,
rotateSkew0 * x + scaleY * y + translateY);
return result;
}
public Point transform(Point point) {
return transform(point.x, point.y);
}
public Point deltaTransform(double x, double y) {
Point result = new Point(
scaleX * x + rotateSkew1 * y,
rotateSkew0 * x + scaleY * y);
return result;
}
public Point deltaTransform(Point point) {
return deltaTransform(point.x, point.y);
}
public java.awt.Point deltaTransform(java.awt.Point point) {
Point p = deltaTransform(point.x, point.y);
return new java.awt.Point((int) p.x, (int) p.y);
}
public java.awt.Point transform(java.awt.Point point) {
Point p = transform(point.x, point.y);
return new java.awt.Point((int) p.x, (int) p.y);
}
public ExportRectangle transform(ExportRectangle rect) {
double minX = Double.MAX_VALUE;
double minY = Double.MAX_VALUE;
double maxX = Double.MIN_VALUE;
double maxY = Double.MIN_VALUE;
Point point;
point = transform(rect.xMin, rect.yMin);
if (point.x < minX) {
minX = point.x;
}
if (point.x > maxX) {
maxX = point.x;
}
if (point.y < minY) {
minY = point.y;
}
if (point.y > maxY) {
maxY = point.y;
}
point = transform(rect.xMax, rect.yMin);
if (point.x < minX) {
minX = point.x;
}
if (point.x > maxX) {
maxX = point.x;
}
if (point.y < minY) {
minY = point.y;
}
if (point.y > maxY) {
maxY = point.y;
}
point = transform(rect.xMin, rect.yMax);
if (point.x < minX) {
minX = point.x;
}
if (point.x > maxX) {
maxX = point.x;
}
if (point.y < minY) {
minY = point.y;
}
if (point.y > maxY) {
maxY = point.y;
}
point = transform(rect.xMax, rect.yMax);
if (point.x < minX) {
minX = point.x;
}
if (point.x > maxX) {
maxX = point.x;
}
if (point.y < minY) {
minY = point.y;
}
if (point.y > maxY) {
maxY = point.y;
}
return new ExportRectangle(minX, minY, maxX, maxY);
}
public void translate(double x, double y) {
translateX = scaleX * x + rotateSkew1 * y + translateX;
translateY = rotateSkew0 * x + scaleY * y + translateY;
}
public void scale(double factor) {
scaleX *= factor;
scaleY *= factor;
rotateSkew0 *= factor;
rotateSkew1 *= factor;
}
public Matrix concatenate(Matrix m) {
Matrix result = new Matrix();
result.scaleX = scaleX * m.scaleX + rotateSkew1 * m.rotateSkew0;
result.rotateSkew0 = rotateSkew0 * m.scaleX + scaleY * m.rotateSkew0;
result.rotateSkew1 = scaleX * m.rotateSkew1 + rotateSkew1 * m.scaleY;
result.scaleY = rotateSkew0 * m.rotateSkew1 + scaleY * m.scaleY;
result.translateX = scaleX * m.translateX + rotateSkew1 * m.translateY + translateX;
result.translateY = rotateSkew0 * m.translateX + scaleY * m.translateY + translateY;
return result;
}
public Matrix preConcatenate(Matrix m) {
Matrix result = new Matrix();
result.scaleX = m.scaleX * scaleX + m.rotateSkew1 * rotateSkew0;
result.rotateSkew0 = m.rotateSkew0 * scaleX + m.scaleY * rotateSkew0;
result.rotateSkew1 = m.scaleX * rotateSkew1 + m.rotateSkew1 * scaleY;
result.scaleY = m.rotateSkew0 * rotateSkew1 + m.scaleY * scaleY;
result.translateX = m.scaleX * translateX + m.rotateSkew1 * translateY + m.translateX;
result.translateY = m.rotateSkew0 * translateX + m.scaleY * translateY + m.translateY;
return result;
}
public AffineTransform toTransform() {
AffineTransform transform = new AffineTransform(scaleX, rotateSkew0,
rotateSkew1, scaleY,
translateX, translateY);
return transform;
}
public String getSvgTransformationString(double translateDivisor, double unitDivisor) {
double translateX = roundPixels400(this.translateX / translateDivisor);
double translateY = roundPixels400(this.translateY / translateDivisor);
double rotateSkew0 = roundPixels400(this.rotateSkew0 / unitDivisor);
double rotateSkew1 = roundPixels400(this.rotateSkew1 / unitDivisor);
double scaleX = roundPixels400(this.scaleX / unitDivisor);
double scaleY = roundPixels400(this.scaleY / unitDivisor);
return "matrix(" + scaleX + ", " + rotateSkew0 + ", "
+ rotateSkew1 + ", " + scaleY + ", " + translateX + ", " + translateY + ")";
}
public static String[] parseSvgNumberList(String params) {
while (params.contains(" ")) {
params = params.replaceAll(" ", " ");
}
params = params.trim();
params = params.replace(", ", ",");
params = params.replace(" ", ",");
String[] args = params.split(",");
return args;
}
public static Matrix parseSvgMatrix(String transformStr, double translateDivisor, double unitDivisor) {
Matrix ret = new Matrix();
while (transformStr != null && transformStr.length() > 0) {
String funcName = transformStr.split("\\(")[0];
transformStr = transformStr.substring(funcName.length() + 1);
String params = transformStr.split("\\)")[0];
transformStr = transformStr.substring(params.length() + 1).trim();
String[] args = parseSvgNumberList(params);
funcName = funcName.trim();
switch (funcName) {
case "matrix":
if (args.length == 6) {
double scaleX = Double.parseDouble(args[0].trim());
double rotateSkew0 = Double.parseDouble(args[1].trim());
double rotateSkew1 = Double.parseDouble(args[2].trim());
double scaleY = Double.parseDouble(args[3].trim());
double translateX = Double.parseDouble(args[4].trim());
double translateY = Double.parseDouble(args[5].trim());
Matrix result = new Matrix();
result.translateX = translateX;
result.translateY = translateY;
result.rotateSkew0 = rotateSkew0;
result.rotateSkew1 = rotateSkew1;
result.scaleX = scaleX;
result.scaleY = scaleY;
ret = ret.concatenate(result);
}
break;
case "translate":
if (args.length == 1 || args.length == 2) {
double translateX = Double.parseDouble(args[0].trim());
double translateY = 0;
if (args.length == 2) {
translateY = Double.parseDouble(args[1].trim());
}
Matrix result = new Matrix();
result.translateX = translateX;
result.translateY = translateY;
ret = ret.concatenate(result);
}
break;
case "scale":
if (args.length == 1 || args.length == 2) {
double scaleX = Double.parseDouble(args[0].trim());
double scaleY = scaleX;
if (args.length == 2) {
scaleY = Double.parseDouble(args[1].trim());
}
Matrix result = new Matrix();
result.scaleX = scaleX;
result.scaleY = scaleY;
ret = ret.concatenate(result);
}
break;
case "skewX":
if (args.length == 1) {
double angle = Double.parseDouble(args[0].trim()) * Math.PI / 180;
Matrix result = new Matrix();
result.rotateSkew1 = Math.tan(angle);
ret = ret.concatenate(result);
}
break;
case "skewY":
if (args.length == 1) {
double angle = Double.parseDouble(args[0].trim()) * Math.PI / 180;
Matrix result = new Matrix();
result.rotateSkew0 = Math.tan(angle);
ret = ret.concatenate(result);
}
break;
case "rotate":
if (args.length == 1 || args.length == 3) {
double rotateAngle = Double.parseDouble(args[0].trim());
double tx = 0;
double ty = 0;
if (args.length > 1) {
tx = Double.parseDouble(args[1].trim());
ty = Double.parseDouble(args[2].trim());
}
double angleRad = -rotateAngle * Math.PI / 180;
Matrix result = new Matrix();
result.rotateSkew0 = -Math.sin(angleRad);
result.rotateSkew1 = Math.sin(angleRad);
result.scaleX = Math.cos(angleRad);
result.scaleY = Math.cos(angleRad);
result = result.preConcatenate(getTranslateInstance(tx, ty))
.concatenate(getTranslateInstance(-tx, -ty));
ret = ret.concatenate(result);
}
break;
}
}
ret.translateX *= translateDivisor;
ret.translateY *= translateDivisor;
ret.rotateSkew0 *= unitDivisor;
ret.rotateSkew1 *= unitDivisor;
ret.scaleX *= unitDivisor;
ret.scaleY *= unitDivisor;
return ret;
}
private double roundPixels400(double pixels) {
return Math.round(pixels * 10000) / 10000.0;
}
@Override
public String toString() {
return "[Matrix scale:" + scaleX + "," + scaleY + ", rotate:" + rotateSkew0 + "," + rotateSkew1 + ", translate:" + translateX + "," + translateY + "]";
}
public Matrix inverse() {
double a = scaleX;
double b = rotateSkew1;
double tx = translateX;
double c = rotateSkew0;
double d = scaleY;
double ty = translateY;
double det = a * d - b * c;
double a2 = d / det;
double b2 = -b / det;
double tx2 = (b * ty - tx * d) / det;
double c2 = -c / det;
double d2 = a / det;
double ty2 = (tx * c - a * ty) / det;
Matrix ret = new Matrix();
ret.scaleX = a2;
ret.rotateSkew0 = c2;
ret.rotateSkew1 = b2;
ret.scaleY = d2;
ret.translateX = tx2;
ret.translateY = ty2;
return ret;
}
public double getTotalSkewAngleX() {
Point px = deltaTransform(new Point(0, 1));
return ((180 / Math.PI) * Math.atan2(px.y, px.x) - 90);
}
public double getTotalSkewAngleY() {
Point py = deltaTransform(new Point(1, 0));
return ((180 / Math.PI) * Math.atan2(py.y, py.x));
}
public double getTotalScaleX() {
return Math.sqrt(scaleX * scaleX + rotateSkew0 * rotateSkew0);
}
public double getTotalScaleY() {
return Math.sqrt(rotateSkew1 * rotateSkew1 + scaleY * scaleY);
}
private int fromFloat(double f) {
return (int) (f * (1 << 16));
}
public MATRIX toMATRIX() {
MATRIX result = new MATRIX();
result.translateX = (int) translateX;
result.translateY = (int) translateY;
result.hasRotate = true;
result.hasScale = true;
result.scaleX = fromFloat(scaleX);
result.scaleY = fromFloat(scaleY);
result.rotateSkew0 = fromFloat(rotateSkew0);
result.rotateSkew1 = fromFloat(rotateSkew1);
return result;
}
}

View File

@@ -1,162 +1,162 @@
/*
* Copyright (C) 2010-2016 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.helpers;
import com.jpexs.decompiler.flash.helpers.hilight.HighlightData;
import com.jpexs.decompiler.flash.helpers.hilight.HighlightSpecialType;
import java.util.Stack;
/**
* Provides methods for highlighting positions of instructions in the text.
*
* @author JPEXS
*/
public class NulWriter extends GraphTextWriter {
private final Stack<LoopWithType> loopStack = new Stack<>();
private final Stack<Boolean> stringAddedStack = new Stack<>();
private boolean stringAdded = false;
public NulWriter() {
super(new CodeFormatting());
}
public void startLoop(long loopId, int loopType) {
LoopWithType loop = new LoopWithType();
loop.loopId = loopId;
loop.type = loopType;
loopStack.add(loop);
}
public LoopWithType endLoop(long loopId) {
LoopWithType loopIdInStack = loopStack.pop();
if (loopId != loopIdInStack.loopId) {
throw new Error("LoopId mismatch");
}
return loopIdInStack;
}
public long getLoop() {
if (loopStack.isEmpty()) {
return -1;
}
return loopStack.peek().loopId;
}
public long getNonSwitchLoop() {
if (loopStack.isEmpty()) {
return -1;
}
int pos = loopStack.size() - 1;
LoopWithType loop;
do {
loop = loopStack.get(pos);
pos--;
} while ((pos >= 0) && (loop.type == LoopWithType.LOOP_TYPE_SWITCH));
if (loop.type == LoopWithType.LOOP_TYPE_SWITCH) {
return -1;
}
return loop.loopId;
}
public void setLoopUsed(long loopId) {
if (loopStack.isEmpty()) {
return;
}
int pos = loopStack.size() - 1;
LoopWithType loop = null;
do {
loop = loopStack.get(pos);
pos--;
} while ((pos >= 0) && (loop.loopId != loopId));
if (loop.loopId == loopId) {
loop.used = true;
}
}
@Override
public NulWriter hilightSpecial(String text, HighlightSpecialType type, String specialValue, HighlightData data) {
stringAdded = true;
return this;
}
@Override
public GraphTextWriter append(char value) {
stringAdded = true;
return this;
}
@Override
public GraphTextWriter append(int value) {
stringAdded = true;
return this;
}
@Override
public GraphTextWriter append(long value) {
stringAdded = true;
return this;
}
@Override
public NulWriter append(String str) {
stringAdded = true;
return this;
}
@Override
public GraphTextWriter appendWithData(String str, HighlightData data) {
stringAdded = true;
return this;
}
@Override
public NulWriter append(String str, long offset, long fileOffset) {
stringAdded = true;
return this;
}
@Override
public NulWriter appendNoHilight(int i) {
stringAdded = true;
return this;
}
@Override
public NulWriter appendNoHilight(String str) {
stringAdded = true;
return this;
}
public void mark() {
stringAddedStack.add(stringAdded);
stringAdded = false;
}
public boolean getMark() {
boolean result = stringAdded;
stringAdded = stringAddedStack.pop() || result;
return result;
}
}
/*
* Copyright (C) 2010-2016 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.helpers;
import com.jpexs.decompiler.flash.helpers.hilight.HighlightData;
import com.jpexs.decompiler.flash.helpers.hilight.HighlightSpecialType;
import java.util.Stack;
/**
* Provides methods for highlighting positions of instructions in the text.
*
* @author JPEXS
*/
public class NulWriter extends GraphTextWriter {
private final Stack<LoopWithType> loopStack = new Stack<>();
private final Stack<Boolean> stringAddedStack = new Stack<>();
private boolean stringAdded = false;
public NulWriter() {
super(new CodeFormatting());
}
public void startLoop(long loopId, int loopType) {
LoopWithType loop = new LoopWithType();
loop.loopId = loopId;
loop.type = loopType;
loopStack.add(loop);
}
public LoopWithType endLoop(long loopId) {
LoopWithType loopIdInStack = loopStack.pop();
if (loopId != loopIdInStack.loopId) {
throw new Error("LoopId mismatch");
}
return loopIdInStack;
}
public long getLoop() {
if (loopStack.isEmpty()) {
return -1;
}
return loopStack.peek().loopId;
}
public long getNonSwitchLoop() {
if (loopStack.isEmpty()) {
return -1;
}
int pos = loopStack.size() - 1;
LoopWithType loop;
do {
loop = loopStack.get(pos);
pos--;
} while ((pos >= 0) && (loop.type == LoopWithType.LOOP_TYPE_SWITCH));
if (loop.type == LoopWithType.LOOP_TYPE_SWITCH) {
return -1;
}
return loop.loopId;
}
public void setLoopUsed(long loopId) {
if (loopStack.isEmpty()) {
return;
}
int pos = loopStack.size() - 1;
LoopWithType loop = null;
do {
loop = loopStack.get(pos);
pos--;
} while ((pos >= 0) && (loop.loopId != loopId));
if (loop.loopId == loopId) {
loop.used = true;
}
}
@Override
public NulWriter hilightSpecial(String text, HighlightSpecialType type, String specialValue, HighlightData data) {
stringAdded = true;
return this;
}
@Override
public GraphTextWriter append(char value) {
stringAdded = true;
return this;
}
@Override
public GraphTextWriter append(int value) {
stringAdded = true;
return this;
}
@Override
public GraphTextWriter append(long value) {
stringAdded = true;
return this;
}
@Override
public NulWriter append(String str) {
stringAdded = true;
return this;
}
@Override
public GraphTextWriter appendWithData(String str, HighlightData data) {
stringAdded = true;
return this;
}
@Override
public NulWriter append(String str, long offset, long fileOffset) {
stringAdded = true;
return this;
}
@Override
public NulWriter appendNoHilight(int i) {
stringAdded = true;
return this;
}
@Override
public NulWriter appendNoHilight(String str) {
stringAdded = true;
return this;
}
public void mark() {
stringAddedStack.add(stringAdded);
stringAdded = false;
}
public boolean getMark() {
boolean result = stringAdded;
stringAdded = stringAddedStack.pop() || result;
return result;
}
}

View File

@@ -1,38 +1,38 @@
# Copyright (C) 2010-2016 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.
decompilationError = Decompilation error
decompilationError.timeout = Timeout ({0}) was reached
decompilationError.timeout.description = Not decompiled due to timeout
decompilationError.obfuscated = Code may be obfuscated
decompilationError.errorType = Error type
decompilationError.error.description = Not decompiled due to error
decompilationError.actionCount = Action count:
decompilationError.instructionCount = Instruction count:
decompilation.skipped = Decompilation skipped
decompilation.unsupported = Unsupported by decompiler
decompilerMark = decompiler mark
#example: 1 hour and 2 minutes
timeFormat.and = and
timeFormat.hour = hour
timeFormat.hours = hours
timeFormat.minute = minute
timeFormat.minutes = minutes
timeFormat.second = second
timeFormat.seconds = seconds
fontNotFound = Font with id=%fontId% was not found.
# Copyright (C) 2010-2016 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.
decompilationError = Decompilation error
decompilationError.timeout = Timeout ({0}) was reached
decompilationError.timeout.description = Not decompiled due to timeout
decompilationError.obfuscated = Code may be obfuscated
decompilationError.errorType = Error type
decompilationError.error.description = Not decompiled due to error
decompilationError.actionCount = Action count:
decompilationError.instructionCount = Instruction count:
decompilation.skipped = Decompilation skipped
decompilation.unsupported = Unsupported by decompiler
decompilerMark = decompiler mark
#example: 1 hour and 2 minutes
timeFormat.and = and
timeFormat.hour = hour
timeFormat.hours = hours
timeFormat.minute = minute
timeFormat.minutes = minutes
timeFormat.second = second
timeFormat.seconds = seconds
fontNotFound = Font with id=%fontId% was not found.

View File

@@ -1,177 +1,177 @@
/*
* Copyright (C) 2010-2016 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.tags.base.FontInfoTag;
import com.jpexs.decompiler.flash.types.BasicType;
import com.jpexs.decompiler.flash.types.LANGCODE;
import com.jpexs.decompiler.flash.types.annotations.Reserved;
import com.jpexs.decompiler.flash.types.annotations.SWFType;
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
import com.jpexs.helpers.ByteArrayRange;
import com.jpexs.helpers.utf8.Utf8Helper;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
*
* @author JPEXS
*/
@SWFVersion(from = 6)
public class DefineFontInfo2Tag extends FontInfoTag {
public static final int ID = 62;
public static final String NAME = "DefineFontInfo2";
public String fontName;
@Reserved
@SWFType(value = BasicType.UB, count = 2)
public int reserved;
public boolean fontFlagsSmallText;
public boolean fontFlagsShiftJIS;
public boolean fontFlagsANSI;
public boolean fontFlagsItalic;
public boolean fontFlagsBold;
public boolean fontFlagsWideCodes; //always 1
public LANGCODE languageCode;
@SWFType(BasicType.UI16)
public List<Integer> codeTable;
/**
* Constructor
*
* @param swf
*/
public DefineFontInfo2Tag(SWF swf) {
super(swf, ID, NAME, null);
fontName = "New Font Info Name";
languageCode = new LANGCODE();
codeTable = new ArrayList<>();
}
/**
* Constructor
*
* @param sis
* @param data
* @throws IOException
*/
public DefineFontInfo2Tag(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");
if (swf.version >= 6) {
fontName = sis.readNetString("fontName", Utf8Helper.charset);
} else {
fontName = sis.readNetString("fontName");
}
reserved = (int) sis.readUB(2, "reserved");
fontFlagsSmallText = sis.readUB(1, "fontFlagsSmallText") == 1;
fontFlagsShiftJIS = sis.readUB(1, "fontFlagsShiftJIS") == 1;
fontFlagsANSI = sis.readUB(1, "fontFlagsANSI") == 1;
fontFlagsItalic = sis.readUB(1, "fontFlagsItalic") == 1;
fontFlagsBold = sis.readUB(1, "fontFlagsBold") == 1;
fontFlagsWideCodes = sis.readUB(1, "fontFlagsWideCodes") == 1; //Always 1
languageCode = sis.readLANGCODE("languageCode");
int ctLen = sis.available() / 2;
codeTable = new ArrayList<>();
for (int i = 0; i < ctLen; i++) {
codeTable.add(sis.readUI16("code"));
}
}
/**
* Gets data bytes
*
* @param sos SWF output stream
* @throws java.io.IOException
*/
@Override
public void getData(SWFOutputStream sos) throws IOException {
sos.writeUI16(fontID);
if (swf.version >= 6) {
sos.writeNetString(fontName, Utf8Helper.charset);
} else {
sos.writeNetString(fontName);
}
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);
}
}
@Override
public List<Integer> getCodeTable() {
return codeTable;
}
@Override
public void addCharacter(int index, int character) {
codeTable.add(index, character);
setModified(true);
}
@Override
public String getFontName() {
return fontName;
}
@Override
public boolean getFontFlagsBold() {
return fontFlagsBold;
}
@Override
public void setFontFlagsBold(boolean value) {
fontFlagsBold = value;
}
@Override
public boolean getFontFlagsItalic() {
return fontFlagsItalic;
}
@Override
public void setFontFlagsItalic(boolean value) {
fontFlagsItalic = value;
}
}
/*
* Copyright (C) 2010-2016 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.tags.base.FontInfoTag;
import com.jpexs.decompiler.flash.types.BasicType;
import com.jpexs.decompiler.flash.types.LANGCODE;
import com.jpexs.decompiler.flash.types.annotations.Reserved;
import com.jpexs.decompiler.flash.types.annotations.SWFType;
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
import com.jpexs.helpers.ByteArrayRange;
import com.jpexs.helpers.utf8.Utf8Helper;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
*
* @author JPEXS
*/
@SWFVersion(from = 6)
public class DefineFontInfo2Tag extends FontInfoTag {
public static final int ID = 62;
public static final String NAME = "DefineFontInfo2";
public String fontName;
@Reserved
@SWFType(value = BasicType.UB, count = 2)
public int reserved;
public boolean fontFlagsSmallText;
public boolean fontFlagsShiftJIS;
public boolean fontFlagsANSI;
public boolean fontFlagsItalic;
public boolean fontFlagsBold;
public boolean fontFlagsWideCodes; //always 1
public LANGCODE languageCode;
@SWFType(BasicType.UI16)
public List<Integer> codeTable;
/**
* Constructor
*
* @param swf
*/
public DefineFontInfo2Tag(SWF swf) {
super(swf, ID, NAME, null);
fontName = "New Font Info Name";
languageCode = new LANGCODE();
codeTable = new ArrayList<>();
}
/**
* Constructor
*
* @param sis
* @param data
* @throws IOException
*/
public DefineFontInfo2Tag(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");
if (swf.version >= 6) {
fontName = sis.readNetString("fontName", Utf8Helper.charset);
} else {
fontName = sis.readNetString("fontName");
}
reserved = (int) sis.readUB(2, "reserved");
fontFlagsSmallText = sis.readUB(1, "fontFlagsSmallText") == 1;
fontFlagsShiftJIS = sis.readUB(1, "fontFlagsShiftJIS") == 1;
fontFlagsANSI = sis.readUB(1, "fontFlagsANSI") == 1;
fontFlagsItalic = sis.readUB(1, "fontFlagsItalic") == 1;
fontFlagsBold = sis.readUB(1, "fontFlagsBold") == 1;
fontFlagsWideCodes = sis.readUB(1, "fontFlagsWideCodes") == 1; //Always 1
languageCode = sis.readLANGCODE("languageCode");
int ctLen = sis.available() / 2;
codeTable = new ArrayList<>();
for (int i = 0; i < ctLen; i++) {
codeTable.add(sis.readUI16("code"));
}
}
/**
* Gets data bytes
*
* @param sos SWF output stream
* @throws java.io.IOException
*/
@Override
public void getData(SWFOutputStream sos) throws IOException {
sos.writeUI16(fontID);
if (swf.version >= 6) {
sos.writeNetString(fontName, Utf8Helper.charset);
} else {
sos.writeNetString(fontName);
}
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);
}
}
@Override
public List<Integer> getCodeTable() {
return codeTable;
}
@Override
public void addCharacter(int index, int character) {
codeTable.add(index, character);
setModified(true);
}
@Override
public String getFontName() {
return fontName;
}
@Override
public boolean getFontFlagsBold() {
return fontFlagsBold;
}
@Override
public void setFontFlagsBold(boolean value) {
fontFlagsBold = value;
}
@Override
public boolean getFontFlagsItalic() {
return fontFlagsItalic;
}
@Override
public void setFontFlagsItalic(boolean value) {
fontFlagsItalic = value;
}
}

View File

@@ -1,178 +1,178 @@
/*
* Copyright (C) 2010-2016 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.tags.base.FontInfoTag;
import com.jpexs.decompiler.flash.types.BasicType;
import com.jpexs.decompiler.flash.types.annotations.Reserved;
import com.jpexs.decompiler.flash.types.annotations.SWFType;
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
import com.jpexs.helpers.ByteArrayRange;
import com.jpexs.helpers.utf8.Utf8Helper;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
*
* @author JPEXS
*/
@SWFVersion(from = 1)
public class DefineFontInfoTag extends FontInfoTag {
public static final int ID = 13;
public static final String NAME = "DefineFontInfo";
public String fontName;
@Reserved
@SWFType(value = BasicType.UB, count = 2)
public int reserved;
public boolean fontFlagsSmallText;
public boolean fontFlagsShiftJIS;
public boolean fontFlagsANSI;
public boolean fontFlagsItalic;
public boolean fontFlagsBold;
public boolean fontFlagsWideCodes;
@SWFType(value = BasicType.UI8, alternateValue = BasicType.UI16, alternateCondition = "fontFlagsWideCodes")
public List<Integer> codeTable;
/**
* Constructor
*
* @param swf
*/
public DefineFontInfoTag(SWF swf) {
super(swf, ID, NAME, null);
fontName = "New Font Info Name";
codeTable = new ArrayList<>();
}
/**
* Constructor
*
* @param sis
* @param data
* @throws IOException
*/
public DefineFontInfoTag(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");
if (swf.version >= 6) {
fontName = sis.readNetString("fontName", Utf8Helper.charset);
} else {
fontName = sis.readNetString("fontName");
}
reserved = (int) sis.readUB(2, "reserved");
fontFlagsSmallText = sis.readUB(1, "fontFlagsSmallText") == 1;
fontFlagsShiftJIS = sis.readUB(1, "fontFlagsShiftJIS") == 1;
fontFlagsANSI = sis.readUB(1, "fontFlagsANSI") == 1;
fontFlagsItalic = sis.readUB(1, "fontFlagsItalic") == 1;
fontFlagsBold = sis.readUB(1, "fontFlagsBold") == 1;
fontFlagsWideCodes = sis.readUB(1, "fontFlagsWideCodes") == 1;
codeTable = new ArrayList<>();
while (sis.available() > 0) {
if (fontFlagsWideCodes) {
codeTable.add(sis.readUI16("code"));
} else {
codeTable.add(sis.readUI8("code"));
}
}
}
/**
* Gets data bytes
*
* @param sos SWF output stream
* @throws java.io.IOException
*/
@Override
public void getData(SWFOutputStream sos) throws IOException {
sos.writeUI16(fontID);
if (swf.version >= 6) {
sos.writeNetString(fontName, Utf8Helper.charset);
} else {
sos.writeNetString(fontName);
}
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);
}
}
}
@Override
public List<Integer> getCodeTable() {
return codeTable;
}
@Override
public void addCharacter(int index, int character) {
codeTable.add(index, character);
setModified(true);
}
@Override
public String getFontName() {
return fontName;
}
@Override
public boolean getFontFlagsBold() {
return fontFlagsBold;
}
@Override
public void setFontFlagsBold(boolean value) {
fontFlagsBold = value;
}
@Override
public boolean getFontFlagsItalic() {
return fontFlagsItalic;
}
@Override
public void setFontFlagsItalic(boolean value) {
fontFlagsItalic = value;
}
}
/*
* Copyright (C) 2010-2016 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.tags.base.FontInfoTag;
import com.jpexs.decompiler.flash.types.BasicType;
import com.jpexs.decompiler.flash.types.annotations.Reserved;
import com.jpexs.decompiler.flash.types.annotations.SWFType;
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
import com.jpexs.helpers.ByteArrayRange;
import com.jpexs.helpers.utf8.Utf8Helper;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
*
* @author JPEXS
*/
@SWFVersion(from = 1)
public class DefineFontInfoTag extends FontInfoTag {
public static final int ID = 13;
public static final String NAME = "DefineFontInfo";
public String fontName;
@Reserved
@SWFType(value = BasicType.UB, count = 2)
public int reserved;
public boolean fontFlagsSmallText;
public boolean fontFlagsShiftJIS;
public boolean fontFlagsANSI;
public boolean fontFlagsItalic;
public boolean fontFlagsBold;
public boolean fontFlagsWideCodes;
@SWFType(value = BasicType.UI8, alternateValue = BasicType.UI16, alternateCondition = "fontFlagsWideCodes")
public List<Integer> codeTable;
/**
* Constructor
*
* @param swf
*/
public DefineFontInfoTag(SWF swf) {
super(swf, ID, NAME, null);
fontName = "New Font Info Name";
codeTable = new ArrayList<>();
}
/**
* Constructor
*
* @param sis
* @param data
* @throws IOException
*/
public DefineFontInfoTag(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");
if (swf.version >= 6) {
fontName = sis.readNetString("fontName", Utf8Helper.charset);
} else {
fontName = sis.readNetString("fontName");
}
reserved = (int) sis.readUB(2, "reserved");
fontFlagsSmallText = sis.readUB(1, "fontFlagsSmallText") == 1;
fontFlagsShiftJIS = sis.readUB(1, "fontFlagsShiftJIS") == 1;
fontFlagsANSI = sis.readUB(1, "fontFlagsANSI") == 1;
fontFlagsItalic = sis.readUB(1, "fontFlagsItalic") == 1;
fontFlagsBold = sis.readUB(1, "fontFlagsBold") == 1;
fontFlagsWideCodes = sis.readUB(1, "fontFlagsWideCodes") == 1;
codeTable = new ArrayList<>();
while (sis.available() > 0) {
if (fontFlagsWideCodes) {
codeTable.add(sis.readUI16("code"));
} else {
codeTable.add(sis.readUI8("code"));
}
}
}
/**
* Gets data bytes
*
* @param sos SWF output stream
* @throws java.io.IOException
*/
@Override
public void getData(SWFOutputStream sos) throws IOException {
sos.writeUI16(fontID);
if (swf.version >= 6) {
sos.writeNetString(fontName, Utf8Helper.charset);
} else {
sos.writeNetString(fontName);
}
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);
}
}
}
@Override
public List<Integer> getCodeTable() {
return codeTable;
}
@Override
public void addCharacter(int index, int character) {
codeTable.add(index, character);
setModified(true);
}
@Override
public String getFontName() {
return fontName;
}
@Override
public boolean getFontFlagsBold() {
return fontFlagsBold;
}
@Override
public void setFontFlagsBold(boolean value) {
fontFlagsBold = value;
}
@Override
public boolean getFontFlagsItalic() {
return fontFlagsItalic;
}
@Override
public void setFontFlagsItalic(boolean value) {
fontFlagsItalic = value;
}
}

View File

@@ -1,224 +1,224 @@
/*
* Copyright (C) 2010-2016 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.DisassemblyListener;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.SWFOutputStream;
import com.jpexs.decompiler.flash.action.Action;
import com.jpexs.decompiler.flash.action.ActionList;
import com.jpexs.decompiler.flash.action.ConstantPoolTooBigException;
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
import com.jpexs.decompiler.flash.tags.base.ASMSource;
import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit;
import com.jpexs.decompiler.flash.types.annotations.Internal;
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
import com.jpexs.helpers.ByteArrayRange;
import com.jpexs.helpers.Helper;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* Instructs Flash Player to perform a list of actions when the current frame is
* complete.
*
* @author JPEXS
*/
@SWFVersion(from = 1)
public class DoActionTag extends Tag implements ASMSource {
public static final int ID = 12;
public static final String NAME = "DoAction";
/**
* List of actions to perform
*/
@HideInRawEdit
public ByteArrayRange actionBytes;
@Internal
private String scriptName = "-";
@Override
public String getScriptName() {
return scriptName;
}
/**
* Constructor
*
* @param swf
*/
public DoActionTag(SWF swf) {
super(swf, ID, NAME, null);
actionBytes = ByteArrayRange.EMPTY;
}
/**
* Constructor
*
* @param swf
* @param data
*/
public DoActionTag(SWF swf, ByteArrayRange data) {
super(swf, ID, NAME, data);
actionBytes = ByteArrayRange.EMPTY;
}
/**
* Constructor
*
* @param sis
* @param data
* @throws java.io.IOException
*/
public DoActionTag(SWFInputStream sis, ByteArrayRange data) throws IOException {
super(sis.getSwf(), ID, NAME, data);
readData(sis, data, 0, false, false, false);
}
@Override
public void setScriptName(String scriptName) {
this.scriptName = scriptName;
}
@Override
public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException {
actionBytes = sis.readByteRangeEx(sis.available(), "actionBytes");
}
/**
* Gets data bytes
*
* @param sos SWF output stream
* @throws java.io.IOException
*/
@Override
public void getData(SWFOutputStream sos) throws IOException {
sos.write(getActionBytes());
}
/**
* Converts actions to ASM source
*
* @param exportMode PCode or hex?
* @param writer
* @param actions
* @return ASM source
* @throws java.lang.InterruptedException
*/
@Override
public GraphTextWriter getASMSource(ScriptExportMode exportMode, GraphTextWriter writer, ActionList actions) throws InterruptedException {
if (actions == null) {
actions = getActions();
}
return Action.actionsToString(listeners, 0, actions, swf.version, exportMode, writer);
}
/**
* Whether or not this object contains ASM source
*
* @return True when contains
*/
@Override
public boolean containsSource() {
return true;
}
@Override
public ActionList getActions() throws InterruptedException {
return SWF.getCachedActionList(this, listeners);
}
@Override
public void setActions(List<Action> actions) {
actionBytes = Action.actionsToByteArrayRange(actions, true, swf.version);
}
@Override
public ByteArrayRange getActionBytes() {
return actionBytes;
}
@Override
public void setActionBytes(byte[] actionBytes) {
this.actionBytes = new ByteArrayRange(actionBytes);
SWF.uncache(this);
}
@Override
public void setConstantPools(List<List<String>> constantPools) throws ConstantPoolTooBigException {
Action.setConstantPools(this, constantPools, false);
}
@Override
public void setModified() {
setModified(true);
}
@Override
public GraphTextWriter getActionBytesAsHex(GraphTextWriter writer) {
return Helper.byteArrayToHexWithHeader(writer, actionBytes.getRangeData());
}
List<DisassemblyListener> listeners = new ArrayList<>();
@Override
public void addDisassemblyListener(DisassemblyListener listener) {
listeners.add(listener);
}
@Override
public void removeDisassemblyListener(DisassemblyListener listener) {
listeners.remove(listener);
}
@Override
public GraphTextWriter getActionSourcePrefix(GraphTextWriter writer) {
return writer;
}
@Override
public GraphTextWriter getActionSourceSuffix(GraphTextWriter writer) {
return writer;
}
@Override
public int getPrefixLineCount() {
return 0;
}
@Override
public String removePrefixAndSuffix(String source) {
return source;
}
@Override
public Tag getSourceTag() {
return this;
}
@Override
public void setSourceTag(Tag t) {
//nothing
}
}
/*
* Copyright (C) 2010-2016 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.DisassemblyListener;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.SWFOutputStream;
import com.jpexs.decompiler.flash.action.Action;
import com.jpexs.decompiler.flash.action.ActionList;
import com.jpexs.decompiler.flash.action.ConstantPoolTooBigException;
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
import com.jpexs.decompiler.flash.tags.base.ASMSource;
import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit;
import com.jpexs.decompiler.flash.types.annotations.Internal;
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
import com.jpexs.helpers.ByteArrayRange;
import com.jpexs.helpers.Helper;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* Instructs Flash Player to perform a list of actions when the current frame is
* complete.
*
* @author JPEXS
*/
@SWFVersion(from = 1)
public class DoActionTag extends Tag implements ASMSource {
public static final int ID = 12;
public static final String NAME = "DoAction";
/**
* List of actions to perform
*/
@HideInRawEdit
public ByteArrayRange actionBytes;
@Internal
private String scriptName = "-";
@Override
public String getScriptName() {
return scriptName;
}
/**
* Constructor
*
* @param swf
*/
public DoActionTag(SWF swf) {
super(swf, ID, NAME, null);
actionBytes = ByteArrayRange.EMPTY;
}
/**
* Constructor
*
* @param swf
* @param data
*/
public DoActionTag(SWF swf, ByteArrayRange data) {
super(swf, ID, NAME, data);
actionBytes = ByteArrayRange.EMPTY;
}
/**
* Constructor
*
* @param sis
* @param data
* @throws java.io.IOException
*/
public DoActionTag(SWFInputStream sis, ByteArrayRange data) throws IOException {
super(sis.getSwf(), ID, NAME, data);
readData(sis, data, 0, false, false, false);
}
@Override
public void setScriptName(String scriptName) {
this.scriptName = scriptName;
}
@Override
public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException {
actionBytes = sis.readByteRangeEx(sis.available(), "actionBytes");
}
/**
* Gets data bytes
*
* @param sos SWF output stream
* @throws java.io.IOException
*/
@Override
public void getData(SWFOutputStream sos) throws IOException {
sos.write(getActionBytes());
}
/**
* Converts actions to ASM source
*
* @param exportMode PCode or hex?
* @param writer
* @param actions
* @return ASM source
* @throws java.lang.InterruptedException
*/
@Override
public GraphTextWriter getASMSource(ScriptExportMode exportMode, GraphTextWriter writer, ActionList actions) throws InterruptedException {
if (actions == null) {
actions = getActions();
}
return Action.actionsToString(listeners, 0, actions, swf.version, exportMode, writer);
}
/**
* Whether or not this object contains ASM source
*
* @return True when contains
*/
@Override
public boolean containsSource() {
return true;
}
@Override
public ActionList getActions() throws InterruptedException {
return SWF.getCachedActionList(this, listeners);
}
@Override
public void setActions(List<Action> actions) {
actionBytes = Action.actionsToByteArrayRange(actions, true, swf.version);
}
@Override
public ByteArrayRange getActionBytes() {
return actionBytes;
}
@Override
public void setActionBytes(byte[] actionBytes) {
this.actionBytes = new ByteArrayRange(actionBytes);
SWF.uncache(this);
}
@Override
public void setConstantPools(List<List<String>> constantPools) throws ConstantPoolTooBigException {
Action.setConstantPools(this, constantPools, false);
}
@Override
public void setModified() {
setModified(true);
}
@Override
public GraphTextWriter getActionBytesAsHex(GraphTextWriter writer) {
return Helper.byteArrayToHexWithHeader(writer, actionBytes.getRangeData());
}
List<DisassemblyListener> listeners = new ArrayList<>();
@Override
public void addDisassemblyListener(DisassemblyListener listener) {
listeners.add(listener);
}
@Override
public void removeDisassemblyListener(DisassemblyListener listener) {
listeners.remove(listener);
}
@Override
public GraphTextWriter getActionSourcePrefix(GraphTextWriter writer) {
return writer;
}
@Override
public GraphTextWriter getActionSourceSuffix(GraphTextWriter writer) {
return writer;
}
@Override
public int getPrefixLineCount() {
return 0;
}
@Override
public String removePrefixAndSuffix(String source) {
return source;
}
@Override
public Tag getSourceTag() {
return this;
}
@Override
public void setSourceTag(Tag t) {
//nothing
}
}

View File

@@ -1,281 +1,281 @@
/*
* Copyright (C) 2010-2016 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.base;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
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.helpers.ImageHelper;
import com.jpexs.decompiler.flash.tags.TagInfo;
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;
import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY;
import com.jpexs.decompiler.flash.types.LINESTYLE;
import com.jpexs.decompiler.flash.types.LINESTYLEARRAY;
import com.jpexs.decompiler.flash.types.MATRIX;
import com.jpexs.decompiler.flash.types.RECT;
import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE;
import com.jpexs.decompiler.flash.types.annotations.SWFType;
import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord;
import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord;
import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord;
import com.jpexs.helpers.ByteArrayRange;
import com.jpexs.helpers.SerializableImage;
import java.awt.Dimension;
import java.awt.Shape;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Set;
/**
*
* @author JPEXS
*/
public abstract class ImageTag extends DrawableTag {
@SWFType(BasicType.UI16)
public int characterID;
protected SerializableImage cachedImage;
public ImageTag(SWF swf, int id, String name, ByteArrayRange data) {
super(swf, id, name, data);
}
public abstract InputStream getOriginalImageData();
protected abstract SerializableImage getImage();
public abstract Dimension getImageDimension();
public abstract void setImage(byte[] data) throws IOException;
public abstract ImageFormat getImageFormat();
public abstract ImageFormat getOriginalImageFormat();
public boolean importSupported() {
return true;
}
public static ImageFormat getImageFormat(byte[] data) {
return getImageFormat(new ByteArrayRange(data));
}
public static ImageFormat getImageFormat(ByteArrayRange data) {
if (hasErrorHeader(data)) {
return ImageFormat.JPEG;
}
if (data.getLength() > 2 && ((data.get(0) & 0xff) == 0xff) && ((data.get(1) & 0xff) == 0xd8)) {
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 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 ImageFormat.PNG;
}
return ImageFormat.UNKNOWN;
}
public SerializableImage getImageCached() {
if (cachedImage != null) {
return cachedImage;
}
SerializableImage image = getImage();
if (Configuration.cacheImages.get()) {
cachedImage = image;
}
return image;
}
public InputStream getImageData() {
InputStream is = getOriginalImageData();
if (is != null) {
return is;
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageHelper.write(getImage().getBufferedImage(), getImageFormat(), baos);
return new ByteArrayInputStream(baos.toByteArray());
}
public static boolean hasErrorHeader(byte[] data) {
return hasErrorHeader(new ByteArrayRange(data));
}
public static boolean hasErrorHeader(ByteArrayRange data) {
if (data.getLength() > 4) {
if ((data.get(0) & 0xff) == 0xff && (data.get(1) & 0xff) == 0xd9
&& (data.get(2) & 0xff) == 0xff && (data.get(3) & 0xff) == 0xd8) {
return true;
}
}
return false;
}
private SHAPEWITHSTYLE getShape() {
RECT rect = getRect();
return getShape(rect, false);
}
public SHAPEWITHSTYLE getShape(RECT rect, boolean fill) {
boolean translated = rect.Xmin != 0 || rect.Ymin != 0;
SHAPEWITHSTYLE shape = new SHAPEWITHSTYLE();
shape.fillStyles = new FILLSTYLEARRAY();
shape.fillStyles.fillStyles = new FILLSTYLE[1];
FILLSTYLE fillStyle = new FILLSTYLE();
fillStyle.fillStyleType = Configuration.shapeImportUseNonSmoothedFill.get()
? FILLSTYLE.NON_SMOOTHED_REPEATING_BITMAP : FILLSTYLE.REPEATING_BITMAP;
fillStyle.bitmapId = getCharacterId();
MATRIX matrix = new MATRIX();
matrix.hasScale = true;
if (fill) {
RECT imageRect = getRect();
matrix.scaleX = (int) ((((long) SWF.unitDivisor) << 16) * rect.getWidth() / imageRect.getWidth());
matrix.scaleY = (int) ((((long) SWF.unitDivisor) << 16) * rect.getHeight() / imageRect.getHeight());
} else {
matrix.scaleX = ((int) SWF.unitDivisor) << 16;
matrix.scaleY = matrix.scaleX;
}
if (translated) {
matrix.translateX = rect.Xmin;
matrix.translateY = rect.Ymin;
}
fillStyle.bitmapMatrix = matrix;
shape.fillStyles.fillStyles[0] = fillStyle;
shape.lineStyles = new LINESTYLEARRAY();
shape.lineStyles.lineStyles = new LINESTYLE[0];
shape.shapeRecords = new ArrayList<>();
StyleChangeRecord style = new StyleChangeRecord();
style.stateFillStyle0 = true;
style.fillStyle0 = 1;
style.stateMoveTo = true;
if (translated) {
style.moveDeltaX = rect.Xmin;
style.moveDeltaY = rect.Ymin;
}
shape.shapeRecords.add(style);
StraightEdgeRecord top = new StraightEdgeRecord();
top.generalLineFlag = true;
top.deltaX = rect.getWidth();
StraightEdgeRecord right = new StraightEdgeRecord();
right.generalLineFlag = true;
right.deltaY = rect.getHeight();
StraightEdgeRecord bottom = new StraightEdgeRecord();
bottom.generalLineFlag = true;
bottom.deltaX = -rect.getWidth();
StraightEdgeRecord left = new StraightEdgeRecord();
left.generalLineFlag = true;
left.deltaY = -rect.getHeight();
shape.shapeRecords.add(top);
shape.shapeRecords.add(right);
shape.shapeRecords.add(bottom);
shape.shapeRecords.add(left);
shape.shapeRecords.add(new EndShapeRecord());
return shape;
}
@Override
public RECT getRect() {
return getRect(null); // parameter not used
}
@Override
public RECT getRect(Set<BoundedTag> added) {
Dimension dimension = getImageDimension();
int widthInTwips = (int) (dimension.getWidth() * SWF.unitDivisor);
int heightInTwips = (int) (dimension.getHeight() * SWF.unitDivisor);
return new RECT(0, widthInTwips, 0, heightInTwips);
}
@Override
public int getUsedParameters() {
return 0;
}
@Override
public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation, boolean stroked) {
return transformation.toTransform().createTransformedShape(getShape().getOutline(swf, stroked));
}
@Override
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix strokeTransformation, Matrix absoluteTransformation, ColorTransform colorTransform) {
BitmapExporter.export(swf, getShape(), null, image, transformation, strokeTransformation, colorTransform);
}
@Override
public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level) throws IOException {
SVGShapeExporter shapeExporter = new SVGShapeExporter(swf, getShape(), exporter, null, colorTransform, 1);
shapeExporter.export();
}
@Override
public void toHtmlCanvas(StringBuilder result, double unitDivisor) {
CanvasShapeExporter cse = new CanvasShapeExporter(null, unitDivisor, swf, getShape(), null, 0, 0);
cse.export();
result.append(cse.getShapeData());
}
@Override
public int getNumFrames() {
return 1;
}
@Override
public boolean isSingleFrame() {
return true;
}
public void clearCache() {
cachedImage = null;
}
@Override
public void getTagInfo(TagInfo tagInfo) {
super.getTagInfo(tagInfo);
Dimension dimension = getImageDimension();
tagInfo.addInfo("general", "width", dimension.getWidth());
tagInfo.addInfo("general", "height", dimension.getHeight());
}
@Override
public int getCharacterId() {
return characterID;
}
@Override
public void setCharacterId(int characterId) {
this.characterID = characterId;
}
}
/*
* Copyright (C) 2010-2016 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.base;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
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.helpers.ImageHelper;
import com.jpexs.decompiler.flash.tags.TagInfo;
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;
import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY;
import com.jpexs.decompiler.flash.types.LINESTYLE;
import com.jpexs.decompiler.flash.types.LINESTYLEARRAY;
import com.jpexs.decompiler.flash.types.MATRIX;
import com.jpexs.decompiler.flash.types.RECT;
import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE;
import com.jpexs.decompiler.flash.types.annotations.SWFType;
import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord;
import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord;
import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord;
import com.jpexs.helpers.ByteArrayRange;
import com.jpexs.helpers.SerializableImage;
import java.awt.Dimension;
import java.awt.Shape;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Set;
/**
*
* @author JPEXS
*/
public abstract class ImageTag extends DrawableTag {
@SWFType(BasicType.UI16)
public int characterID;
protected SerializableImage cachedImage;
public ImageTag(SWF swf, int id, String name, ByteArrayRange data) {
super(swf, id, name, data);
}
public abstract InputStream getOriginalImageData();
protected abstract SerializableImage getImage();
public abstract Dimension getImageDimension();
public abstract void setImage(byte[] data) throws IOException;
public abstract ImageFormat getImageFormat();
public abstract ImageFormat getOriginalImageFormat();
public boolean importSupported() {
return true;
}
public static ImageFormat getImageFormat(byte[] data) {
return getImageFormat(new ByteArrayRange(data));
}
public static ImageFormat getImageFormat(ByteArrayRange data) {
if (hasErrorHeader(data)) {
return ImageFormat.JPEG;
}
if (data.getLength() > 2 && ((data.get(0) & 0xff) == 0xff) && ((data.get(1) & 0xff) == 0xd8)) {
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 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 ImageFormat.PNG;
}
return ImageFormat.UNKNOWN;
}
public SerializableImage getImageCached() {
if (cachedImage != null) {
return cachedImage;
}
SerializableImage image = getImage();
if (Configuration.cacheImages.get()) {
cachedImage = image;
}
return image;
}
public InputStream getImageData() {
InputStream is = getOriginalImageData();
if (is != null) {
return is;
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageHelper.write(getImage().getBufferedImage(), getImageFormat(), baos);
return new ByteArrayInputStream(baos.toByteArray());
}
public static boolean hasErrorHeader(byte[] data) {
return hasErrorHeader(new ByteArrayRange(data));
}
public static boolean hasErrorHeader(ByteArrayRange data) {
if (data.getLength() > 4) {
if ((data.get(0) & 0xff) == 0xff && (data.get(1) & 0xff) == 0xd9
&& (data.get(2) & 0xff) == 0xff && (data.get(3) & 0xff) == 0xd8) {
return true;
}
}
return false;
}
private SHAPEWITHSTYLE getShape() {
RECT rect = getRect();
return getShape(rect, false);
}
public SHAPEWITHSTYLE getShape(RECT rect, boolean fill) {
boolean translated = rect.Xmin != 0 || rect.Ymin != 0;
SHAPEWITHSTYLE shape = new SHAPEWITHSTYLE();
shape.fillStyles = new FILLSTYLEARRAY();
shape.fillStyles.fillStyles = new FILLSTYLE[1];
FILLSTYLE fillStyle = new FILLSTYLE();
fillStyle.fillStyleType = Configuration.shapeImportUseNonSmoothedFill.get()
? FILLSTYLE.NON_SMOOTHED_REPEATING_BITMAP : FILLSTYLE.REPEATING_BITMAP;
fillStyle.bitmapId = getCharacterId();
MATRIX matrix = new MATRIX();
matrix.hasScale = true;
if (fill) {
RECT imageRect = getRect();
matrix.scaleX = (int) ((((long) SWF.unitDivisor) << 16) * rect.getWidth() / imageRect.getWidth());
matrix.scaleY = (int) ((((long) SWF.unitDivisor) << 16) * rect.getHeight() / imageRect.getHeight());
} else {
matrix.scaleX = ((int) SWF.unitDivisor) << 16;
matrix.scaleY = matrix.scaleX;
}
if (translated) {
matrix.translateX = rect.Xmin;
matrix.translateY = rect.Ymin;
}
fillStyle.bitmapMatrix = matrix;
shape.fillStyles.fillStyles[0] = fillStyle;
shape.lineStyles = new LINESTYLEARRAY();
shape.lineStyles.lineStyles = new LINESTYLE[0];
shape.shapeRecords = new ArrayList<>();
StyleChangeRecord style = new StyleChangeRecord();
style.stateFillStyle0 = true;
style.fillStyle0 = 1;
style.stateMoveTo = true;
if (translated) {
style.moveDeltaX = rect.Xmin;
style.moveDeltaY = rect.Ymin;
}
shape.shapeRecords.add(style);
StraightEdgeRecord top = new StraightEdgeRecord();
top.generalLineFlag = true;
top.deltaX = rect.getWidth();
StraightEdgeRecord right = new StraightEdgeRecord();
right.generalLineFlag = true;
right.deltaY = rect.getHeight();
StraightEdgeRecord bottom = new StraightEdgeRecord();
bottom.generalLineFlag = true;
bottom.deltaX = -rect.getWidth();
StraightEdgeRecord left = new StraightEdgeRecord();
left.generalLineFlag = true;
left.deltaY = -rect.getHeight();
shape.shapeRecords.add(top);
shape.shapeRecords.add(right);
shape.shapeRecords.add(bottom);
shape.shapeRecords.add(left);
shape.shapeRecords.add(new EndShapeRecord());
return shape;
}
@Override
public RECT getRect() {
return getRect(null); // parameter not used
}
@Override
public RECT getRect(Set<BoundedTag> added) {
Dimension dimension = getImageDimension();
int widthInTwips = (int) (dimension.getWidth() * SWF.unitDivisor);
int heightInTwips = (int) (dimension.getHeight() * SWF.unitDivisor);
return new RECT(0, widthInTwips, 0, heightInTwips);
}
@Override
public int getUsedParameters() {
return 0;
}
@Override
public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation, boolean stroked) {
return transformation.toTransform().createTransformedShape(getShape().getOutline(swf, stroked));
}
@Override
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix strokeTransformation, Matrix absoluteTransformation, ColorTransform colorTransform) {
BitmapExporter.export(swf, getShape(), null, image, transformation, strokeTransformation, colorTransform);
}
@Override
public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level) throws IOException {
SVGShapeExporter shapeExporter = new SVGShapeExporter(swf, getShape(), exporter, null, colorTransform, 1);
shapeExporter.export();
}
@Override
public void toHtmlCanvas(StringBuilder result, double unitDivisor) {
CanvasShapeExporter cse = new CanvasShapeExporter(null, unitDivisor, swf, getShape(), null, 0, 0);
cse.export();
result.append(cse.getShapeData());
}
@Override
public int getNumFrames() {
return 1;
}
@Override
public boolean isSingleFrame() {
return true;
}
public void clearCache() {
cachedImage = null;
}
@Override
public void getTagInfo(TagInfo tagInfo) {
super.getTagInfo(tagInfo);
Dimension dimension = getImageDimension();
tagInfo.addInfo("general", "width", dimension.getWidth());
tagInfo.addInfo("general", "height", dimension.getHeight());
}
@Override
public int getCharacterId() {
return characterID;
}
@Override
public void setCharacterId(int characterId) {
this.characterID = characterId;
}
}

View File

@@ -1,52 +1,52 @@
/*
* Copyright (C) 2010-2016 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.types;
import com.jpexs.decompiler.flash.tags.DefineShape3Tag;
import com.jpexs.decompiler.flash.tags.DefineShape4Tag;
import com.jpexs.decompiler.flash.tags.base.NeedsCharacters;
import com.jpexs.decompiler.flash.types.annotations.ConditionalType;
import com.jpexs.decompiler.flash.types.annotations.SWFType;
import java.io.Serializable;
import java.util.Set;
/**
*
* @author JPEXS
*/
public class LINESTYLE implements NeedsCharacters, Serializable {
@SWFType(BasicType.UI16)
public int width;
@ConditionalType(tags = {DefineShape3Tag.ID, DefineShape4Tag.ID}, type = RGBA.class)
public RGB color;
@Override
public void getNeededCharacters(Set<Integer> needed) {
}
@Override
public boolean replaceCharacter(int oldCharacterId, int newCharacterId) {
return false;
}
@Override
public boolean removeCharacter(int characterId) {
return false;
}
}
/*
* Copyright (C) 2010-2016 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.types;
import com.jpexs.decompiler.flash.tags.DefineShape3Tag;
import com.jpexs.decompiler.flash.tags.DefineShape4Tag;
import com.jpexs.decompiler.flash.tags.base.NeedsCharacters;
import com.jpexs.decompiler.flash.types.annotations.ConditionalType;
import com.jpexs.decompiler.flash.types.annotations.SWFType;
import java.io.Serializable;
import java.util.Set;
/**
*
* @author JPEXS
*/
public class LINESTYLE implements NeedsCharacters, Serializable {
@SWFType(BasicType.UI16)
public int width;
@ConditionalType(tags = {DefineShape3Tag.ID, DefineShape4Tag.ID}, type = RGBA.class)
public RGB color;
@Override
public void getNeededCharacters(Set<Integer> needed) {
}
@Override
public boolean replaceCharacter(int oldCharacterId, int newCharacterId) {
return false;
}
@Override
public boolean removeCharacter(int characterId) {
return false;
}
}