-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement functionality to extract smgXml file from SMG, edit it, and…
… repackage it. The input SMG file is not a zip archive, for some reason it is an SFX zip. Added a filter input stream to ignore the local headers, enabling us to read the file. The entries are cached and bundled into a fresh zip once the transformations are complete.
- Loading branch information
Showing
3 changed files
with
191 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
83 changes: 83 additions & 0 deletions
83
src/main/java/com/lmco/spectrum/systemnavigation3d/service/SmgService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package com.lmco.spectrum.systemnavigation3d.service; | ||
|
||
import com.amazonaws.util.IOUtils; | ||
import com.lmco.spectrum.systemnavigation3d.util.io.SfxZipInputStream; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import org.springframework.stereotype.Service; | ||
|
||
import javax.annotation.Nullable; | ||
import java.io.ByteArrayInputStream; | ||
import java.io.ByteArrayOutputStream; | ||
import java.io.IOException; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
import java.util.zip.ZipEntry; | ||
import java.util.zip.ZipInputStream; | ||
import java.util.zip.ZipOutputStream; | ||
|
||
@Service | ||
public class SmgService { | ||
|
||
private static final Logger log = LoggerFactory.getLogger(SmgService.class); | ||
private static final String PRODUCT_XML = "product.smgXml"; | ||
|
||
// Max capacity is 2^31-1 bytes or ~2GB. | ||
@Nullable | ||
public byte[] processSmg(byte[] data){ | ||
Map<String, byte[]> entryMap = getSmgXmlEntry(data); | ||
byte[] smgXmlData = entryMap.get(PRODUCT_XML); | ||
if(smgXmlData != null) { | ||
String smgXml = new String(smgXmlData); | ||
// TODO transform | ||
|
||
// Update XML entry. | ||
entryMap.put(PRODUCT_XML, smgXml.getBytes()); | ||
return repackageSmg(entryMap); | ||
} else { | ||
return null; | ||
} | ||
} | ||
|
||
public Map<String, byte[]> getSmgXmlEntry(byte[] data) { | ||
|
||
Map<String, byte[]> entryMap = new HashMap<>(); | ||
|
||
try(ZipInputStream zis = new ZipInputStream(new SfxZipInputStream(new ByteArrayInputStream(data)))) { | ||
|
||
ZipEntry entry; | ||
while((entry = zis.getNextEntry()) != null) { | ||
entryMap.put(entry.getName(), IOUtils.toByteArray(zis)); | ||
zis.closeEntry(); | ||
} | ||
return entryMap; | ||
|
||
} catch (IOException e) { | ||
log.error("Failed to read .smgXml entry!"); | ||
e.printStackTrace(); | ||
} | ||
|
||
return entryMap; | ||
} | ||
|
||
@Nullable | ||
public byte[] repackageSmg(Map<String, byte[]> entryMap) { | ||
ByteArrayOutputStream bos = new ByteArrayOutputStream(); | ||
try (ZipOutputStream zos = new ZipOutputStream(bos)) { | ||
for(Map.Entry<String, byte[]> entry : entryMap.entrySet()) { | ||
ZipEntry zipEntry = new ZipEntry(entry.getKey()); | ||
zos.putNextEntry(zipEntry); | ||
zos.write(entry.getValue()); | ||
zos.closeEntry(); | ||
} | ||
} catch (IOException e) { | ||
log.error("Failed to repackage smg file"); | ||
e.printStackTrace(); | ||
return null; | ||
} | ||
|
||
return bos.toByteArray(); | ||
|
||
} | ||
|
||
} |
46 changes: 46 additions & 0 deletions
46
src/main/java/com/lmco/spectrum/systemnavigation3d/util/io/SfxZipInputStream.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package com.lmco.spectrum.systemnavigation3d.util.io; | ||
|
||
import javax.annotation.Nonnull; | ||
import java.io.FilterInputStream; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
|
||
// Credit | ||
// https://stackoverflow.com/questions/7924895/how-can-i-read-from-a-winzip-self-extracting-exe-zip-file-in-java | ||
public class SfxZipInputStream extends FilterInputStream { | ||
|
||
// https://en.wikipedia.org/wiki/Zip_(file_format)#Local_file_header | ||
public static final byte[] ZIP_LOCAL = { 0x50, 0x4b, 0x03, 0x04 }; | ||
protected int ip; | ||
protected int op; | ||
|
||
public SfxZipInputStream(InputStream is) { | ||
super(is); | ||
} | ||
|
||
@Override | ||
public int read() throws IOException { | ||
while(ip < ZIP_LOCAL.length) { | ||
int c = super.read(); | ||
if (c == ZIP_LOCAL[ip]) { | ||
ip++; | ||
} | ||
else ip = 0; | ||
} | ||
|
||
if (op < ZIP_LOCAL.length) | ||
return ZIP_LOCAL[op++]; | ||
else | ||
return super.read(); | ||
} | ||
|
||
@Override | ||
public int read(@Nonnull byte[] b, int off, int len) throws IOException { | ||
if (op == ZIP_LOCAL.length) return super.read(b, off, len); | ||
int l = 0; | ||
while (l < Math.min(len, ZIP_LOCAL.length)) { | ||
b[l++] = (byte)read(); | ||
} | ||
return l; | ||
} | ||
} |