Skip to content

Commit 3b0d7ab

Browse files
committed
Add some leniency to content validation
Based on some strange but apparently still valid .unitypackage files.
1 parent dfd0e2e commit 3b0d7ab

File tree

10 files changed

+68
-53
lines changed

10 files changed

+68
-53
lines changed

README.md

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,14 @@ I didn't read any specification (assuming there is one). There could certainly b
4141
# The `.unitypackage` file format
4242

4343
A `.unitypackage` is just a compressed TAR archive.
44-
Inside it contains several root directories.
45-
Each directory name is a GUID.
44+
Inside it contains several root directories (in most cases).
45+
Each directory name is a GUID (in most cases).
4646

4747
![](.github/tar-directories.png?raw=true)
4848

4949

5050
Inside each of them is the contents of the asset with that GUID.
51-
Specifically, each GUID directory contains some of these 4 files.
51+
Specifically, each GUID directory contains some of these 4 files (among others).
5252

5353
![](.github/tar-directory-contents.png?raw=true)
5454

@@ -70,15 +70,14 @@ As shown in this tool:
7070

7171
# Existing open source tools I found
7272

73-
### https://gist.github.com/yasirkula/dfc43134fbfefb820d0adbc5d7c25fb3
73+
https://gist.github.com/yasirkula/dfc43134fbfefb820d0adbc5d7c25fb3 A very nice Unity script to explore `.unitypackage`s
7474

75-
A very nice Unity script to explore `.unitypackages`.
75+
https://github.com/Switch-9867/UnitypackgeExtractor C# command-line tool
7676

77-
### https://github.com/Switch-9867/UnitypackgeExtractor
77+
https://github.com/ntrf/UnityUnpack Haxe command-line tool
7878

79-
C# command-line tool.
79+
https://github.com/Cobertos/unitypackage_extractor Python command-line tool. Its associated pypi package at https://pypi.org/project/unitypackage-extractor/
8080

81-
### https://github.com/Cobertos/unitypackage_extractor
82-
83-
Python command-line tool. Its associated pypi package at https://pypi.org/project/unitypackage-extractor/
81+
https://github.com/FatihBAKIR/UnityPacker C# "Create unitypackages without unity, from command line"
8482

83+
https://github.com/ngyewch/UnityPackager Java library and command line tools to manipulate .unitypackage files.

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<modelVersion>4.0.0</modelVersion>
44
<groupId>m35-projects</groupId>
55
<artifactId>unity-package-viewer</artifactId>
6-
<version>0.0.2</version>
6+
<version>0.0.3</version>
77
<packaging>jar</packaging>
88
<properties>
99
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

src/main/java/unitypackage/model/UnityAsset.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
import java.util.Date;
2525

