mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-07-01 11:01:34 +00:00
SWFs in zip based bundles can be modified & saved
This commit is contained in:
@@ -12,7 +12,8 @@
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
import com.jpexs.helpers.SwfHeaderStreamSearch;
|
||||
@@ -81,4 +82,14 @@ public class BinarySWFBundle implements SWFBundle {
|
||||
public String getExtension() {
|
||||
return "bin";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadOnly() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putSWF(String key,InputStream is) {
|
||||
throw new UnsupportedOperationException("Save not supported for this type of bundle");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,10 +16,9 @@
|
||||
*/
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
import javax.xml.parsers.SAXParser;
|
||||
@@ -36,38 +35,44 @@ public class SWC extends ZippedSWFBundle {
|
||||
|
||||
public SWC(InputStream is) throws IOException {
|
||||
super(is);
|
||||
}
|
||||
|
||||
public SWC(File filename) throws IOException {
|
||||
super(filename);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initBundle(InputStream is, File filename) throws IOException {
|
||||
super.initBundle(is, filename);
|
||||
keySet.clear();
|
||||
this.is.reset();
|
||||
ZipInputStream zip = new ZipInputStream(this.is);
|
||||
ZipEntry entry;
|
||||
try {
|
||||
while ((entry = zip.getNextEntry()) != null) {
|
||||
if (entry.getName().equals("catalog.xml")) {
|
||||
try {
|
||||
SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||
SAXParser saxParser = factory.newSAXParser();
|
||||
DefaultHandler handler = new DefaultHandler() {
|
||||
|
||||
@Override
|
||||
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
|
||||
if (qName.equalsIgnoreCase("library")) {
|
||||
String path = attributes.getValue("path");
|
||||
if (path != null) {
|
||||
keySet.add(path);
|
||||
}
|
||||
while ((entry = zip.getNextEntry()) != null) {
|
||||
if (entry.getName().equals("catalog.xml")) {
|
||||
try {
|
||||
SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||
SAXParser saxParser = factory.newSAXParser();
|
||||
DefaultHandler handler = new DefaultHandler() {
|
||||
|
||||
@Override
|
||||
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
|
||||
if (qName.equalsIgnoreCase("library")) {
|
||||
String path = attributes.getValue("path");
|
||||
if (path != null) {
|
||||
keySet.add(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
saxParser.parse(zip, handler);
|
||||
} catch (Exception ex) {
|
||||
};
|
||||
saxParser.parse(zip, handler);
|
||||
} catch (Exception ex) {
|
||||
|
||||
}
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(SWC.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -276,6 +276,9 @@ public final class SWF implements SWFContainerItem, Timelined {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(SWF.class.getName());
|
||||
|
||||
@Internal
|
||||
public SWFBundle bundle;
|
||||
|
||||
@Internal
|
||||
private Timeline timeline;
|
||||
|
||||
|
||||
@@ -12,11 +12,13 @@
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
import com.jpexs.helpers.streams.SeekableInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -35,4 +37,9 @@ public interface SWFBundle {
|
||||
public Map<String, SeekableInputStream> getAll() throws IOException;
|
||||
|
||||
public String getExtension();
|
||||
|
||||
public boolean isReadOnly();
|
||||
|
||||
public boolean putSWF(String key,InputStream is) throws IOException;
|
||||
|
||||
}
|
||||
|
||||
@@ -88,14 +88,13 @@ public class SWFSourceInfo {
|
||||
}
|
||||
|
||||
String extension = Path.getExtension(new File(file));
|
||||
InputStream is = new BufferedInputStream(new FileInputStream(file));
|
||||
switch (extension) {
|
||||
case ".swc":
|
||||
return new SWC(is);
|
||||
return new SWC(new File(file));
|
||||
case ".zip":
|
||||
return new ZippedSWFBundle(is);
|
||||
return new ZippedSWFBundle(new File(file));
|
||||
default:
|
||||
return new BinarySWFBundle(is, noCheck, searchMode);
|
||||
return new BinarySWFBundle(new BufferedInputStream(new FileInputStream(file)), noCheck, searchMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,10 @@ import com.jpexs.helpers.Helper;
|
||||
import com.jpexs.helpers.MemoryInputStream;
|
||||
import com.jpexs.helpers.ReReadableInputStream;
|
||||
import com.jpexs.helpers.streams.SeekableInputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
@@ -30,6 +34,7 @@ import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -39,23 +44,39 @@ public class ZippedSWFBundle implements SWFBundle {
|
||||
|
||||
protected Set<String> keySet = new HashSet<>();
|
||||
|
||||
private final Map<String, SeekableInputStream> cachedSWFs = new HashMap<>();
|
||||
|
||||
//private final Map<String, SeekableInputStream> cachedSWFs = new HashMap<>();
|
||||
protected FileInputStream fis;
|
||||
protected ReReadableInputStream is;
|
||||
protected File filename;
|
||||
|
||||
public ZippedSWFBundle(InputStream is) {
|
||||
public ZippedSWFBundle(InputStream is) throws IOException {
|
||||
this(is, null);
|
||||
}
|
||||
|
||||
public ZippedSWFBundle(File filename) throws IOException {
|
||||
this(null, filename);
|
||||
}
|
||||
|
||||
protected ZippedSWFBundle(InputStream is, File filename) throws IOException {
|
||||
initBundle(is, filename);
|
||||
}
|
||||
|
||||
protected void initBundle(InputStream is, File filename) throws IOException {
|
||||
if (filename != null) {
|
||||
fis = new FileInputStream(filename);
|
||||
is = fis;
|
||||
}
|
||||
this.filename = filename;
|
||||
this.is = new ReReadableInputStream(is);
|
||||
ZipInputStream zip = new ZipInputStream(this.is);
|
||||
ZipEntry entry;
|
||||
try {
|
||||
while ((entry = zip.getNextEntry()) != null) {
|
||||
if (entry.getName().toLowerCase().endsWith(".swf")
|
||||
|| entry.getName().toLowerCase().endsWith(".gfx")) {
|
||||
keySet.add(entry.getName());
|
||||
}
|
||||
keySet.clear();
|
||||
|
||||
while ((entry = zip.getNextEntry()) != null) {
|
||||
if (entry.getName().toLowerCase().endsWith(".swf")
|
||||
|| entry.getName().toLowerCase().endsWith(".gfx")) {
|
||||
keySet.add(entry.getName());
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(ZippedSWFBundle.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,38 +95,98 @@ public class ZippedSWFBundle implements SWFBundle {
|
||||
if (!keySet.contains(key)) {
|
||||
return null;
|
||||
}
|
||||
if (!cachedSWFs.containsKey(key)) {
|
||||
//if (!cachedSWFs.containsKey(key)) {
|
||||
SeekableInputStream ret = null;
|
||||
this.is.reset();
|
||||
ZipInputStream zip = new ZipInputStream(this.is);
|
||||
ZipEntry entry;
|
||||
|
||||
this.is.reset();
|
||||
ZipInputStream zip = new ZipInputStream(this.is);
|
||||
ZipEntry entry;
|
||||
try {
|
||||
while ((entry = zip.getNextEntry()) != null) {
|
||||
if (entry.getName().equals(key)) {
|
||||
MemoryInputStream mis = new MemoryInputStream(Helper.readStream(zip));
|
||||
cachedSWFs.put(key, mis);
|
||||
break;
|
||||
}
|
||||
zip.closeEntry();
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(ZippedSWFBundle.class.getName()).log(Level.SEVERE, null, ex);
|
||||
while ((entry = zip.getNextEntry()) != null) {
|
||||
if (entry.getName().equals(key)) {
|
||||
MemoryInputStream mis = new MemoryInputStream(Helper.readStream(zip));
|
||||
ret = mis;
|
||||
//cachedSWFs.put(key, mis);
|
||||
break;
|
||||
}
|
||||
|
||||
zip.closeEntry();
|
||||
}
|
||||
return cachedSWFs.get(key);
|
||||
|
||||
return ret;
|
||||
//return cachedSWFs.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, SeekableInputStream> getAll() throws IOException {
|
||||
Map<String, SeekableInputStream> ret = new HashMap<>();
|
||||
for (String key : getKeys()) { // cache everything first
|
||||
getSWF(key);
|
||||
ret.put(key, getSWF(key));
|
||||
}
|
||||
return cachedSWFs;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExtension() {
|
||||
return "zip";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadOnly() {
|
||||
return this.filename == null || !this.filename.canWrite();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putSWF(String key, InputStream swfIs) throws IOException {
|
||||
if (this.isReadOnly()) {
|
||||
return false;
|
||||
}
|
||||
if (key == null) {
|
||||
return false;
|
||||
}
|
||||
if (!getKeys().contains(key)) { //replace only existing keys
|
||||
return false;
|
||||
}
|
||||
//Write to temp file first
|
||||
File tempFile = new File((filename.getAbsolutePath()) + ".tmp");
|
||||
|
||||
try {
|
||||
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(tempFile));
|
||||
this.is.reset();
|
||||
ZipInputStream zis = new ZipInputStream(this.is);
|
||||
ZipEntry entryIn;
|
||||
ZipEntry entryOut;
|
||||
|
||||
byte swfData[] = Helper.readStream(swfIs);
|
||||
|
||||
try {
|
||||
while ((entryIn = zis.getNextEntry()) != null) {
|
||||
InputStream src;
|
||||
if (entryIn.getName().equals(key)) {
|
||||
entryOut = new ZipEntry(entryIn);
|
||||
entryOut.setSize(swfData.length);
|
||||
src = new ByteArrayInputStream(swfData);
|
||||
} else {
|
||||
src = zis;
|
||||
entryOut = entryIn;
|
||||
}
|
||||
zos.putNextEntry(entryOut);
|
||||
Helper.copyStream(src, zos, entryOut.getSize() == -1 ? Long.MAX_VALUE : entryOut.getSize());
|
||||
}
|
||||
} finally {
|
||||
zis.closeEntry();
|
||||
zis.close();
|
||||
zos.closeEntry();
|
||||
zos.close();
|
||||
}
|
||||
this.is.close();
|
||||
this.fis.close();
|
||||
} catch (IOException ex) {
|
||||
tempFile.delete();
|
||||
throw ex;
|
||||
}
|
||||
filename.delete();
|
||||
tempFile.renameTo(filename);
|
||||
initBundle(null, filename);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.jpexs.decompiler.flash.treeitems;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFBundle;
|
||||
import com.jpexs.decompiler.flash.SWFContainerItem;
|
||||
import com.jpexs.decompiler.flash.SWFSourceInfo;
|
||||
import java.util.ArrayList;
|
||||
@@ -33,9 +34,11 @@ public class SWFList implements List<SWF>, SWFContainerItem {
|
||||
|
||||
public String name;
|
||||
|
||||
public boolean isBundle;
|
||||
//public boolean isBundle;
|
||||
|
||||
public SWFBundle bundle;
|
||||
|
||||
public Class bundleClass;
|
||||
//public Class bundleClass;
|
||||
|
||||
public SWFSourceInfo sourceInfo;
|
||||
|
||||
@@ -48,7 +51,7 @@ public class SWFList implements List<SWF>, SWFContainerItem {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (isBundle) {
|
||||
if (bundle != null) {
|
||||
return name;
|
||||
} else {
|
||||
return swfs.get(0).getFileTitle();
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.jpexs.decompiler.flash.treeitems;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFBundle;
|
||||
|
||||
/**
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user