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