This commit is contained in:
Jindra Petk
2014-02-26 22:10:18 +01:00
9 changed files with 189 additions and 21 deletions

View File

@@ -16,7 +16,7 @@
*/
package com.jpexs.decompiler.flash;
import com.jpexs.helpers.StreamSearch;
import com.jpexs.helpers.SwfHeaderStreamSearch;
import com.jpexs.helpers.streams.SeekableInputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -34,7 +34,7 @@ public class BinarySWFBundle implements SWFBundle {
private final SWFSearch search;
public BinarySWFBundle(InputStream is, boolean noCheck, SearchMode searchMode) {
search = new SWFSearch(new StreamSearch(is), noCheck, searchMode);
search = new SWFSearch(new SwfHeaderStreamSearch(is), noCheck, searchMode);
search.process();
}

View File

@@ -335,9 +335,83 @@ public final class SWF implements TreeItem {
* @throws java.lang.InterruptedException
*/
public SWF(InputStream is, ProgressListener listener, boolean parallelRead) throws IOException, InterruptedException {
this(is, listener, parallelRead, false, false);
this(is, listener, parallelRead, false);
}
/**
* Faster constructor to check SWF only
* @param is
*/
public SWF(InputStream is) throws IOException {
byte[] hdr = new byte[3];
is.read(hdr);
String shdr = new String(hdr, Utf8Helper.charset);
if (!Arrays.asList(
"FWS", //Uncompressed Flash
"CWS", //ZLib compressed Flash
"ZWS", //LZMA compressed Flash
"GFX", //Uncompressed ScaleForm GFx
"CFX" //Compressed ScaleForm GFx
).contains(shdr)) {
throw new IOException("Invalid SWF file");
}
version = is.read();
fileSize = (is.read() + (is.read() << 8) + (is.read() << 16) + (is.read() << 24)) & 0xffffffff;
if (hdr[0] == 'C') {
is = new InflaterInputStream(is);
}
if (hdr[0] == 'Z') {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
//outSize
is.read();
is.read();
is.read();
is.read();
int propertiesSize = 5;
lzmaProperties = new byte[propertiesSize];
if (is.read(lzmaProperties, 0, propertiesSize) != propertiesSize) {
throw new IOException("LZMA:input .lzma file is too short");
}
long dictionarySize = 0;
for (int i = 0; i < 4; i++) {
dictionarySize += ((int) (lzmaProperties[1 + i]) & 0xFF) << (i * 8);
if (dictionarySize > Runtime.getRuntime().freeMemory()) {
throw new IOException("LZMA: Too large dictionary size");
}
}
SevenZip.Compression.LZMA.Decoder decoder = new SevenZip.Compression.LZMA.Decoder();
if (!decoder.SetDecoderProperties(lzmaProperties)) {
throw new IOException("LZMA:Incorrect stream properties");
}
if (!decoder.Code(is, baos, fileSize - 8)) {
throw new IOException("LZMA:Error in data stream");
}
} else {
long toRead = fileSize - 8;
if (toRead > 0) {
byte[] bytes = new byte[4096];
while (toRead > 4096) {
int read = is.read(bytes);
if (read == -1) {
throw new IOException("Invalid SWF file");
}
toRead -= read;
}
while (toRead > 0) {
int read = is.read(bytes, 0, (int) toRead);
if (read == -1) {
throw new IOException("Invalid SWF file");
}
toRead -= read;
}
}
}
}
/**
* Construct SWF from stream
*
@@ -345,11 +419,10 @@ public final class SWF implements TreeItem {
* @param listener
* @param parallelRead Use parallel threads?
* @param checkOnly Check only file validity
* @param skipTagReading
* @throws IOException
* @throws java.lang.InterruptedException
*/
public SWF(InputStream is, ProgressListener listener, boolean parallelRead, boolean checkOnly, boolean skipTagReading) throws IOException, InterruptedException {
public SWF(InputStream is, ProgressListener listener, boolean parallelRead, boolean checkOnly) throws IOException, InterruptedException {
byte[] hdr = new byte[3];
is.read(hdr);
String shdr = new String(hdr, Utf8Helper.charset);
@@ -412,13 +485,6 @@ public final class SWF implements TreeItem {
sis.readUI8(); //tmpFirstByetOfFrameRate
frameRate = sis.readUI8();
frameCount = sis.readUI16();
if (skipTagReading) {
long toRead = fileSize - sis.getPos();
if (toRead > 0) {
sis.readBytes(toRead);
}
return;
}
tags = sis.readTagList(this, 0, parallelRead, true, !checkOnly, gfx);
if (!checkOnly) {
Map<Long, Tag> tagMap = new HashMap<>();

View File

@@ -82,7 +82,7 @@ public class SWFSearch {
MemoryInputStream mis = (MemoryInputStream) ret.get(addr);
mis.reset();
PosMarkedInputStream pmi = new PosMarkedInputStream(mis);
SWF swf = new SWF(pmi, null, false, true, noCheck);
SWF swf = noCheck ? new SWF(pmi) : new SWF(pmi, null, false, true);
boolean valid = swf.fileSize > 0
&& swf.version > 0
&& (!swf.tags.isEmpty() || noCheck)

View File

@@ -173,7 +173,12 @@ public class CommandLineArgumentParser {
*/
public static String parseArguments(String[] arguments) throws IOException {
Level traceLevel = Level.WARNING;
Queue<String> args = new LinkedList<>(Arrays.asList(arguments));
Queue<String> args = new LinkedList<>();
for (String arg : arguments) {
if (arg.length() > 0) {
args.add(arg);
}
}
AbortRetryIgnoreHandler handler = null;
Map<String, String> format = new HashMap<>();

View File

@@ -136,7 +136,7 @@ public class LoadFromMemoryFrame extends AppFrame implements ActionListener {
try {
PosMarkedInputStream pmi = new PosMarkedInputStream(ret.get(addr));
ReReadableInputStream is = new ReReadableInputStream(pmi);
SWF swf = new SWF(is, null, false, true, false);
SWF swf = new SWF(is, null, false, true);
long limit = pmi.getPos();
is.seek(0);
is = new ReReadableInputStream(new LimitedInputStream(is, limit));

View File

@@ -428,10 +428,24 @@ filter.zip = ZIP komprimerade filer (*.zip)
filter.binary = Bin\u00e4r s\u00f6kning - alla filer (*.*)
open.error = Fel
open.error.fileNotFound = Filen kunde inte hittas
open.error.fileNotFound = Filen hittades inte
open.error.cannotOpen = Kan inte \u00f6ppna filen
node.others = andra
#after version 1.8.1
menu.tools.search = Text S\u00f6kning
#after version 1.8.1u1
menu.tools.timeline = Tidslinje
dialog.selectcolor.title = V\u00e4lj f\u00e4rg
button.selectcolor.hint = Klicka f\u00f6r att v\u00e4lja f\u00e4rg
#default item name, will be used in following sentences
generictag.array.item = artikel
generictag.array.insertbeginning = Infoga %item% vid b\u00f6rjan
generictag.array.insertbefore = Infoga %item% f\u00f6re
generictag.array.remove = Tabort %item%
generictag.array.insertafter = Infoga %item% efter
generictag.array.insertend = Infoga %item% vid slutet

View File

@@ -412,6 +412,10 @@ public class Helper {
}
public static byte[] readStream(InputStream is) {
if (is instanceof MemoryInputStream) {
return ((MemoryInputStream) is).getAllRead();
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
byte[] buf = new byte[4096];

View File

@@ -54,8 +54,8 @@ public class StreamSearch implements Searchable {
try {
is.seek(0);
byte buf[] = new byte[4096];
byte last[] = null;
byte[] buf = new byte[4096];
byte[] last = null;
int cnt = 0;
long pos = 0;
while ((cnt = is.read(buf)) > 0) {
@@ -63,7 +63,7 @@ public class StreamSearch implements Searchable {
for (int i = -maxFindLen + 1; i < cnt; i++) {
loopdata:
for (byte onedata[] : data) {
for (byte[] onedata : data) {
boolean match = true;
for (int d = 0; d < onedata.length; d++) {
byte b;
@@ -71,7 +71,7 @@ public class StreamSearch implements Searchable {
if (last != null) {
b = last[last.length + i + d];
} else {
continue;
continue;
}
} else if (i + d >= buf.length) {
continue;
@@ -81,6 +81,7 @@ public class StreamSearch implements Searchable {
if (b != onedata[d]) {
match = false;
break;
}
}
if (match) {
@@ -90,7 +91,6 @@ public class StreamSearch implements Searchable {
continue loopdata;
}
}
}
pos = pos + cnt;
}

View File

@@ -0,0 +1,79 @@
/*
* Copyright (C) 2014 JPEXS
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
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) {
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;
}
}