Introduce end-of-line normalization

This commit is contained in:
Jindra Petřík
2016-07-23 21:19:44 +02:00
parent 09af6c030b
commit afc2c05cbb
142 changed files with 38460 additions and 38429 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);
}
}

File diff suppressed because it is too large Load Diff

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,164 +1,164 @@
/*
* 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.dumpview;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.tags.Tag;
import com.jpexs.decompiler.flash.tags.TagStub;
import com.jpexs.decompiler.flash.treeitems.TreeItem;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author JPEXS
*/
public class DumpInfo implements TreeItem {
public String name;
public String type;
public TagStub tagToResolve = null;
public Tag resolvedTag = null;
public Object previewValue;
public long startByte;
public int startBit;
public long lengthBytes;
public int lengthBits;
public DumpInfo parent;
private List<DumpInfo> childInfos;
public DumpInfo(String name, String type, Object value, long startByte, long lengthBytes) {
this.name = name;
this.type = type;
this.previewValue = value;
this.startByte = startByte;
this.lengthBytes = lengthBytes;
}
public DumpInfo(String name, String type, Object value, long startByte, int startBit, long lengthBytes, int lengthBits) {
this.name = name;
this.type = type;
this.previewValue = value;
this.startByte = startByte;
this.lengthBytes = lengthBytes;
this.startBit = startBit;
this.lengthBits = lengthBits;
}
public int getChildCount() {
return childInfos == null ? 0 : childInfos.size();
}
public List<DumpInfo> getChildInfos() {
if (childInfos == null) {
childInfos = new ArrayList<>();
}
return childInfos;
}
public void sortChildren() {
if (childInfos == null) {
return;
}
Collections.sort(childInfos, new Comparator<DumpInfo>() {
@Override
public int compare(DumpInfo o1, DumpInfo o2) {
int res = Long.compare(o1.startByte, o2.startByte);
if (res != 0) {
return res;
}
return Integer.compare(o1.startBit, o1.startBit);
}
});
}
public long getEndByte() {
int end = (int) startByte;
if (lengthBytes != 0) {
end += lengthBytes;
} else {
int bits = startBit + lengthBits;
end += bits / 8;
if (bits % 8 != 0) {
end++;
}
}
return end - 1;
}
@Override
public String toString() {
String value = previewValue == null ? "" : previewValue.toString();
return name + " (" + type + ")" + (value.isEmpty() ? "" : " = " + value);
}
public void resolveTag() {
if (tagToResolve != null) {
TagStub tagStub = tagToResolve;
try {
SWFInputStream sis = tagStub.getDataStream();
sis.seek(tagStub.getDataPos());
sis.dumpInfo = this;
resolvedTag = SWFInputStream.resolveTag(tagStub, 0, false, true, false);
} catch (InterruptedException | IOException ex) {
Logger.getLogger(DumpInfo.class.getName()).log(Level.SEVERE, null, ex);
}
tagToResolve = null;
}
}
public Tag getTag() {
resolveTag();
return resolvedTag;
}
@Override
public SWF getSwf() {
Tag tag = getTag();
if (tag != null) {
return tag.getSwf();
}
return DumpInfoSwfNode.getSwfNode(this).getSwf();
}
@Override
public boolean isModified() {
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.dumpview;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.tags.Tag;
import com.jpexs.decompiler.flash.tags.TagStub;
import com.jpexs.decompiler.flash.treeitems.TreeItem;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author JPEXS
*/
public class DumpInfo implements TreeItem {
public String name;
public String type;
public TagStub tagToResolve = null;
public Tag resolvedTag = null;
public Object previewValue;
public long startByte;
public int startBit;
public long lengthBytes;
public int lengthBits;
public DumpInfo parent;
private List<DumpInfo> childInfos;
public DumpInfo(String name, String type, Object value, long startByte, long lengthBytes) {
this.name = name;
this.type = type;
this.previewValue = value;
this.startByte = startByte;
this.lengthBytes = lengthBytes;
}
public DumpInfo(String name, String type, Object value, long startByte, int startBit, long lengthBytes, int lengthBits) {
this.name = name;
this.type = type;
this.previewValue = value;
this.startByte = startByte;
this.lengthBytes = lengthBytes;
this.startBit = startBit;
this.lengthBits = lengthBits;
}
public int getChildCount() {
return childInfos == null ? 0 : childInfos.size();
}
public List<DumpInfo> getChildInfos() {
if (childInfos == null) {
childInfos = new ArrayList<>();
}
return childInfos;
}
public void sortChildren() {
if (childInfos == null) {
return;
}
Collections.sort(childInfos, new Comparator<DumpInfo>() {
@Override
public int compare(DumpInfo o1, DumpInfo o2) {
int res = Long.compare(o1.startByte, o2.startByte);
if (res != 0) {
return res;
}
return Integer.compare(o1.startBit, o1.startBit);
}
});
}
public long getEndByte() {
int end = (int) startByte;
if (lengthBytes != 0) {
end += lengthBytes;
} else {
int bits = startBit + lengthBits;
end += bits / 8;
if (bits % 8 != 0) {
end++;
}
}
return end - 1;
}
@Override
public String toString() {
String value = previewValue == null ? "" : previewValue.toString();
return name + " (" + type + ")" + (value.isEmpty() ? "" : " = " + value);
}
public void resolveTag() {
if (tagToResolve != null) {
TagStub tagStub = tagToResolve;
try {
SWFInputStream sis = tagStub.getDataStream();
sis.seek(tagStub.getDataPos());
sis.dumpInfo = this;
resolvedTag = SWFInputStream.resolveTag(tagStub, 0, false, true, false);
} catch (InterruptedException | IOException ex) {
Logger.getLogger(DumpInfo.class.getName()).log(Level.SEVERE, null, ex);
}
tagToResolve = null;
}
}
public Tag getTag() {
resolveTag();
return resolvedTag;
}
@Override
public SWF getSwf() {
Tag tag = getTag();
if (tag != null) {
return tag.getSwf();
}
return DumpInfoSwfNode.getSwfNode(this).getSwf();
}
@Override
public boolean isModified() {
return false;
}
}

View File

@@ -1,164 +1,164 @@
/*
* 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;
import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler;
import com.jpexs.decompiler.flash.EventListener;
import com.jpexs.decompiler.flash.ReadOnlyTagList;
import com.jpexs.decompiler.flash.RetryTask;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.exporters.commonshape.ExportRectangle;
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
import com.jpexs.decompiler.flash.exporters.modes.ShapeExportMode;
import com.jpexs.decompiler.flash.exporters.settings.ShapeExportSettings;
import com.jpexs.decompiler.flash.exporters.shape.CanvasShapeExporter;
import com.jpexs.decompiler.flash.helpers.BMPFile;
import com.jpexs.decompiler.flash.helpers.ImageHelper;
import com.jpexs.decompiler.flash.tags.Tag;
import com.jpexs.decompiler.flash.tags.base.RenderContext;
import com.jpexs.decompiler.flash.tags.base.ShapeTag;
import com.jpexs.decompiler.flash.tags.enums.ImageFormat;
import com.jpexs.decompiler.flash.types.CXFORMWITHALPHA;
import com.jpexs.decompiler.flash.types.RECT;
import com.jpexs.decompiler.flash.types.SHAPE;
import com.jpexs.helpers.Helper;
import com.jpexs.helpers.Path;
import com.jpexs.helpers.SerializableImage;
import com.jpexs.helpers.utf8.Utf8Helper;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
*
* @author JPEXS
*/
public class ShapeExporter {
public List<File> exportShapes(AbortRetryIgnoreHandler handler, final String outdir, ReadOnlyTagList tags, final ShapeExportSettings settings, EventListener evl) throws IOException, InterruptedException {
List<File> ret = new ArrayList<>();
if (tags.isEmpty()) {
return ret;
}
File foutdir = new File(outdir);
Path.createDirectorySafe(foutdir);
int count = 0;
for (Tag t : tags) {
if (t instanceof ShapeTag) {
count++;
}
}
if (count == 0) {
return ret;
}
int currentIndex = 1;
for (final Tag t : tags) {
if (t instanceof ShapeTag) {
final ShapeTag st = (ShapeTag) t;
if (evl != null) {
evl.handleExportingEvent("shape", currentIndex, count, t.getName());
}
int characterID = st.getCharacterId();
String ext = ".svg";
if (settings.mode == ShapeExportMode.PNG) {
ext = ".png";
}
if (settings.mode == ShapeExportMode.BMP) {
ext = ".bmp";
}
if (settings.mode == ShapeExportMode.CANVAS) {
ext = ".html";
}
final File file = new File(outdir + File.separator + Helper.makeFileName(st.getCharacterExportFileName() + ext));
new RetryTask(() -> {
switch (settings.mode) {
case SVG:
try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(file))) {
ExportRectangle rect = new ExportRectangle(st.getRect());
rect.xMax *= settings.zoom;
rect.yMax *= settings.zoom;
rect.xMin *= settings.zoom;
rect.yMin *= settings.zoom;
SVGExporter exporter = new SVGExporter(rect, settings.zoom);
st.toSVG(exporter, -2, new CXFORMWITHALPHA(), 0);
fos.write(Utf8Helper.getBytes(exporter.getSVG()));
}
break;
case PNG:
case BMP:
RECT rect = st.getRect();
int newWidth = (int) (rect.getWidth() * settings.zoom / SWF.unitDivisor) + 1;
int newHeight = (int) (rect.getHeight() * settings.zoom / SWF.unitDivisor) + 1;
SerializableImage img = new SerializableImage(newWidth, newHeight, SerializableImage.TYPE_INT_ARGB_PRE);
img.fillTransparent();
Matrix m = Matrix.getScaleInstance(settings.zoom);
m.translate(-rect.Xmin, -rect.Ymin);
st.toImage(0, 0, 0, new RenderContext(), img, false, m, m, m, new CXFORMWITHALPHA());
if (settings.mode == ShapeExportMode.PNG) {
ImageHelper.write(img.getBufferedImage(), ImageFormat.PNG, file);
} else {
BMPFile.saveBitmap(img.getBufferedImage(), file);
}
break;
case CANVAS:
try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(file))) {
SHAPE shp = st.getShapes();
int deltaX = -shp.getBounds().Xmin;
int deltaY = -shp.getBounds().Ymin;
CanvasShapeExporter cse = new CanvasShapeExporter(null, SWF.unitDivisor / settings.zoom, ((Tag) st).getSwf(), shp, new CXFORMWITHALPHA(), deltaX, deltaY);
cse.export();
Set<Integer> needed = new HashSet<>();
needed.add(st.getCharacterId());
st.getNeededCharactersDeep(needed);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
SWF.writeLibrary(st.getSwf(), needed, baos);
fos.write(Utf8Helper.getBytes(cse.getHtml(new String(baos.toByteArray(), Utf8Helper.charset), SWF.getTypePrefix(st) + st.getCharacterId(), st.getRect())));
}
break;
}
}, handler).run();
ret.add(file);
if (evl != null) {
evl.handleExportedEvent("shape", currentIndex, count, t.getName());
}
currentIndex++;
}
}
if (settings.mode == ShapeExportMode.CANVAS) {
File fcanvas = new File(foutdir + File.separator + "canvas.js");
Helper.saveStream(SWF.class.getClassLoader().getResourceAsStream("com/jpexs/helpers/resource/canvas.js"), fcanvas);
ret.add(fcanvas);
}
return ret;
}
}
/*
* 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;
import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler;
import com.jpexs.decompiler.flash.EventListener;
import com.jpexs.decompiler.flash.ReadOnlyTagList;
import com.jpexs.decompiler.flash.RetryTask;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.exporters.commonshape.ExportRectangle;
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
import com.jpexs.decompiler.flash.exporters.modes.ShapeExportMode;
import com.jpexs.decompiler.flash.exporters.settings.ShapeExportSettings;
import com.jpexs.decompiler.flash.exporters.shape.CanvasShapeExporter;
import com.jpexs.decompiler.flash.helpers.BMPFile;
import com.jpexs.decompiler.flash.helpers.ImageHelper;
import com.jpexs.decompiler.flash.tags.Tag;
import com.jpexs.decompiler.flash.tags.base.RenderContext;
import com.jpexs.decompiler.flash.tags.base.ShapeTag;
import com.jpexs.decompiler.flash.tags.enums.ImageFormat;
import com.jpexs.decompiler.flash.types.CXFORMWITHALPHA;
import com.jpexs.decompiler.flash.types.RECT;
import com.jpexs.decompiler.flash.types.SHAPE;
import com.jpexs.helpers.Helper;
import com.jpexs.helpers.Path;
import com.jpexs.helpers.SerializableImage;
import com.jpexs.helpers.utf8.Utf8Helper;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
*
* @author JPEXS
*/
public class ShapeExporter {
public List<File> exportShapes(AbortRetryIgnoreHandler handler, final String outdir, ReadOnlyTagList tags, final ShapeExportSettings settings, EventListener evl) throws IOException, InterruptedException {
List<File> ret = new ArrayList<>();
if (tags.isEmpty()) {
return ret;
}
File foutdir = new File(outdir);
Path.createDirectorySafe(foutdir);
int count = 0;
for (Tag t : tags) {
if (t instanceof ShapeTag) {
count++;
}
}
if (count == 0) {
return ret;
}
int currentIndex = 1;
for (final Tag t : tags) {
if (t instanceof ShapeTag) {
final ShapeTag st = (ShapeTag) t;
if (evl != null) {
evl.handleExportingEvent("shape", currentIndex, count, t.getName());
}
int characterID = st.getCharacterId();
String ext = ".svg";
if (settings.mode == ShapeExportMode.PNG) {
ext = ".png";
}
if (settings.mode == ShapeExportMode.BMP) {
ext = ".bmp";
}
if (settings.mode == ShapeExportMode.CANVAS) {
ext = ".html";
}
final File file = new File(outdir + File.separator + Helper.makeFileName(st.getCharacterExportFileName() + ext));
new RetryTask(() -> {
switch (settings.mode) {
case SVG:
try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(file))) {
ExportRectangle rect = new ExportRectangle(st.getRect());
rect.xMax *= settings.zoom;
rect.yMax *= settings.zoom;
rect.xMin *= settings.zoom;
rect.yMin *= settings.zoom;
SVGExporter exporter = new SVGExporter(rect, settings.zoom);
st.toSVG(exporter, -2, new CXFORMWITHALPHA(), 0);
fos.write(Utf8Helper.getBytes(exporter.getSVG()));
}
break;
case PNG:
case BMP:
RECT rect = st.getRect();
int newWidth = (int) (rect.getWidth() * settings.zoom / SWF.unitDivisor) + 1;
int newHeight = (int) (rect.getHeight() * settings.zoom / SWF.unitDivisor) + 1;
SerializableImage img = new SerializableImage(newWidth, newHeight, SerializableImage.TYPE_INT_ARGB_PRE);
img.fillTransparent();
Matrix m = Matrix.getScaleInstance(settings.zoom);
m.translate(-rect.Xmin, -rect.Ymin);
st.toImage(0, 0, 0, new RenderContext(), img, false, m, m, m, new CXFORMWITHALPHA());
if (settings.mode == ShapeExportMode.PNG) {
ImageHelper.write(img.getBufferedImage(), ImageFormat.PNG, file);
} else {
BMPFile.saveBitmap(img.getBufferedImage(), file);
}
break;
case CANVAS:
try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(file))) {
SHAPE shp = st.getShapes();
int deltaX = -shp.getBounds().Xmin;
int deltaY = -shp.getBounds().Ymin;
CanvasShapeExporter cse = new CanvasShapeExporter(null, SWF.unitDivisor / settings.zoom, ((Tag) st).getSwf(), shp, new CXFORMWITHALPHA(), deltaX, deltaY);
cse.export();
Set<Integer> needed = new HashSet<>();
needed.add(st.getCharacterId());
st.getNeededCharactersDeep(needed);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
SWF.writeLibrary(st.getSwf(), needed, baos);
fos.write(Utf8Helper.getBytes(cse.getHtml(new String(baos.toByteArray(), Utf8Helper.charset), SWF.getTypePrefix(st) + st.getCharacterId(), st.getRect())));
}
break;
}
}, handler).run();
ret.add(file);
if (evl != null) {
evl.handleExportedEvent("shape", currentIndex, count, t.getName());
}
currentIndex++;
}
}
if (settings.mode == ShapeExportMode.CANVAS) {
File fcanvas = new File(foutdir + File.separator + "canvas.js");
Helper.saveStream(SWF.class.getClassLoader().getResourceAsStream("com/jpexs/helpers/resource/canvas.js"), fcanvas);
ret.add(fcanvas);
}
return ret;
}
}

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,183 +1,183 @@
/*
* 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 addFontCharacter(int index, int character) {
codeTable.add(index, character);
setModified(true);
}
@Override
public void removeFontCharacter(int index) {
codeTable.remove(index);
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 addFontCharacter(int index, int character) {
codeTable.add(index, character);
setModified(true);
}
@Override
public void removeFontCharacter(int index) {
codeTable.remove(index);
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,184 +1,184 @@
/*
* 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 addFontCharacter(int index, int character) {
codeTable.add(index, character);
setModified(true);
}
@Override
public void removeFontCharacter(int index) {
codeTable.remove(index);
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 addFontCharacter(int index, int character) {
codeTable.add(index, character);
setModified(true);
}
@Override
public void removeFontCharacter(int index) {
codeTable.remove(index);
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,382 +1,382 @@
/*
* 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.CharacterIdTag;
import com.jpexs.decompiler.flash.tags.base.FontInfoTag;
import com.jpexs.decompiler.flash.tags.base.FontTag;
import com.jpexs.decompiler.flash.types.BasicType;
import com.jpexs.decompiler.flash.types.SHAPE;
import com.jpexs.decompiler.flash.types.annotations.Internal;
import com.jpexs.decompiler.flash.types.annotations.SWFType;
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD;
import com.jpexs.helpers.ByteArrayRange;
import java.awt.Font;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
*
* @author JPEXS
*/
@SWFVersion(from = 1)
public class DefineFontTag extends FontTag {
public static final int ID = 10;
public static final String NAME = "DefineFont";
@SWFType(BasicType.UI16)
public int fontId;
public List<SHAPE> glyphShapeTable;
@Internal
private FontInfoTag fontInfoTag = null;
/**
* Constructor
*
* @param swf
*/
public DefineFontTag(SWF swf) {
super(swf, ID, NAME, null);
fontId = swf.getNextCharacterId();
glyphShapeTable = new ArrayList<>();
}
/**
* Constructor
*
* @param sis
* @param data
* @throws IOException
*/
public DefineFontTag(SWFInputStream sis, ByteArrayRange data) throws IOException {
super(sis.getSwf(), ID, NAME, data);
readData(sis, data, 0, false, false, false);
}
@Override
public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException {
fontId = sis.readUI16("fontId");
glyphShapeTable = new ArrayList<>();
if (sis.available() > 0) {
long pos = sis.getPos();
int firstOffset = sis.readUI16("firstOffset");
int nGlyphs = firstOffset / 2;
long[] offsetTable = new long[nGlyphs];
offsetTable[0] = firstOffset;
for (int i = 1; i < nGlyphs; i++) {
offsetTable[i] = sis.readUI16("offset");
}
for (int i = 0; i < nGlyphs; i++) {
sis.seek(pos + offsetTable[i]);
glyphShapeTable.add(sis.readSHAPE(1, false, "shape"));
}
}
}
/**
* Gets data bytes
*
* @param sos SWF output stream
* @throws java.io.IOException
*/
@Override
public void getData(SWFOutputStream sos) throws IOException {
sos.writeUI16(fontId);
ByteArrayOutputStream baos2 = new ByteArrayOutputStream();
List<Integer> offsetTable = new ArrayList<>();
SWFOutputStream sos2 = new SWFOutputStream(baos2, getVersion());
for (SHAPE shape : glyphShapeTable) {
offsetTable.add(glyphShapeTable.size() * 2 + (int) sos2.getPos());
sos2.writeSHAPE(shape, 1);
}
for (int offset : offsetTable) {
sos.writeUI16(offset);
}
sos.write(baos2.toByteArray());
}
@Override
public boolean isSmall() {
return false;
}
@Override
public double getGlyphAdvance(int glyphIndex) {
return -1;
}
@Override
public int getGlyphWidth(int glyphIndex) {
return glyphShapeTable.get(glyphIndex).getBounds().getWidth();
}
private void ensureFontInfo() {
if (fontInfoTag == null) {
List<CharacterIdTag> characterIdTags = swf.getCharacterIdTags(fontId);
if (characterIdTags != null) {
for (CharacterIdTag t : characterIdTags) {
if (t instanceof FontInfoTag) {
if (((FontInfoTag) t).fontID == fontId) {
fontInfoTag = (FontInfoTag) t;
break;
}
}
}
}
}
}
@Override
public char glyphToChar(int glyphIndex) {
ensureFontInfo();
if (fontInfoTag != null) {
return (char) (int) fontInfoTag.getCodeTable().get(glyphIndex);
} else {
return '?';
}
}
@Override
public int charToGlyph(char c) {
ensureFontInfo();
if (fontInfoTag != null) {
return fontInfoTag.getCodeTable().indexOf((int) c);
}
return -1;
}
@Override
public List<SHAPE> getGlyphShapeTable() {
return glyphShapeTable;
}
@Override
public int getCharacterId() {
return fontId;
}
@Override
public void setCharacterId(int characterId) {
this.fontId = characterId;
}
@Override
public String getFontNameIntag() {
ensureFontInfo();
if (fontInfoTag != null) {
return fontInfoTag.getFontName();
}
return null;
}
@Override
public boolean isBold() {
if (fontInfoTag != null) {
return fontInfoTag.getFontFlagsBold();
}
return false;
}
@Override
public boolean isItalic() {
if (fontInfoTag != null) {
return fontInfoTag.getFontFlagsItalic();
}
return false;
}
@Override
public boolean isSmallEditable() {
return false;
}
@Override
public boolean isBoldEditable() {
return fontInfoTag != null;
}
@Override
public boolean isItalicEditable() {
return fontInfoTag != null;
}
@Override
public void setSmall(boolean value) {
}
@Override
public void setBold(boolean value) {
if (fontInfoTag != null) {
fontInfoTag.setFontFlagsBold(value);
}
}
@Override
public void setItalic(boolean value) {
if (fontInfoTag != null) {
fontInfoTag.setFontFlagsItalic(value);
}
}
@Override
public int getAscent() {
return -1;
}
@Override
public int getDescent() {
return -1;
}
@Override
public int getLeading() {
return -1;
}
@Override
public double getDivider() {
return 1;
}
@Override
public void addCharacter(char character, Font font) {
SHAPE shp = SHAPERECORD.fontCharacterToSHAPE(font, (int) Math.round(getDivider() * 1024), character);
ensureFontInfo();
int code = (int) character;
int pos = -1;
boolean exists = false;
if (fontInfoTag != null) {
List<Integer> codeTable = fontInfoTag.getCodeTable();
for (int i = 0; i < codeTable.size(); i++) {
if (codeTable.get(i) >= code) {
if (codeTable.get(i) == code) {
exists = true;
}
pos = i;
break;
}
}
if (pos == -1) {
pos = codeTable.size();
}
} else {
pos = 0;
}
if (!exists) {
shiftGlyphIndices(fontId, pos, true);
glyphShapeTable.add(pos, shp);
if (fontInfoTag != null) {
fontInfoTag.addFontCharacter(pos, (int) character);
}
} else {
glyphShapeTable.set(pos, shp);
}
setModified(true);
getSwf().clearImageCache();
}
@Override
public boolean removeCharacter(char character) {
ensureFontInfo();
if (fontInfoTag == null) {
return false;
}
int code = (int) character;
int pos = -1;
List<Integer> codeTable = fontInfoTag.getCodeTable();
for (int i = 0; i < codeTable.size(); i++) {
if (codeTable.get(i) >= code) {
if (codeTable.get(i) == code) {
pos = i;
break;
}
return false;
}
}
if (pos == -1) {
return false;
}
glyphShapeTable.remove(pos);
fontInfoTag.removeFontCharacter(pos);
shiftGlyphIndices(fontId, pos + 1, false);
setModified(true);
getSwf().clearImageCache();
return true;
}
@Override
public void setAdvanceValues(Font font) {
throw new UnsupportedOperationException("Setting the advance values for DefineFontTag is not supported.");
}
@Override
public int getCharacterCount() {
ensureFontInfo();
if (fontInfoTag != null) {
List<Integer> codeTable = fontInfoTag.getCodeTable();
return codeTable.size();
}
return 0;
}
@Override
public String getCharacters() {
ensureFontInfo();
if (fontInfoTag != null) {
List<Integer> codeTable = fontInfoTag.getCodeTable();
StringBuilder ret = new StringBuilder(codeTable.size());
for (int i : codeTable) {
ret.append((char) i);
}
return ret.toString();
}
return "";
}
@Override
public int getGlyphKerningAdjustment(int glyphIndex, int nextGlyphIndex) {
return 0;
}
@Override
public int getCharKerningAdjustment(char c1, char c2) {
return 0;
}
}
/*
* 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.CharacterIdTag;
import com.jpexs.decompiler.flash.tags.base.FontInfoTag;
import com.jpexs.decompiler.flash.tags.base.FontTag;
import com.jpexs.decompiler.flash.types.BasicType;
import com.jpexs.decompiler.flash.types.SHAPE;
import com.jpexs.decompiler.flash.types.annotations.Internal;
import com.jpexs.decompiler.flash.types.annotations.SWFType;
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD;
import com.jpexs.helpers.ByteArrayRange;
import java.awt.Font;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
*
* @author JPEXS
*/
@SWFVersion(from = 1)
public class DefineFontTag extends FontTag {
public static final int ID = 10;
public static final String NAME = "DefineFont";
@SWFType(BasicType.UI16)
public int fontId;
public List<SHAPE> glyphShapeTable;
@Internal
private FontInfoTag fontInfoTag = null;
/**
* Constructor
*
* @param swf
*/
public DefineFontTag(SWF swf) {
super(swf, ID, NAME, null);
fontId = swf.getNextCharacterId();
glyphShapeTable = new ArrayList<>();
}
/**
* Constructor
*
* @param sis
* @param data
* @throws IOException
*/
public DefineFontTag(SWFInputStream sis, ByteArrayRange data) throws IOException {
super(sis.getSwf(), ID, NAME, data);
readData(sis, data, 0, false, false, false);
}
@Override
public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException {
fontId = sis.readUI16("fontId");
glyphShapeTable = new ArrayList<>();
if (sis.available() > 0) {
long pos = sis.getPos();
int firstOffset = sis.readUI16("firstOffset");
int nGlyphs = firstOffset / 2;
long[] offsetTable = new long[nGlyphs];
offsetTable[0] = firstOffset;
for (int i = 1; i < nGlyphs; i++) {
offsetTable[i] = sis.readUI16("offset");
}
for (int i = 0; i < nGlyphs; i++) {
sis.seek(pos + offsetTable[i]);
glyphShapeTable.add(sis.readSHAPE(1, false, "shape"));
}
}
}
/**
* Gets data bytes
*
* @param sos SWF output stream
* @throws java.io.IOException
*/
@Override
public void getData(SWFOutputStream sos) throws IOException {
sos.writeUI16(fontId);
ByteArrayOutputStream baos2 = new ByteArrayOutputStream();
List<Integer> offsetTable = new ArrayList<>();
SWFOutputStream sos2 = new SWFOutputStream(baos2, getVersion());
for (SHAPE shape : glyphShapeTable) {
offsetTable.add(glyphShapeTable.size() * 2 + (int) sos2.getPos());
sos2.writeSHAPE(shape, 1);
}
for (int offset : offsetTable) {
sos.writeUI16(offset);
}
sos.write(baos2.toByteArray());
}
@Override
public boolean isSmall() {
return false;
}
@Override
public double getGlyphAdvance(int glyphIndex) {
return -1;
}
@Override
public int getGlyphWidth(int glyphIndex) {
return glyphShapeTable.get(glyphIndex).getBounds().getWidth();
}
private void ensureFontInfo() {
if (fontInfoTag == null) {
List<CharacterIdTag> characterIdTags = swf.getCharacterIdTags(fontId);
if (characterIdTags != null) {
for (CharacterIdTag t : characterIdTags) {
if (t instanceof FontInfoTag) {
if (((FontInfoTag) t).fontID == fontId) {
fontInfoTag = (FontInfoTag) t;
break;
}
}
}
}
}
}
@Override
public char glyphToChar(int glyphIndex) {
ensureFontInfo();
if (fontInfoTag != null) {
return (char) (int) fontInfoTag.getCodeTable().get(glyphIndex);
} else {
return '?';
}
}
@Override
public int charToGlyph(char c) {
ensureFontInfo();
if (fontInfoTag != null) {
return fontInfoTag.getCodeTable().indexOf((int) c);
}
return -1;
}
@Override
public List<SHAPE> getGlyphShapeTable() {
return glyphShapeTable;
}
@Override
public int getCharacterId() {
return fontId;
}
@Override
public void setCharacterId(int characterId) {
this.fontId = characterId;
}
@Override
public String getFontNameIntag() {
ensureFontInfo();
if (fontInfoTag != null) {
return fontInfoTag.getFontName();
}
return null;
}
@Override
public boolean isBold() {
if (fontInfoTag != null) {
return fontInfoTag.getFontFlagsBold();
}
return false;
}
@Override
public boolean isItalic() {
if (fontInfoTag != null) {
return fontInfoTag.getFontFlagsItalic();
}
return false;
}
@Override
public boolean isSmallEditable() {
return false;
}
@Override
public boolean isBoldEditable() {
return fontInfoTag != null;
}
@Override
public boolean isItalicEditable() {
return fontInfoTag != null;
}
@Override
public void setSmall(boolean value) {
}
@Override
public void setBold(boolean value) {
if (fontInfoTag != null) {
fontInfoTag.setFontFlagsBold(value);
}
}
@Override
public void setItalic(boolean value) {
if (fontInfoTag != null) {
fontInfoTag.setFontFlagsItalic(value);
}
}
@Override
public int getAscent() {
return -1;
}
@Override
public int getDescent() {
return -1;
}
@Override
public int getLeading() {
return -1;
}
@Override
public double getDivider() {
return 1;
}
@Override
public void addCharacter(char character, Font font) {
SHAPE shp = SHAPERECORD.fontCharacterToSHAPE(font, (int) Math.round(getDivider() * 1024), character);
ensureFontInfo();
int code = (int) character;
int pos = -1;
boolean exists = false;
if (fontInfoTag != null) {
List<Integer> codeTable = fontInfoTag.getCodeTable();
for (int i = 0; i < codeTable.size(); i++) {
if (codeTable.get(i) >= code) {
if (codeTable.get(i) == code) {
exists = true;
}
pos = i;
break;
}
}
if (pos == -1) {
pos = codeTable.size();
}
} else {
pos = 0;
}
if (!exists) {
shiftGlyphIndices(fontId, pos, true);
glyphShapeTable.add(pos, shp);
if (fontInfoTag != null) {
fontInfoTag.addFontCharacter(pos, (int) character);
}
} else {
glyphShapeTable.set(pos, shp);
}
setModified(true);
getSwf().clearImageCache();
}
@Override
public boolean removeCharacter(char character) {
ensureFontInfo();
if (fontInfoTag == null) {
return false;
}
int code = (int) character;
int pos = -1;
List<Integer> codeTable = fontInfoTag.getCodeTable();
for (int i = 0; i < codeTable.size(); i++) {
if (codeTable.get(i) >= code) {
if (codeTable.get(i) == code) {
pos = i;
break;
}
return false;
}
}
if (pos == -1) {
return false;
}
glyphShapeTable.remove(pos);
fontInfoTag.removeFontCharacter(pos);
shiftGlyphIndices(fontId, pos + 1, false);
setModified(true);
getSwf().clearImageCache();
return true;
}
@Override
public void setAdvanceValues(Font font) {
throw new UnsupportedOperationException("Setting the advance values for DefineFontTag is not supported.");
}
@Override
public int getCharacterCount() {
ensureFontInfo();
if (fontInfoTag != null) {
List<Integer> codeTable = fontInfoTag.getCodeTable();
return codeTable.size();
}
return 0;
}
@Override
public String getCharacters() {
ensureFontInfo();
if (fontInfoTag != null) {
List<Integer> codeTable = fontInfoTag.getCodeTable();
StringBuilder ret = new StringBuilder(codeTable.size());
for (int i : codeTable) {
ret.append((char) i);
}
return ret.toString();
}
return "";
}
@Override
public int getGlyphKerningAdjustment(int glyphIndex, int nextGlyphIndex) {
return 0;
}
@Override
public int getCharKerningAdjustment(char c1, char c2) {
return 0;
}
}

