Separated FFDec core library and the rest (GUI).

FFDec Library is now LGPLv3, others stay GPLv3.
Version changed to 3.0.0 for FFDec, 1.0.0 for FFDec Library.
This commit is contained in:
Jindra Petřík
2014-08-24 17:55:42 +02:00
parent 2479c59b03
commit 04922aaf69
1323 changed files with 53605 additions and 52175 deletions
@@ -0,0 +1,49 @@
/*
* Copyright (C) 2010-2014 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.␍ */
package com.jpexs.helpers;
/**
*
* @author JPEXS
*/
public class ByteArrayRange {
public final byte[] array;
public final int pos;
public final int length;
public ByteArrayRange() {
this(new byte[0]);
}
public ByteArrayRange(byte[] array) {
this.array = array;
this.pos = 0;
this.length = array.length;
}
public ByteArrayRange(byte[] array, int pos, int length) {
this.array = array;
this.pos = pos;
this.length = length;
}
public byte[] getRangeData() {
byte[] data = new byte[length];
System.arraycopy(array, pos, data, 0, length);
return data;
}
}
@@ -0,0 +1,181 @@
/*
* Copyright (C) 2010-2014 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.␍ */
package com.jpexs.helpers;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author JPEXS
* @param <E>
*/
public class Cache<E> {
private final Map<Object, File> cacheFiles;
private final Map<Object, E> cacheMemory;
private static final List<Cache> instances = new ArrayList<>();
public static final int STORAGE_FILES = 1;
public static final int STORAGE_MEMORY = 2;
public static <E> Cache<E> getInstance(boolean weak) {
Cache<E> instance = new Cache<>(weak);
instances.add(instance);
return instance;
}
private static int storageType = STORAGE_FILES;
public static void clearAll() {
for (Cache c : instances) {
c.clear();
}
}
public static void setStorageType(int storageType) {
if (storageType == Cache.storageType) {
return;
}
switch (storageType) {
case STORAGE_FILES:
case STORAGE_MEMORY:
break;
default:
throw new IllegalArgumentException("storageType must be one of STORAGE_FILES or STORAGE_MEMORY");
}
if (storageType != Cache.storageType) {
clearAll();
}
Cache.storageType = storageType;
}
public static int getStorageType() {
return storageType;
}
private Cache(boolean weak) {
if (weak) {
cacheFiles = new WeakHashMap<>();
cacheMemory = new WeakHashMap<>();
} else {
cacheFiles = new HashMap<>();
cacheMemory = new HashMap<>();
}
}
public boolean contains(Object key) {
if (storageType == STORAGE_FILES) {
return cacheFiles.containsKey(key);
} else if (storageType == STORAGE_MEMORY) {
return cacheMemory.containsKey(key);
}
return false;
}
public void clear() {
cacheMemory.clear();
for (File f : cacheFiles.values()) {
f.delete();
}
cacheFiles.clear();
}
public void remove(Object key) {
if (storageType == STORAGE_FILES) {
if (cacheFiles.containsKey(key)) {
File f = cacheFiles.get(key);
f.delete();
cacheFiles.remove(key);
}
} else if (storageType == STORAGE_MEMORY) {
if (cacheMemory.containsKey(key)) {
cacheMemory.remove(key);
}
}
}
public E get(Object key) {
if (storageType == STORAGE_FILES) {
if (!cacheFiles.containsKey(key)) {
return null;
}
File f = cacheFiles.get(key);
try (FileInputStream fis = new FileInputStream(f)) {
ObjectInputStream ois = new ObjectInputStream(fis);
@SuppressWarnings("unchecked")
E item = (E) ois.readObject();
return item;
} catch (IOException | ClassNotFoundException ex) {
Logger.getLogger(Helper.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
} else if (storageType == STORAGE_MEMORY) {
if (cacheMemory.containsKey(key)) {
return cacheMemory.get(key);
}
return null;
}
return null;
}
public void put(Object key, E value) {
if (storageType == STORAGE_FILES) {
File temp = null;
try {
temp = File.createTempFile("ffdec_cache", ".tmp");
} catch (IOException ex) {
Logger.getLogger(Cache.class
.getName()).log(Level.SEVERE, null, ex);
return;
}
try {
temp.deleteOnExit();
} catch (IllegalStateException iex) {
return;
}
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(temp))) {
if (value instanceof Serializable) {
oos.writeObject(value);
} else {
// Object serialization not supported
return;
}
oos.flush();
cacheFiles.put(key, temp);
} catch (IOException ex) {
//ignore
}
} else if (storageType == STORAGE_MEMORY) {
cacheMemory.put(key, value);
}
}
}
@@ -0,0 +1,27 @@
/*
* Copyright (C) 2010-2014 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.␍ */
package com.jpexs.helpers;
/**
* Class with helper method
*
* @author JPEXS
* @param <T>
*/
public abstract class Callback<T> {
public abstract void call(T arg1);
}
@@ -0,0 +1,128 @@
/*
* Copyright (C) 2010-2014 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.␍ */
package com.jpexs.helpers;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.RunnableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
*
* @author JPEXS
* @param <T>
*/
public abstract class CancellableWorker<T> implements RunnableFuture<T> {
private static final ExecutorService THREAD_POOL = Executors.newCachedThreadPool();
private static List<CancellableWorker> workers = Collections.synchronizedList(new ArrayList<CancellableWorker>());
private final FutureTask<T> future;
public CancellableWorker() {
super();
Callable<T> callable
= new Callable<T>() {
@Override
public T call() throws Exception {
return doInBackground();
}
};
future = new FutureTask<T>(callable) {
@Override
protected void done() {
workerDone();
}
};
}
protected abstract T doInBackground() throws Exception;
@Override
public final void run() {
workers.add(this);
future.run();
}
protected void done() {
}
public final void execute() {
THREAD_POOL.execute(this);
}
@Override
public final boolean cancel(boolean mayInterruptIfRunning) {
return future.cancel(mayInterruptIfRunning);
}
@Override
public final boolean isCancelled() {
return future.isCancelled();
}
@Override
public final boolean isDone() {
return future.isDone();
}
@Override
public final T get() throws InterruptedException, ExecutionException {
return future.get();
}
@Override
public final T get(long timeout, TimeUnit unit) throws InterruptedException,
ExecutionException, TimeoutException {
return future.get(timeout, unit);
}
private void workerDone() {
workers.remove(this);
done();
}
public static <T> T call(final Callable<T> c, long timeout, TimeUnit timeUnit) throws InterruptedException, ExecutionException, TimeoutException {
CancellableWorker<T> worker = new CancellableWorker<T>() {
@Override
protected T doInBackground() throws Exception {
return c.call();
}
};
try {
worker.execute();
return worker.get(timeout, timeUnit);
} finally {
worker.cancel(true);
}
}
public static void cancelBackgroundThreads() {
List<CancellableWorker> oldWorkers = workers;
workers = new ArrayList<>();
for (CancellableWorker worker : oldWorkers) {
worker.cancel(true);
}
}
}
@@ -0,0 +1,884 @@
/*
* Copyright (C) 2010-2014 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.␍ */
package com.jpexs.helpers;
import com.jpexs.decompiler.flash.AppStrings;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.helpers.Freed;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
import com.jpexs.decompiler.flash.helpers.HilightedTextWriter;
import com.jpexs.decompiler.graph.TranslateStack;
import com.jpexs.decompiler.graph.model.LocalData;
import com.jpexs.helpers.utf8.Utf8Helper;
import java.awt.Component;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.Area;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collection;
import java.util.List;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Class with helper method
*
* @author JPEXS, Paolo Cancedda
*/
public class Helper {
public static String newLine = System.getProperty("line.separator");
/**
* Converts array of int values to string
*
* @param array Array of int values
* @return String representation of the array
*/
public static String intArrToString(int[] array) {
String s = "[";
for (int i = 0; i < array.length; i++) {
if (i > 0) {
s += ",";
}
s += array[i];
}
s += "]";
return s;
}
/**
* Converts array of byte values to string
*
* @param array Array of byte values
* @return String representation of the array
*/
public static String byteArrToString(byte[] array) {
String s = "[";
for (int i = 0; i < array.length; i++) {
if (i > 0) {
s += " ";
}
s += padZeros(Integer.toHexString(array[i] & 0xff), 2);
}
s += "]";
return s;
}
/**
* Adds zeros to beginning of the number to fill specified length. Returns
* as string
*
* @param number Number as string
* @param length Length of new string
* @return Number with added zeros
*/
public static String padZeros(String number, int length) {
int count = length - number.length();
for (int i = 0; i < count; i++) {
number = "0" + number;
}
return number;
}
/**
* Formats specified address to four numbers xxxx
*
* @param number Address to format
* @return String representation of the address
*/
public static String formatAddress(long number) {
if (Configuration.decimalAddress.get()) {
return padZeros(Long.toString(number), 4);
}
return padZeros(Long.toHexString(number), 4);
}
/**
* Adds space to text to fill specified width
*
* @param text Text to add spaces to
* @param width New width
* @return Text with appended spaces
*/
public static String padSpaceRight(String text, int width) {
int oldLen = text.length();
for (int i = oldLen; i < width; i++) {
text += " ";
}
return text;
}
/**
* Escapes string by adding backslashes
*
* @param s String to escape
* @return Escaped string
*/
public static String escapeString(String s) {
StringBuilder ret = new StringBuilder(s.length());
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == '\n') {
ret.append("\\n");
} else if (c == '\r') {
ret.append("\\r");
} else if (c == '\t') {
ret.append("\\t");
} else if (c == '\b') {
ret.append("\\b");
} else if (c == '\t') {
ret.append("\\t");
} else if (c == '\f') {
ret.append("\\f");
} else if (c == '\\') {
ret.append("\\\\");
} else if (c == '"') {
ret.append("\\\"");
} else if (c == '\'') {
ret.append("\\'");
} else {
ret.append(c);
}
}
return ret.toString();
}
public static String getValidHtmlId(String text) {
// ID and NAME tokens must begin with a letter ([A-Za-z]) and
// may be followed by any number of letters, digits ([0-9]),
// hyphens ("-"), underscores ("_"), colons (":"), and periods (".").
StringBuilder sb = new StringBuilder();
for (int i = 0; i < text.length(); i++) {
char ch = text.charAt(i);
if ((ch >= 'a' && ch <= 'z')
|| (ch >= 'A' && ch <= 'Z')
|| (i > 0 && ((ch >= '0' && ch <= '9')
|| ch == '-' || ch == '_' || ch == ':' || ch == '.'))) {
sb.append(ch);
} else {
sb.append('_');
}
}
return sb.toString();
}
private final static String SPACES12 = " ";
private final static String ZEROS8 = "00000000";
public static String formatHex(int value, int width) {
StringBuilder sb = new StringBuilder();
sb.append(Integer.toHexString(value));
if (width > sb.length()) {
sb.insert(0, ZEROS8, 0, width - sb.length());
}
return sb.toString();
}
public static String formatInt(int value, int width) {
StringBuilder sb = new StringBuilder();
sb.append(value);
if (width > sb.length()) {
sb.insert(0, SPACES12, 0, width - sb.length());
}
return sb.toString();
}
public static String indent(int level, String ss, String indentStr) {
StringBuilder sb = new StringBuilder();
for (int ii = 0; ii < level; ii++) {
sb.append(indentStr);
}
sb.append(ss);
return sb.toString();
}
public static String indentRows(int level, String ss, String indentStr) {
StringBuilder sb = new StringBuilder();
for (int ii = 0; ii < level; ii++) {
sb.append(indentStr);
}
ss = ss.replaceAll("(\r\n|\r|\n)", "\r\n");
ss = "\r\n" + ss;
String repl = "\r\n" + sb.toString();
ss = ss.replace("\r\n", repl);
if (ss.endsWith(repl)) {
ss = ss.substring(0, ss.length() - sb.toString().length());
}
ss = ss.substring(2);
return ss;
}
public static String unindentRows(int prefixLineCount, int level, String text) {
StringBuilder sb = new StringBuilder();
Scanner scanner = new Scanner(text);
String indentStr = "";
for (int i = 0; i < level; i++) {
indentStr += Configuration.getCodeFormatting().indentString;
}
int indentLength = indentStr.length();
for (int i = 0; i < prefixLineCount; i++) {
scanner.nextLine(); // ignore line
}
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
if (line.startsWith(indentStr)) {
sb.append(line.substring(indentLength)).append(Configuration.getCodeFormatting().newLineChars);
} else {
return sb.toString();
}
}
return sb.toString();
}
public static int getLineCount(String s) {
if (s.endsWith("\r\n")) {
s = s.substring(0, s.length() - 2);
} else if (s.endsWith("\r")) {
s = s.substring(0, s.length() - 1);
} else if (s.endsWith("\n")) {
s = s.substring(0, s.length() - 1);
}
String[] parts = s.split("(\r\n|\r|\n)");
return parts.length;
}
public static String padZeros(long number, int length) {
String ret = "" + number;
while (ret.length() < length) {
ret = "0" + ret;
}
return ret;
}
public static String bytesToHexString(byte[] bytes) {
return bytesToHexString(bytes, 0);
}
public static String bytesToHexString(byte[] bytes, int start) {
StringBuilder sb = new StringBuilder();
if (start < bytes.length) {
for (int ii = start; ii < bytes.length; ii++) {
sb.append(formatHex(bytes[ii] & 0xff, 2));
sb.append(' ');
}
sb.setLength(sb.length() - 1);
}
return sb.toString();
}
public static String bytesToHexString(int maxByteCountInString, byte[] bytes, int start) {
if (bytes.length - start <= maxByteCountInString) {
return bytesToHexString(bytes, start);
}
byte[] trailingBytes = new byte[maxByteCountInString / 2];
byte[] headingBytes = new byte[maxByteCountInString - trailingBytes.length];
System.arraycopy(bytes, start, headingBytes, 0, headingBytes.length);
int startOfTrailingBytes = bytes.length - trailingBytes.length;
System.arraycopy(bytes, startOfTrailingBytes, trailingBytes, 0, trailingBytes.length);
StringBuilder sb = new StringBuilder();
sb.append(bytesToHexString(headingBytes, 0));
if (trailingBytes.length > 0) {
sb.append(" ... ");
sb.append(bytesToHexString(trailingBytes, 0));
}
return sb.toString();
}
public static String format(String str, int len) {
if (len <= str.length()) {
return str;
}
StringBuilder sb = new StringBuilder(str);
for (int ii = str.length(); ii < len; ii++) {
sb.append(' ');
}
return sb.toString();
}
public static String joinStrings(List<String> arr, String glue) {
String ret = "";
boolean first = true;
for (String s : arr) {
if (!first) {
ret += glue;
} else {
first = false;
}
ret += s;
}
return ret;
}
public static String joinStrings(String[] arr, String glue) {
String ret = "";
boolean first = true;
for (String s : arr) {
if (!first) {
ret += glue;
} else {
first = false;
}
ret += s;
}
return ret;
}
public static String joinStrings(List<String> arr, String formatString, String glue) {
String ret = "";
boolean first = true;
for (String s : arr) {
if (!first) {
ret += glue;
} else {
first = false;
}
ret += String.format(formatString, s);
}
return ret;
}
public static String joinStrings(String[] arr, String formatString, String glue) {
String ret = "";
boolean first = true;
for (String s : arr) {
if (!first) {
ret += glue;
} else {
first = false;
}
ret += String.format(formatString, s);
}
return ret;
}
@SuppressWarnings("unchecked")
public static <E> E deepCopy(E o) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
oos.writeObject(o);
oos.flush();
}
E copy;
try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) {
copy = (E) ois.readObject();
}
return copy;
} catch (IOException | ClassNotFoundException ex) {
Logger.getLogger(Helper.class.getName()).log(Level.SEVERE, "Copy error", ex);
return null;
}
}
public static List<Object> toList(Object... rest) {
List<Object> ret = new ArrayList<>();
ret.addAll(Arrays.asList(rest));
return ret;
}
public static ByteArrayInputStream getInputStream(byte[]
... data) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
for (byte[] d : data) {
baos.write(d);
}
} catch (IOException iex) {
}
return new ByteArrayInputStream(baos.toByteArray());
}
public static byte[] readFile(String... file) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
for (String f : file) {
try (FileInputStream fis = new FileInputStream(f)) {
byte[] buf = new byte[4096];
int cnt = 0;
while ((cnt = fis.read(buf)) > 0) {
baos.write(buf, 0, cnt);
}
} catch (IOException ex) {
Logger.getLogger(Helper.class.getName()).log(Level.SEVERE, null, ex);
}
}
return baos.toByteArray();
}
public static String readTextFile(String... file) {
byte[] data = readFile(file);
if (data.length > 1 && data[0] == (byte) 0xef && data[1] == (byte) 0xbb && data[2] == (byte) 0xbf) {
// remove UTF-8 BOM
return new String(data, 3, data.length - 3, Utf8Helper.charset);
}
return new String(data, Utf8Helper.charset);
}
public static byte[] readStream(InputStream is) {
if (is instanceof MemoryInputStream) {
return ((MemoryInputStream) is).getAllRead();
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
copyStream(is, baos, Long.MAX_VALUE);
return baos.toByteArray();
}
public static void copyStream(InputStream is, OutputStream os, long maxLength) {
try {
final int bufSize = 4096;
byte[] buf = new byte[bufSize];
int cnt = 0;
while ((cnt = is.read(buf)) > 0) {
os.write(buf, 0, cnt);
maxLength -= cnt;
// last chunk is smaller
if (maxLength < bufSize) {
buf = new byte[(int) maxLength];
}
}
} catch (IOException ex) {
Logger.getLogger(Helper.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static void writeFile(String file, byte[]
... data) {
try (FileOutputStream fos = new FileOutputStream(file)) {
for (byte[] d : data) {
fos.write(d);
}
} catch (IOException ex) {
//ignore
}
}
public static String stackToString(TranslateStack stack, LocalData localData) throws InterruptedException {
String ret = "[";
for (int i = stack.size() - 1; i >= 0; i--) {
if (i < stack.size() - 1) {
ret += ", ";
}
ret += stack.get(i).toString(localData);
}
ret += "]";
return ret;
}
public static File fixDialogFile(File f) {
Pattern pat = Pattern.compile("\"([^\"]+)\"");
String name = f.getAbsolutePath();
Matcher m = pat.matcher(name);
if (m.find()) {
f = new File(m.group(1));
}
return f;
}
private static final BitSet fileNameInvalidChars;
private static final List<String> invalidFilenamesParts;
static {
BitSet toEncode = new BitSet(256);
for (int i = 0; i < 32; i++) {
toEncode.set(i);
}
toEncode.set('\\');
toEncode.set('/');
toEncode.set(':');
toEncode.set('*');
toEncode.set('?');
toEncode.set('"');
toEncode.set('<');
toEncode.set('>');
toEncode.set('|');
fileNameInvalidChars = toEncode;
//windows reserved filenames:
invalidFilenamesParts = new ArrayList<>();
invalidFilenamesParts.add("CON");
invalidFilenamesParts.add("PRN");
invalidFilenamesParts.add("AUX");
invalidFilenamesParts.add("CLOCK$");
invalidFilenamesParts.add("NUL");
for (int i = 1; i <= 9; i++) {
invalidFilenamesParts.add("COM" + i);
invalidFilenamesParts.add("LPT" + i);
}
}
public static String makeFileName(String str) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < str.length(); i++) {
int ch = (int) str.charAt(i);
if (ch < 256 && fileNameInvalidChars.get(ch)) {
sb.append("%").append(String.format("%02X", ch));
} else {
sb.append((char) ch);
}
}
str = sb.toString();
if (str.endsWith(" ")) {
str = str.substring(0, str.length() - 1) + "%20";
}
if (str.endsWith(".")) {
str = str.substring(0, str.length() - 1) + "%2E";
}
str = "." + str + ".";
for (String inv : invalidFilenamesParts) {
str = Pattern.compile("\\." + Pattern.quote(inv) + "\\.", Pattern.CASE_INSENSITIVE).matcher(str).replaceAll("._" + inv + ".");
}
str = str.substring(1, str.length() - 1); //remove dots
if (str.isEmpty()) {
str = "unnamed";
}
return str;
}
public static String strToHex(String s) {
byte[] bs = Utf8Helper.getBytes(s);
String sn = "";
for (int i = 0; i < bs.length; i++) {
sn += "0x" + Integer.toHexString(bs[i] & 0xff) + " ";
}
return sn;
}
public static void emptyObject(Object obj) {
Field[] fields = obj.getClass().getDeclaredFields();
for (Field f : fields) {
try {
f.setAccessible(true);
Object v = f.get(obj);
if (v != null) {
if (v instanceof Collection) {
((Collection) v).clear();
}
if (v instanceof Component) {
if (((Component) v).getParent() != null) {
((Component) v).getParent().remove((Component) v);
}
}
if (v instanceof Freed) {
Freed freed = ((Freed) v);
if (!freed.isFreeing()) {
((Freed) v).free();
}
}
f.set(obj, null);
}
} catch (UnsupportedOperationException | SecurityException | IllegalArgumentException | IllegalAccessException ex) {
}
}
}
public static String formatTimeSec(long timeMs) {
long timeS = timeMs / 1000;
timeMs %= 1000;
long timeM = timeS / 60;
timeS %= 60;
long timeH = timeM / 60;
timeM %= 60;
String timeStr = "";
if (timeH > 0) {
timeStr += Helper.padZeros(timeH, 2) + ":";
}
timeStr += Helper.padZeros(timeM, 2) + ":";
timeStr += Helper.padZeros(timeS, 2) + "." + Helper.padZeros(timeMs, 3);
return timeStr;
}
public static String formatFileSize(long fileSizeLong) {
double fileSize = fileSizeLong;
if (fileSize < 1024) {
return String.format("%d bytes", fileSizeLong);
}
fileSize /= 1024;
if (fileSize < 1024) {
return String.format("%.2f KB", fileSize);
}
fileSize /= 1024;
return String.format("%.2f MB", fileSize);
}
public static void freeMem() {
Cache.clearAll();
System.gc();
}
public static String formatTimeToText(int timeS) {
long timeM = timeS / 60;
timeS %= 60;
long timeH = timeM / 60;
timeM %= 60;
String timeStr = "";
String strAnd = AppStrings.translate("timeFormat.and");
String strHour = AppStrings.translate("timeFormat.hour");
String strHours = AppStrings.translate("timeFormat.hours");
String strMinute = AppStrings.translate("timeFormat.minute");
String strMinutes = AppStrings.translate("timeFormat.minutes");
String strSecond = AppStrings.translate("timeFormat.second");
String strSeconds = AppStrings.translate("timeFormat.seconds");
if (timeH > 0) {
timeStr += timeH + " " + (timeH > 1 ? strHours : strHour);
}
if (timeM > 0) {
if (timeStr.length() > 0) {
timeStr += " " + strAnd + " ";
}
timeStr += timeM + " " + (timeM > 1 ? strMinutes : strMinute);
}
if (timeS > 0) {
if (timeStr.length() > 0) {
timeStr += " " + strAnd + " ";
}
timeStr += timeS + " " + (timeS > 1 ? strSeconds : strSecond);
}
// (currently) used only in log, so no localization is required
return timeStr;
}
public static GraphTextWriter byteArrayToHexWithHeader(GraphTextWriter writer, byte[] data) {
writer.appendNoHilight("#hexdata").newLine().newLine();
return byteArrayToHex(writer, data, 8, 8, -1, false, false);
}
public static GraphTextWriter byteArrayToHex(GraphTextWriter writer, byte[] data, int bytesPerRow, int groupSize, int limit, boolean addChars, boolean showAddress) {
/* // hex data from decompiled actions
Scanner scanner = new Scanner(srcWithHex);
while (scanner.hasNextLine()) {
String line = scanner.nextLine().trim();
if (line.startsWith(";")) {
result.append(line.substring(1).trim()).append(nl);
} else {
result.append(";").append(line).append(nl);
}
}*/
int length = data.length;
if (limit != -1 && length > limit) {
length = limit;
}
int rowCount = length / bytesPerRow;
if (length % bytesPerRow > 0) {
rowCount++;
}
long address = 0;
for (int row = 0; row < rowCount; row++) {
if (row > 0) {
writer.newLine();
}
if (showAddress) {
writer.appendNoHilight("0x" + String.format("%08x ", address));
}
for (int i = 0; i < bytesPerRow; i++) {
int idx = row * bytesPerRow + i;
if (length > idx) {
if (i > 0 && i % groupSize == 0) {
writer.appendNoHilight(" ");
}
writer.appendNoHilight(String.format("%02x ", data[idx]));
} else {
if (addChars) {
if (i > 0 && i % groupSize == 0) {
writer.appendNoHilight(" ");
}
writer.appendNoHilight(" ");
}
}
address += bytesPerRow;
}
if (addChars) {
writer.appendNoHilight(" ");
for (int i = 0; i < bytesPerRow; i++) {
int idx = row * bytesPerRow + i;
if (length == idx) {
break;
}
if (i > 0 && i % groupSize == 0) {
writer.appendNoHilight(" ");
}
byte ch = data[idx];
if (ch >= 0 && ch < 32) {
ch = '.';
}
writer.appendNoHilight((char) ch + "");
}
}
}
writer.newLine();
if (limit != -1 && data.length > limit) {
writer.appendNoHilight(AppStrings.translate("binaryData.truncateWarning").replace("%count%", Integer.toString(data.length - limit)));
}
return writer;
}
public static String byteArrayToHex(byte[] data, int bytesPerRow, int limit) {
HilightedTextWriter writer = new HilightedTextWriter(Configuration.getCodeFormatting(), false);
byteArrayToHex(writer, data, bytesPerRow, 8, limit, true, true);
return writer.toString();
}
public static byte[] getBytesFromHexaText(String text) {
Scanner scanner = new Scanner(text);
scanner.nextLine(); // ignore first line
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while (scanner.hasNextLine()) {
String line = scanner.nextLine().trim();
if (line.startsWith(";")) {
continue;
}
line = line.replace(" ", "");
for (int i = 0; i < line.length() / 2; i++) {
String hexStr = line.substring(i * 2, (i + 1) * 2);
byte b = (byte) Integer.parseInt(hexStr, 16);
baos.write(b);
}
}
byte[] data = baos.toByteArray();
return data;
}
public static boolean contains(int[] array, int value) {
for (int i : array) {
if (i == value) {
return true;
}
}
return false;
}
public static void saveStream(InputStream is, File output) throws IOException {
byte[] buf = new byte[1024];
int cnt;
try (FileOutputStream fos = new FileOutputStream(output)) {
while ((cnt = is.read(buf)) > 0) {
fos.write(buf, 0, cnt);
fos.flush();
}
}
}
public static void appendTimeoutComment(GraphTextWriter writer, int timeout) {
writer.appendNoHilight("/*").newLine();
writer.appendNoHilight(" * ").appendNoHilight(AppStrings.translate("decompilationError")).newLine();
writer.appendNoHilight(" * ").appendNoHilight(MessageFormat.format(AppStrings.translate("decompilationError.timeout"), Helper.formatTimeToText(timeout))).newLine();
writer.appendNoHilight(" */").newLine();
writer.appendNoHilight("throw new flash.errors.IllegalOperationError(\"").
appendNoHilight(AppStrings.translate("decompilationError.timeout.description")).
appendNoHilight("\");").newLine();
}
public static void appendErrorComment(GraphTextWriter writer, Throwable ex) {
writer.appendNoHilight("/*").newLine();
writer.appendNoHilight(" * ").appendNoHilight(AppStrings.translate("decompilationError")).newLine();
writer.appendNoHilight(" * ").appendNoHilight(AppStrings.translate("decompilationError.obfuscated")).newLine();
writer.appendNoHilight(" * ").appendNoHilight(AppStrings.translate("decompilationError.errorType")).
appendNoHilight(": " + ex.getClass().getSimpleName()).newLine();
writer.appendNoHilight(" */").newLine();
writer.appendNoHilight("throw new flash.errors.IllegalOperationError(\"").
appendNoHilight(AppStrings.translate("decompilationError.error.description")).
appendNoHilight("\");").newLine();
}
public static String escapeHTML(String text) {
String from[] = new String[]{"&", "<", ">", "\"", "'", "/"};
String to[] = new String[]{"&amp;", "&lt;", "&gt;", "&quot;", "&#x27;", "&#x2F;"};
for (int i = 0; i < from.length; i++) {
text = text.replace(from[i], to[i]);
}
return text;
}
public static Shape imageToShape(BufferedImage image) {
Area area = new Area();
Rectangle rectangle = new Rectangle();
int y1, y2;
for (int x = 0; x < image.getWidth(); x++) {
y1 = Integer.MAX_VALUE;
y2 = -1;
for (int y = 0; y < image.getHeight(); y++) {
int rgb = image.getRGB(x, y);
rgb = rgb >>> 24;
if (rgb > 0) {
if (y1 == Integer.MAX_VALUE) {
y1 = y;
y2 = y;
}
if (y > (y2 + 1)) {
rectangle.setBounds(x, y1, 1, y2 - y1 + 1);
area.add(new Area(rectangle));
y1 = y;
}
y2 = y;
}
}
if ((y2 - y1) >= 0) {
rectangle.setBounds(x, y1, 1, y2 - y1 + 1);
area.add(new Area(rectangle));
}
}
return area;
}
/**
* Formats double value (removes .0 from end)
*
* @param d
* @return String
*/
public static String doubleStr(double d) {
String ret = "" + d;
if (ret.endsWith(".0")) {
ret = ret.substring(0, ret.length() - 2);
}
return ret;
}
}
@@ -0,0 +1,60 @@
/*
* Copyright (C) 2010-2014 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.␍ */
package com.jpexs.helpers;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
*
* @author JPEXS
* @param <V>
*/
public class ImmediateFuture<V> implements Future<V> {
private final V value;
public ImmediateFuture(V value) {
this.value = value;
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
return false;
}
@Override
public boolean isCancelled() {
return false;
}
@Override
public boolean isDone() {
return true;
}
@Override
public V get() throws InterruptedException, ExecutionException {
return value;
}
@Override
public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
return value;
}
}
@@ -0,0 +1,53 @@
/*
* Copyright (C) 2010-2014 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.␍ */
package com.jpexs.helpers;
import java.io.IOException;
import java.io.InputStream;
/**
*
* @author JPEXS
*/
public class LimitedInputStream extends InputStream {
private final InputStream is;
private long pos = 0;
private final long limit;
public LimitedInputStream(InputStream is, long limit) {
this.is = is;
this.limit = limit;
}
@Override
public int read() throws IOException {
if (pos >= limit) {
return -1;
}
pos++;
return is.read();
}
@Override
public int available() throws IOException {
int avail = is.available();
if (pos + avail > limit) {
avail = (int) (limit - pos);
}
return avail;
}
}
@@ -0,0 +1,100 @@
/*
* Copyright (C) 2010-2014 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.␍ */
package com.jpexs.helpers;
import com.jpexs.helpers.streams.SeekableInputStream;
import java.io.IOException;
/**
*
* @author JPEXS
*/
public class MemoryInputStream extends SeekableInputStream {
private final byte[] buffer;
private long pos;
private int startPos;
private int maxLength;
public MemoryInputStream(byte[] buffer) throws IOException {
this(buffer, 0, buffer.length);
}
public MemoryInputStream(byte[] buffer, int startPos) throws IOException {
this(buffer, startPos, buffer.length - startPos);
}
public MemoryInputStream(byte[] buffer, int startPos, int maxLength) throws IOException {
this.buffer = buffer;
this.startPos = startPos;
if (startPos >= buffer.length) {
throw new IOException("Invalid startPos");
}
this.maxLength = maxLength;
if (startPos + maxLength >= buffer.length) {
this.maxLength = buffer.length - startPos;
}
}
public byte[] getAllRead() {
return buffer;
}
public long getPos() {
return pos;
}
@Override
public void seek(long pos) throws IOException {
if (pos < 0) {
throw new IOException("Seek to negative position");
}
this.pos = pos;
}
@Override
public synchronized void reset() throws IOException {
seek(0);
}
@Override
public int read() throws IOException {
if (pos < maxLength) {
int ret = buffer[(int) pos + startPos] & 0xff;
pos++;
return ret;
}
return -1;
}
@Override
public int read(byte[] bytes) throws IOException {
if (pos < maxLength) {
int toRead = Math.min(available(), bytes.length);
System.arraycopy(buffer, (int) pos + startPos, bytes, 0, toRead);
pos += toRead;
return toRead;
}
return -1;
}
@Override
public int available() throws IOException {
return maxLength - (int) pos;
}
}
@@ -0,0 +1,30 @@
/*
* Copyright (C) 2010-2014 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.␍ */
package com.jpexs.helpers;
import java.io.OutputStream;
/**
*
* @author JPEXS
*/
public class NulStream extends OutputStream {
@Override
public void write(int i) {
}
}
@@ -0,0 +1,72 @@
/*
* Copyright (C) 2010-2014 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.␍ */
package com.jpexs.helpers;
import java.io.File;
/**
*
* @author JPEXS
*/
public class Path {
public static String combine(String... paths) {
String result = "";
String separator = File.separator;
for (String path : paths) {
if (path.startsWith(separator)) {
result = result.substring(separator.length());
}
if (!result.endsWith(separator)) {
result += separator;
}
result += path;
}
return result;
}
/*
* Get the extension of a file.
*/
public static String getExtension(String fileName) {
return getExtension(new File(fileName));
}
/*
* Get the extension of a file.
*/
public static String getExtension(File f) {
String ext = null;
String s = f.getName();
int i = s.lastIndexOf('.');
if (i > 0 && i < s.length() - 1) {
ext = s.substring(i).toLowerCase();
}
return ext;
}
public static String getFileNameWithoutExtension(File f) {
String ext = null;
String s = f.getName();
int i = s.lastIndexOf('.');
if (i > 0 && i < s.length() - 1) {
ext = s.substring(0, i).toLowerCase();
}
return ext;
}
}
@@ -0,0 +1,51 @@
/*
* Copyright (C) 2010-2014 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.␍ */
package com.jpexs.helpers;
import java.io.IOException;
import java.io.InputStream;
/**
*
* @author JPEXS
*/
public class PosMarkedInputStream extends InputStream {
private long pos = 0;
private final InputStream is;
public PosMarkedInputStream(InputStream is) {
this.is = is;
}
@Override
public int read() throws IOException {
incPos();
return is.read();
}
public long getPos() {
return pos;
}
public void setPos(long pos) throws IOException {
this.pos = pos;
}
public void incPos() {
this.pos++;
}
}
@@ -0,0 +1,25 @@
/*
* Copyright (C) 2010-2014 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.␍ */
package com.jpexs.helpers;
/**
*
* @author JPEXS
*/
public interface ProgressListener {
public void progress(int p);
}
@@ -0,0 +1,94 @@
/*
* Copyright (C) 2010-2014 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.␍ */
package com.jpexs.helpers;
import com.jpexs.helpers.streams.SeekableInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
/**
*
* @author JPEXS
*/
public class ReReadableInputStream extends SeekableInputStream {
InputStream is;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] converted;
long pos = 0;
int count = 0;
public int getCount() {
return count;
}
public byte[] getAllRead() {
return baos.toByteArray();
}
public long getPos() {
return pos;
}
public ReReadableInputStream(InputStream is) {
this.is = is;
}
@Override
public void seek(long pos) throws IOException {
if (pos > count) {
this.pos = count;
skip(pos - count);
}
this.pos = pos;
}
@Override
public synchronized void reset() throws IOException {
seek(0);
}
@Override
public int read() throws IOException {
if (pos < count) {
if (converted == null) {
converted = baos.toByteArray();
}
int ret = converted[(int) pos] & 0xff;
pos++;
return ret;
}
int i = is.read();
if (i > -1) {
baos.write(i);
count++;
}
pos++;
converted = null;
return i;
}
@Override
public int available() throws IOException {
return (count + is.available()) - (int) pos;
}
public long length() throws IOException {
return count + is.available();
}
}
@@ -0,0 +1,46 @@
/*
* Copyright (C) 2014 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.␍ */
package com.jpexs.helpers;
import java.io.InputStream;
import java.util.Map;
/**
*
* @author JPEXS
*/
public interface Searchable {
/**
* Searches for byte sequences
*
* @param data
* @return Map Position=>Input stream
*/
public Map<Long, InputStream> search(byte[]
... data);
/**
* Searches for byte sequences with progress listener
* @param progListener Listener
* @param data
* @return Map Position=>Input stream
*/
public Map<Long, InputStream> search(ProgressListener progListener, byte[]
... data);
}
@@ -0,0 +1,155 @@
/*
* Copyright (C) 2010-2014 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.␍ */
package com.jpexs.helpers;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.IndexColorModel;
import java.awt.image.WritableRaster;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Hashtable;
import javax.imageio.ImageIO;
/**
*
* @author JPEXS
*/
public class SerializableImage implements Serializable {
public static int TYPE_INT_ARGB = BufferedImage.TYPE_INT_ARGB;
public static int TYPE_INT_RGB = BufferedImage.TYPE_INT_RGB;
public static int TYPE_INT_ARGB_PRE = BufferedImage.TYPE_INT_ARGB_PRE;
public static int TYPE_4BYTE_ABGR = BufferedImage.TYPE_4BYTE_ABGR;
static int imageid = 0;
private BufferedImage image;
private transient Graphics graphics;
private SerializableImage() {
}
public SerializableImage(BufferedImage image) {
this.image = image;
}
public SerializableImage(int i, int i1, int i2) {
image = new BufferedImage(i, i1, i2);
}
public SerializableImage(ColorModel cm, WritableRaster wr, boolean bln, Hashtable<?, ?> hshtbl) {
image = new BufferedImage(cm, wr, bln, hshtbl);
}
public SerializableImage(int i, int i1, int i2, IndexColorModel icm) {
image = new BufferedImage(i, i1, i2, icm);
}
public BufferedImage getBufferedImage() {
/*try {
javax.imageio.ImageIO.write(image, "png", new File("c:\\10\\x\\imageid" + String.format("%03d", imageid++) + ".png"));
} catch (IOException ex) {
}*/
return image;
}
public void fillTransparent() {
// Make all pixels transparent
Graphics2D g = (Graphics2D) getGraphics();
g.setComposite(AlphaComposite.Src);
g.setColor(new Color(0, 0, 0, 0f));
g.fillRect(0, 0, getWidth(), getHeight());
}
@Override
protected Object clone() throws CloneNotSupportedException {
SerializableImage retImage = new SerializableImage();
retImage.image = image;
return retImage;
}
public Graphics getGraphics() {
//One graphics rule them all
if (graphics != null) {
return graphics;
}
Graphics2D g = (Graphics2D) image.getGraphics();
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
return graphics = g;
}
public int getType() {
return image.getType();
}
public int getWidth() {
return image.getWidth();
}
public int getHeight() {
return image.getHeight();
}
public int getRGB(int i, int i1) {
return image.getRGB(i, i1);
}
public int[] getRGB(int i, int i1, int i2, int i3, int[] ints, int i4, int i5) {
return image.getRGB(i, i1, i2, i3, ints, i4, i5);
}
public synchronized void setRGB(int i, int i1, int i2) {
image.setRGB(i, i1, i2);
}
public void setRGB(int i, int i1, int i2, int i3, int[] ints, int i4, int i5) {
image.setRGB(i, i1, i2, i3, ints, i4, i5);
}
public ColorModel getColorModel() {
return image.getColorModel();
}
public WritableRaster getRaster() {
return image.getRaster();
}
@Override
public String toString() {
return image.toString();
}
private void writeObject(ObjectOutputStream out) throws IOException {
try {
ImageIO.write(image, "png", out);
} catch (Exception ex) {
//ignore
}
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
image = ImageIO.read(in);
}
}
@@ -0,0 +1,103 @@
/*
* Copyright (C) 2010-2014 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.␍ */
package com.jpexs.helpers;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.Line;
import javax.sound.sampled.LineEvent;
import javax.sound.sampled.LineListener;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
/**
*
* @author JPEXS
*/
public class SoundPlayer {
private final Clip clip;
public SoundPlayer(InputStream is) throws LineUnavailableException, IOException, UnsupportedAudioFileException {
clip = (Clip) AudioSystem.getLine(new Line.Info(Clip.class));
clip.open(AudioSystem.getAudioInputStream(new BufferedInputStream(is)));
}
public long samplesCount() {
return clip.getMicrosecondLength();
}
public void play() {
final SoundPlayer t = this;
clip.addLineListener(new LineListener() {
@Override
public void update(LineEvent event) {
if (event.getType() == LineEvent.Type.STOP) {
//clip.close();
synchronized (t) {
t.notifyAll();
}
}
}
});
clip.start();
try {
synchronized (this) {
wait();
}
} catch (InterruptedException ex) {
//Ignore
}
}
public long getSamplePosition() {
return clip.getMicrosecondPosition();
}
public void setPosition(long frames) {
clip.setMicrosecondPosition(frames);
}
public void stop() {
clip.stop();
}
public boolean isPlaying() {
return clip.isActive();
}
public long getFrameRate() {
return 1000000L;
}
@Override
protected void finalize() throws Throwable {
try {
if (clip != null) {
clip.close();
}
} finally {
super.finalize();
}
}
}
@@ -0,0 +1,58 @@
/*
* Copyright (C) 2010-2014 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.␍ */
package com.jpexs.helpers;
import java.util.Date;
/**
*
* @author JPEXS
*/
public class Stopwatch {
private long startTime, elapsedTime;
private boolean running;
public Date startDate, endDate;
public static Stopwatch startNew() {
Stopwatch sw = new Stopwatch();
sw.start();
return sw;
}
public void start() {
running = true;
startDate = new Date();
startTime = System.nanoTime();
}
public void stop() {
elapsedTime = System.nanoTime() - startTime;
endDate = new Date();
running = false;
}
public long getElapsedNanoseconds() {
if (running) {
return System.nanoTime() - startTime;
}
return elapsedTime;
}
public long getElapsedMilliseconds() {
return getElapsedNanoseconds() / 1000000;
}
}
@@ -0,0 +1,103 @@
/*
* Copyright (C) 2014 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.␍ */
package com.jpexs.helpers;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author JPEXS
*/
public class StreamSearch implements Searchable {
private final MemoryInputStream is;
public StreamSearch(InputStream is) throws IOException {
this.is = new MemoryInputStream(Helper.readStream(is));
}
@Override
public Map<Long, InputStream> search(byte[]
... data) {
return search(null, data);
}
@Override
public Map<Long, InputStream> search(ProgressListener progListener, byte[]
... data) {
Map<Long, InputStream> ret = new HashMap<>();
int maxFindLen = 0;
for (int i = 0; i < data.length; i++) {
if (data[i].length > maxFindLen) {
maxFindLen = data[i].length;
}
}
try {
is.seek(0);
byte[] buf = new byte[4096];
byte[] last = null;
int cnt = 0;
long pos = 0;
while ((cnt = is.read(buf)) > 0) {
for (int i = -maxFindLen + 1; i < cnt; i++) {
loopdata:
for (byte[] onedata : data) {
boolean match = true;
for (int d = 0; d < onedata.length; d++) {
byte b;
if (i + d < 0) {
if (last != null) {
b = last[last.length + i + d];
} else {
continue;
}
} else if (i + d >= buf.length) {
continue;
} else {
b = buf[i + d];
}
if (b != onedata[d]) {
match = false;
break;
}
}
if (match) {
// todo: support > 2GB files
InputStream fis = new MemoryInputStream(is.getAllRead(), (int) pos + i);
ret.put(pos + i, fis);
continue loopdata;
}
}
}
pos = pos + cnt;
}
} catch (IOException ex) {
Logger.getLogger(StreamSearch.class.getName()).log(Level.SEVERE, null, ex);
}
return ret;
}
}
@@ -0,0 +1,80 @@
/*
* Copyright (C) 2014 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.␍ */
package com.jpexs.helpers;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author JPEXS
*/
public class SwfHeaderStreamSearch implements Searchable {
private final MemoryInputStream is;
public SwfHeaderStreamSearch(InputStream is) throws IOException {
this.is = new MemoryInputStream(Helper.readStream(is));
}
@Override
public Map<Long, InputStream> search(byte[]
... data) {
return search(null, data);
}
@Override
public Map<Long, InputStream> search(ProgressListener progListener, byte[]
... data) {
// Ignore data parameter, find only FWS, CWS, ZWS, GFX and CFX
Map<Long, InputStream> ret = new HashMap<>();
byte[] buf = is.getAllRead();
byte byte2 = buf[0], byte3 = buf[1];
boolean match = false;
for (int i = 2; i < buf.length - 2; i++) {
byte b = byte2;
byte2 = byte3;
byte3 = buf[i];
if (byte2 == 'W' && byte3 == 'S') {
if (b == 'F' || b == 'C' || b == 'Z') {
match = true;
}
} else if (byte2 == 'F' && byte3 == 'X') {
if (b == 'G' || b == 'C') {
match = true;
}
}
if (match) {
// todo: support > 2GB files
InputStream fis;
try {
fis = new MemoryInputStream(buf, i - 2);
ret.put((long) i - 2, fis);
match = false;
} catch (IOException ex) {
Logger.getLogger(SwfHeaderStreamSearch.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
return ret;
}
}
@@ -0,0 +1,58 @@
/*
* Copyright (C) 2010-2014 JPEXS, Miron Sadziak, 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.helpers.plugin;
import java.net.URI;
import javax.tools.JavaFileObject.Kind;
import javax.tools.SimpleJavaFileObject;
/**
*
* @author JPEXS
*/
public class CharSequenceJavaFileObject extends SimpleJavaFileObject {
/**
* CharSequence representing the source code to be compiled
*/
private final CharSequence content;
/**
* This constructor will store the source code in the internal "content"
* variable and register it as a source code, using a URI containing the
* class full name
*
* @param className name of the public class in the source code
* @param content source code to compile
*/
public CharSequenceJavaFileObject(String className, CharSequence content) {
super(URI.create("string:///" + className.replace('.', '/')
+ Kind.SOURCE.extension), Kind.SOURCE);
this.content = content;
}
/**
* Answers the CharSequence to be compiled. It will give the source code
* stored in variable "content"
*
* @param ignoreEncodingErrors
* @return
*/
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
return content;
}
}
@@ -0,0 +1,89 @@
/*
* Copyright (C) 2010-2014 JPEXS, Miron Sadziak, 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.helpers.plugin;
import java.io.IOException;
import java.security.SecureClassLoader;
import javax.tools.FileObject;
import javax.tools.ForwardingJavaFileManager;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.JavaFileObject.Kind;
import javax.tools.StandardJavaFileManager;
/**
*
* @author JPEXS
*/
public class ClassFileManager extends
ForwardingJavaFileManager<JavaFileManager> {
/**
* Instance of JavaClassObject that will store the compiled bytecode of our
* class
*/
private JavaClassObject jclassObject;
/**
* Will initialize the manager with the specified standard java file manager
*
* @param standardManager
*/
public ClassFileManager(StandardJavaFileManager standardManager) {
super(standardManager);
}
/**
* Will be used by us to get the class loader for our compiled class. It
* creates an anonymous class extending the SecureClassLoader which uses the
* byte code created by the compiler and stored in the JavaClassObject, and
* returns the Class for it
*
* @param location
* @return
*/
@Override
public ClassLoader getClassLoader(Location location) {
return new SecureClassLoader() {
@Override
protected Class<?> findClass(String name)
throws ClassNotFoundException {
byte[] b = jclassObject.getBytes();
return super.defineClass(name, jclassObject
.getBytes(), 0, b.length);
}
};
}
/**
* Gives the compiler an instance of the JavaClassObject so that the
* compiler can write the byte code into it.
*
* @param location
* @param className
* @param kind
* @param sibling
* @return
* @throws java.io.IOException
*/
@Override
public JavaFileObject getJavaFileForOutput(Location location,
String className, Kind kind, FileObject sibling)
throws IOException {
jclassObject = new JavaClassObject(className, kind);
return jclassObject;
}
}
@@ -0,0 +1,72 @@
/*
* Copyright (C) 2010-2014 JPEXS, Miron Sadziak, 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.helpers.plugin;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import javax.tools.JavaFileObject.Kind;
import javax.tools.SimpleJavaFileObject;
/**
*
* @author JPEXS
*/
public class JavaClassObject extends SimpleJavaFileObject {
/**
* Byte code created by the compiler will be stored in this
* ByteArrayOutputStream so that we can later get the byte array out of it
* and put it in the memory as an instance of our class.
*/
protected final ByteArrayOutputStream bos = new ByteArrayOutputStream();
/**
* Registers the compiled class object under URI containing the class full
* name
*
* @param name Full name of the compiled class
* @param kind Kind of the data. It will be CLASS in our case
*/
public JavaClassObject(String name, Kind kind) {
super(URI.create("string:///" + name.replace('.', '/')
+ kind.extension), kind);
}
/**
* Will be used by our file manager to get the byte code that can be put
* into memory to instantiate our class
*
* @return compiled byte code
*/
public byte[] getBytes() {
return bos.toByteArray();
}
/**
* Will provide the compiler with an output stream that leads to our byte
* array. This way the compiler will write everything into the byte array
* that we will instantiate later
*
* @return
* @throws java.io.IOException
*/
@Override
public OutputStream openOutputStream() throws IOException {
return bos;
}
}
@@ -0,0 +1,997 @@
/**
* JPEXS Free Flash Decompiler Filters
*/
Filters = {};
var createCanvas = function(width, height) {
var c = document.createElement("canvas");
c.width = width;
c.height = height;
c.style.display = "none";
//temporary add to document to get this work (getImageData, etc.)
document.body.appendChild(c);
document.body.removeChild(c);
return c;
};
Filters._premultiply = function(data) {
var len = data.length;
for (var i = 0; i < len; i += 4) {
var f = data[i + 3] * 0.003921569;
data[i] = Math.round(data[i] * f);
data[i + 1] = Math.round(data[i + 1] * f);
data[i + 2] = Math.round(data[i + 2] * f);
}
};
Filters._unpremultiply = function(data) {
var len = data.length;
for (var i = 0; i < len; i += 4) {
var a = data[i + 3];
if (a == 0 || a == 255) {
continue;
}
var f = 255 / a;
var r = (data[i] * f);
var g = (data[i + 1] * f);
var b = (data[i + 2] * f);
if (r > 255) {
r = 255;
}
if (g > 255) {
g = 255;
}
if (b > 255) {
b = 255;
}
data[i] = r;
data[i + 1] = g;
data[i + 2] = b;
}
};
Filters._boxBlurHorizontal = function(pixels, mask, w, h, radius) {
var index = 0;
var newColors = [];
for (var y = 0; y < h; y++) {
var hits = 0;
var r = 0;
var g = 0;
var b = 0;
var a = 0;
for (var x = -radius * 4; x < w * 4; x += 4) {
var oldPixel = x - radius * 4 - 4;
if (oldPixel >= 0) {
if ((mask == null) || (mask[index + oldPixel + 3] > 0)) {
a -= pixels[index + oldPixel + 3];
r -= pixels[index + oldPixel];
g -= pixels[index + oldPixel + 1];
b -= pixels[index + oldPixel + 2];
hits--;
}
}
var newPixel = x + radius * 4;
if (newPixel < w * 4) {
if ((mask == null) || (mask[index + newPixel + 3] > 0)) {
a += pixels[index + newPixel + 3];
r += pixels[index + newPixel];
g += pixels[index + newPixel + 1];
b += pixels[index + newPixel + 2];
hits++;
}
}
if (x >= 0) {
if ((mask == null) || (mask[index + x + 3] > 0)) {
if (hits == 0) {
newColors[x] = 0;
newColors[x + 1] = 0;
newColors[x + 2] = 0;
newColors[x + 3] = 0;
} else {
newColors[x] = Math.round(r / hits);
newColors[x + 1] = Math.round(g / hits);
newColors[x + 2] = Math.round(b / hits);
newColors[x + 3] = Math.round(a / hits);
}
} else {
newColors[x] = 0;
newColors[x + 1] = 0;
newColors[x + 2] = 0;
newColors[x + 3] = 0;
}
}
}
for (var p = 0; p < w * 4; p += 4) {
pixels[index + p] = newColors[p];
pixels[index + p + 1] = newColors[p + 1];
pixels[index + p + 2] = newColors[p + 2];
pixels[index + p + 3] = newColors[p + 3];
}
index += w * 4;
}
};
Filters._boxBlurVertical = function(pixels, mask, w, h, radius) {
var newColors = [];
var oldPixelOffset = -(radius + 1) * w * 4;
var newPixelOffset = (radius) * w * 4;
for (var x = 0; x < w * 4; x += 4) {
var hits = 0;
var r = 0;
var g = 0;
var b = 0;
var a = 0;
var index = -radius * w * 4 + x;
for (var y = -radius; y < h; y++) {
var oldPixel = y - radius - 1;
if (oldPixel >= 0) {
if ((mask == null) || (mask[index + oldPixelOffset + 3] > 0)) {
a -= pixels[index + oldPixelOffset + 3];
r -= pixels[index + oldPixelOffset];
g -= pixels[index + oldPixelOffset + 1];
b -= pixels[index + oldPixelOffset + 2];
hits--;
}
}
var newPixel = y + radius;
if (newPixel < h) {
if ((mask == null) || (mask[index + newPixelOffset + 3] > 0)) {
a += pixels[index + newPixelOffset + 3];
r += pixels[index + newPixelOffset];
g += pixels[index + newPixelOffset + 1];
b += pixels[index + newPixelOffset + 2];
hits++;
}
}
if (y >= 0) {
if ((mask == null) || (mask[y * w * 4 + x + 3] > 0)) {
if (hits == 0) {
newColors[4 * y] = 0;
newColors[4 * y + 1] = 0;
newColors[4 * y + 2] = 0;
newColors[4 * y + 3] = 0;
} else {
newColors[4 * y] = Math.round(r / hits);
newColors[4 * y + 1] = Math.round(g / hits);
newColors[4 * y + 2] = Math.round(b / hits);
newColors[4 * y + 3] = Math.round(a / hits);
}
} else {
newColors[4 * y] = 0;
newColors[4 * y + 1] = 0;
newColors[4 * y + 2] = 0;
newColors[4 * y + 3] = 0;
}
}
index += w * 4;
}
for (var y = 0; y < h; y++) {
pixels[y * w * 4 + x] = newColors[4 * y];
pixels[y * w * 4 + x + 1] = newColors[4 * y + 1];
pixels[y * w * 4 + x + 2] = newColors[4 * y + 2];
pixels[y * w * 4 + x + 3] = newColors[4 * y + 3];
}
}
};
Filters.blur = function(canvas, ctx, hRadius, vRadius, iterations, mask) {
var imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
var data = imgData.data;
Filters._premultiply(data);
for (var i = 0; i < iterations; i++) {
Filters._boxBlurHorizontal(data, mask, canvas.width, canvas.height, Math.floor(hRadius / 2));
Filters._boxBlurVertical(data, mask, canvas.width, canvas.height, Math.floor(vRadius / 2));
}
Filters._unpremultiply(data);
var width = canvas.width;
var height = canvas.height;
var retCanvas = createCanvas(width, height);
var retImg = retCanvas.getContext("2d");
retImg.putImageData(imgData, 0, 0);
return retCanvas;
}
Filters._moveRGB = function(width, height, rgb, deltaX, deltaY, fill) {
var img = createCanvas(width, height);
var ig = img.getContext("2d");
Filters._setRGB(ig, 0, 0, width, height, rgb);
var retImg = createCanvas(width, height);
retImg.width = width;
retImg.heigth = height;
var g = retImg.getContext("2d");
g.fillStyle = fill;
g.globalCompositeOperation = "copy";
g.fillRect(0, 0, width, height);
g.drawImage(img, deltaX, deltaY);
return g.getImageData(0, 0, width, height).data;
};
Filters.FULL = 1;
Filters.INNER = 2;
Filters.OUTER = 3;
Filters._setRGB = function(ctx, x, y, width, height, data) {
var id = ctx.createImageData(width, height);
for (var i = 0; i < data.length; i++) {
id.data[i] = data[i];
}
ctx.putImageData(id, x, y);
};
Filters.gradientGlow = function(srcCanvas, src, blurX, blurY, angle, distance, colors, ratios, type, iterations, strength, knockout) {
var width = canvas.width;
var height = canvas.height;
var retCanvas = createCanvas(width, height);
var retImg = retCanvas.getContext("2d");
var gradCanvas = createCanvas(256, 1);
var gradient = gradCanvas.getContext("2d");
var grd = ctx.createLinearGradient(0, 0, 255, 0);
for (var s = 0; s < colors.length; s++) {
var v = "rgba(" + colors[s][0] + "," + colors[s][1] + "," + colors[s][2] + "," + colors[s][3] + ")";
grd.addColorStop(ratios[s], v);
}
gradient.fillStyle = grd;
gradient.fillRect(0, 0, 256, 1);
var gradientPixels = gradient.getImageData(0, 0, gradCanvas.width, gradCanvas.height).data;
var angleRad = angle / 180 * Math.PI;
var moveX = (distance * Math.cos(angleRad));
var moveY = (distance * Math.sin(angleRad));
var srcPixels = src.getImageData(0, 0, width, height).data;
var revPixels = [];
for (var i = 0; i < srcPixels.length; i += 4) {
revPixels[i] = srcPixels[i];
revPixels[i + 1] = srcPixels[i + 1];
revPixels[i + 2] = srcPixels[i + 2];
revPixels[i + 3] = 255 - srcPixels[i + 3];
}
var shadow = [];
for (var i = 0; i < srcPixels.length; i += 4) {
var alpha = srcPixels[i + 3];
shadow[i] = 0;
shadow[i + 1] = 0;
shadow[i + 2] = 0;
shadow[i + 3] = Math.round(alpha * strength);
}
var colorAlpha = "rgba(0,0,0,0)";
shadow = Filters._moveRGB(width, height, shadow, moveX, moveY, colorAlpha);
Filters._setRGB(retImg, 0, 0, width, height, shadow);
var mask = null;
if (type == Filters.INNER) {
mask = srcPixels;
}
if (type == Filters.OUTER) {
mask = revPixels;
}
retCanvas = Filters.blur(retCanvas, retCanvas.getContext("2d"), blurX, blurY, iterations, mask);
retImg = retCanvas.getContext("2d");
shadow = retImg.getImageData(0, 0, width, height).data;
if (mask != null) {
for (var i = 0; i < mask.length; i += 4) {
if (mask[i + 3] == 0) {
shadow[i] = 0;
shadow[i + 1] = 0;
shadow[i + 2] = 0;
shadow[i + 3] = 0;
}
}
}
for (var i = 0; i < shadow.length; i += 4) {
var a = shadow[i + 3];
shadow[i] = gradientPixels[a * 4];
shadow[i + 1] = gradientPixels[a * 4 + 1];
shadow[i + 2] = gradientPixels[a * 4 + 2];
shadow[i + 3] = gradientPixels[a * 4 + 3];
}
Filters._setRGB(retImg, 0, 0, width, height, shadow);
if (!knockout) {
retImg.globalCompositeOperation = "destination-over";
retImg.drawImage(srcCanvas, 0, 0);
}
return retCanvas;
};
Filters.dropShadow = function(canvas, src, blurX, blurY, angle, distance, color, inner, iterations, strength, knockout) {
var width = canvas.width;
var height = canvas.height;
var srcPixels = src.getImageData(0, 0, width, height).data;
var shadow = [];
for (var i = 0; i < srcPixels.length; i += 4) {
var alpha = srcPixels[i + 3];
if (inner) {
alpha = 255 - alpha;
}
shadow[i] = color[0];
shadow[i + 1] = color[1];
shadow[i + 2] = color[2];
var sa = color[3] * alpha * strength;
if (sa > 255)
sa = 255;
shadow[i + 3] = Math.round(sa);
}
var colorFirst = "#000000";
var colorAlpha = "rgba(0,0,0,0)";
var angleRad = angle / 180 * Math.PI;
var moveX = (distance * Math.cos(angleRad));
var moveY = (distance * Math.sin(angleRad));
shadow = Filters._moveRGB(width, height, shadow, moveX, moveY, inner ? colorFirst : colorAlpha);
var retCanvas = createCanvas(canvas.width, canvas.height);
Filters._setRGB(retCanvas.getContext("2d"), 0, 0, width, height, shadow);
if (blurX > 0 || blurY > 0) {
retCanvas = Filters.blur(retCanvas, retCanvas.getContext("2d"), blurX, blurY, iterations, null);
}
shadow = retCanvas.getContext("2d").getImageData(0, 0, width, height).data;
var srcPixels = src.getImageData(0, 0, width, height).data;
for (var i = 0; i < shadow.length; i += 4) {
var mask = srcPixels[i + 3];
if (!inner) {
mask = 255 - mask;
}
shadow[i + 3] = mask * shadow[i + 3] / 255;
}
Filters._setRGB(retCanvas.getContext("2d"), 0, 0, width, height, shadow);
if (!knockout) {
var g = retCanvas.getContext("2d");
g.globalCompositeOperation = "destination-over";
g.drawImage(canvas, 0, 0);
}
return retCanvas;
};
Filters._cut = function(a, min, max) {
if (a > max)
a = max;
if (a < min)
a = min;
return a;
}
Filters.gradientBevel = function(canvas, src, colors, ratios, blurX, blurY, strength, type, angle, distance, knockout, iterations) {
var width = canvas.width;
var height = canvas.height;
var retImg = createCanvas(width, height);
var srcPixels = src.getImageData(0, 0, width, height).data;
var revPixels = [];
for (var i = 0; i < srcPixels.length; i += 4) {
revPixels[i] = srcPixels[i];
revPixels[i + 1] = srcPixels[i + 1];
revPixels[i + 2] = srcPixels[i + 2];
revPixels[i + 3] = 255 - srcPixels[i + 3];
}
var gradient = createCanvas(512, 1);
var gg = gradient.getContext("2d");
var grd = ctx.createLinearGradient(0, 0, 511, 0);
for (var s = 0; s < colors.length; s++) {
var v = "rgba(" + colors[s][0] + "," + colors[s][1] + "," + colors[s][2] + "," + colors[s][3] + ")";
grd.addColorStop(ratios[s], v);
}
gg.fillStyle = grd;
gg.globalCompositeOperation = "copy";
gg.fillRect(0, 0, gradient.width, gradient.height);
var gradientPixels = gg.getImageData(0, 0, gradient.width, gradient.height).data;
if (type != Filters.OUTER) {
var hilightIm = Filters.dropShadow(canvas, src, 0, 0, angle, distance, [255, 0, 0, 1], true, iterations, strength, true);
var shadowIm = Filters.dropShadow(canvas, src, 0, 0, angle + 180, distance, [0, 0, 255, 1], true, iterations, strength, true);
var h2 = createCanvas(width, height);
var s2 = createCanvas(width, height);
var hc = h2.getContext("2d");
var sc = s2.getContext("2d");
hc.drawImage(hilightIm, 0, 0);
hc.globalCompositeOperation = "destination-out";
hc.drawImage(shadowIm, 0, 0);
sc.drawImage(shadowIm, 0, 0);
sc.globalCompositeOperation = "destination-out";
sc.drawImage(hilightIm, 0, 0);
var shadowInner = s2;
var hilightInner = h2;
}
if (type != Filters.INNER) {
var hilightIm = Filters.dropShadow(canvas, src, 0, 0, angle + 180, distance, [255, 0, 0, 1], false, iterations, strength, true);
var shadowIm = Filters.dropShadow(canvas, src, 0, 0, angle, distance, [0, 0, 255, 1], false, iterations, strength, true);
var h2 = createCanvas(width, height);
var s2 = createCanvas(width, height);
var hc = h2.getContext("2d");
var sc = s2.getContext("2d");
hc.drawImage(hilightIm, 0, 0);
hc.globalCompositeOperation = "destination-out";
hc.drawImage(shadowIm, 0, 0);
sc.drawImage(shadowIm, 0, 0);
sc.globalCompositeOperation = "destination-out";
sc.drawImage(hilightIm, 0, 0);
var shadowOuter = s2;
var hilightOuter = h2;
}
var hilightIm;
var shadowIm;
switch (type)
{
case Filters.OUTER:
hilightIm = hilightOuter;
shadowIm = shadowOuter;
break;
case Filters.INNER:
hilightIm = hilightInner;
shadowIm = shadowInner;
break;
case Filters.FULL:
hilightIm = hilightInner;
shadowIm = shadowInner;
var hc = hilightIm.getContext("2d");
hc.globalCompositeOperation = "source-over";
hc.drawImage(hilightOuter, 0, 0);
var sc = shadowIm.getContext("2d");
sc.globalCompositeOperation = "source-over";
sc.drawImage(shadowOuter, 0, 0);
break;
}
var mask = null;
if (type == Filters.INNER) {
mask = srcPixels;
}
if (type == Filters.OUTER) {
mask = revPixels;
}
var retc = retImg.getContext("2d");
retc.fillStyle = "#000000";
retc.fillRect(0, 0, width, height);
retc.drawImage(shadowIm, 0, 0);
retc.drawImage(hilightIm, 0, 0);
retImg = Filters.blur(retImg, retImg.getContext("2d"), blurX, blurY, iterations, mask);
var ret = retImg.getContext("2d").getImageData(0, 0, width, height).data;
for (var i = 0; i < srcPixels.length; i += 4) {
var ah = ret[i] * strength;
var as = ret[i + 2] * strength;
var ra = Filters._cut(ah - as, -255, 255);
ret[i] = gradientPixels[4 * (255 + ra)];
ret[i + 1] = gradientPixels[4 * (255 + ra) + 1];
ret[i + 2] = gradientPixels[4 * (255 + ra) + 2];
ret[i + 3] = gradientPixels[4 * (255 + ra) + 3];
}
Filters._setRGB(retImg.getContext("2d"), 0, 0, width, height, ret);
if (!knockout) {
var g = retImg.getContext("2d");
g.globalCompositeOperation = "destination-over";
g.drawImage(canvas, 0, 0);
}
return retImg;
}
Filters.bevel = function(canvas, src, blurX, blurY, strength, type, highlightColor, shadowColor, angle, distance, knockout, iterations) {
return Filters.gradientBevel(canvas, src, [
shadowColor,
[shadowColor[0], shadowColor[1], shadowColor[2], 0],
[highlightColor[0], highlightColor[1], highlightColor[2], 0],
highlightColor
], [0, 127 / 255, 128 / 255, 1], blurX, blurY, strength, type, angle, distance, knockout, iterations);
}
//http://www.html5rocks.com/en/tutorials/canvas/imagefilters/
Filters.convolution = function(canvas, ctx, weights, opaque) {
var pixels = ctx.getImageData(0, 0, canvas.width, canvas.height);
var side = Math.round(Math.sqrt(weights.length));
var halfSide = Math.floor(side / 2);
var src = pixels.data;
var sw = pixels.width;
var sh = pixels.height;
// pad output by the convolution matrix
var w = sw;
var h = sh;
var outCanvas = createCanvas(w, h);
var outCtx = outCanvas.getContext("2d");
var output = outCtx.getImageData(0, 0, w, h);
var dst = output.data;
// go through the destination image pixels
var alphaFac = opaque ? 1 : 0;
for (var y = 0; y < h; y++) {
for (var x = 0; x < w; x++) {
var sy = y;
var sx = x;
var dstOff = (y * w + x) * 4;
// calculate the weighed sum of the source image pixels that
// fall under the convolution matrix
var r = 0, g = 0, b = 0, a = 0;
for (var cy = 0; cy < side; cy++) {
for (var cx = 0; cx < side; cx++) {
var scy = sy + cy - halfSide;
var scx = sx + cx - halfSide;
if (scy >= 0 && scy < sh && scx >= 0 && scx < sw) {
var srcOff = (scy * sw + scx) * 4;
var wt = weights[cy * side + cx];
r += src[srcOff] * wt;
g += src[srcOff + 1] * wt;
b += src[srcOff + 2] * wt;
a += src[srcOff + 3] * wt;
}
}
}
dst[dstOff] = r;
dst[dstOff + 1] = g;
dst[dstOff + 2] = b;
dst[dstOff + 3] = a + alphaFac * (255 - a);
}
}
outCtx.putImageData(output, 0, 0);
return outCanvas;
};
Filters.colorMatrix = function(canvas, ctx, m) {
var pixels = ctx.getImageData(0, 0, canvas.width, canvas.height);
var data = pixels.data;
for (var i = 0; i < data.length; i += 4)
{
var r = i;
var g = i + 1;
var b = i + 2;
var a = i + 3;
var oR = data[r];
var oG = data[g];
var oB = data[b];
var oA = data[a];
data[r] = (m[0] * oR) + (m[1] * oG) + (m[2] * oB) + (m[3] * oA) + m[4];
data[g] = (m[5] * oR) + (m[6] * oG) + (m[7] * oB) + (m[8] * oA) + m[9];
data[b] = (m[10] * oR) + (m[11] * oG) + (m[12] * oB) + (m[13] * oA) + m[14];
data[a] = (m[15] * oR) + (m[16] * oG) + (m[17] * oB) + (m[18] * oA) + m[19];
}
var outCanvas = createCanvas(canvas.width, canvas.height);
var outCtx = outCanvas.getContext("2d");
outCtx.putImageData(pixels, 0, 0);
return outCanvas;
};
Filters.glow = function(canvas, src, blurX, blurY, strength, color, inner, knockout, iterations) {
return Filters.dropShadow(canvas, src, blurX, blurY, 45, 0, color, inner, iterations, strength, knockout);
};
var BlendModes = {};
BlendModes._cut = function(v) {
if (v < 0)
v = 0;
if (v > 255)
v = 255;
return v;
};
BlendModes.normal = function(src, dst, result, pos) {
var am = (255 - src[pos + 3]) / 255;
result[pos] = this._cut(src[pos] * src[pos + 3] / 255 + dst[pos] * dst[pos + 3] / 255 * am);
result[pos + 1] = this._cut(src[pos + 1] * src[pos + 3] / 255 + dst[pos + 1] * dst[pos + 3] / 255 * am);
result[pos + 2] = this._cut(src[pos + 2] * src[pos + 3] / 255 + dst[pos + 2] * dst[pos + 3] / 255 * am);
result[pos + 3] = this._cut(src[pos + 3] + dst[pos + 3] * am);
};
BlendModes.layer = function(src, dst, result, pos) {
BlendModes.normal(src, dst, result, pos);
};
BlendModes.multiply = function(src, dst, result, pos) {
result[pos + 0] = (src[pos + 0] * dst[pos + 0]) >> 8;
result[pos + 1] = (src[pos + 1] * dst[pos + 1]) >> 8;
result[pos + 2] = (src[pos + 2] * dst[pos + 2]) >> 8;
result[pos + 3] = Math.min(255, src[pos + 3] + dst[pos + 3] - (src[pos + 3] * dst[pos + 3]) / 255);
};
BlendModes.screen = function(src, dst, result, pos) {
result[pos + 0] = 255 - ((255 - src[pos + 0]) * (255 - dst[pos + 0]) >> 8);
result[pos + 1] = 255 - ((255 - src[pos + 1]) * (255 - dst[pos + 1]) >> 8);
result[pos + 2] = 255 - ((255 - src[pos + 2]) * (255 - dst[pos + 2]) >> 8);
result[pos + 3] = Math.min(255, src[pos + 3] + dst[pos + 3] - (src[pos + 3] * dst[pos + 3]) / 255);
};
BlendModes.lighten = function(src, dst, result, pos) {
result[pos + 0] = Math.max(src[pos + 0], dst[pos + 0]);
result[pos + 1] = Math.max(src[pos + 1], dst[pos + 1]);
result[pos + 2] = Math.max(src[pos + 2], dst[pos + 2]);
result[pos + 3] = Math.min(255, src[pos + 3] + dst[pos + 3] - (src[pos + 3] * dst[pos + 3]) / 255);
};
BlendModes.darken = function(src, dst, result, pos) {
result[pos + 0] = Math.min(src[pos + 0], dst[pos + 0]);
result[pos + 1] = Math.min(src[pos + 1], dst[pos + 1]);
result[pos + 2] = Math.min(src[pos + 2], dst[pos + 2]);
result[pos + 3] = Math.min(255, src[pos + 3] + dst[pos + 3] - (src[pos + 3] * dst[pos + 3]) / 255);
};
BlendModes.difference = function(src, dst, result, pos) {
result[pos + 0] = Math.abs(dst[pos + 0] - src[pos + 0]);
result[pos + 1] = Math.abs(dst[pos + 1] - src[pos + 1]);
result[pos + 2] = Math.abs(dst[pos + 2] - src[pos + 2]);
result[pos + 3] = Math.min(255, src[pos + 3] + dst[pos + 3] - (src[pos + 3] * dst[pos + 3]) / 255);
};
BlendModes.add = function(src, dst, result, pos) {
result[pos + 0] = Math.min(255, src[pos + 0] + dst[pos + 0]);
result[pos + 1] = Math.min(255, src[pos + 1] + dst[pos + 1]);
result[pos + 2] = Math.min(255, src[pos + 2] + dst[pos + 2]);
result[pos + 3] = Math.min(255, src[pos + 3] + dst[pos + 3]);
};
BlendModes.subtract = function(src, dst, result, pos) {
result[pos + 0] = Math.max(0, src[pos + 0] + dst[pos + 0] - 256);
result[pos + 1] = Math.max(0, src[pos + 1] + dst[pos + 1] - 256);
result[pos + 2] = Math.max(0, src[pos + 2] + dst[pos + 2] - 256);
result[pos + 3] = Math.min(255, src[pos + 3] + dst[pos + 3] - (src[pos + 3] * dst[pos + 3]) / 255);
};
BlendModes.invert = function(src, dst, result, pos) {
result[pos + 0] = 255 - dst[pos + 0];
result[pos + 1] = 255 - dst[pos + 1];
result[pos + 2] = 255 - dst[pos + 2];
result[pos + 3] = src[pos + 3];
};
BlendModes.alpha = function(src, dst, result, pos) {
result[pos + 0] = src[pos + 0];
result[pos + 1] = src[pos + 1];
result[pos + 2] = src[pos + 2];
result[pos + 3] = dst[pos + 3]; //?
};
BlendModes.erase = function(src, dst, result, pos) {
result[pos + 0] = src[pos + 0];
result[pos + 1] = src[pos + 1];
result[pos + 2] = src[pos + 2];
result[pos + 3] = 255 - dst[pos + 3]; //?
};
BlendModes.overlay = function(src, dst, result, pos) {
result[pos + 0] = dst[pos + 0] < 128 ? dst[pos + 0] * src[pos + 0] >> 7
: 255 - ((255 - dst[pos + 0]) * (255 - src[pos + 0]) >> 7);
result[pos + 1] = dst[pos + 1] < 128 ? dst[pos + 1] * src[pos + 1] >> 7
: 255 - ((255 - dst[pos + 1]) * (255 - src[pos + 1]) >> 7);
result[pos + 2] = dst[pos + 2] < 128 ? dst[pos + 2] * src[pos + 2] >> 7
: 255 - ((255 - dst[pos + 2]) * (255 - src[pos + 2]) >> 7);
result[pos + 3] = Math.min(255, src[pos + 3] + dst[pos + 3] - (src[pos + 3] * dst[pos + 3]) / 255);
};
BlendModes.hardlight = function(src, dst, result, pos) {
result[pos + 0] = src[pos + 0] < 128 ? dst[pos + 0] * src[pos + 0] >> 7
: 255 - ((255 - src[pos + 0]) * (255 - dst[pos + 0]) >> 7);
result[pos + 1] = src[pos + 1] < 128 ? dst[pos + 1] * src[pos + 1] >> 7
: 255 - ((255 - src[pos + 1]) * (255 - dst[pos + 1]) >> 7);
result[pos + 2] = src[pos + 2] < 128 ? dst[pos + 2] * src[pos + 2] >> 7
: 255 - ((255 - src[pos + 2]) * (255 - dst[pos + 2]) >> 7);
result[pos + 3] = Math.min(255, src[pos + 3] + dst[pos + 3] - (src[pos + 3] * dst[pos + 3]) / 255);
};
BlendModes._list = [
BlendModes.normal,
BlendModes.normal,
BlendModes.layer,
BlendModes.multiply,
BlendModes.screen,
BlendModes.lighten,
BlendModes.darken,
BlendModes.difference,
BlendModes.add,
BlendModes.subtract,
BlendModes.invert,
BlendModes.alpha,
BlendModes.erase,
BlendModes.overlay,
BlendModes.hardlight
];
BlendModes.blendData = function(srcPixel, dstPixel, retData, modeIndex) {
var result = [];
var retPixel = [];
var alpha = 1.0;
for (var i = 0; i < retData.length; i += 4) {
this._list[modeIndex](srcPixel, dstPixel, result, i);
retPixel[i + 0] = this._cut(dstPixel[i + 0] + (result[i + 0] - dstPixel[i + 0]) * alpha);
retPixel[i + 1] = this._cut(dstPixel[i + 1] + (result[i + 1] - dstPixel[i + 1]) * alpha);
retPixel[i + 2] = this._cut(dstPixel[i + 2] + (result[i + 2] - dstPixel[i + 2]) * alpha);
retPixel[i + 3] = this._cut(dstPixel[i + 3] + (result[i + 3] - dstPixel[i + 3]) * alpha);
var af = srcPixel[i + 3] / 255;
retData[i + 0] = this._cut((1 - af) * dstPixel[i + 0] + af * retPixel[i + 0]);
retData[i + 1] = this._cut((1 - af) * dstPixel[i + 1] + af * retPixel[i + 1]);
retData[i + 2] = this._cut((1 - af) * dstPixel[i + 2] + af * retPixel[i + 2]);
retData[i + 3] = this._cut((1 - af) * dstPixel[i + 3] + af * retPixel[i + 3]);
}
};
BlendModes.blendCanvas = function(src, dst, result, modeIndex) {
var width = src.width;
var height = src.height;
var rctx = result.getContext("2d");
var sctx = src.getContext("2d");
var dctx = dst.getContext("2d");
var ridata = rctx.getImageData(0, 0, width, height);
var sidata = sctx.getImageData(0, 0, width, height);
var didata = dctx.getImageData(0, 0, width, height);
this.blendData(sidata.data, didata.data, ridata.data, modeIndex);
rctx.putImageData(ridata, 0, 0);
};
var enhanceContext = function(context) {
var m = [1, 0, 0, 1, 0, 0];
context._matrices = [m];
//the stack of saved matrices
context._savedMatrices = [[m]];
var super_ = context.__proto__;
context.__proto__ = ({
save: function() {
this._savedMatrices.push(this._matrices.slice());
super_.save.call(this);
},
//if the stack of matrices we're managing doesn't have a saved matrix,
//we won't even call the context's original `restore` method.
restore: function() {
if (this._savedMatrices.length == 0)
return;
super_.restore.call(this);
this._matrices = this._savedMatrices.pop();
},
scale: function(x, y) {
super_.scale.call(this, x, y);
},
rotate: function(theta) {
super_.rotate.call(this, theta);
},
translate: function(x, y) {
super_.translate.call(this, x, y);
},
transform: function(a, b, c, d, e, f) {
this._matrices.push([a, b, c, d, e, f]);
super_.transform.call(this, a, b, c, d, e, f);
},
setTransform: function(a, b, c, d, e, f) {
this._matrices = [];
this._matrices.push([a, b, c, d, e, f]);
super_.setTransform.call(this, a, b, c, d, e, f);
},
resetTransform: function() {
super_.resetTransform.call(this);
},
applyTransforms: function(m) {
this.setTransform(1, 0, 0, 1, 0, 0);
for (var i = 0; i < m.length; i++) {
this.transform(m[i][0], m[i][1], m[i][2], m[i][3], m[i][4], m[i][5]);
}
},
__proto__: super_
});
return context;
};
var cxform = function(r_add, g_add, b_add, a_add, r_mult, g_mult, b_mult, a_mult) {
this.r_add = r_add;
this.g_add = g_add;
this.b_add = b_add;
this.a_add = a_add;
this.r_mult = r_mult;
this.g_mult = g_mult;
this.b_mult = b_mult;
this.a_mult = a_mult;
this._cut = function(v, min, max) {
if (v < min)
v = min;
if (v > max)
v = max;
return v;
};
this.apply = function(c) {
var d = c;
d[0] = this._cut(Math.round(d[0] * this.r_mult / 255 + this.r_add), 0, 255);
d[1] = this._cut(Math.round(d[1] * this.g_mult / 255 + this.g_add), 0, 255);
d[2] = this._cut(Math.round(d[2] * this.b_mult / 255 + this.b_add), 0, 255);
d[3] = this._cut(Math.round(d[3] * this.a_mult / 255 + this.a_add / 255), 0, 1);
return d;
};
this.applyToImage = function(fimg) {
if (this.isEmpty()) {
return fimg
}
;
var icanvas = createCanvas(fimg.width, fimg.height);
var ictx = icanvas.getContext("2d");
ictx.drawImage(fimg, 0, 0);
var imdata = ictx.getImageData(0, 0, icanvas.width, icanvas.height);
var idata = imdata.data;
for (var i = 0; i < idata.length; i += 4) {
var c = this.apply([idata[i], idata[i + 1], idata[i + 2], idata[i + 3] / 255]);
idata[i] = c[0];
idata[i + 1] = c[1];
idata[i + 2] = c[2];
idata[i + 3] = Math.round(c[3] * 255);
}
ictx.putImageData(imdata, 0, 0);
return icanvas;
};
this.merge = function(cx) {
return new cxform(this.r_add + cx.r_add, this.g_add + cx.g_add, this.b_add + cx.b_add, this.a_add + cx.a_add, this.r_mult * cx.r_mult / 255, this.g_mult * cx.g_mult / 255, this.b_mult * cx.b_mult / 255, this.a_mult * cx.a_mult / 255);
};
this.isEmpty = function() {
return this.r_add == 0 && this.g_add == 0 && this.b_add == 0 && this.a_add == 0 && this.r_mult == 255 && this.g_mult == 255 && this.b_mult == 255 && this.a_mult == 255;
};
};
var place = function(obj, canvas, ctx, matrix, ctrans, blendMode, frame, ratio, time) {
ctx.save();
ctx.transform(matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]);
if (blendMode > 1) {
var oldctx = ctx;
var ncanvas = createCanvas(canvas.width, canvas.height);
ctx = ncanvas.getContext("2d");
enhanceContext(ctx);
ctx.applyTransforms(oldctx._matrices);
}
if (blendMode > 1) {
eval(obj + "(ctx,new cxform(0,0,0,0,255,255,255,255),frame,ratio,time);");
} else {
eval(obj + "(ctx,ctrans,frame,ratio,time);");
}
if (blendMode > 1) {
BlendModes.blendCanvas(ctrans.applyToImage(ncanvas), canvas, canvas, blendMode);
ctx = oldctx;
}
ctx.restore();
}
var tocolor = function(c) {
var r = "rgba(" + c[0] + "," + c[1] + "," + c[2] + "," + c[3] + ")";
return r;
};
window.addEventListener('load', function() {
var wsize = document.getElementById("width_size");
var hsize = document.getElementById("height_size");
//var bsize = document.getElementById("both_size");
//bsize.addEventListener('mousedown', initDragBoth, false);
wsize.addEventListener('mousedown', initDragWidth, false);
hsize.addEventListener('mousedown', initDragHeight, false);
});
var startWidth = 0;
var startHeight = 0;
var dragWidth = false;
var dragHeight = false;
function initDragWidth(e) {
dragWidth = true;
dragHeight = false;
initDrag(e);
}
function initDragHeight(e) {
dragWidth = false;
dragHeight = true;
initDrag(e);
}
function initDragBoth(e) {
dragWidth = true;
dragHeight = true;
initDrag(e);
}
function initDrag(e) {
startX = e.clientX;
startY = e.clientY;
startWidth = canvas.width;
startHeight = canvas.height;
document.documentElement.addEventListener('mousemove', doDrag, false);
document.documentElement.addEventListener('mouseup', stopDrag, false);
}
function doDrag(e) {
if (dragWidth) {
canvas.width = (startWidth + e.clientX - startX);
canvas.height = canvas.width * originalHeight / originalWidth;
}
else if (dragHeight) {
canvas.height = (startHeight + e.clientY - startY);
canvas.width = canvas.height * originalWidth / originalHeight;
}
drawFrame();
}
function stopDrag(e) {
document.documentElement.removeEventListener('mousemove', doDrag, false);
document.documentElement.removeEventListener('mouseup', stopDrag, false);
}
function drawPath(ctx, p) {
ctx.beginPath();
var parts = p.split(" ");
var len = parts.length;
var drawCommand = "";
for (var i = 0; i < len; i++) {
switch (parts[i]) {
case 'L':
case 'M':
case 'Q':
drawCommand = parts[i];
break;
default:
switch (drawCommand) {
case 'L':
ctx.lineTo(parts[i], parts[i + 1]);
i++;
break;
case 'M':
ctx.moveTo(parts[i], parts[i + 1]);
i++;
break;
case 'Q':
ctx.quadraticCurveTo(parts[i], parts[i + 1], parts[i + 2], parts[i + 3]);
i += 3;
break;
}
break;
}
}
}
@@ -0,0 +1,46 @@
/*
* Copyright (C) 2010-2014 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.␍ */
package com.jpexs.helpers.sound;
import java.io.InputStream;
/**
*
* @author JPEXS
*/
public abstract class SoundPlayer {
protected InputStream is;
protected SoundPlayer(InputStream is) {
this.is = is;
}
public abstract long samplesCount();
public abstract long getSamplePosition();
public abstract void play();
public abstract void stop();
public abstract void skip(long samples);
public abstract boolean isPlaying();
public abstract long getFrameRate();
}
@@ -0,0 +1,28 @@
/*
* Copyright (C) 2010-2014 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.␍ */
package com.jpexs.helpers.streams;
import java.io.IOException;
import java.io.InputStream;
/**
*
* @author JPEXS
*/
public abstract class SeekableInputStream extends InputStream {
public abstract void seek(long pos) throws IOException;
}
@@ -0,0 +1,41 @@
/*
* Copyright (C) 2010-2014 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.␍ */
package com.jpexs.helpers.utf8;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.charset.Charset;
/**
*
* @author JPEXS
*/
public class Utf8Helper {
public static Charset charset = Charset.forName("UTF-8");
public static String urlDecode(String s) {
try {
return URLDecoder.decode(s, "UTF-8");
} catch (UnsupportedEncodingException ex) {
throw new Error(ex);
}
}
public static byte[] getBytes(String string) {
return string.getBytes(charset);
}
}
@@ -0,0 +1,30 @@
/*
* Copyright (C) 2010-2014 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.␍ */
package com.jpexs.helpers.utf8;
import java.io.InputStream;
import java.io.InputStreamReader;
/**
*
* @author JPEXS
*/
public class Utf8InputStreamReader extends InputStreamReader {
public Utf8InputStreamReader(InputStream in) {
super(in, Utf8Helper.charset);
}
}
@@ -0,0 +1,30 @@
/*
* Copyright (C) 2010-2014 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.␍ */
package com.jpexs.helpers.utf8;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
/**
*
* @author JPEXS
*/
public class Utf8OutputStreamWriter extends OutputStreamWriter {
public Utf8OutputStreamWriter(OutputStream out) {
super(out, Utf8Helper.charset);
}
}
@@ -0,0 +1,30 @@
/*
* Copyright (C) 2010-2014 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.␍ */
package com.jpexs.helpers.utf8;
import java.io.OutputStream;
import java.io.PrintWriter;
/**
*
* @author JPEXS
*/
public class Utf8PrintWriter extends PrintWriter {
public Utf8PrintWriter(OutputStream out) {
super(new Utf8OutputStreamWriter(out));
}
}