Skip to content

Commit 53eee0a

Browse files
feat: support for 6 version and 5 metadata
1 parent b7c41f2 commit 53eee0a

7 files changed

Lines changed: 52 additions & 83 deletions

File tree

gradle.properties

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
version=1.0.2
2-
zstd_version=1.5.7-3
1+
version=1.0.3
2+
zstd_version=1.5.7-4

src/main/java/dev/donutquine/swf/file/Hasher.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ private Hasher() {
1919
}
2020

2121
public static boolean verifyHash(byte[] data, byte[] hash) {
22-
return Arrays.equals(createHash(data), hash);
22+
return Arrays.equals(calculateHash(data), hash);
2323
}
2424

25-
public static byte[] createHash(byte[] data) {
25+
public static byte[] calculateHash(byte[] data) {
2626
return MD5.digest(data);
2727
}
2828
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
package dev.donutquine.swf.file;
22

3-
public record ScFileInfo(int version, byte[] data) {
3+
public record ScFileInfo(int version, int flagsMaybe, byte[] data) {
44
}

src/main/java/dev/donutquine/swf/file/ScFilePacker.java

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@
99
import java.io.IOException;
1010

1111
public final class ScFilePacker {
12-
private static final byte[] LZMA_PROPERTIES = new byte[]{0x5d, 0x00, 0x00, 0x04, 0x00};
13-
1412
private static final int SC_MAGIC = 0x5343;
1513

1614
private ScFilePacker() {
@@ -22,32 +20,35 @@ public static byte[] pack(byte[] data, byte[] metadata, int version) throws IOEx
2220

2321
dos.writeShort(SC_MAGIC);
2422

25-
dos.writeInt(version);
26-
if (version == 4) {
27-
version = 1;
23+
if (version < 5) {
2824
dos.writeInt(version);
25+
if (version == 4) {
26+
version = 1;
27+
dos.writeInt(version);
28+
}
29+
} else {
30+
dos.writeInt(Integer.reverseBytes(version));
2931
}
3032

3133
if (version < 5) {
32-
byte[] hash = Hasher.createHash(data);
34+
byte[] hash = Hasher.calculateHash(data);
3335

3436
dos.writeInt(hash.length);
3537
dos.write(hash);
3638
} else {
39+
if (version == 6) {
40+
dos.writeShort(0);
41+
}
42+
3743
dos.writeInt(metadata.length);
3844
dos.write(metadata);
3945
}
4046

4147
switch (version) {
4248
case 1 -> {
43-
dos.write(LZMA_PROPERTIES);
44-
for (int i = 0; i < 4; i++) {
45-
dos.writeByte((data.length >> (8 * i)) & 0xFF);
46-
}
47-
4849
dos.write(Lzma.compress(data));
4950
}
50-
case 2, 3, 5 -> dos.write(Zstandard.compress(data));
51+
case 2, 3, 5, 6 -> dos.write(Zstandard.compress(data));
5152
default ->
5253
throw new UnknownFileVersionException("Unknown file version: " + version);
5354
}

src/main/java/dev/donutquine/swf/file/ScFileUnpacker.java

Lines changed: 24 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,18 @@
1010
import java.io.ByteArrayInputStream;
1111
import java.io.DataInputStream;
1212
import java.io.IOException;
13+
import java.util.Arrays;
1314

1415
public final class ScFileUnpacker {
1516
private static final int SC_MAGIC = 0x5343;
16-
private static final int FIVE_LITTLE_ENDIAN = swapEndian32(5);
17-
private static final byte[] START_SECTION_BYTES = {'S', 'T', 'A', 'R', 'T'};
1817

1918
private ScFileUnpacker() {
2019
}
2120

2221
public static ScFileInfo unpack(byte[] compressedData) throws UnknownFileVersionException, IOException, FileVerificationException {
2322
DataInputStream stream = createDataInputStreamFromBytes(compressedData);
2423

25-
checkMagic(stream);
24+
verifyMagic(stream);
2625

2726
byte[] hash = null;
2827

@@ -32,9 +31,18 @@ public static ScFileInfo unpack(byte[] compressedData) throws UnknownFileVersion
3231
int hashLength = stream.readInt();
3332
hash = readBytes(hashLength, stream);
3433
}
35-
case 5 -> {
36-
int metadataRootTableOffset = swapEndian32(stream.readInt());
37-
skipBytes(stream, metadataRootTableOffset);
34+
// Note: returns compressed data to allow user parse metadata and other compressed chunks
35+
case 5, 6 -> {
36+
int flagsMaybe;
37+
if (version == 6) {
38+
flagsMaybe = Short.reverseBytes(stream.readShort()) & 0xFFFF;
39+
} else {
40+
flagsMaybe = 0; // TODO: ?
41+
}
42+
43+
byte[] data = Arrays.copyOfRange(compressedData, compressedData.length - stream.available(), compressedData.length);
44+
45+
return new ScFileInfo(version, flagsMaybe, data);
3846
}
3947
}
4048

@@ -44,25 +52,20 @@ public static ScFileInfo unpack(byte[] compressedData) throws UnknownFileVersion
4452
throw new HashVerificationException("Decompressed data hash doesn't equal to hash from file");
4553
}
4654

47-
return new ScFileInfo(version, decompressed);
55+
return new ScFileInfo(version, 0, decompressed);
4856
}
4957

5058
private static byte[] decompress(byte[] compressedData, int version, DataInputStream stream) throws IOException, UnknownFileVersionException {
5159
byte[] decompressed;
5260

5361
switch (version) {
5462
case 1 -> decompressed = Lzma.decompress(stream);
55-
case 2, 3, 5 -> {
63+
case 2, 3 -> {
5664
int offset = compressedData.length - stream.available();
57-
int startSectionOffset = indexOf(compressedData, START_SECTION_BYTES);
58-
if (startSectionOffset != -1) {
59-
decompressed = Zstandard.decompress(compressedData, offset, startSectionOffset - offset);
60-
} else {
61-
decompressed = Zstandard.decompress(compressedData, offset);
62-
}
65+
decompressed = Zstandard.decompress(compressedData, offset);
6366
}
6467
default ->
65-
throw new UnknownFileVersionException("Unknown file version: " + version);
68+
throw new UnknownFileVersionException("Unsupported file version: " + version);
6669
}
6770

6871
return decompressed;
@@ -78,7 +81,7 @@ private static byte[] readBytes(int hashLength, DataInputStream stream) throws I
7881
return data;
7982
}
8083

81-
private static void checkMagic(DataInputStream stream) throws IOException, WrongFileMagicException {
84+
private static void verifyMagic(DataInputStream stream) throws IOException, WrongFileMagicException {
8285
int magic = stream.readShort();
8386
if (magic != SC_MAGIC) {
8487
throw new WrongFileMagicException("Unknown file magic: " + magic);
@@ -90,42 +93,15 @@ private static int parseVersion(DataInputStream stream) throws IOException {
9093
if (version == 4) {
9194
version = stream.readInt();
9295
}
93-
if (version == FIVE_LITTLE_ENDIAN) {
94-
version = 5;
95-
}
96-
return version;
97-
}
9896

99-
private static DataInputStream createDataInputStreamFromBytes(byte[] compressedData) {
100-
return new DataInputStream(new ByteArrayInputStream(compressedData));
101-
}
102-
103-
private static void skipBytes(DataInputStream stream, int bytesToBeSkipped) throws IOException {
104-
long actualSkipped = stream.skip(bytesToBeSkipped);
105-
if (actualSkipped != bytesToBeSkipped) {
106-
throw new IllegalStateException("The number of bytes skipped is not equal to the requested number of bytes: " + actualSkipped + " vs " + bytesToBeSkipped);
97+
if (version <= 4) {
98+
return version;
10799
}
108-
}
109100

110-
private static int swapEndian32(int metadataRootTableOffset) {
111-
return (metadataRootTableOffset >> 24) & 0xFF | (((metadataRootTableOffset >> 16) & 0xFF) << 8) | (((metadataRootTableOffset >> 8) & 0xFF) << 16) | ((metadataRootTableOffset & 0xFF) << 24);
101+
return Integer.reverseBytes(version);
112102
}
113103

114-
private static int indexOf(byte[] array, byte[] bytesToFind) {
115-
for (int i = 0; i < array.length; i++) {
116-
boolean found = true;
117-
for (int j = 0; j < bytesToFind.length; j++) {
118-
if (array[i+j] != bytesToFind[j]) {
119-
found = false;
120-
break;
121-
}
122-
}
123-
124-
if (found) {
125-
return i;
126-
}
127-
}
128-
129-
return -1;
104+
private static DataInputStream createDataInputStreamFromBytes(byte[] compressedData) {
105+
return new DataInputStream(new ByteArrayInputStream(compressedData));
130106
}
131107
}

src/main/java/dev/donutquine/swf/file/compression/Lzma.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
import java.io.IOException;
1010

1111
public final class Lzma {
12+
private static final int UNCOMPRESSED_SIZE_LENGTH = 4;
13+
1214
private Lzma() {
1315
}
1416

@@ -19,7 +21,7 @@ public static byte[] decompress(DataInputStream stream) throws IOException {
1921
decoder.setDecoderProperties(decoderProperties);
2022

2123
int outSize = 0;
22-
for (int i = 0; i < 4; i++) {
24+
for (int i = 0; i < UNCOMPRESSED_SIZE_LENGTH; i++) {
2325
outSize |= (stream.read() & 0xFF) << (i * 8);
2426
}
2527

@@ -34,6 +36,10 @@ public static byte[] compress(byte[] data) throws IOException {
3436
ByteArrayOutputStream outputArray = new ByteArrayOutputStream();
3537

3638
Encoder encoder = new Encoder();
39+
encoder.writeCoderProperties(outputArray);
40+
for (int i = 0; i < UNCOMPRESSED_SIZE_LENGTH; i++) {
41+
outputArray.write((data.length >> (8 * i)) & 0xFF);
42+
}
3743
encoder.code(byteArrayInputStream, outputArray, null);
3844

3945
return outputArray.toByteArray();

src/main/java/dev/donutquine/swf/file/compression/Zstandard.java

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,9 @@ private Zstandard() {
77
}
88

99
public static byte[] decompress(byte[] compressedData, int offset) {
10-
return decompress(compressedData, offset, compressedData.length - offset);
11-
}
12-
13-
public static byte[] decompress(byte[] compressedData, int offset, int length) {
14-
int decompressedSize = (int) Zstd.getFrameContentSize(compressedData, offset, length);
15-
16-
byte[] zstdContent;
17-
if (offset > 0 || length != compressedData.length - offset) {
18-
zstdContent = new byte[length];
19-
System.arraycopy(compressedData, offset, zstdContent, 0, zstdContent.length);
20-
} else {
21-
zstdContent = compressedData;
22-
}
23-
24-
return Zstd.decompress(
25-
zstdContent,
26-
decompressedSize
10+
return Zstd.decompressFrame(
11+
compressedData,
12+
offset
2713
);
2814
}
2915

0 commit comments

Comments
 (0)