diff --git a/trunk/src/com/jpexs/decompiler/flash/BinarySWFBundle.java b/trunk/src/com/jpexs/decompiler/flash/BinarySWFBundle.java index fcb48b052..89dee6d37 100644 --- a/trunk/src/com/jpexs/decompiler/flash/BinarySWFBundle.java +++ b/trunk/src/com/jpexs/decompiler/flash/BinarySWFBundle.java @@ -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(); } diff --git a/trunk/src/com/jpexs/decompiler/flash/SWF.java b/trunk/src/com/jpexs/decompiler/flash/SWF.java index 01e5abba9..1dbe69b22 100644 --- a/trunk/src/com/jpexs/decompiler/flash/SWF.java +++ b/trunk/src/com/jpexs/decompiler/flash/SWF.java @@ -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 tagMap = new HashMap<>(); diff --git a/trunk/src/com/jpexs/decompiler/flash/SWFSearch.java b/trunk/src/com/jpexs/decompiler/flash/SWFSearch.java index 1f1752f39..1435ae787 100644 --- a/trunk/src/com/jpexs/decompiler/flash/SWFSearch.java +++ b/trunk/src/com/jpexs/decompiler/flash/SWFSearch.java @@ -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) diff --git a/trunk/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java b/trunk/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java index c0cdfdc2e..6a2f1892f 100644 --- a/trunk/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java +++ b/trunk/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java @@ -173,7 +173,12 @@ public class CommandLineArgumentParser { */ public static String parseArguments(String[] arguments) throws IOException { Level traceLevel = Level.WARNING; - Queue args = new LinkedList<>(Arrays.asList(arguments)); + Queue args = new LinkedList<>(); + for (String arg : arguments) { + if (arg.length() > 0) { + args.add(arg); + } + } AbortRetryIgnoreHandler handler = null; Map format = new HashMap<>(); diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/LoadFromMemoryFrame.java b/trunk/src/com/jpexs/decompiler/flash/gui/LoadFromMemoryFrame.java index 14bc73dbf..1db9cc0b5 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/LoadFromMemoryFrame.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/LoadFromMemoryFrame.java @@ -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)); diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/Main.java b/trunk/src/com/jpexs/decompiler/flash/gui/Main.java index 58df2166b..5341a92eb 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/Main.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/Main.java @@ -883,6 +883,7 @@ public class Main { * @throws IOException */ public static void main(String[] args) throws IOException { + args = "-extract C:\\Projectek\\ffdec\\FFDec\\lwt.exe nocheck biggest".split(" "); startFreeMemThread(); initLogging(Configuration.debugMode.get()); initLang(); diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_sv.properties b/trunk/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_sv.properties index b3324d90e..fbc93072a 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_sv.properties +++ b/trunk/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_sv.properties @@ -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 diff --git a/trunk/src/com/jpexs/helpers/Helper.java b/trunk/src/com/jpexs/helpers/Helper.java index 06e3a4b42..996f04b30 100644 --- a/trunk/src/com/jpexs/helpers/Helper.java +++ b/trunk/src/com/jpexs/helpers/Helper.java @@ -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]; diff --git a/trunk/src/com/jpexs/helpers/StreamSearch.java b/trunk/src/com/jpexs/helpers/StreamSearch.java index 30e054d24..fa3fa88b4 100644 --- a/trunk/src/com/jpexs/helpers/StreamSearch.java +++ b/trunk/src/com/jpexs/helpers/StreamSearch.java @@ -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; } diff --git a/trunk/src/com/jpexs/helpers/SwfHeaderStreamSearch.java b/trunk/src/com/jpexs/helpers/SwfHeaderStreamSearch.java new file mode 100644 index 000000000..f36bf3184 --- /dev/null +++ b/trunk/src/com/jpexs/helpers/SwfHeaderStreamSearch.java @@ -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 . + */ +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 search(byte[]... data) { + return search(null, data); + } + + @Override + public Map search(ProgressListener progListener, byte[]... data) { + // Ignore data parameter, find only FWS, CWS, ZWS, GFX and CFX + + Map 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; + } + +}