Changed the loader to pull *.rkt files from zip containers.
[debian/openrocket] / core / src / net / sf / openrocket / file / GeneralRocketLoader.java
1 package net.sf.openrocket.file;
2
3 import java.io.BufferedInputStream;
4 import java.io.IOException;
5 import java.io.InputStream;
6 import java.nio.charset.Charset;
7 import java.util.Arrays;
8 import java.util.zip.GZIPInputStream;
9 import java.util.zip.ZipEntry;
10 import java.util.zip.ZipInputStream;
11
12 import net.sf.openrocket.document.OpenRocketDocument;
13 import net.sf.openrocket.file.openrocket.importt.OpenRocketLoader;
14 import net.sf.openrocket.file.rocksim.importt.RocksimLoader;
15 import net.sf.openrocket.util.ArrayUtils;
16 import net.sf.openrocket.util.TextUtil;
17
18
19 /**
20  * A rocket loader that auto-detects the document type and uses the appropriate
21  * loading.  Supports loading of GZIPed files as well with transparent
22  * uncompression.
23  * 
24  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
25  */
26 public class GeneralRocketLoader extends AbstractRocketLoader {
27         
28         private static final int READ_BYTES = 300;
29         
30         private static final byte[] GZIP_SIGNATURE = { 31, -117 }; // 0x1f, 0x8b
31         private static final byte[] ZIP_SIGNATURE = TextUtil.convertStringToBytes("PK",Charset.forName("US-ASCII"));
32         private static final byte[] OPENROCKET_SIGNATURE = TextUtil.convertStringToBytes("<openrocket",Charset.forName("US-ASCII"));
33         private static final byte[] ROCKSIM_SIGNATURE = TextUtil.convertStringToBytes("<RockSimDoc",Charset.forName("US-ASCII"));
34         
35         private final OpenRocketLoader openRocketLoader = new OpenRocketLoader();
36         
37         private final RocksimLoader rocksimLoader = new RocksimLoader();
38         
39         @Override
40         protected OpenRocketDocument loadFromStream(InputStream source, MotorFinder motorFinder) throws IOException,
41                         RocketLoadException {
42                 
43                 // Check for mark() support
44                 if (!source.markSupported()) {
45                         source = new BufferedInputStream(source);
46                 }
47                 
48                 // Read using mark()
49                 byte[] buffer = new byte[READ_BYTES];
50                 int count;
51                 source.mark(READ_BYTES + 10);
52                 count = source.read(buffer);
53                 source.reset();
54                 
55                 if (count < 10) {
56                         throw new RocketLoadException("Unsupported or corrupt file.");
57                 }
58                 
59                 // Detect the appropriate loader
60                 
61                 // Check for GZIP
62                 if (buffer[0] == GZIP_SIGNATURE[0] && buffer[1] == GZIP_SIGNATURE[1]) {
63                         OpenRocketDocument doc = loadFromStream(new GZIPInputStream(source), motorFinder);
64                         doc.getDefaultStorageOptions().setCompressionEnabled(true);
65                         return doc;
66                 }
67                 
68                 // Check for ZIP (for future compatibility)
69                 if (buffer[0] == ZIP_SIGNATURE[0] && buffer[1] == ZIP_SIGNATURE[1]) {
70                         // Search for entry with name *.ork
71                         ZipInputStream in = new ZipInputStream(source);
72                         while (true) {
73                                 ZipEntry entry = in.getNextEntry();
74                                 if (entry == null) {
75                                         throw new RocketLoadException("Unsupported or corrupt file.");
76                                 }
77                                 if (entry.getName().matches(".*\\.[oO][rR][kK]$")) {
78                                         OpenRocketDocument doc = loadFromStream(in, motorFinder);
79                                         doc.getDefaultStorageOptions().setCompressionEnabled(true);
80                                         return doc;
81                                 } else if ( entry.getName().matches(".*\\.[rR][kK][tT]$")) {
82                                         OpenRocketDocument doc = loadFromStream(in, motorFinder);
83                                         return doc;
84                                 }
85                         }
86                 }
87                 
88                 // Check for OpenRocket
89                 int match = 0;
90                 for (int i = 0; i < count; i++) {
91                         if (buffer[i] == OPENROCKET_SIGNATURE[match]) {
92                                 match++;
93                                 if (match == OPENROCKET_SIGNATURE.length) {
94                                         return loadUsing(source, openRocketLoader, motorFinder);
95                                 }
96                         } else {
97                                 match = 0;
98                         }
99                 }
100                 
101                 byte[] typeIdentifier = ArrayUtils.copyOf(buffer, ROCKSIM_SIGNATURE.length);
102                 if (Arrays.equals(ROCKSIM_SIGNATURE, typeIdentifier)) {
103                         return loadUsing(source, rocksimLoader, motorFinder);
104                 }
105                 throw new RocketLoadException("Unsupported or corrupt file.");
106         }
107         
108         private OpenRocketDocument loadUsing(InputStream source, RocketLoader loader, MotorFinder motorFinder)
109                         throws RocketLoadException {
110                 warnings.clear();
111                 OpenRocketDocument doc = loader.load(source, motorFinder);
112                 warnings.addAll(loader.getWarnings());
113                 return doc;
114         }
115 }