View File

@@ -1,112 +1,112 @@
/*
* 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.abc.ABC;
import com.jpexs.decompiler.flash.abc.ABCInputStream;
import com.jpexs.decompiler.flash.abc.types.ScriptInfo;
import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit;
import com.jpexs.decompiler.flash.types.annotations.SWFField;
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
import com.jpexs.helpers.ByteArrayRange;
import java.io.IOException;
/**
* Defines a series of ActionScript 3 bytecodes to be executed
*
* @author JPEXS
*/
@SWFVersion(from = 9)
public class DoABCTag extends Tag implements ABCContainerTag {
public static final int ID = 72;
public static final String NAME = "DoABC";
/**
* ActionScript 3 bytecodes
*/
@HideInRawEdit
@SWFField
private ABC abc;
/**
* Constructor
*
* @param swf
*/
public DoABCTag(SWF swf) {
super(swf, ID, NAME, null);
abc = new ABC(this);
}
/**
* Constructor
*
* @param sis
* @param data
* @throws IOException
*/
public DoABCTag(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 {
ABCInputStream ais = new ABCInputStream(sis.getBaseStream());
// put it to the dumpview:
sis.readByteRangeEx(sis.available(), "abcBytes");
abc = new ABC(ais, swf, this);
}
/**
* Gets data bytes
*
* @param sos SWF output stream
* @throws java.io.IOException
*/
@Override
public void getData(SWFOutputStream sos) throws IOException {
abc.saveToStream(sos);
}
@Override
public ABC getABC() {
return abc;
}
@Override
public int compareTo(ABCContainerTag o) {
return 0;
}
@Override
public void setModified(boolean value) {
super.setModified(value);
if (value == false && !isModified()) {
ABC abc = getABC();
for (ScriptInfo si : abc.script_info) {
si.setModified(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.tags;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.SWFOutputStream;
import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.ABCInputStream;
import com.jpexs.decompiler.flash.abc.types.ScriptInfo;
import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit;
import com.jpexs.decompiler.flash.types.annotations.SWFField;
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
import com.jpexs.helpers.ByteArrayRange;
import java.io.IOException;
/**
* Defines a series of ActionScript 3 bytecodes to be executed
*
* @author JPEXS
*/
@SWFVersion(from = 9)
public class DoABCTag extends Tag implements ABCContainerTag {
public static final int ID = 72;
public static final String NAME = "DoABC";
/**
* ActionScript 3 bytecodes
*/
@HideInRawEdit
@SWFField
private ABC abc;
/**
* Constructor
*
* @param swf
*/
public DoABCTag(SWF swf) {
super(swf, ID, NAME, null);
abc = new ABC(this);
}
/**
* Constructor
*
* @param sis
* @param data
* @throws IOException
*/
public DoABCTag(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 {
ABCInputStream ais = new ABCInputStream(sis.getBaseStream());
// put it to the dumpview:
sis.readByteRangeEx(sis.available(), "abcBytes");
abc = new ABC(ais, swf, this);
}
/**
* Gets data bytes
*
* @param sos SWF output stream
* @throws java.io.IOException
*/
@Override
public void getData(SWFOutputStream sos) throws IOException {
abc.saveToStream(sos);
}
@Override
public ABC getABC() {
return abc;
}
@Override
public int compareTo(ABCContainerTag o) {
return 0;
}
@Override
public void setModified(boolean value) {
super.setModified(value);
if (value == false && !isModified()) {
ABC abc = getABC();
for (ScriptInfo si : abc.script_info) {
si.setModified(false);
}
}
}
}

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,261 +1,261 @@
/*
* 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.SoundStreamHeadTypeTag;
import com.jpexs.decompiler.flash.timeline.Timeline;
import com.jpexs.decompiler.flash.types.BasicType;
import com.jpexs.decompiler.flash.types.annotations.Conditional;
import com.jpexs.decompiler.flash.types.annotations.Internal;
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.decompiler.flash.types.sound.SoundExportFormat;
import com.jpexs.decompiler.flash.types.sound.SoundFormat;
import com.jpexs.helpers.ByteArrayRange;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
/**
*
* @author JPEXS
*/
@SWFVersion(from = 3)
public class SoundStreamHead2Tag extends Tag implements SoundStreamHeadTypeTag {
public static final int ID = 45;
public static final String NAME = "SoundStreamHead2";
@Reserved
@SWFType(value = BasicType.UB, count = 4)
public int reserved;
@SWFType(value = BasicType.UB, count = 2)
public int playBackSoundRate;
public boolean playBackSoundSize;
public boolean playBackSoundType;
@SWFType(value = BasicType.UB, count = 4)
public int streamSoundCompression;
@SWFType(value = BasicType.UB, count = 2)
public int streamSoundRate;
public boolean streamSoundSize;
public boolean streamSoundType;
@SWFType(BasicType.UI16)
public int streamSoundSampleCount;
@SWFType(BasicType.SI16)
@Conditional(value = "streamSoundCompression", options = {2})
public int latencySeek;
@Internal
private int virtualCharacterId = 0;
/**
* Constructor
*
* @param swf
*/
public SoundStreamHead2Tag(SWF swf) {
super(swf, ID, NAME, null);
}
/**
* Constructor
*
* @param sis
* @param data
* @throws IOException
*/
public SoundStreamHead2Tag(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 {
reserved = (int) sis.readUB(4, "reserved");
playBackSoundRate = (int) sis.readUB(2, "playBackSoundRate");
playBackSoundSize = sis.readUB(1, "playBackSoundSize") == 1;
playBackSoundType = sis.readUB(1, "playBackSoundType") == 1;
streamSoundCompression = (int) sis.readUB(4, "streamSoundCompression");
streamSoundRate = (int) sis.readUB(2, "streamSoundRate");
streamSoundSize = sis.readUB(1, "streamSoundSize") == 1;
streamSoundType = sis.readUB(1, "streamSoundType") == 1;
streamSoundSampleCount = sis.readUI16("streamSoundSampleCount");
if (streamSoundCompression == 2) {
latencySeek = sis.readSI16("latencySeek");
}
}
/**
* Gets data bytes
*
* @param sos SWF output stream
* @throws java.io.IOException
*/
@Override
public void getData(SWFOutputStream sos) throws IOException {
sos.writeUB(4, reserved);
sos.writeUB(2, playBackSoundRate);
sos.writeUB(1, playBackSoundSize ? 1 : 0);
sos.writeUB(1, playBackSoundType ? 1 : 0);
sos.writeUB(4, streamSoundCompression);
sos.writeUB(2, streamSoundRate);
sos.writeUB(1, streamSoundSize ? 1 : 0);
sos.writeUB(1, streamSoundType ? 1 : 0);
sos.writeUI16(streamSoundSampleCount);
if (streamSoundCompression == 2) {
sos.writeSI16(latencySeek);
}
}
@Override
public int getCharacterId() {
return virtualCharacterId;
}
@Override
public void setCharacterId(int characterId) {
virtualCharacterId = characterId;
}
@Override
public SoundExportFormat getExportFormat() {
if (streamSoundCompression == SoundFormat.FORMAT_MP3) {
return SoundExportFormat.MP3;
}
if (streamSoundCompression == SoundFormat.FORMAT_ADPCM) {
return SoundExportFormat.WAV;
}
if (streamSoundCompression == SoundFormat.FORMAT_UNCOMPRESSED_LITTLE_ENDIAN) {
return SoundExportFormat.WAV;
}
if (streamSoundCompression == SoundFormat.FORMAT_UNCOMPRESSED_NATIVE_ENDIAN) {
return SoundExportFormat.WAV;
}
if (streamSoundCompression == SoundFormat.FORMAT_NELLYMOSER || streamSoundCompression == SoundFormat.FORMAT_NELLYMOSER16KHZ || streamSoundCompression == SoundFormat.FORMAT_NELLYMOSER8KHZ) {
return SoundExportFormat.WAV;
}
return SoundExportFormat.FLV;
}
@Override
public long getSoundSampleCount() {
return streamSoundSampleCount;
}
@Override
public void setVirtualCharacterId(int ch) {
virtualCharacterId = ch;
}
@Override
public int getSoundFormatId() {
return streamSoundCompression;
}
@Override
public int getSoundRate() {
return streamSoundRate;
}
@Override
public boolean getSoundSize() {
return streamSoundSize;
}
@Override
public boolean getSoundType() {
return streamSoundType;
}
@Override
public List<SoundStreamBlockTag> getBlocks() {
Timeline timeline = swf.getTimeline();
List<SoundStreamBlockTag> ret = timeline.getSoundStreamBlocks(this);
return ret;
}
@Override
public boolean importSupported() {
return false;
}
@Override
public boolean setSound(InputStream is, int newSoundFormat) {
return false;
}
@Override
public List<ByteArrayRange> getRawSoundData() {
List<ByteArrayRange> ret = new ArrayList<>();
List<SoundStreamBlockTag> blocks = getBlocks();
if (blocks != null) {
for (SoundStreamBlockTag block : blocks) {
ByteArrayRange data = block.streamSoundData;
if (streamSoundCompression == SoundFormat.FORMAT_MP3) {
ret.add(data.getSubRange(4, data.getLength() - 4));
} else {
ret.add(data);
}
}
}
return ret;
}
@Override
public long getTotalSoundSampleCount() {
return getBlocks().size() * streamSoundSampleCount;
}
@Override
public SoundFormat getSoundFormat() {
final int[] rateMap = {5512, 11025, 22050, 44100};
return new SoundFormat(getSoundFormatId(), rateMap[getSoundRate()], getSoundType());
}
@Override
public String getCharacterExportFileName() {
String exportName = swf.getExportName(getCharacterId());
return getCharacterId() + (exportName != null ? "_" + exportName : "");
}
@Override
public void getTagInfo(TagInfo tagInfo) {
super.getTagInfo(tagInfo);
SoundFormat soundFormat = getSoundFormat();
tagInfo.addInfo("general", "codecName", soundFormat.getFormatName());
tagInfo.addInfo("general", "exportFormat", soundFormat.getNativeExportFormat());
tagInfo.addInfo("general", "samplingRate", soundFormat.samplingRate);
tagInfo.addInfo("general", "stereo", soundFormat.stereo);
tagInfo.addInfo("general", "sampleCount", streamSoundSampleCount);
}
}
/*
* 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.SoundStreamHeadTypeTag;
import com.jpexs.decompiler.flash.timeline.Timeline;
import com.jpexs.decompiler.flash.types.BasicType;
import com.jpexs.decompiler.flash.types.annotations.Conditional;
import com.jpexs.decompiler.flash.types.annotations.Internal;
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.decompiler.flash.types.sound.SoundExportFormat;
import com.jpexs.decompiler.flash.types.sound.SoundFormat;
import com.jpexs.helpers.ByteArrayRange;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
/**
*
* @author JPEXS
*/
@SWFVersion(from = 3)
public class SoundStreamHead2Tag extends Tag implements SoundStreamHeadTypeTag {
public static final int ID = 45;
public static final String NAME = "SoundStreamHead2";
@Reserved
@SWFType(value = BasicType.UB, count = 4)
public int reserved;
@SWFType(value = BasicType.UB, count = 2)
public int playBackSoundRate;
public boolean playBackSoundSize;
public boolean playBackSoundType;
@SWFType(value = BasicType.UB, count = 4)
public int streamSoundCompression;
@SWFType(value = BasicType.UB, count = 2)
public int streamSoundRate;
public boolean streamSoundSize;
public boolean streamSoundType;
@SWFType(BasicType.UI16)
public int streamSoundSampleCount;
@SWFType(BasicType.SI16)
@Conditional(value = "streamSoundCompression", options = {2})
public int latencySeek;
@Internal
private int virtualCharacterId = 0;
/**
* Constructor
*
* @param swf
*/
public SoundStreamHead2Tag(SWF swf) {
super(swf, ID, NAME, null);
}
/**
* Constructor
*
* @param sis
* @param data
* @throws IOException
*/
public SoundStreamHead2Tag(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 {
reserved = (int) sis.readUB(4, "reserved");
playBackSoundRate = (int) sis.readUB(2, "playBackSoundRate");
playBackSoundSize = sis.readUB(1, "playBackSoundSize") == 1;
playBackSoundType = sis.readUB(1, "playBackSoundType") == 1;
streamSoundCompression = (int) sis.readUB(4, "streamSoundCompression");
streamSoundRate = (int) sis.readUB(2, "streamSoundRate");
streamSoundSize = sis.readUB(1, "streamSoundSize") == 1;
streamSoundType = sis.readUB(1, "streamSoundType") == 1;
streamSoundSampleCount = sis.readUI16("streamSoundSampleCount");
if (streamSoundCompression == 2) {
latencySeek = sis.readSI16("latencySeek");
}
}
/**
* Gets data bytes
*
* @param sos SWF output stream
* @throws java.io.IOException
*/
@Override
public void getData(SWFOutputStream sos) throws IOException {
sos.writeUB(4, reserved);
sos.writeUB(2, playBackSoundRate);
sos.writeUB(1, playBackSoundSize ? 1 : 0);
sos.writeUB(1, playBackSoundType ? 1 : 0);
sos.writeUB(4, streamSoundCompression);
sos.writeUB(2, streamSoundRate);
sos.writeUB(1, streamSoundSize ? 1 : 0);
sos.writeUB(1, streamSoundType ? 1 : 0);
sos.writeUI16(streamSoundSampleCount);
if (streamSoundCompression == 2) {
sos.writeSI16(latencySeek);
}
}
@Override
public int getCharacterId() {
return virtualCharacterId;
}
@Override
public void setCharacterId(int characterId) {
virtualCharacterId = characterId;
}
@Override
public SoundExportFormat getExportFormat() {
if (streamSoundCompression == SoundFormat.FORMAT_MP3) {
return SoundExportFormat.MP3;
}
if (streamSoundCompression == SoundFormat.FORMAT_ADPCM) {
return SoundExportFormat.WAV;
}
if (streamSoundCompression == SoundFormat.FORMAT_UNCOMPRESSED_LITTLE_ENDIAN) {
return SoundExportFormat.WAV;
}
if (streamSoundCompression == SoundFormat.FORMAT_UNCOMPRESSED_NATIVE_ENDIAN) {
return SoundExportFormat.WAV;
}
if (streamSoundCompression == SoundFormat.FORMAT_NELLYMOSER || streamSoundCompression == SoundFormat.FORMAT_NELLYMOSER16KHZ || streamSoundCompression == SoundFormat.FORMAT_NELLYMOSER8KHZ) {
return SoundExportFormat.WAV;
}
return SoundExportFormat.FLV;
}
@Override
public long getSoundSampleCount() {
return streamSoundSampleCount;
}
@Override
public void setVirtualCharacterId(int ch) {
virtualCharacterId = ch;
}
@Override
public int getSoundFormatId() {
return streamSoundCompression;
}
@Override
public int getSoundRate() {
return streamSoundRate;
}
@Override
public boolean getSoundSize() {
return streamSoundSize;
}
@Override
public boolean getSoundType() {
return streamSoundType;
}
@Override
public List<SoundStreamBlockTag> getBlocks() {
Timeline timeline = swf.getTimeline();
List<SoundStreamBlockTag> ret = timeline.getSoundStreamBlocks(this);
return ret;
}
@Override
public boolean importSupported() {
return false;
}
@Override
public boolean setSound(InputStream is, int newSoundFormat) {
return false;
}
@Override
public List<ByteArrayRange> getRawSoundData() {
List<ByteArrayRange> ret = new ArrayList<>();
List<SoundStreamBlockTag> blocks = getBlocks();
if (blocks != null) {
for (SoundStreamBlockTag block : blocks) {
ByteArrayRange data = block.streamSoundData;
if (streamSoundCompression == SoundFormat.FORMAT_MP3) {
ret.add(data.getSubRange(4, data.getLength() - 4));
} else {
ret.add(data);
}
}
}
return ret;
}
@Override
public long getTotalSoundSampleCount() {
return getBlocks().size() * streamSoundSampleCount;
}
@Override
public SoundFormat getSoundFormat() {
final int[] rateMap = {5512, 11025, 22050, 44100};
return new SoundFormat(getSoundFormatId(), rateMap[getSoundRate()], getSoundType());
}
@Override
public String getCharacterExportFileName() {
String exportName = swf.getExportName(getCharacterId());
return getCharacterId() + (exportName != null ? "_" + exportName : "");
}
@Override
public void getTagInfo(TagInfo tagInfo) {
super.getTagInfo(tagInfo);
SoundFormat soundFormat = getSoundFormat();
tagInfo.addInfo("general", "codecName", soundFormat.getFormatName());
tagInfo.addInfo("general", "exportFormat", soundFormat.getNativeExportFormat());
tagInfo.addInfo("general", "samplingRate", soundFormat.samplingRate);
tagInfo.addInfo("general", "stereo", soundFormat.stereo);
tagInfo.addInfo("general", "sampleCount", streamSoundSampleCount);
}
}

View File

@@ -1,64 +1,64 @@
/*
* 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.tags.Tag;
import com.jpexs.decompiler.flash.types.BasicType;
import com.jpexs.decompiler.flash.types.annotations.SWFType;
import com.jpexs.helpers.ByteArrayRange;
import java.util.List;
/**
*
* @author JPEXS
*/
public abstract class FontInfoTag extends Tag implements CharacterIdTag {
@SWFType(BasicType.UI16)
public int fontID;
public FontInfoTag(SWF swf, int id, String name, ByteArrayRange data) {
super(swf, id, name, data);
}
public abstract List<Integer> getCodeTable();
public abstract void addFontCharacter(int index, int character);
public abstract void removeFontCharacter(int index);
@Override
public int getCharacterId() {
return fontID;
}
@Override
public void setCharacterId(int characterId) {
this.fontID = characterId;
}
public abstract String getFontName();
public abstract boolean getFontFlagsBold();
public abstract void setFontFlagsBold(boolean value);
public abstract boolean getFontFlagsItalic();
public abstract void setFontFlagsItalic(boolean 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.base;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.tags.Tag;
import com.jpexs.decompiler.flash.types.BasicType;
import com.jpexs.decompiler.flash.types.annotations.SWFType;
import com.jpexs.helpers.ByteArrayRange;
import java.util.List;
/**
*
* @author JPEXS
*/
public abstract class FontInfoTag extends Tag implements CharacterIdTag {
@SWFType(BasicType.UI16)
public int fontID;
public FontInfoTag(SWF swf, int id, String name, ByteArrayRange data) {
super(swf, id, name, data);
}
public abstract List<Integer> getCodeTable();
public abstract void addFontCharacter(int index, int character);
public abstract void removeFontCharacter(int index);
@Override
public int getCharacterId() {
return fontID;
}
@Override
public void setCharacterId(int characterId) {
this.fontID = characterId;
}
public abstract String getFontName();
public abstract boolean getFontFlagsBold();
public abstract void setFontFlagsBold(boolean value);
public abstract boolean getFontFlagsItalic();
public abstract void setFontFlagsItalic(boolean value);
}

View File

@@ -1,417 +1,417 @@
/*
* 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.configuration.SwfSpecificConfiguration;
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
import com.jpexs.decompiler.flash.exporters.shape.CanvasShapeExporter;
import com.jpexs.decompiler.flash.helpers.FontHelper;
import com.jpexs.decompiler.flash.tags.DefineFontNameTag;
import com.jpexs.decompiler.flash.tags.Tag;
import com.jpexs.decompiler.flash.types.ColorTransform;
import com.jpexs.decompiler.flash.types.GLYPHENTRY;
import com.jpexs.decompiler.flash.types.RECT;
import com.jpexs.decompiler.flash.types.SHAPE;
import com.jpexs.decompiler.flash.types.TEXTRECORD;
import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD;
import com.jpexs.helpers.ByteArrayRange;
import com.jpexs.helpers.SerializableImage;
import java.awt.Color;
import java.awt.Font;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphMetrics;
import java.awt.font.GlyphVector;
import java.awt.geom.Area;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
*
* @author JPEXS
*/
public abstract class FontTag extends DrawableTag implements AloneTag {
public static final int PREVIEWSIZE = 500;
public FontTag(SWF swf, int id, String name, ByteArrayRange data) {
super(swf, id, name, data);
}
public abstract List<SHAPE> getGlyphShapeTable();
public abstract void addCharacter(char character, Font font);
public abstract boolean removeCharacter(char character);
public abstract void setAdvanceValues(Font font);
public abstract char glyphToChar(int glyphIndex);
public abstract int charToGlyph(char c);
public abstract double getGlyphAdvance(int glyphIndex);
public abstract int getGlyphKerningAdjustment(int glyphIndex, int nextGlyphIndex);
public abstract int getCharKerningAdjustment(char c1, char c2);
public abstract int getGlyphWidth(int glyphIndex);
public abstract String getFontNameIntag();
public abstract boolean isSmall();
public abstract boolean isBold();
public abstract boolean isItalic();
public abstract boolean isSmallEditable();
public abstract boolean isBoldEditable();
public abstract boolean isItalicEditable();
public abstract void setSmall(boolean value);
public abstract void setBold(boolean value);
public abstract void setItalic(boolean value);
public abstract double getDivider();
public abstract int getAscent();
public abstract int getDescent();
public abstract int getLeading();
public String getFontName() {
DefineFontNameTag fontNameTag = getFontNameTag();
if (fontNameTag == null) {
return getFontNameIntag();
}
return fontNameTag.fontName;
}
public String getFontCopyright() {
DefineFontNameTag fontNameTag = getFontNameTag();
if (fontNameTag == null) {
return "";
}
return fontNameTag.fontCopyright;
}
public static Map<String, Map<String, Font>> installedFontsByFamily;
public static Map<String, Font> installedFontsByName;
public static String defaultFontName;
static {
reload();
}
public int getFontId() {
return getCharacterId();
}
public boolean hasLayout() {
return false;
}
public boolean containsChar(char character) {
return charToGlyph(character) > -1;
}
public int getFontStyle() {
int fontStyle = 0;
if (isBold()) {
fontStyle |= Font.BOLD;
}
if (isItalic()) {
fontStyle |= Font.ITALIC;
}
return fontStyle;
}
public abstract int getCharacterCount();
public abstract String getCharacters();
@Override
public String getName() {
String nameAppend = "";
if (exportName != null) {
nameAppend = ": " + exportName;
}
if (className != null) {
nameAppend = ": " + className;
}
String fontName = getFontNameIntag();
if (fontName != null) {
nameAppend = ": " + fontName;
}
return tagName + " (" + getCharacterId() + nameAppend + ")";
}
@Override
public String getExportFileName() {
String result = super.getExportFileName();
String fontName = getFontNameIntag();
if (fontName != null) {
fontName = fontName.replace(" ", "_");
}
return result + (fontName != null ? "_" + fontName : "");
}
public String getSystemFontName() {
int fontId = getFontId();
String selectedFont = swf.sourceFontNamesMap.get(fontId);
if (selectedFont == null) {
SwfSpecificConfiguration swfConf = Configuration.getSwfSpecificConfiguration(swf.getShortFileName());
String key = fontId + "_" + getFontNameIntag();
if (swfConf != null) {
selectedFont = swfConf.fontPairingMap.get(key);
}
}
if (selectedFont == null) {
selectedFont = Configuration.getFontToNameMap().get(getFontNameIntag());
}
if (selectedFont != null && FontTag.installedFontsByName.containsKey(selectedFont)) {
return selectedFont;
}
// findInstalledFontName always returns an available font name
return FontTag.findInstalledFontName(getFontName());
}
public Font getSystemFont() {
return FontTag.installedFontsByName.get(getSystemFontName());
}
protected void shiftGlyphIndices(int fontId, int startIndex, boolean increment) {
for (Tag t : swf.getTags()) {
List<TEXTRECORD> textRecords = null;
if (t instanceof StaticTextTag) {
textRecords = ((StaticTextTag) t).textRecords;
}
if (textRecords != null) {
int curFontId = 0;
for (TEXTRECORD tr : textRecords) {
if (tr.styleFlagsHasFont) {
curFontId = tr.fontId;
}
if (curFontId != fontId) {
continue;
}
for (GLYPHENTRY en : tr.glyphEntries) {
if (en == null) { //Currently edited
continue;
}
if (en.glyphIndex >= startIndex) {
if (increment) {
en.glyphIndex++;
} else {
en.glyphIndex--;
}
}
}
t.setModified(true);
}
}
}
}
public static float getSystemFontAdvance(String fontName, int fontStyle, int fontSize, Character character, Character nextCharacter) {
return getSystemFontAdvance(new Font(fontName, fontStyle, fontSize), character, nextCharacter);
}
public static float getSystemFontAdvance(Font aFont, Character character, Character nextCharacter) {
String chars = "" + character + (nextCharacter == null ? "" : nextCharacter);
GlyphVector gv = aFont.layoutGlyphVector(new FontRenderContext(aFont.getTransform(), true, true), chars.toCharArray(), 0, chars.length(), Font.LAYOUT_LEFT_TO_RIGHT);
GlyphMetrics gm = gv.getGlyphMetrics(0);
return gm.getAdvanceX();
}
public static void reload() {
installedFontsByFamily = FontHelper.getInstalledFonts();
installedFontsByName = new HashMap<>();
for (String fam : installedFontsByFamily.keySet()) {
for (String nam : installedFontsByFamily.get(fam).keySet()) {
installedFontsByName.put(nam, installedFontsByFamily.get(fam).get(nam));
}
}
if (installedFontsByFamily.containsKey("Times New Roman")) {
defaultFontName = "Times New Roman";
} else if (installedFontsByFamily.containsKey("Arial")) {
defaultFontName = "Arial";
} else {
defaultFontName = installedFontsByFamily.keySet().iterator().next();
}
}
public static String getFontNameWithFallback(String fontName) {
if (installedFontsByFamily.containsKey(fontName)) {
return fontName;
}
if (installedFontsByFamily.containsKey("Times New Roman")) {
return "Times New Roman";
}
if (installedFontsByFamily.containsKey("Arial")) {
return "Arial";
}
//First font
return installedFontsByFamily.keySet().iterator().next();
}
public static String isFontFamilyInstalled(String fontFamily) {
if (installedFontsByFamily.containsKey(fontFamily)) {
return fontFamily;
}
if (fontFamily.contains("_")) {
String beforeUnderscore = fontFamily.substring(0, fontFamily.indexOf('_'));
if (installedFontsByFamily.containsKey(beforeUnderscore)) {
return beforeUnderscore;
}
}
return null;
}
public static String findInstalledFontName(String fontName) {
if (installedFontsByName.containsKey(fontName)) {
return fontName;
}
if (fontName != null && fontName.contains("_")) {
String beforeUnderscore = fontName.substring(0, fontName.indexOf('_'));
if (installedFontsByName.containsKey(beforeUnderscore)) {
return beforeUnderscore;
}
}
return defaultFontName;
}
@Override
public int getUsedParameters() {
return PARAMETER_FRAME;
}
@Override
public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation, boolean stroked) {
RECT r = getRect();
return new Area(new Rectangle(r.Xmin, r.Ymin, r.getWidth(), r.getHeight()));
}
@Override
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix strokeTransformation, Matrix absoluteTransformation, ColorTransform colorTransform) {
SHAPERECORD.shapeListToImage(swf, getGlyphShapeTable(), image, frame, Color.black, colorTransform);
}
@Override
public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level) {
}
@Override
public void toHtmlCanvas(StringBuilder result, double unitDivisor) {
List<SHAPE> shapes = getGlyphShapeTable();
result.append("\tdefaultFill = textColor;\r\n");
result.append("\tswitch(ch){\r\n");
for (int i = 0; i < shapes.size(); i++) {
char c = glyphToChar(i);
String cs = "" + c;
cs = cs.replace("\\", "\\\\").replace("\"", "\\\"");
result.append("\t\tcase \"").append(cs).append("\":\r\n");
CanvasShapeExporter exporter = new CanvasShapeExporter(null, unitDivisor, swf, shapes.get(i), null, 0, 0);
exporter.export();
result.append("\t\t").append(exporter.getShapeData().replaceAll("\r\n", "\r\n\t\t"));
result.append("\tbreak;\r\n");
}
result.append("\t}\r\n");
}
@Override
public int getNumFrames() {
int frameCount = (getGlyphShapeTable().size() - 1) / SHAPERECORD.MAX_CHARACTERS_IN_FONT_PREVIEW + 1;
if (frameCount < 1) {
frameCount = 1;
}
return frameCount;
}
@Override
public boolean isSingleFrame() {
return true;
}
@Override
public RECT getRect() {
return getRect(null); // parameter not used
}
@Override
public RECT getRect(Set<BoundedTag> added) {
return new RECT(0, (int) (PREVIEWSIZE * SWF.unitDivisor), 0, (int) (PREVIEWSIZE * SWF.unitDivisor));
}
@Override
public String getCharacterExportFileName() {
return super.getCharacterExportFileName() + "_" + getFontNameIntag();
}
public DefineFontNameTag getFontNameTag() {
for (Tag t : swf.getTags()) {
if (t instanceof DefineFontNameTag) {
DefineFontNameTag dfn = (DefineFontNameTag) t;
if (dfn.fontId == getFontId()) {
return dfn;
}
}
}
return null;
}
public String getCopyright() {
DefineFontNameTag dfn = getFontNameTag();
if (dfn == null) {
return null;
}
return dfn.fontCopyright;
}
public RECT getGlyphBounds(int glyphIndex) {
return getGlyphShapeTable().get(glyphIndex).getBounds();
}
public FontTag toClassicFont() {
return this;
}
}
/*
* 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.configuration.SwfSpecificConfiguration;
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
import com.jpexs.decompiler.flash.exporters.shape.CanvasShapeExporter;
import com.jpexs.decompiler.flash.helpers.FontHelper;
import com.jpexs.decompiler.flash.tags.DefineFontNameTag;
import com.jpexs.decompiler.flash.tags.Tag;
import com.jpexs.decompiler.flash.types.ColorTransform;
import com.jpexs.decompiler.flash.types.GLYPHENTRY;
import com.jpexs.decompiler.flash.types.RECT;
import com.jpexs.decompiler.flash.types.SHAPE;
import com.jpexs.decompiler.flash.types.TEXTRECORD;
import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD;
import com.jpexs.helpers.ByteArrayRange;
import com.jpexs.helpers.SerializableImage;
import java.awt.Color;
import java.awt.Font;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphMetrics;
import java.awt.font.GlyphVector;
import java.awt.geom.Area;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
*
* @author JPEXS
*/
public abstract class FontTag extends DrawableTag implements AloneTag {
public static final int PREVIEWSIZE = 500;
public FontTag(SWF swf, int id, String name, ByteArrayRange data) {
super(swf, id, name, data);
}
public abstract List<SHAPE> getGlyphShapeTable();
public abstract void addCharacter(char character, Font font);
public abstract boolean removeCharacter(char character);
public abstract void setAdvanceValues(Font font);
public abstract char glyphToChar(int glyphIndex);
public abstract int charToGlyph(char c);
public abstract double getGlyphAdvance(int glyphIndex);
public abstract int getGlyphKerningAdjustment(int glyphIndex, int nextGlyphIndex);
public abstract int getCharKerningAdjustment(char c1, char c2);
public abstract int getGlyphWidth(int glyphIndex);
public abstract String getFontNameIntag();
public abstract boolean isSmall();
public abstract boolean isBold();
public abstract boolean isItalic();
public abstract boolean isSmallEditable();
public abstract boolean isBoldEditable();
public abstract boolean isItalicEditable();
public abstract void setSmall(boolean value);
public abstract void setBold(boolean value);
public abstract void setItalic(boolean value);
public abstract double getDivider();
public abstract int getAscent();
public abstract int getDescent();
public abstract int getLeading();
public String getFontName() {
DefineFontNameTag fontNameTag = getFontNameTag();
if (fontNameTag == null) {
return getFontNameIntag();
}
return fontNameTag.fontName;
}
public String getFontCopyright() {
DefineFontNameTag fontNameTag = getFontNameTag();
if (fontNameTag == null) {
return "";
}
return fontNameTag.fontCopyright;
}
public static Map<String, Map<String, Font>> installedFontsByFamily;
public static Map<String, Font> installedFontsByName;
public static String defaultFontName;
static {
reload();
}
public int getFontId() {
return getCharacterId();
}
public boolean hasLayout() {
return false;
}
public boolean containsChar(char character) {
return charToGlyph(character) > -1;
}
public int getFontStyle() {
int fontStyle = 0;
if (isBold()) {
fontStyle |= Font.BOLD;
}
if (isItalic()) {
fontStyle |= Font.ITALIC;
}
return fontStyle;
}
public abstract int getCharacterCount();
public abstract String getCharacters();
@Override
public String getName() {
String nameAppend = "";
if (exportName != null) {
nameAppend = ": " + exportName;
}
if (className != null) {
nameAppend = ": " + className;
}
String fontName = getFontNameIntag();
if (fontName != null) {
nameAppend = ": " + fontName;
}
return tagName + " (" + getCharacterId() + nameAppend + ")";
}
@Override
public String getExportFileName() {
String result = super.getExportFileName();
String fontName = getFontNameIntag();
if (fontName != null) {
fontName = fontName.replace(" ", "_");
}
return result + (fontName != null ? "_" + fontName : "");
}
public String getSystemFontName() {
int fontId = getFontId();
String selectedFont = swf.sourceFontNamesMap.get(fontId);
if (selectedFont == null) {
SwfSpecificConfiguration swfConf = Configuration.getSwfSpecificConfiguration(swf.getShortFileName());
String key = fontId + "_" + getFontNameIntag();
if (swfConf != null) {
selectedFont = swfConf.fontPairingMap.get(key);
}
}
if (selectedFont == null) {
selectedFont = Configuration.getFontToNameMap().get(getFontNameIntag());
}
if (selectedFont != null && FontTag.installedFontsByName.containsKey(selectedFont)) {
return selectedFont;
}
// findInstalledFontName always returns an available font name
return FontTag.findInstalledFontName(getFontName());
}
public Font getSystemFont() {
return FontTag.installedFontsByName.get(getSystemFontName());
}
protected void shiftGlyphIndices(int fontId, int startIndex, boolean increment) {
for (Tag t : swf.getTags()) {
List<TEXTRECORD> textRecords = null;
if (t instanceof StaticTextTag) {
textRecords = ((StaticTextTag) t).textRecords;
}
if (textRecords != null) {
int curFontId = 0;
for (TEXTRECORD tr : textRecords) {
if (tr.styleFlagsHasFont) {
curFontId = tr.fontId;
}
if (curFontId != fontId) {
continue;
}
for (GLYPHENTRY en : tr.glyphEntries) {
if (en == null) { //Currently edited
continue;
}
if (en.glyphIndex >= startIndex) {
if (increment) {
en.glyphIndex++;
} else {
en.glyphIndex--;
}
}
}
t.setModified(true);
}
}
}
}
public static float getSystemFontAdvance(String fontName, int fontStyle, int fontSize, Character character, Character nextCharacter) {
return getSystemFontAdvance(new Font(fontName, fontStyle, fontSize), character, nextCharacter);
}
public static float getSystemFontAdvance(Font aFont, Character character, Character nextCharacter) {
String chars = "" + character + (nextCharacter == null ? "" : nextCharacter);
GlyphVector gv = aFont.layoutGlyphVector(new FontRenderContext(aFont.getTransform(), true, true), chars.toCharArray(), 0, chars.length(), Font.LAYOUT_LEFT_TO_RIGHT);
GlyphMetrics gm = gv.getGlyphMetrics(0);
return gm.getAdvanceX();
}
public static void reload() {
installedFontsByFamily = FontHelper.getInstalledFonts();
installedFontsByName = new HashMap<>();
for (String fam : installedFontsByFamily.keySet()) {
for (String nam : installedFontsByFamily.get(fam).keySet()) {
installedFontsByName.put(nam, installedFontsByFamily.get(fam).get(nam));
}
}
if (installedFontsByFamily.containsKey("Times New Roman")) {
defaultFontName = "Times New Roman";
} else if (installedFontsByFamily.containsKey("Arial")) {
defaultFontName = "Arial";
} else {
defaultFontName = installedFontsByFamily.keySet().iterator().next();
}
}
public static String getFontNameWithFallback(String fontName) {
if (installedFontsByFamily.containsKey(fontName)) {
return fontName;
}
if (installedFontsByFamily.containsKey("Times New Roman")) {
return "Times New Roman";
}
if (installedFontsByFamily.containsKey("Arial")) {
return "Arial";
}
//First font
return installedFontsByFamily.keySet().iterator().next();
}
public static String isFontFamilyInstalled(String fontFamily) {
if (installedFontsByFamily.containsKey(fontFamily)) {
return fontFamily;
}
if (fontFamily.contains("_")) {
String beforeUnderscore = fontFamily.substring(0, fontFamily.indexOf('_'));
if (installedFontsByFamily.containsKey(beforeUnderscore)) {
return beforeUnderscore;
}
}
return null;
}
public static String findInstalledFontName(String fontName) {
if (installedFontsByName.containsKey(fontName)) {
return fontName;
}
if (fontName != null && fontName.contains("_")) {
String beforeUnderscore = fontName.substring(0, fontName.indexOf('_'));
if (installedFontsByName.containsKey(beforeUnderscore)) {
return beforeUnderscore;
}
}
return defaultFontName;
}
@Override
public int getUsedParameters() {
return PARAMETER_FRAME;
}
@Override
public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation, boolean stroked) {
RECT r = getRect();
return new Area(new Rectangle(r.Xmin, r.Ymin, r.getWidth(), r.getHeight()));
}
@Override
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix strokeTransformation, Matrix absoluteTransformation, ColorTransform colorTransform) {
SHAPERECORD.shapeListToImage(swf, getGlyphShapeTable(), image, frame, Color.black, colorTransform);
}
@Override
public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level) {
}
@Override
public void toHtmlCanvas(StringBuilder result, double unitDivisor) {
List<SHAPE> shapes = getGlyphShapeTable();
result.append("\tdefaultFill = textColor;\r\n");
result.append("\tswitch(ch){\r\n");
for (int i = 0; i < shapes.size(); i++) {
char c = glyphToChar(i);
String cs = "" + c;
cs = cs.replace("\\", "\\\\").replace("\"", "\\\"");
result.append("\t\tcase \"").append(cs).append("\":\r\n");
CanvasShapeExporter exporter = new CanvasShapeExporter(null, unitDivisor, swf, shapes.get(i), null, 0, 0);
exporter.export();
result.append("\t\t").append(exporter.getShapeData().replaceAll("\r\n", "\r\n\t\t"));
result.append("\tbreak;\r\n");
}
result.append("\t}\r\n");
}
@Override
public int getNumFrames() {
int frameCount = (getGlyphShapeTable().size() - 1) / SHAPERECORD.MAX_CHARACTERS_IN_FONT_PREVIEW + 1;
if (frameCount < 1) {
frameCount = 1;
}
return frameCount;
}
@Override
public boolean isSingleFrame() {
return true;
}
@Override
public RECT getRect() {
return getRect(null); // parameter not used
}
@Override
public RECT getRect(Set<BoundedTag> added) {
return new RECT(0, (int) (PREVIEWSIZE * SWF.unitDivisor), 0, (int) (PREVIEWSIZE * SWF.unitDivisor));
}
@Override
public String getCharacterExportFileName() {
return super.getCharacterExportFileName() + "_" + getFontNameIntag();
}
public DefineFontNameTag getFontNameTag() {
for (Tag t : swf.getTags()) {
if (t instanceof DefineFontNameTag) {
DefineFontNameTag dfn = (DefineFontNameTag) t;
if (dfn.fontId == getFontId()) {
return dfn;
}
}
}
return null;
}
public String getCopyright() {
DefineFontNameTag dfn = getFontNameTag();
if (dfn == null) {
return null;
}
return dfn.fontCopyright;
}
public RECT getGlyphBounds(int glyphIndex) {
return getGlyphShapeTable().get(glyphIndex).getBounds();
}
public FontTag toClassicFont() {
return this;
}
}

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,459 +1,459 @@
/*
* 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.gfx;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.SWFOutputStream;
import com.jpexs.decompiler.flash.helpers.FontHelper;
import com.jpexs.decompiler.flash.tags.DefineFont2Tag;
import com.jpexs.decompiler.flash.tags.base.FontTag;
import com.jpexs.decompiler.flash.types.KERNINGRECORD;
import com.jpexs.decompiler.flash.types.LANGCODE;
import com.jpexs.decompiler.flash.types.RECT;
import com.jpexs.decompiler.flash.types.SHAPE;
import com.jpexs.decompiler.flash.types.gfx.FontType;
import com.jpexs.decompiler.flash.types.gfx.GFxInputStream;
import com.jpexs.decompiler.flash.types.gfx.GFxOutputStream;
import com.jpexs.decompiler.flash.types.gfx.GlyphInfoType;
import com.jpexs.decompiler.flash.types.gfx.GlyphType;
import com.jpexs.decompiler.flash.types.gfx.KerningPairType;
import com.jpexs.decompiler.flash.types.shaperecords.CurvedEdgeRecord;
import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD;
import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord;
import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord;
import com.jpexs.helpers.ByteArrayRange;
import com.jpexs.helpers.MemoryInputStream;
import java.awt.Font;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author JPEXS
*/
public final class DefineCompactedFont extends FontTag {
public static final int ID = 1005;
public static final String NAME = "DefineCompactedFont";
public int fontId;
public List<FontType> fonts;
private List<SHAPE> shapeCache;
/**
* Gets data bytes
*
* @param sos SWF output stream
* @throws java.io.IOException
*/
@Override
public void getData(SWFOutputStream sos) throws IOException {
sos.writeUI16(fontId);
for (FontType ft : fonts) {
ft.write(new GFxOutputStream(sos));
}
}
/**
* Constructor
*
* @param swf
*/
public DefineCompactedFont(SWF swf) {
super(swf, ID, NAME, null);
fontId = swf.getNextCharacterId();
fonts = new ArrayList<>();
FontType ft = new FontType();
fonts.add(ft);
rebuildShapeCache();
}
/**
* Constructor
*
* @param sis
* @param data
* @throws IOException
*/
public DefineCompactedFont(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");
fonts = new ArrayList<>();
MemoryInputStream mis = sis.getBaseStream();
while (mis.available() > 0) {
GFxInputStream gis = new GFxInputStream(mis);
gis.dumpInfo = sis.dumpInfo;
gis.newDumpLevel("fontType", "FontType");
fonts.add(new FontType(gis));
gis.endDumpLevel();
}
sis.skipBytes(sis.available());
if (fonts.size() > 1) {
Logger.getLogger(DefineCompactedFont.class.getName()).log(Level.WARNING, "Compacted font has more than one FontType inside. This may cause problems while editing.");
}
rebuildShapeCache();
}
public void rebuildShapeCache() {
shapeCache = fonts.get(0).getGlyphShapes();
}
@Override
public String getFontNameIntag() {
StringBuilder ret = new StringBuilder();
for (int i = 0; i < fonts.size(); i++) {
if (i > 0) {
ret.append(", ");
}
ret.append(fonts.get(i).fontName);
}
return ret.toString();
}
@Override
public int getCharacterId() {
return fontId;
}
@Override
public void setCharacterId(int characterId) {
this.fontId = characterId;
}
@Override
public List<SHAPE> getGlyphShapeTable() {
return shapeCache;
}
@Override
public void addCharacter(char character, Font cfont) {
int fontStyle = getFontStyle();
FontType font = fonts.get(0);
double d = 1;
SHAPE shp = SHAPERECORD.fontCharacterToSHAPE(cfont, (int) (font.nominalSize * d), character);
int code = (int) character;
int pos = -1;
boolean exists = false;
for (int i = 0; i < font.glyphInfo.size(); i++) {
if (font.glyphInfo.get(i).glyphCode >= code) {
if (font.glyphInfo.get(i).glyphCode == code) {
exists = true;
}
pos = i;
break;
}
}
if (pos == -1) {
pos = font.glyphInfo.size();
}
if (!exists) {
shiftGlyphIndices(fontId, pos, true);
}
Font fnt = cfont.deriveFont(fontStyle, Math.round(font.nominalSize * d));
int advance = (int) Math.round(FontHelper.getFontAdvance(fnt, character));
if (!exists) {
font.glyphInfo.add(pos, new GlyphInfoType(code, advance, 0));
font.glyphs.add(pos, new GlyphType(shp.shapeRecords));
shapeCache.add(pos, font.glyphs.get(pos).toSHAPE());
} else {
font.glyphInfo.set(pos, new GlyphInfoType(code, advance, 0));
font.glyphs.set(pos, new GlyphType(shp.shapeRecords));
shapeCache.set(pos, font.glyphs.get(pos).toSHAPE());
}
setModified(true);
getSwf().clearImageCache();
}
@Override
public boolean removeCharacter(char character) {
FontType font = fonts.get(0);
int code = (int) character;
int pos = -1;
for (int i = 0; i < font.glyphInfo.size(); i++) {
if (font.glyphInfo.get(i).glyphCode >= code) {
if (font.glyphInfo.get(i).glyphCode == code) {
pos = i;
break;
}
return false;
}
}
if (pos == -1) {
return false;
}
font.glyphInfo.remove(pos);
font.glyphs.remove(pos);
shapeCache.remove(pos);
shiftGlyphIndices(fontId, pos + 1, false);
setModified(true);
getSwf().clearImageCache();
return true;
}
@Override
public void setAdvanceValues(Font font) {
throw new UnsupportedOperationException("Setting the advance values for DefineCompactedFont is not supported.");
}
@Override
public char glyphToChar(int glyphIndex) {
return (char) fonts.get(0).glyphInfo.get(glyphIndex).glyphCode;
}
@Override
public int charToGlyph(char c) {
FontType ft = fonts.get(0);
for (int i = 0; i < ft.glyphInfo.size(); i++) {
if (ft.glyphInfo.get(i).glyphCode == c) {
return i;
}
}
return -1;
}
@Override
public double getGlyphAdvance(int glyphIndex) {
return resize(fonts.get(0).glyphInfo.get(glyphIndex).advanceX);
}
@Override
public int getGlyphKerningAdjustment(int glyphIndex, int nextGlyphIndex) {
char c1 = glyphToChar(glyphIndex);
char c2 = glyphToChar(nextGlyphIndex);
return getCharKerningAdjustment(c1, c2);
}
@Override
public int getCharKerningAdjustment(char c1, char c2) {
for (KerningPairType kp : fonts.get(0).kerning) {
if (kp.char1 == c1 && kp.char2 == c2) {
return resize(kp.advance);
}
}
return 0;
}
@Override
public int getGlyphWidth(int glyphIndex) {
return resize(getGlyphShapeTable().get(glyphIndex).getBounds().getWidth());
}
@Override
public boolean isSmall() {
return false;
}
@Override
public boolean isBold() {
return (fonts.get(0).flags & FontType.FF_Bold) == FontType.FF_Bold;
}
@Override
public boolean isItalic() {
return (fonts.get(0).flags & FontType.FF_Italic) == FontType.FF_Italic;
}
@Override
public boolean isSmallEditable() {
return false;
}
@Override
public boolean isBoldEditable() {
return true;
}
@Override
public boolean isItalicEditable() {
return true;
}
@Override
public void setSmall(boolean value) {
}
@Override
public void setBold(boolean value) {
for (FontType font : fonts) {
font.flags &= FontType.FF_Bold;
if (!value) {
font.flags ^= FontType.FF_Bold;
}
}
}
@Override
public void setItalic(boolean value) {
for (FontType font : fonts) {
font.flags &= FontType.FF_Italic;
if (!value) {
font.flags ^= FontType.FF_Italic;
}
}
}
@Override
public double getDivider() {
return 1;
}
@Override
public int getAscent() {
return fonts.get(0).ascent;
}
@Override
public int getDescent() {
return fonts.get(0).descent;
}
@Override
public int getLeading() {
return fonts.get(0).leading;
}
@Override
public int getCharacterCount() {
FontType ft = fonts.get(0);
return ft.glyphInfo.size();
}
@Override
public String getCharacters() {
FontType ft = fonts.get(0);
StringBuilder ret = new StringBuilder(ft.glyphInfo.size());
for (GlyphInfoType gi : ft.glyphInfo) {
ret.append((char) gi.glyphCode);
}
return ret.toString();
}
@Override
public RECT getGlyphBounds(int glyphIndex) {
GlyphType gt = fonts.get(0).glyphs.get(glyphIndex);
return new RECT(resize(gt.boundingBox[0]), resize(gt.boundingBox[1]), resize(gt.boundingBox[2]), resize(gt.boundingBox[3]));
}
public SHAPE resizeShape(SHAPE shp) {
SHAPE ret = new SHAPE();
ret.numFillBits = 1;
ret.numLineBits = 0;
List<SHAPERECORD> recs = new ArrayList<>();
for (SHAPERECORD r : shp.shapeRecords) {
SHAPERECORD c = r.clone();
if (c instanceof StyleChangeRecord) {
StyleChangeRecord scr = (StyleChangeRecord) c;
scr.moveDeltaX = resize(scr.moveDeltaX);
scr.moveDeltaY = resize(scr.moveDeltaY);
scr.calculateBits();
}
if (c instanceof CurvedEdgeRecord) {
CurvedEdgeRecord cer = (CurvedEdgeRecord) c;
cer.controlDeltaX = resize(cer.controlDeltaX);
cer.controlDeltaY = resize(cer.controlDeltaY);
cer.anchorDeltaX = resize(cer.anchorDeltaX);
cer.anchorDeltaY = resize(cer.anchorDeltaY);
cer.calculateBits();
}
if (c instanceof StraightEdgeRecord) {
StraightEdgeRecord ser = (StraightEdgeRecord) c;
ser.deltaX = resize(ser.deltaX);
ser.deltaY = resize(ser.deltaY);
ser.calculateBits();
}
recs.add(c);
}
ret.shapeRecords = recs;
return ret;
}
protected int resize(double val) {
FontType ft = fonts.get(0);
return (int) Math.round(val * 1024.0 / ft.nominalSize);
}
@Override
public FontTag toClassicFont() {
DefineFont2Tag ret = new DefineFont2Tag(swf);
ret.fontID = getFontId();
ret.fontFlagsBold = isBold();
ret.fontFlagsItalic = isItalic();
ret.fontFlagsWideOffsets = true;
ret.fontFlagsWideCodes = true;
ret.fontFlagsHasLayout = true;
ret.fontAscent = (getAscent());
ret.fontDescent = (getDescent());
ret.fontLeading = (getLeading());
ret.fontAdvanceTable = new ArrayList<>();
ret.fontBoundsTable = new ArrayList<>();
ret.codeTable = new ArrayList<>();
ret.glyphShapeTable = new ArrayList<>();
List<SHAPE> shp = getGlyphShapeTable();
for (int g = 0; g < shp.size(); g++) {
ret.fontAdvanceTable.add(resize(getGlyphAdvance(g)));
ret.codeTable.add((int) glyphToChar(g));
SHAPE shpX = resizeShape(shp.get(g));
ret.glyphShapeTable.add(shpX);
ret.fontBoundsTable.add(getGlyphBounds(g));
}
ret.fontName = getFontNameIntag();
ret.languageCode = new LANGCODE(1);
ret.fontKerningTable = new ArrayList<>();
FontType ft = fonts.get(0);
for (int i = 0; i < ft.kerning.size(); i++) {
KERNINGRECORD kr = new KERNINGRECORD();
kr.fontKerningAdjustment = resize(ft.kerning.get(i).advance);
kr.fontKerningCode1 = ft.kerning.get(i).char1;
kr.fontKerningCode2 = ft.kerning.get(i).char2;
ret.fontKerningTable.add(kr);
}
return ret;
}
@Override
public boolean hasLayout() {
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.tags.gfx;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.SWFOutputStream;
import com.jpexs.decompiler.flash.helpers.FontHelper;
import com.jpexs.decompiler.flash.tags.DefineFont2Tag;
import com.jpexs.decompiler.flash.tags.base.FontTag;
import com.jpexs.decompiler.flash.types.KERNINGRECORD;
import com.jpexs.decompiler.flash.types.LANGCODE;
import com.jpexs.decompiler.flash.types.RECT;
import com.jpexs.decompiler.flash.types.SHAPE;
import com.jpexs.decompiler.flash.types.gfx.FontType;
import com.jpexs.decompiler.flash.types.gfx.GFxInputStream;
import com.jpexs.decompiler.flash.types.gfx.GFxOutputStream;
import com.jpexs.decompiler.flash.types.gfx.GlyphInfoType;
import com.jpexs.decompiler.flash.types.gfx.GlyphType;
import com.jpexs.decompiler.flash.types.gfx.KerningPairType;
import com.jpexs.decompiler.flash.types.shaperecords.CurvedEdgeRecord;
import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD;
import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord;
import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord;
import com.jpexs.helpers.ByteArrayRange;
import com.jpexs.helpers.MemoryInputStream;
import java.awt.Font;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author JPEXS
*/
public final class DefineCompactedFont extends FontTag {
public static final int ID = 1005;
public static final String NAME = "DefineCompactedFont";
public int fontId;
public List<FontType> fonts;
private List<SHAPE> shapeCache;
/**
* Gets data bytes
*
* @param sos SWF output stream
* @throws java.io.IOException
*/
@Override
public void getData(SWFOutputStream sos) throws IOException {
sos.writeUI16(fontId);
for (FontType ft : fonts) {
ft.write(new GFxOutputStream(sos));
}
}
/**
* Constructor
*
* @param swf
*/
public DefineCompactedFont(SWF swf) {
super(swf, ID, NAME, null);
fontId = swf.getNextCharacterId();
fonts = new ArrayList<>();
FontType ft = new FontType();
fonts.add(ft);
rebuildShapeCache();
}
/**
* Constructor
*
* @param sis
* @param data
* @throws IOException
*/
public DefineCompactedFont(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");
fonts = new ArrayList<>();
MemoryInputStream mis = sis.getBaseStream();
while (mis.available() > 0) {
GFxInputStream gis = new GFxInputStream(mis);
gis.dumpInfo = sis.dumpInfo;
gis.newDumpLevel("fontType", "FontType");
fonts.add(new FontType(gis));
gis.endDumpLevel();
}
sis.skipBytes(sis.available());
if (fonts.size() > 1) {
Logger.getLogger(DefineCompactedFont.class.getName()).log(Level.WARNING, "Compacted font has more than one FontType inside. This may cause problems while editing.");
}
rebuildShapeCache();
}
public void rebuildShapeCache() {
shapeCache = fonts.get(0).getGlyphShapes();
}
@Override
public String getFontNameIntag() {
StringBuilder ret = new StringBuilder();
for (int i = 0; i < fonts.size(); i++) {
if (i > 0) {
ret.append(", ");
}
ret.append(fonts.get(i).fontName);
}
return ret.toString();
}
@Override
public int getCharacterId() {
return fontId;
}
@Override
public void setCharacterId(int characterId) {
this.fontId = characterId;
}
@Override
public List<SHAPE> getGlyphShapeTable() {
return shapeCache;
}
@Override
public void addCharacter(char character, Font cfont) {
int fontStyle = getFontStyle();
FontType font = fonts.get(0);
double d = 1;
SHAPE shp = SHAPERECORD.fontCharacterToSHAPE(cfont, (int) (font.nominalSize * d), character);
int code = (int) character;
int pos = -1;
boolean exists = false;
for (int i = 0; i < font.glyphInfo.size(); i++) {
if (font.glyphInfo.get(i).glyphCode >= code) {
if (font.glyphInfo.get(i).glyphCode == code) {
exists = true;
}
pos = i;
break;
}
}
if (pos == -1) {
pos = font.glyphInfo.size();
}
if (!exists) {
shiftGlyphIndices(fontId, pos, true);
}
Font fnt = cfont.deriveFont(fontStyle, Math.round(font.nominalSize * d));
int advance = (int) Math.round(FontHelper.getFontAdvance(fnt, character));
if (!exists) {
font.glyphInfo.add(pos, new GlyphInfoType(code, advance, 0));
font.glyphs.add(pos, new GlyphType(shp.shapeRecords));
shapeCache.add(pos, font.glyphs.get(pos).toSHAPE());
} else {
font.glyphInfo.set(pos, new GlyphInfoType(code, advance, 0));
font.glyphs.set(pos, new GlyphType(shp.shapeRecords));
shapeCache.set(pos, font.glyphs.get(pos).toSHAPE());
}
setModified(true);
getSwf().clearImageCache();
}
@Override
public boolean removeCharacter(char character) {
FontType font = fonts.get(0);
int code = (int) character;
int pos = -1;
for (int i = 0; i < font.glyphInfo.size(); i++) {
if (font.glyphInfo.get(i).glyphCode >= code) {
if (font.glyphInfo.get(i).glyphCode == code) {
pos = i;
break;
}
return false;
}
}
if (pos == -1) {
return false;
}
font.glyphInfo.remove(pos);
font.glyphs.remove(pos);
shapeCache.remove(pos);
shiftGlyphIndices(fontId, pos + 1, false);
setModified(true);
getSwf().clearImageCache();
return true;
}
@Override
public void setAdvanceValues(Font font) {
throw new UnsupportedOperationException("Setting the advance values for DefineCompactedFont is not supported.");
}
@Override
public char glyphToChar(int glyphIndex) {
return (char) fonts.get(0).glyphInfo.get(glyphIndex).glyphCode;
}
@Override
public int charToGlyph(char c) {
FontType ft = fonts.get(0);
for (int i = 0; i < ft.glyphInfo.size(); i++) {
if (ft.glyphInfo.get(i).glyphCode == c) {
return i;
}
}
return -1;
}
@Override
public double getGlyphAdvance(int glyphIndex) {
return resize(fonts.get(0).glyphInfo.get(glyphIndex).advanceX);
}
@Override
public int getGlyphKerningAdjustment(int glyphIndex, int nextGlyphIndex) {
char c1 = glyphToChar(glyphIndex);
char c2 = glyphToChar(nextGlyphIndex);
return getCharKerningAdjustment(c1, c2);
}
@Override
public int getCharKerningAdjustment(char c1, char c2) {
for (KerningPairType kp : fonts.get(0).kerning) {
if (kp.char1 == c1 && kp.char2 == c2) {
return resize(kp.advance);
}
}
return 0;
}
@Override
public int getGlyphWidth(int glyphIndex) {
return resize(getGlyphShapeTable().get(glyphIndex).getBounds().getWidth());
}
@Override
public boolean isSmall() {
return false;
}
@Override
public boolean isBold() {
return (fonts.get(0).flags & FontType.FF_Bold) == FontType.FF_Bold;
}
@Override
public boolean isItalic() {
return (fonts.get(0).flags & FontType.FF_Italic) == FontType.FF_Italic;
}
@Override
public boolean isSmallEditable() {
return false;
}
@Override
public boolean isBoldEditable() {
return true;
}
@Override
public boolean isItalicEditable() {
return true;
}
@Override
public void setSmall(boolean value) {
}
@Override
public void setBold(boolean value) {
for (FontType font : fonts) {
font.flags &= FontType.FF_Bold;
if (!value) {
font.flags ^= FontType.FF_Bold;
}
}
}
@Override
public void setItalic(boolean value) {
for (FontType font : fonts) {
font.flags &= FontType.FF_Italic;
if (!value) {
font.flags ^= FontType.FF_Italic;
}
}
}
@Override
public double getDivider() {
return 1;
}
@Override
public int getAscent() {
return fonts.get(0).ascent;
}
@Override
public int getDescent() {
return fonts.get(0).descent;
}
@Override
public int getLeading() {
return fonts.get(0).leading;
}
@Override
public int getCharacterCount() {
FontType ft = fonts.get(0);
return ft.glyphInfo.size();
}
@Override
public String getCharacters() {
FontType ft = fonts.get(0);
StringBuilder ret = new StringBuilder(ft.glyphInfo.size());
for (GlyphInfoType gi : ft.glyphInfo) {
ret.append((char) gi.glyphCode);
}
return ret.toString();
}
@Override
public RECT getGlyphBounds(int glyphIndex) {
GlyphType gt = fonts.get(0).glyphs.get(glyphIndex);
return new RECT(resize(gt.boundingBox[0]), resize(gt.boundingBox[1]), resize(gt.boundingBox[2]), resize(gt.boundingBox[3]));
}
public SHAPE resizeShape(SHAPE shp) {
SHAPE ret = new SHAPE();
ret.numFillBits = 1;
ret.numLineBits = 0;
List<SHAPERECORD> recs = new ArrayList<>();
for (SHAPERECORD r : shp.shapeRecords) {
SHAPERECORD c = r.clone();
if (c instanceof StyleChangeRecord) {
StyleChangeRecord scr = (StyleChangeRecord) c;
scr.moveDeltaX = resize(scr.moveDeltaX);
scr.moveDeltaY = resize(scr.moveDeltaY);
scr.calculateBits();
}
if (c instanceof CurvedEdgeRecord) {
CurvedEdgeRecord cer = (CurvedEdgeRecord) c;
cer.controlDeltaX = resize(cer.controlDeltaX);
cer.controlDeltaY = resize(cer.controlDeltaY);
cer.anchorDeltaX = resize(cer.anchorDeltaX);
cer.anchorDeltaY = resize(cer.anchorDeltaY);
cer.calculateBits();
}
if (c instanceof StraightEdgeRecord) {
StraightEdgeRecord ser = (StraightEdgeRecord) c;
ser.deltaX = resize(ser.deltaX);
ser.deltaY = resize(ser.deltaY);
ser.calculateBits();
}
recs.add(c);
}
ret.shapeRecords = recs;
return ret;
}
protected int resize(double val) {
FontType ft = fonts.get(0);
return (int) Math.round(val * 1024.0 / ft.nominalSize);
}
@Override
public FontTag toClassicFont() {
DefineFont2Tag ret = new DefineFont2Tag(swf);
ret.fontID = getFontId();
ret.fontFlagsBold = isBold();
ret.fontFlagsItalic = isItalic();
ret.fontFlagsWideOffsets = true;
ret.fontFlagsWideCodes = true;
ret.fontFlagsHasLayout = true;
ret.fontAscent = (getAscent());
ret.fontDescent = (getDescent());
ret.fontLeading = (getLeading());
ret.fontAdvanceTable = new ArrayList<>();
ret.fontBoundsTable = new ArrayList<>();
ret.codeTable = new ArrayList<>();
ret.glyphShapeTable = new ArrayList<>();
List<SHAPE> shp = getGlyphShapeTable();
for (int g = 0; g < shp.size(); g++) {
ret.fontAdvanceTable.add(resize(getGlyphAdvance(g)));
ret.codeTable.add((int) glyphToChar(g));
SHAPE shpX = resizeShape(shp.get(g));
ret.glyphShapeTable.add(shpX);
ret.fontBoundsTable.add(getGlyphBounds(g));
}
ret.fontName = getFontNameIntag();
ret.languageCode = new LANGCODE(1);
ret.fontKerningTable = new ArrayList<>();
FontType ft = fonts.get(0);
for (int i = 0; i < ft.kerning.size(); i++) {
KERNINGRECORD kr = new KERNINGRECORD();
kr.fontKerningAdjustment = resize(ft.kerning.get(i).advance);
kr.fontKerningCode1 = ft.kerning.get(i).char1;
kr.fontKerningCode2 = ft.kerning.get(i).char2;
ret.fontKerningTable.add(kr);
}
return ret;
}
@Override
public boolean hasLayout() {
return true;
}
}

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;
}
}

View File

@@ -1,484 +1,484 @@
/*
* 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.gfx;
import com.jpexs.decompiler.flash.types.shaperecords.CurvedEdgeRecord;
import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD;
import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord;
import java.io.IOException;
import java.io.Serializable;
/**
*
* @author JPEXS
*/
public class EdgeType implements Serializable {
private static final int[] sizes = new int[]{1, 2, 1, 2, 1, 2, 3, 4, 2, 3, 4, 5, 6, 7, 8, 9};
private static final int Edge_H12 = 0; // 2 bytes
private static final int Edge_H20 = 1; // 3 bytes
private static final int Edge_V12 = 2; // 2 bytes
private static final int Edge_V20 = 3; // 3 bytes
private static final int Edge_L6 = 4; // 2 bytes
private static final int Edge_L10 = 5; // 3 bytes
private static final int Edge_L14 = 6; // 4 bytes
private static final int Edge_L18 = 7; // 5 bytes
private static final int Edge_C5 = 8; // 3 bytes
private static final int Edge_C7 = 9; // 4 bytes
private static final int Edge_C9 = 10; // 5 bytes
private static final int Edge_C11 = 11; // 6 bytes
private static final int Edge_C13 = 12; // 7 bytes
private static final int Edge_C15 = 13; // 8 bytes
private static final int Edge_C17 = 14; // 9 bytes
private static final int Edge_C19 = 15; // 10 bytes
private static final int Edge_HLine = 0;
private static final int Edge_VLine = 1;
private static final int Edge_Line = 2;
private static final int Edge_Quad = 3;
public int[] data;
public EdgeType(boolean vertical, int v) {
data = new int[]{vertical ? Edge_VLine : Edge_HLine, v};
}
public EdgeType(int x, int y) {
data = new int[]{Edge_Line, x, y};
}
public EdgeType(int cx, int cy, int ax, int ay) {
data = new int[]{Edge_Quad, cx, cy, ax, ay};
}
@Override
public String toString() {
String ret = "[Edge data:";
for (int i = 0; i < data.length; i++) {
if (i > 0) {
ret += ", ";
}
ret += "" + data[i];
}
ret += "]";
return ret;
}
public EdgeType(GFxInputStream sis) throws IOException {
data = readEdge(sis);
/*if((raw[0]&0xf) == Edge_V20){
data[1] = 0;
}
if((raw[0]&0xf) == Edge_C17){
//System.out.println("========== 17 : "+toString()) ;
data[1] = 0;
data[2] = 0;
data[3] = 0;
data[4] = 0;
}*/
}
private static int SInt8(int val) {
/*boolean sign = (val & 0x80) == 0x80;
val = val & 0x7F;
if (sign) {
val = -val;
}
return val;*/
return (byte) val;
}
public SHAPERECORD toSHAPERECORD() {
int multiplier = 1;
StraightEdgeRecord ser;
CurvedEdgeRecord cer;
switch (data[0]) {
case Edge_HLine:
ser = new StraightEdgeRecord();
ser.generalLineFlag = false;
ser.deltaX = data[1] * multiplier;
ser.calculateBits();
return ser;
case Edge_VLine:
ser = new StraightEdgeRecord();
ser.generalLineFlag = false;
ser.vertLineFlag = true;
ser.deltaY = data[1] * multiplier;
ser.calculateBits();
return ser;
case Edge_Line:
ser = new StraightEdgeRecord();
ser.generalLineFlag = true;
ser.deltaX = data[1] * multiplier;
ser.deltaY = data[2] * multiplier;
ser.calculateBits();
return ser;
case Edge_Quad:
cer = new CurvedEdgeRecord();
cer.controlDeltaX = data[1] * multiplier;
cer.controlDeltaY = data[2] * multiplier;
cer.anchorDeltaX = data[3] * multiplier;
cer.anchorDeltaY = data[4] * multiplier;
cer.calculateBits();
return cer;
}
return null;
}
private int[] readEdge(GFxInputStream sis) throws IOException {
byte firstByte = (byte) sis.readUI8("firstByte");
byte raw1, raw2, raw3, raw4, raw5, raw6, raw7, raw8, raw9;
raw1 = (byte) sis.readUI8("byte1");
int[] data = new int[5];
switch (firstByte & 0xF) {
case Edge_H12:
data[0] = Edge_HLine;
data[1] = ((firstByte & 0xff) >> 4) | (SInt8(raw1 & 0xff) << 4);
break;
case Edge_H20:
raw2 = (byte) sis.readUI8("byte2");
data[0] = Edge_HLine;
data[1] = ((firstByte & 0xff) >> 4) | ((raw1 & 0xff) << 4) | (SInt8(raw2 & 0xff) << 12);
break;
case Edge_V12:
data[0] = Edge_VLine;
data[1] = ((firstByte & 0xff) >> 4) | (SInt8(raw1 & 0xff) << 4);
break;
case Edge_V20:
data[0] = Edge_VLine;
raw2 = (byte) sis.readUI8("byte2");
data[1] = ((firstByte & 0xff) >> 4) | ((raw1 & 0xff) << 4) | (SInt8(raw2 & 0xff) << 12);
break;
case Edge_L6:
data[0] = Edge_Line;
data[1] = ((firstByte & 0xff) >> 4) | (SInt8((raw1 & 0xff) << 6) >> 2);
data[2] = SInt8(raw1 & 0xff) >> 2;
break;
case Edge_L10:
raw2 = (byte) sis.readUI8("byte2");
data[0] = Edge_Line;
data[1] = ((firstByte & 0xff) >> 4) | (SInt8((raw1 & 0xff) << 2) << 2);
data[2] = ((raw1 & 0xff) >> 6) | (SInt8((raw2 & 0xff)) << 2);
break;
case Edge_L14:
raw2 = (byte) sis.readUI8("byte2");
raw3 = (byte) sis.readUI8("byte3");
data[0] = Edge_Line;
data[1] = ((firstByte & 0xff) >> 4) | ((raw1 & 0xff) << 4) | (SInt8((raw2 & 0xff) << 6) << 6);
data[2] = ((raw2 & 0xff) >> 2) | (SInt8((raw3 & 0xff)) << 6);
break;
case Edge_L18:
raw2 = (byte) sis.readUI8("byte2");
raw3 = (byte) sis.readUI8("byte3");
raw4 = (byte) sis.readUI8("byte4");
data[0] = Edge_Line;
data[1] = ((firstByte & 0xff) >> 4) | ((raw1 & 0xff) << 4) | (SInt8((raw2 & 0xff) << 2) << 10);
data[2] = ((raw2 & 0xff) >> 6) | ((raw3 & 0xff) << 2) | (SInt8((raw4 & 0xff)) << 10);
break;
case Edge_C5:
raw2 = (byte) sis.readUI8("byte2");
data[0] = Edge_Quad;
data[1] = ((firstByte & 0xff) >> 4) | (SInt8((raw1 & 0xff) << 7) >> 3);
data[2] = SInt8((raw1 & 0xff) << 2) >> 3;
data[3] = ((raw1 & 0xff) >> 6) | (SInt8((raw2 & 0xff) << 5) >> 3);
data[4] = SInt8((raw2 & 0xff)) >> 3;
break;
case Edge_C7:
raw2 = (byte) sis.readUI8("byte2");
raw3 = (byte) sis.readUI8("byte3");
data[0] = Edge_Quad;
data[1] = ((firstByte & 0xff) >> 4) | (SInt8((raw1 & 0xff) << 5) >> 1);
data[2] = ((raw1 & 0xff) >> 3) | (SInt8((raw2 & 0xff) << 6) >> 1);
data[3] = ((raw2 & 0xff) >> 2) | (SInt8((raw3 & 0xff) << 7) >> 1);
data[4] = SInt8(raw3) >> 1;
break;
case Edge_C9:
raw2 = (byte) sis.readUI8("byte2");
raw3 = (byte) sis.readUI8("byte3");
raw4 = (byte) sis.readUI8("byte4");
data[0] = Edge_Quad;
data[1] = ((firstByte & 0xff) >> 4) | (SInt8((raw1 & 0xff) << 3) << 1);
data[2] = ((raw1 & 0xff) >> 5) | (SInt8((raw2 & 0xff) << 2) << 1);
data[3] = ((raw2 & 0xff) >> 6) | (SInt8((raw3 & 0xff) << 1) << 1);
data[4] = ((raw3 & 0xff) >> 7) | (SInt8(raw4 & 0xff) << 1);
break;
case Edge_C11:
raw2 = (byte) sis.readUI8("byte2");
raw3 = (byte) sis.readUI8("byte3");
raw4 = (byte) sis.readUI8("byte4");
raw5 = (byte) sis.readUI8("byte5");
data[0] = Edge_Quad;
data[1] = ((firstByte & 0xff) >> 4) | (SInt8((raw1 & 0xff) << 1) << 3);
data[2] = (raw1 >> 7) | ((raw2 & 0xff) << 1) | (SInt8((raw3 & 0xff) << 6) << 3);
data[3] = ((raw3 & 0xff) >> 2) | (SInt8((raw4 & 0xff) << 3) << 3);
data[4] = ((raw4 & 0xff) >> 5) | (SInt8(raw5 & 0xff) << 3);
break;
case Edge_C13:
raw2 = (byte) sis.readUI8("byte2");
raw3 = (byte) sis.readUI8("byte3");
raw4 = (byte) sis.readUI8("byte4");
raw5 = (byte) sis.readUI8("byte5");
raw6 = (byte) sis.readUI8("byte6");
data[0] = Edge_Quad;
data[1] = ((firstByte & 0xff) >> 4) | ((raw1 & 0xff) << 4) | (SInt8((raw2 & 0xff) << 7) << 5);
data[2] = ((raw2 & 0xff) >> 1) | (SInt8((raw3 & 0xff) << 2) << 5);
data[3] = ((raw3 & 0xff) >> 6) | ((raw4 & 0xff) << 2) | (SInt8((raw5 & 0xff) << 5) << 5);
data[4] = ((raw5 & 0xff) >> 3) | (SInt8(raw6 & 0xff) << 5);
break;
case Edge_C15:
raw2 = (byte) sis.readUI8("byte2");
raw3 = (byte) sis.readUI8("byte3");
raw4 = (byte) sis.readUI8("byte4");
raw5 = (byte) sis.readUI8("byte5");
raw6 = (byte) sis.readUI8("byte6");
raw7 = (byte) sis.readUI8("byte7");
data[0] = Edge_Quad;
data[1] = ((firstByte & 0xff) >> 4) | ((raw1 & 0xff) << 4) | (SInt8((raw2 & 0xff) << 5) << 7);
data[2] = ((raw2 & 0xff) >> 3) | ((raw3 & 0xff) << 5) | (SInt8((raw4 & 0xff) << 6) << 7);
data[3] = ((raw4 & 0xff) >> 2) | ((raw5 & 0xff) << 6) | (SInt8((raw6 & 0xff) << 7) << 7);
data[4] = ((raw6 & 0xff) >> 1) | (SInt8((raw7 & 0xff)) << 7);
break;
case Edge_C17:
raw2 = (byte) sis.readUI8("byte2");
raw3 = (byte) sis.readUI8("byte3");
raw4 = (byte) sis.readUI8("byte4");
raw5 = (byte) sis.readUI8("byte5");
raw6 = (byte) sis.readUI8("byte6");
raw7 = (byte) sis.readUI8("byte7");
raw8 = (byte) sis.readUI8("byte8");
data[0] = Edge_Quad;
data[1] = ((firstByte & 0xff) >> 4) | ((raw1 & 0xff) << 4) | (SInt8((raw2 & 0xff) << 3) << 9);
data[2] = ((raw2 & 0xff) >> 5) | ((raw3 & 0xff) << 3) | (SInt8((raw4 & 0xff) << 2) << 9);
data[3] = ((raw4 & 0xff) >> 6) | ((raw5 & 0xff) << 2) | (SInt8((raw6 & 0xff) << 1) << 9);
data[4] = ((raw6 & 0xff) >> 7) | ((raw7 & 0xff) << 1) | (SInt8(raw8 & 0xff) << 9);
break;
case Edge_C19:
raw2 = (byte) sis.readUI8("byte2");
raw3 = (byte) sis.readUI8("byte3");
raw4 = (byte) sis.readUI8("byte4");
raw5 = (byte) sis.readUI8("byte5");
raw6 = (byte) sis.readUI8("byte6");
raw7 = (byte) sis.readUI8("byte7");
raw8 = (byte) sis.readUI8("byte8");
raw9 = (byte) sis.readUI8("byte9");
data[0] = Edge_Quad;
data[1] = ((firstByte & 0xff) >> 4) | ((raw1 & 0xff) << 4) | (SInt8(raw2 << 1) << 11);
data[2] = ((raw2 & 0xff) >> 7) | ((raw3 & 0xff) << 1) | ((raw4 & 0xff) << 9) | (SInt8(raw5 << 6) << 11);
data[3] = ((raw5 & 0xff) >> 2) | ((raw6 & 0xff) << 6) | (SInt8(raw7 << 3) << 11);
data[4] = ((raw7 & 0xff) >> 5) | ((raw8 & 0xff) << 3) | (SInt8(raw9) << 11);
break;
}
return data;
}
public void write(GFxOutputStream sos) throws IOException {
int x;
int y;
int m1 = 1;
int m2 = 3;
int m3 = 7;
int m4 = 0xF;
int m5 = 0x1F;
int m6 = 0x3F;
int m7 = 0x7F;
switch (data[0]) {
case Edge_HLine:
x = data[1];
if (x >= GFxOutputStream.MinSInt12 && x <= GFxOutputStream.MaxSInt12) {
sos.writeUI8((x << 4) | Edge_H12);
sos.writeUI8(x >> 4);
return;
}
sos.writeUI8((x << 4) | Edge_H20);
sos.writeUI8(x >> 4);
sos.writeUI8(x >> 12);
break;
case Edge_VLine:
y = data[1];
if (y >= GFxOutputStream.MinSInt12 && y <= GFxOutputStream.MaxSInt12) {
sos.writeUI8((y << 4) | Edge_V12);
sos.writeUI8(y >> 4);
return;
}
sos.writeUI8((y << 4) | Edge_V20);
sos.writeUI8(y >> 4);
sos.writeUI8(y >> 12);
return;
case Edge_Line:
x = data[1];
y = data[2];
if (x >= GFxOutputStream.MinSInt6 && x <= GFxOutputStream.MaxSInt6 && y >= GFxOutputStream.MinSInt6 && y <= GFxOutputStream.MaxSInt6) {
sos.writeUI8((x << 4) | Edge_L6);
sos.writeUI8(((x >> 4) & m2) | (y << 2));
return;
}
if (x >= GFxOutputStream.MinSInt10 && x <= GFxOutputStream.MaxSInt10 && y >= GFxOutputStream.MinSInt10 && y <= GFxOutputStream.MaxSInt10) {
sos.writeUI8((x << 4) | Edge_L10);
sos.writeUI8(((x >> 4) & m6) | (y << 6));
sos.writeUI8(y >> 2);
return;
}
if (x >= GFxOutputStream.MinSInt14 && x <= GFxOutputStream.MaxSInt14 && y >= GFxOutputStream.MinSInt14 && y <= GFxOutputStream.MaxSInt14) {
sos.writeUI8((x << 4) | Edge_L14);
sos.writeUI8(x >> 4);
sos.writeUI8(((x >> 12) & m2) | (y << 2));
sos.writeUI8(y >> 6);
return;
}
sos.writeUI8((x << 4) | Edge_L18);
sos.writeUI8(x >> 4);
sos.writeUI8(((x >> 12) & m6) | (y << 6));
sos.writeUI8(y >> 2);
sos.writeUI8(y >> 10);
return;
case Edge_Quad:
int cx = data[1];
int cy = data[2];
int ax = data[3];
int ay = data[4];
int minV = cx;
int maxV = cx;
if (cy < minV) {
minV = cy;
}
if (cy > maxV) {
maxV = cy;
}
if (ax < minV) {
minV = ax;
}
if (ax > maxV) {
maxV = ax;
}
if (ay < minV) {
minV = ay;
}
if (ay > maxV) {
maxV = ay;
}
if (minV >= GFxOutputStream.MinSInt5 && maxV <= GFxOutputStream.MaxSInt5) {
sos.writeUI8(((cx << 4) | Edge_C5));
sos.writeUI8((((cx >> 4) & m1) | ((cy << 1) & m6) | (ax << 6)));
sos.writeUI8((((ax >> 2) & m3) | (ay << 3)));
return;
}
if (minV >= GFxOutputStream.MinSInt7 && maxV <= GFxOutputStream.MaxSInt7) {
sos.writeUI8(((cx << 4) | Edge_C7));
sos.writeUI8((((cx >> 4) & m3) | (cy << 3)));
sos.writeUI8((((cy >> 5) & m2) | (ax << 2)));
sos.writeUI8((((ax >> 6) & m1) | (ay << 1)));
return;
}
if (minV >= GFxOutputStream.MinSInt9 && maxV <= GFxOutputStream.MaxSInt9) {
sos.writeUI8(((cx << 4) | Edge_C9));
sos.writeUI8((((cx >> 4) & m5) | (cy << 5)));
sos.writeUI8((((cy >> 3) & m6) | (ax << 6)));
sos.writeUI8((((ax >> 2) & m7) | (ay << 7)));
sos.writeUI8(((ay >> 1)));
return;
}
if (minV >= GFxOutputStream.MinSInt11 && maxV <= GFxOutputStream.MaxSInt11) {
sos.writeUI8(((cx << 4) | Edge_C11));
sos.writeUI8((((cx >> 4) & m7) | (cy << 7)));
sos.writeUI8(((cy >> 1)));
sos.writeUI8((((cy >> 9) & m2) | (ax << 2)));
sos.writeUI8((((ax >> 6) & m5) | (ay << 5)));
sos.writeUI8(((ay >> 3)));
return;
}
if (minV >= GFxOutputStream.MinSInt13 && maxV <= GFxOutputStream.MaxSInt13) {
sos.writeUI8(((cx << 4) | Edge_C13));
sos.writeUI8(((cx >> 4)));
sos.writeUI8((((cx >> 12) & m1) | (cy << 1)));
sos.writeUI8((((cy >> 7) & m6) | (ax << 6)));
sos.writeUI8(((ax >> 2)));
sos.writeUI8((((ax >> 10) & m3) | (ay << 3)));
sos.writeUI8(((ay >> 5)));
return;
}
if (minV >= GFxOutputStream.MinSInt15 && maxV <= GFxOutputStream.MaxSInt15) {
sos.writeUI8(((cx << 4) | Edge_C15));
sos.writeUI8(((cx >> 4)));
sos.writeUI8((((cx >> 12) & m3) | (cy << 3)));
sos.writeUI8(((cy >> 5)));
sos.writeUI8((((cy >> 13) & m2) | (ax << 2)));
sos.writeUI8(((ax >> 6)));
sos.writeUI8((((ax >> 14) & m1) | (ay << 1)));
sos.writeUI8(((ay >> 7)));
return;
}
if (minV >= GFxOutputStream.MinSInt17 && maxV <= GFxOutputStream.MaxSInt17) {
sos.writeUI8(((cx << 4) | Edge_C17));
sos.writeUI8(((cx >> 4)));
sos.writeUI8((((cx >> 12) & m5) | (cy << 5)));
sos.writeUI8(((cy >> 3)));
sos.writeUI8((((cy >> 11) & m6) | (ax << 6)));
sos.writeUI8(((ax >> 2)));
sos.writeUI8((((ax >> 10) & m7) | (ay << 7)));
sos.writeUI8(((ay >> 1)));
sos.writeUI8(((ay >> 9)));
return;
}
sos.writeUI8(((cx << 4) | Edge_C19));
sos.writeUI8(((cx >> 4)));
sos.writeUI8((((cx >> 12) & m7) | (cy << 7)));
sos.writeUI8(((cy >> 1)));
sos.writeUI8(((cy >> 9)));
sos.writeUI8((((cy >> 17) & m2) | (ax << 2)));
sos.writeUI8(((ax >> 6)));
sos.writeUI8((((ax >> 14) & m5) | (ay << 5)));
sos.writeUI8(((ay >> 3)));
sos.writeUI8(((ay >> 11)));
}
}
}
/*
* 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.gfx;
import com.jpexs.decompiler.flash.types.shaperecords.CurvedEdgeRecord;
import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD;
import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord;
import java.io.IOException;
import java.io.Serializable;
/**
*
* @author JPEXS
*/
public class EdgeType implements Serializable {
private static final int[] sizes = new int[]{1, 2, 1, 2, 1, 2, 3, 4, 2, 3, 4, 5, 6, 7, 8, 9};
private static final int Edge_H12 = 0; // 2 bytes
private static final int Edge_H20 = 1; // 3 bytes
private static final int Edge_V12 = 2; // 2 bytes
private static final int Edge_V20 = 3; // 3 bytes
private static final int Edge_L6 = 4; // 2 bytes
private static final int Edge_L10 = 5; // 3 bytes
private static final int Edge_L14 = 6; // 4 bytes
private static final int Edge_L18 = 7; // 5 bytes
private static final int Edge_C5 = 8; // 3 bytes
private static final int Edge_C7 = 9; // 4 bytes
private static final int Edge_C9 = 10; // 5 bytes
private static final int Edge_C11 = 11; // 6 bytes
private static final int Edge_C13 = 12; // 7 bytes
private static final int Edge_C15 = 13; // 8 bytes
private static final int Edge_C17 = 14; // 9 bytes
private static final int Edge_C19 = 15; // 10 bytes
private static final int Edge_HLine = 0;
private static final int Edge_VLine = 1;
private static final int Edge_Line = 2;
private static final int Edge_Quad = 3;
public int[] data;
public EdgeType(boolean vertical, int v) {
data = new int[]{vertical ? Edge_VLine : Edge_HLine, v};
}
public EdgeType(int x, int y) {
data = new int[]{Edge_Line, x, y};
}
public EdgeType(int cx, int cy, int ax, int ay) {
data = new int[]{Edge_Quad, cx, cy, ax, ay};
}
@Override
public String toString() {
String ret = "[Edge data:";
for (int i = 0; i < data.length; i++) {
if (i > 0) {
ret += ", ";
}
ret += "" + data[i];
}
ret += "]";
return ret;
}
public EdgeType(GFxInputStream sis) throws IOException {
data = readEdge(sis);
/*if((raw[0]&0xf) == Edge_V20){
data[1] = 0;
}
if((raw[0]&0xf) == Edge_C17){
//System.out.println("========== 17 : "+toString()) ;
data[1] = 0;
data[2] = 0;
data[3] = 0;
data[4] = 0;
}*/
}
private static int SInt8(int val) {
/*boolean sign = (val & 0x80) == 0x80;
val = val & 0x7F;
if (sign) {
val = -val;
}
return val;*/
return (byte) val;
}
public SHAPERECORD toSHAPERECORD() {
int multiplier = 1;
StraightEdgeRecord ser;
CurvedEdgeRecord cer;
switch (data[0]) {
case Edge_HLine:
ser = new StraightEdgeRecord();
ser.generalLineFlag = false;
ser.deltaX = data[1] * multiplier;
ser.calculateBits();
return ser;
case Edge_VLine:
ser = new StraightEdgeRecord();
ser.generalLineFlag = false;
ser.vertLineFlag = true;
ser.deltaY = data[1] * multiplier;
ser.calculateBits();
return ser;
case Edge_Line:
ser = new StraightEdgeRecord();
ser.generalLineFlag = true;
ser.deltaX = data[1] * multiplier;
ser.deltaY = data[2] * multiplier;
ser.calculateBits();
return ser;
case Edge_Quad:
cer = new CurvedEdgeRecord();
cer.controlDeltaX = data[1] * multiplier;
cer.controlDeltaY = data[2] * multiplier;
cer.anchorDeltaX = data[3] * multiplier;
cer.anchorDeltaY = data[4] * multiplier;
cer.calculateBits();
return cer;
}
return null;
}
private int[] readEdge(GFxInputStream sis) throws IOException {
byte firstByte = (byte) sis.readUI8("firstByte");
byte raw1, raw2, raw3, raw4, raw5, raw6, raw7, raw8, raw9;
raw1 = (byte) sis.readUI8("byte1");
int[] data = new int[5];
switch (firstByte & 0xF) {
case Edge_H12:
data[0] = Edge_HLine;
data[1] = ((firstByte & 0xff) >> 4) | (SInt8(raw1 & 0xff) << 4);
break;
case Edge_H20:
raw2 = (byte) sis.readUI8("byte2");
data[0] = Edge_HLine;
data[1] = ((firstByte & 0xff) >> 4) | ((raw1 & 0xff) << 4) | (SInt8(raw2 & 0xff) << 12);
break;
case Edge_V12:
data[0] = Edge_VLine;
data[1] = ((firstByte & 0xff) >> 4) | (SInt8(raw1 & 0xff) << 4);
break;
case Edge_V20:
data[0] = Edge_VLine;
raw2 = (byte) sis.readUI8("byte2");
data[1] = ((firstByte & 0xff) >> 4) | ((raw1 & 0xff) << 4) | (SInt8(raw2 & 0xff) << 12);
break;
case Edge_L6:
data[0] = Edge_Line;
data[1] = ((firstByte & 0xff) >> 4) | (SInt8((raw1 & 0xff) << 6) >> 2);
data[2] = SInt8(raw1 & 0xff) >> 2;
break;
case Edge_L10:
raw2 = (byte) sis.readUI8("byte2");
data[0] = Edge_Line;
data[1] = ((firstByte & 0xff) >> 4) | (SInt8((raw1 & 0xff) << 2) << 2);
data[2] = ((raw1 & 0xff) >> 6) | (SInt8((raw2 & 0xff)) << 2);
break;
case Edge_L14:
raw2 = (byte) sis.readUI8("byte2");
raw3 = (byte) sis.readUI8("byte3");
data[0] = Edge_Line;
data[1] = ((firstByte & 0xff) >> 4) | ((raw1 & 0xff) << 4) | (SInt8((raw2 & 0xff) << 6) << 6);
data[2] = ((raw2 & 0xff) >> 2) | (SInt8((raw3 & 0xff)) << 6);
break;
case Edge_L18:
raw2 = (byte) sis.readUI8("byte2");
raw3 = (byte) sis.readUI8("byte3");
raw4 = (byte) sis.readUI8("byte4");
data[0] = Edge_Line;
data[1] = ((firstByte & 0xff) >> 4) | ((raw1 & 0xff) << 4) | (SInt8((raw2 & 0xff) << 2) << 10);
data[2] = ((raw2 & 0xff) >> 6) | ((raw3 & 0xff) << 2) | (SInt8((raw4 & 0xff)) << 10);
break;
case Edge_C5:
raw2 = (byte) sis.readUI8("byte2");
data[0] = Edge_Quad;
data[1] = ((firstByte & 0xff) >> 4) | (SInt8((raw1 & 0xff) << 7) >> 3);
data[2] = SInt8((raw1 & 0xff) << 2) >> 3;
data[3] = ((raw1 & 0xff) >> 6) | (SInt8((raw2 & 0xff) << 5) >> 3);
data[4] = SInt8((raw2 & 0xff)) >> 3;
break;
case Edge_C7:
raw2 = (byte) sis.readUI8("byte2");
raw3 = (byte) sis.readUI8("byte3");
data[0] = Edge_Quad;
data[1] = ((firstByte & 0xff) >> 4) | (SInt8((raw1 & 0xff) << 5) >> 1);
data[2] = ((raw1 & 0xff) >> 3) | (SInt8((raw2 & 0xff) << 6) >> 1);
data[3] = ((raw2 & 0xff) >> 2) | (SInt8((raw3 & 0xff) << 7) >> 1);
data[4] = SInt8(raw3) >> 1;
break;
case Edge_C9:
raw2 = (byte) sis.readUI8("byte2");
raw3 = (byte) sis.readUI8("byte3");
raw4 = (byte) sis.readUI8("byte4");
data[0] = Edge_Quad;
data[1] = ((firstByte & 0xff) >> 4) | (SInt8((raw1 & 0xff) << 3) << 1);
data[2] = ((raw1 & 0xff) >> 5) | (SInt8((raw2 & 0xff) << 2) << 1);
data[3] = ((raw2 & 0xff) >> 6) | (SInt8((raw3 & 0xff) << 1) << 1);
data[4] = ((raw3 & 0xff) >> 7) | (SInt8(raw4 & 0xff) << 1);
break;
case Edge_C11:
raw2 = (byte) sis.readUI8("byte2");
raw3 = (byte) sis.readUI8("byte3");
raw4 = (byte) sis.readUI8("byte4");
raw5 = (byte) sis.readUI8("byte5");
data[0] = Edge_Quad;
data[1] = ((firstByte & 0xff) >> 4) | (SInt8((raw1 & 0xff) << 1) << 3);
data[2] = (raw1 >> 7) | ((raw2 & 0xff) << 1) | (SInt8((raw3 & 0xff) << 6) << 3);
data[3] = ((raw3 & 0xff) >> 2) | (SInt8((raw4 & 0xff) << 3) << 3);
data[4] = ((raw4 & 0xff) >> 5) | (SInt8(raw5 & 0xff) << 3);
break;
case Edge_C13:
raw2 = (byte) sis.readUI8("byte2");
raw3 = (byte) sis.readUI8("byte3");
raw4 = (byte) sis.readUI8("byte4");
raw5 = (byte) sis.readUI8("byte5");
raw6 = (byte) sis.readUI8("byte6");
data[0] = Edge_Quad;
data[1] = ((firstByte & 0xff) >> 4) | ((raw1 & 0xff) << 4) | (SInt8((raw2 & 0xff) << 7) << 5);
data[2] = ((raw2 & 0xff) >> 1) | (SInt8((raw3 & 0xff) << 2) << 5);
data[3] = ((raw3 & 0xff) >> 6) | ((raw4 & 0xff) << 2) | (SInt8((raw5 & 0xff) << 5) << 5);
data[4] = ((raw5 & 0xff) >> 3) | (SInt8(raw6 & 0xff) << 5);
break;
case Edge_C15:
raw2 = (byte) sis.readUI8("byte2");
raw3 = (byte) sis.readUI8("byte3");
raw4 = (byte) sis.readUI8("byte4");
raw5 = (byte) sis.readUI8("byte5");
raw6 = (byte) sis.readUI8("byte6");
raw7 = (byte) sis.readUI8("byte7");
data[0] = Edge_Quad;
data[1] = ((firstByte & 0xff) >> 4) | ((raw1 & 0xff) << 4) | (SInt8((raw2 & 0xff) << 5) << 7);
data[2] = ((raw2 & 0xff) >> 3) | ((raw3 & 0xff) << 5) | (SInt8((raw4 & 0xff) << 6) << 7);
data[3] = ((raw4 & 0xff) >> 2) | ((raw5 & 0xff) << 6) | (SInt8((raw6 & 0xff) << 7) << 7);
data[4] = ((raw6 & 0xff) >> 1) | (SInt8((raw7 & 0xff)) << 7);
break;
case Edge_C17:
raw2 = (byte) sis.readUI8("byte2");
raw3 = (byte) sis.readUI8("byte3");
raw4 = (byte) sis.readUI8("byte4");
raw5 = (byte) sis.readUI8("byte5");
raw6 = (byte) sis.readUI8("byte6");
raw7 = (byte) sis.readUI8("byte7");
raw8 = (byte) sis.readUI8("byte8");
data[0] = Edge_Quad;
data[1] = ((firstByte & 0xff) >> 4) | ((raw1 & 0xff) << 4) | (SInt8((raw2 & 0xff) << 3) << 9);
data[2] = ((raw2 & 0xff) >> 5) | ((raw3 & 0xff) << 3) | (SInt8((raw4 & 0xff) << 2) << 9);
data[3] = ((raw4 & 0xff) >> 6) | ((raw5 & 0xff) << 2) | (SInt8((raw6 & 0xff) << 1) << 9);
data[4] = ((raw6 & 0xff) >> 7) | ((raw7 & 0xff) << 1) | (SInt8(raw8 & 0xff) << 9);
break;
case Edge_C19:
raw2 = (byte) sis.readUI8("byte2");
raw3 = (byte) sis.readUI8("byte3");
raw4 = (byte) sis.readUI8("byte4");
raw5 = (byte) sis.readUI8("byte5");
raw6 = (byte) sis.readUI8("byte6");
raw7 = (byte) sis.readUI8("byte7");
raw8 = (byte) sis.readUI8("byte8");
raw9 = (byte) sis.readUI8("byte9");
data[0] = Edge_Quad;
data[1] = ((firstByte & 0xff) >> 4) | ((raw1 & 0xff) << 4) | (SInt8(raw2 << 1) << 11);
data[2] = ((raw2 & 0xff) >> 7) | ((raw3 & 0xff) << 1) | ((raw4 & 0xff) << 9) | (SInt8(raw5 << 6) << 11);
data[3] = ((raw5 & 0xff) >> 2) | ((raw6 & 0xff) << 6) | (SInt8(raw7 << 3) << 11);
data[4] = ((raw7 & 0xff) >> 5) | ((raw8 & 0xff) << 3) | (SInt8(raw9) << 11);
break;
}
return data;
}
public void write(GFxOutputStream sos) throws IOException {
int x;
int y;
int m1 = 1;
int m2 = 3;
int m3 = 7;
int m4 = 0xF;
int m5 = 0x1F;
int m6 = 0x3F;
int m7 = 0x7F;
switch (data[0]) {
case Edge_HLine:
x = data[1];
if (x >= GFxOutputStream.MinSInt12 && x <= GFxOutputStream.MaxSInt12) {
sos.writeUI8((x << 4) | Edge_H12);
sos.writeUI8(x >> 4);
return;
}
sos.writeUI8((x << 4) | Edge_H20);
sos.writeUI8(x >> 4);
sos.writeUI8(x >> 12);
break;
case Edge_VLine:
y = data[1];
if (y >= GFxOutputStream.MinSInt12 && y <= GFxOutputStream.MaxSInt12) {
sos.writeUI8((y << 4) | Edge_V12);
sos.writeUI8(y >> 4);
return;
}
sos.writeUI8((y << 4) | Edge_V20);
sos.writeUI8(y >> 4);
sos.writeUI8(y >> 12);
return;
case Edge_Line:
x = data[1];
y = data[2];
if (x >= GFxOutputStream.MinSInt6 && x <= GFxOutputStream.MaxSInt6 && y >= GFxOutputStream.MinSInt6 && y <= GFxOutputStream.MaxSInt6) {
sos.writeUI8((x << 4) | Edge_L6);
sos.writeUI8(((x >> 4) & m2) | (y << 2));
return;
}
if (x >= GFxOutputStream.MinSInt10 && x <= GFxOutputStream.MaxSInt10 && y >= GFxOutputStream.MinSInt10 && y <= GFxOutputStream.MaxSInt10) {
sos.writeUI8((x << 4) | Edge_L10);
sos.writeUI8(((x >> 4) & m6) | (y << 6));
sos.writeUI8(y >> 2);
return;
}
if (x >= GFxOutputStream.MinSInt14 && x <= GFxOutputStream.MaxSInt14 && y >= GFxOutputStream.MinSInt14 && y <= GFxOutputStream.MaxSInt14) {
sos.writeUI8((x << 4) | Edge_L14);
sos.writeUI8(x >> 4);
sos.writeUI8(((x >> 12) & m2) | (y << 2));
sos.writeUI8(y >> 6);
return;
}
sos.writeUI8((x << 4) | Edge_L18);
sos.writeUI8(x >> 4);
sos.writeUI8(((x >> 12) & m6) | (y << 6));
sos.writeUI8(y >> 2);
sos.writeUI8(y >> 10);
return;
case Edge_Quad:
int cx = data[1];
int cy = data[2];
int ax = data[3];
int ay = data[4];
int minV = cx;
int maxV = cx;
if (cy < minV) {
minV = cy;
}
if (cy > maxV) {
maxV = cy;
}
if (ax < minV) {
minV = ax;
}
if (ax > maxV) {
maxV = ax;
}
if (ay < minV) {
minV = ay;
}
if (ay > maxV) {
maxV = ay;
}
if (minV >= GFxOutputStream.MinSInt5 && maxV <= GFxOutputStream.MaxSInt5) {
sos.writeUI8(((cx << 4) | Edge_C5));
sos.writeUI8((((cx >> 4) & m1) | ((cy << 1) & m6) | (ax << 6)));
sos.writeUI8((((ax >> 2) & m3) | (ay << 3)));
return;
}
if (minV >= GFxOutputStream.MinSInt7 && maxV <= GFxOutputStream.MaxSInt7) {
sos.writeUI8(((cx << 4) | Edge_C7));
sos.writeUI8((((cx >> 4) & m3) | (cy << 3)));
sos.writeUI8((((cy >> 5) & m2) | (ax << 2)));
sos.writeUI8((((ax >> 6) & m1) | (ay << 1)));
return;
}
if (minV >= GFxOutputStream.MinSInt9 && maxV <= GFxOutputStream.MaxSInt9) {
sos.writeUI8(((cx << 4) | Edge_C9));
sos.writeUI8((((cx >> 4) & m5) | (cy << 5)));
sos.writeUI8((((cy >> 3) & m6) | (ax << 6)));
sos.writeUI8((((ax >> 2) & m7) | (ay << 7)));
sos.writeUI8(((ay >> 1)));
return;
}
if (minV >= GFxOutputStream.MinSInt11 && maxV <= GFxOutputStream.MaxSInt11) {
sos.writeUI8(((cx << 4) | Edge_C11));
sos.writeUI8((((cx >> 4) & m7) | (cy << 7)));
sos.writeUI8(((cy >> 1)));
sos.writeUI8((((cy >> 9) & m2) | (ax << 2)));
sos.writeUI8((((ax >> 6) & m5) | (ay << 5)));
sos.writeUI8(((ay >> 3)));
return;
}
if (minV >= GFxOutputStream.MinSInt13 && maxV <= GFxOutputStream.MaxSInt13) {
sos.writeUI8(((cx << 4) | Edge_C13));
sos.writeUI8(((cx >> 4)));
sos.writeUI8((((cx >> 12) & m1) | (cy << 1)));
sos.writeUI8((((cy >> 7) & m6) | (ax << 6)));
sos.writeUI8(((ax >> 2)));
sos.writeUI8((((ax >> 10) & m3) | (ay << 3)));
sos.writeUI8(((ay >> 5)));
return;
}
if (minV >= GFxOutputStream.MinSInt15 && maxV <= GFxOutputStream.MaxSInt15) {
sos.writeUI8(((cx << 4) | Edge_C15));
sos.writeUI8(((cx >> 4)));
sos.writeUI8((((cx >> 12) & m3) | (cy << 3)));
sos.writeUI8(((cy >> 5)));
sos.writeUI8((((cy >> 13) & m2) | (ax << 2)));
sos.writeUI8(((ax >> 6)));
sos.writeUI8((((ax >> 14) & m1) | (ay << 1)));
sos.writeUI8(((ay >> 7)));
return;
}
if (minV >= GFxOutputStream.MinSInt17 && maxV <= GFxOutputStream.MaxSInt17) {
sos.writeUI8(((cx << 4) | Edge_C17));
sos.writeUI8(((cx >> 4)));
sos.writeUI8((((cx >> 12) & m5) | (cy << 5)));
sos.writeUI8(((cy >> 3)));
sos.writeUI8((((cy >> 11) & m6) | (ax << 6)));
sos.writeUI8(((ax >> 2)));
sos.writeUI8((((ax >> 10) & m7) | (ay << 7)));
sos.writeUI8(((ay >> 1)));
sos.writeUI8(((ay >> 9)));
return;
}
sos.writeUI8(((cx << 4) | Edge_C19));
sos.writeUI8(((cx >> 4)));
sos.writeUI8((((cx >> 12) & m7) | (cy << 7)));
sos.writeUI8(((cy >> 1)));
sos.writeUI8(((cy >> 9)));
sos.writeUI8((((cy >> 17) & m2) | (ax << 2)));
sos.writeUI8(((ax >> 6)));
sos.writeUI8((((ax >> 14) & m5) | (ay << 5)));
sos.writeUI8(((ay >> 3)));
sos.writeUI8(((ay >> 11)));
}
}
}