forked from isuftin/geo-data-portal
/
GeoTIFFParser.java
148 lines (133 loc) · 5.31 KB
/
GeoTIFFParser.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package gov.usgs.cida.gdp.wps.parser;
import gov.usgs.cida.gdp.constants.AppConstant;
import gov.usgs.cida.gdp.wps.binding.GeoTIFFFileBinding;
import gov.usgs.cida.gdp.wps.util.GeoTIFFUtil;
import gov.usgs.cida.gdp.wps.util.MIMEMultipartStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.FileChannel;
import java.util.Map;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.n52.wps.io.datahandler.parser.AbstractParser;
public class GeoTIFFParser extends AbstractParser {
public final static short TIFF_MAGIC_LE = 0x4949; // "II"
public final static short TIFF_MAGIC_BE = 0x4D4D; // "MM"
public final static short TIFF_MAGIC_42 = 42;
public final static short MIME_MAGIC = 0x2D2D; // "--"
public GeoTIFFParser() {
supportedIDataTypes.add(GeoTIFFFileBinding.class);
}
@Override
public GeoTIFFFileBinding parse(InputStream inputStream, String mimeType, String schema) {
File tempFile = null;
FileChannel tempChannel = null;
try {
tempFile = File.createTempFile(getClass().getSimpleName(), ".tmp", new File(AppConstant.WORK_LOCATION.getValue()));
FileUtils.copyInputStreamToFile(inputStream, tempFile);
ByteBuffer buffer = ByteBuffer.allocate(4 + MIMEMultipartStream.MAX_BOUNDARY_LENGTH);
tempChannel = new FileInputStream(tempFile).getChannel();
tempChannel.read(buffer);
tempChannel.close();
tempChannel = null;
short magic01 = buffer.getShort();
if (magic01 == TIFF_MAGIC_LE || magic01 == TIFF_MAGIC_BE) {
// InputStream references a GeoTIFF image
short magic23 = magic01 == TIFF_MAGIC_LE
? buffer.order(ByteOrder.LITTLE_ENDIAN).getShort()
: buffer.getShort();
if (magic23 == TIFF_MAGIC_42) {
String tiffFileName = tempFile.getAbsolutePath().concat(".tiff");
File tiffFile = new File(tempFile.getAbsolutePath());
boolean status = tiffFile.renameTo(new File(tiffFileName));
if (status) {
return new GeoTIFFFileBinding(tiffFile);
} else {
throw new RuntimeException("Error generating temporary tiff file.");
}
} else {
throw new RuntimeException("Unexpected value parsing tiff file.");
}
} else if (magic01 == MIME_MAGIC) {
// InputStream references a GeoTIFF image encoded in a multipart mime response.
// this is tricky because if we were given an input stream as a result
// of a URL call the header for the mime response is missing. the input stream
// be positioned at the beginning of the '--' part bounary, we read it so that
// we can pass the boundary to the multipart stream parser. This code doesn't
// expect a full mime response header...
byte[] boundary = extractBoundaryFromBuffer(buffer);
if (boundary != null) {
File tiffFile = extractFromMIMEMultipartStream(tempFile, boundary);
if (tiffFile != null) {
return new GeoTIFFFileBinding(tiffFile);
} else {
throw new RuntimeException("unable to extract tiff file from mime-multipart stream");
}
} else {
throw new RuntimeException("unable to extract boundary from mime-multipart stream");
}
} else {
throw new RuntimeException("unknown content");
}
} catch (IOException e) {
throw new RuntimeException("Error extracting GeoTIFF", e);
} finally {
if (tempChannel != null) {
try { tempChannel.close(); } catch (IOException ex) { }
}
if (tempFile != null && tempFile.exists()) {
tempFile.delete();
}
}
}
private byte[] extractBoundaryFromBuffer(ByteBuffer buffer) {
ByteArrayOutputStream boundaryOutputStream = new ByteArrayOutputStream();
boolean foundCRLF = false;
while (buffer.hasRemaining() && !foundCRLF) {
byte b = buffer.get();
if (b == MIMEMultipartStream.CR) {
b = buffer.get();
}
if (b == MIMEMultipartStream.LF) {
foundCRLF = true;
} else {
boundaryOutputStream.write(b);
}
}
return foundCRLF
? boundaryOutputStream.toByteArray()
: null;
}
private File extractFromMIMEMultipartStream(File tempFile, byte[] boundary) throws IOException {
File extractedFile = null;
FileInputStream tempFileInputStream = null;
try {
MIMEMultipartStream mimeMultipartStream = new MIMEMultipartStream(
new FileInputStream(tempFile), boundary);
mimeMultipartStream.skipPreamble();
boolean hasNext = true;
while (hasNext && extractedFile == null) {
Map<String, String> headerMap = mimeMultipartStream.readHeaders();
String contentType = headerMap.get("Content-Type");
if (GeoTIFFUtil.isAllowedMimeType(contentType)) {
String extractedFileName = tempFile.getAbsolutePath().concat(".tiff");
extractedFile = new File(extractedFileName);
String contentTransferEncoding = headerMap.get("Content-Transfer-Encoding");
mimeMultipartStream.readBodyData(new FileOutputStream(extractedFile), contentTransferEncoding);
} else {
mimeMultipartStream.discardBodyData();
}
hasNext = mimeMultipartStream.readBoundary();
}
} finally {
IOUtils.closeQuietly(tempFileInputStream);
}
return extractedFile;
}
}