2626
/**
27-
* An asset as it would appear in the tree of stuff you see when you import a .unitypackage into unity.
27+
* An asset as it would appear in the tree of stuff you see when you import a .unitypackage into Unity.
2828
* This could be a directory or a file.
2929
*/
3030
public class UnityAsset {
@@ -51,6 +51,9 @@ public String getFileName() {
5151
return getFileNameAsPath().toString();
5252
}
5353

54+
/**
55+
* Returns -1 if the asset is not a file.
56+
*/
5457
public long getSize() {
5558
return source.getAsset_fileSize();
5659
}
@@ -63,10 +66,17 @@ public String getDirectoryGuid() {
6366
return source.getGuidBaseDirectory();
6467
}
6568

69+
/**
70+
* May be null.
71+
*/
6672
public BufferedImage getPreview() {
6773
return source.getPreview();
6874
}
6975

76+
/**
77+
* In the .unitypackage, the originating directory does not contain a file named "asset",
78+
* which probably means it represents a directory (in practice this seems to be the case).
79+
*/
7080
public boolean isProbablyDirectory() {
7181
return source.getRawPathTo_asset_file() == null;
7282
}

src/main/java/unitypackage/model/UnityAssetBuilder.java

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020

2121
import java.awt.image.BufferedImage;
2222
import java.io.BufferedReader;
23-
import java.io.File;
2423
import java.io.IOException;
2524
import java.io.InputStream;
2625
import java.io.InputStreamReader;
@@ -34,13 +33,14 @@
3433

3534
/**
3635
* Collects information about the files inside one directory in the .unitypackage tar file.
36+
* Each directory in the .unitypackage tar file represents one asset file or directory that appears in Unity.
3737
*/
3838
class UnityAssetBuilder {
3939

40-
private static final boolean STRICT = false;
40+
private static final boolean STRICT_DIRECTORY_GUID = false;
4141

4242
/**
43-
* The directory name, which is also the GUID of the asset.
43+
* The directory name, which is also usually the GUID of the asset.
4444
*/
4545
private final String guidBaseDirectory;
4646

@@ -128,8 +128,8 @@ public void assertGuidMatchesDirectoryName(String directoryGuidName) {
128128
}
129129
}
130130

131-
public void addFileFoundInDirectory(String directoryGuidName, String fileName, TarArchiveEntry tarEntry,
132-
TarArchiveInputStream tarInputStream) throws IOException {
131+
final public void addFileFoundInDirectory(String directoryGuidName, String fileName, TarArchiveEntry tarEntry,
132+
TarArchiveInputStream tarInputStream) throws IOException {
133133

134134
assertGuidMatchesDirectoryName(directoryGuidName);
135135

@@ -142,9 +142,9 @@ public void addFileFoundInDirectory(String directoryGuidName, String fileName, T
142142
case "asset.meta":
143143
asset_meta_guid = findGuidIn_asset_meta_File(tarEntry, tarInputStream);
144144
if (!asset_meta_guid.equals(guidBaseDirectory)) {
145-
// Usually the directory guid matches the guid in the asset.meta file, but not always
146-
String s = "Corrupted .unitypackage? directory guid" + " " + guidBaseDirectory + " != " + "asset.meta guid " + asset_meta_guid;
147-
if (STRICT) {
145+
// Usually the directory guid matches the guid in the asset.meta file, but not always it seems
146+
String s = "[WARN] Corrupted .unitypackage? directory guid " + guidBaseDirectory + " != asset.meta guid " + asset_meta_guid;
147+
if (STRICT_DIRECTORY_GUID) {
148148
throw new RuntimeException(s);
149149
} else {
150150
System.out.println(s);
@@ -157,8 +157,11 @@ public void addFileFoundInDirectory(String directoryGuidName, String fileName, T
157157
case "preview.png":
158158
_preview = ImageIO.read(tarInputStream);
159159
break;
160+
case "metaData":
161+
System.out.println("[WARN] Found metaData file \"" + tarEntry.getName() + "\"");
162+
break;
160163
default:
161-
throw new RuntimeException("File name not recognized " + tarEntry.getName());
164+
throw new RuntimeException("[ERROR] File name not recognized in tar file \"" + tarEntry.getName() + "\"");
162165
}
163166
}
164167

@@ -189,7 +192,7 @@ private static String readFirstLine(TarArchiveEntry tarEntry, InputStream inputS
189192
if (lines.size() == 2 && "00".equals(lines.get(1))) {
190193
// Sometimes there's a second line with "00"?
191194
} else if (lines.size() != 1) {
192-
throw new RuntimeException(tarEntry.getName() + ": File expected to have 1 line, but found " + lines.size() + " lines: " + lines);
195+
System.out.println("[WARN] \"" + tarEntry.getName() + ": File expected to have 1 line, but found " + lines.size() + " lines: " + lines);
193196
}
194197

195198
return lines.get(0);

src/main/java/unitypackage/model/UnityPackage.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ public UnityPackage(File unitypackageFile) throws IOException {
8888

8989
if (isDirectory) {
9090
if (rawPathParent != null) {
91-
throw new RuntimeException("Found nested directory " + rawFilePathString);
91+
throw new RuntimeException("Found nested directory \"" + rawFilePathString + "\"");
9292
}
9393
guidDirectory = rawPath.toString();
9494
fileName = null;
@@ -104,7 +104,7 @@ public UnityPackage(File unitypackageFile) throws IOException {
104104
// For now ignore it
105105
continue;
106106
} else {
107-
throw new RuntimeException("Found nested directory " + rawFilePathString);
107+
throw new RuntimeException("Found nested directory \"" + rawFilePathString + "\"");
108108
}
109109
}
110110

src/main/java/unitypackage/viewer/Main.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,11 @@
3131
import unitypackage.model.UnityAsset;
3232
import unitypackage.model.UnityPackage;
3333
import unitypackage.viewer.gui.MainWindow;
34-
import unitypackage.viewer.gui.UnitypackageFileName;
3534

3635
public class Main {
3736

3837
private static final String VERSION_PROPERTY_FILE = "app.properties";
39-
public static String DEVELOPMENT_VERSION = "(development)";
38+
private static final String DEVELOPMENT_VERSION = "(development)";
4039
public static String VERSION = DEVELOPMENT_VERSION;
4140

4241
private static final String EXTRACT_ALL_COMMAND = "--extract-all";
@@ -92,9 +91,6 @@ public static void main(String[] args) throws IOException {
9291

9392
private static void extractAll(String fileToOpen) throws IOException {
9493
File file = new File(fileToOpen);
95-
if (!UnitypackageFileName.isUnitypackage(file)) {
96-
System.out.println("File \""+fileToOpen+"\" doesn't have a normal unitypackage file name.");
97-
}
9894

9995
UnityPackage unityPackage = new UnityPackage(file);
10096
try (UnityArchiveInputStream unityIS = unityPackage.getUnityArchiveInputStream()) {

src/main/java/unitypackage/viewer/gui/HistoryIni.java

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,16 @@
1818

1919
package unitypackage.viewer.gui;
2020

21-
import java.io.BufferedReader;
2221
import java.io.File;
23-
import java.io.FileInputStream;
2422
import java.io.FileNotFoundException;
2523
import java.io.FileOutputStream;
26-
import java.io.InputStreamReader;
24+
import java.io.IOException;
2725
import java.io.PrintStream;
2826
import java.nio.charset.StandardCharsets;
29-
import java.util.ArrayList;
27+
import java.nio.file.Files;
28+
import java.nio.file.Paths;
29+
import java.util.Collections;
3030
import java.util.List;
31-
import java.util.stream.Collectors;
3231

3332
/**
3433
* Just stores the last .unitypackage file that was opened.
@@ -42,7 +41,8 @@ public static void addLastFile(File file) {
4241
try (PrintStream p = new PrintStream(new FileOutputStream(INI_FILE))) {
4342
p.println(file.toString());
4443
} catch (FileNotFoundException ex) {
45-
System.out.println("Unable to save " + INI_FILE);
44+
System.out.println("[ERROR] Unable to save " + INI_FILE);
45+
ex.printStackTrace(System.out);
4646
}
4747
}
4848

@@ -59,14 +59,10 @@ public static File getLastDirectory() {
5959

6060
private static List<String> getLastFiles() {
6161
try {
62-
List<String> text = new BufferedReader(
63-
new InputStreamReader(new FileInputStream(INI_FILE), StandardCharsets.UTF_8))
64-
.lines()
65-
.collect(Collectors.toList());
66-
return text;
67-
} catch (FileNotFoundException ex) {
68-
ex.printStackTrace();
69-
return new ArrayList<>();
62+
return Files.readAllLines(Paths.get(INI_FILE), StandardCharsets.UTF_8);
63+
} catch (IOException ex) {
64+
ex.printStackTrace(System.out);
65+
return Collections.emptyList();
7066
}
7167
}
7268

src/main/java/unitypackage/viewer/gui/MainWindow.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,13 @@ public synchronized void drop(DropTargetDropEvent evt) {
7676
List<File> droppedFiles = (List<File>)evt.getTransferable().getTransferData(DataFlavor.javaFileListFlavor);
7777
if (droppedFiles.size() == 1) {
7878
File f = droppedFiles.get(0);
79-
if (UnitypackageFileName.isUnitypackage(f)) {
79+
if (f.isFile()) {
8080
openFile(f);
8181
} else {
82-
System.out.println("Weird file name " + droppedFiles);
82+
System.out.println("File \""+f+"\" is not a file.");
8383
}
8484
} else {
85-
System.out.println("Weird # of files " + droppedFiles);
85+
System.out.println("Only drop 1 file instead of "+droppedFiles.size()+": " + droppedFiles);
8686
}
8787
} catch (UnsupportedFlavorException | IOException ex) {
8888
ex.printStackTrace();
@@ -150,8 +150,10 @@ public void componentShown(ComponentEvent e) {
150150

151151
if (fileToOpen != null) {
152152
File file = new File(fileToOpen);
153-
if (UnitypackageFileName.isUnitypackage(file)) {
153+
if (file.isFile()) {
154154
openFile(file);
155+
} else {
156+
System.out.println("File \""+fileToOpen+"\" is not a file.");
155157
}
156158
}
157159
}

src/main/java/unitypackage/viewer/gui/UnitypackageFileName.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,13 @@
2424
public class UnitypackageFileName {
2525

2626
public static boolean isUnitypackage(File file) {
27-
return file.isFile() && isUnitypackage(file.getName());
27+
return file.isFile() && hasUnitypackageExtension(file.getName());
2828
}
2929

30-
public static boolean isUnitypackage(String fileName) {
31-
return fileName.toLowerCase().endsWith(".unitypackage");
30+
public static boolean hasUnitypackageExtension(String fileName) {
31+
final String lowerCase = fileName.toLowerCase();
32+
return lowerCase.endsWith(".unitypackage") ||
33+
lowerCase.endsWith(".gz");
3234
}
3335

3436
public static class UnitypackageFileFilter extends FileFilter {

src/main/java/unitypackage/viewer/gui/model/UnityTreeNode.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ public String toString() {
173173
} else {
174174
// I've seen some .unitypackage where directories get their own GUID and associated data.
175175
// I've also seen some where directories have no GUID, but are implied to exist by the asset paths.
176-
sb.append(" <i><font color=#ffaaaa>{missing directory .meta}</font></i>");
176+
sb.append(" <i><font color=#ffaaaa>{missing directory asset.meta}</font></i>");
177177
}
178178

179179
sb.append("</html>");
@@ -243,8 +243,15 @@ public String getStringForSearchingAndSorting() {
243243
*/
244244
@Override
245245
public String toString() {
246-
String s = String.format("<html>%s <font color=#bbbbbb>(%,d bytes) <i>{%s}</i> %s</font></html>",
247-
getAssetName(), getAssetSize(), getGuid(), getDateModified());
246+
String guid = getGuid();
247+
if (guid == null) {
248+
guid = "<font color=#ffaaaa>{missing asset.meta}</font>";
249+
} else {
250+
guid = "{"+guid+"}";
251+
}
252+
253+
String s = String.format("<html>%s <font color=#bbbbbb>(%,d bytes) <i>%s</i> %s</font></html>",
254+
getAssetName(), getAssetSize(), guid, getDateModified());
248255
return s;
249256
}
250257

0 commit comments

Comments
 (0)