1 : /******************************************************************************
2 : * $Id: gdaljp2box.cpp 17636 2009-09-12 23:19:18Z warmerdam $
3 : *
4 : * Project: GDAL
5 : * Purpose: GDALJP2Box Implementation - Low level JP2 box reader.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2005, Frank Warmerdam <warmerdam@pobox.com>
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "gdaljp2metadata.h"
31 : #include "cpl_string.h"
32 :
33 : CPL_CVSID("$Id: gdaljp2box.cpp 17636 2009-09-12 23:19:18Z warmerdam $");
34 :
35 : /************************************************************************/
36 : /* GDALJP2Box() */
37 : /************************************************************************/
38 :
39 225 : GDALJP2Box::GDALJP2Box( FILE *fpIn )
40 :
41 : {
42 225 : fpVSIL = fpIn;
43 225 : szBoxType[0] = '\0';
44 225 : nBoxOffset = -1;
45 225 : nDataOffset = -1;
46 225 : nBoxLength = 0;
47 :
48 225 : pabyData = NULL;
49 225 : }
50 :
51 : /************************************************************************/
52 : /* ~GDALJP2Box() */
53 : /************************************************************************/
54 :
55 225 : GDALJP2Box::~GDALJP2Box()
56 :
57 : {
58 225 : CPLFree( pabyData );
59 225 : }
60 :
61 : /************************************************************************/
62 : /* SetOffset() */
63 : /************************************************************************/
64 :
65 456 : int GDALJP2Box::SetOffset( GIntBig nNewOffset )
66 :
67 : {
68 456 : szBoxType[0] = '\0';
69 456 : return VSIFSeekL( fpVSIL, nNewOffset, SEEK_SET ) == 0;
70 : }
71 :
72 : /************************************************************************/
73 : /* ReadFirst() */
74 : /************************************************************************/
75 :
76 82 : int GDALJP2Box::ReadFirst()
77 :
78 : {
79 82 : return SetOffset(0) && ReadBox();
80 : }
81 :
82 : /************************************************************************/
83 : /* ReadNext() */
84 : /************************************************************************/
85 :
86 323 : int GDALJP2Box::ReadNext()
87 :
88 : {
89 323 : return SetOffset( nBoxOffset + nBoxLength ) && ReadBox();
90 : }
91 :
92 : /************************************************************************/
93 : /* ReadFirstChild() */
94 : /************************************************************************/
95 :
96 51 : int GDALJP2Box::ReadFirstChild( GDALJP2Box *poSuperBox )
97 :
98 : {
99 51 : if( !poSuperBox->IsSuperBox() )
100 0 : return FALSE;
101 :
102 51 : return SetOffset( poSuperBox->nDataOffset ) && ReadBox();
103 : }
104 :
105 : /************************************************************************/
106 : /* ReadNextChild() */
107 : /************************************************************************/
108 :
109 68 : int GDALJP2Box::ReadNextChild( GDALJP2Box *poSuperBox )
110 :
111 : {
112 68 : if( !ReadNext() )
113 0 : return FALSE;
114 :
115 68 : if( nBoxOffset >= poSuperBox->nBoxOffset + poSuperBox->nBoxLength )
116 : {
117 34 : szBoxType[0] = '\0';
118 34 : return FALSE;
119 : }
120 :
121 34 : return TRUE;
122 : }
123 :
124 : /************************************************************************/
125 : /* ReadBox() */
126 : /************************************************************************/
127 :
128 456 : int GDALJP2Box::ReadBox()
129 :
130 : {
131 : GUInt32 nLBox;
132 : GUInt32 nTBox;
133 :
134 456 : nBoxOffset = VSIFTellL( fpVSIL );
135 :
136 456 : if( VSIFReadL( &nLBox, 4, 1, fpVSIL ) != 1
137 : || VSIFReadL( &nTBox, 4, 1, fpVSIL ) != 1 )
138 : {
139 54 : return FALSE;
140 : }
141 :
142 402 : memcpy( szBoxType, &nTBox, 4 );
143 402 : szBoxType[4] = '\0';
144 :
145 402 : nLBox = CPL_MSBWORD32( nLBox );
146 :
147 402 : if( nLBox != 1 )
148 : {
149 402 : nBoxLength = nLBox;
150 402 : nDataOffset = nBoxOffset + 8;
151 : }
152 : else
153 : {
154 : GByte abyXLBox[8];
155 0 : if( VSIFReadL( abyXLBox, 8, 1, fpVSIL ) != 1 )
156 0 : return FALSE;
157 :
158 :
159 : if( sizeof(nBoxLength) == 8 )
160 : {
161 0 : CPL_MSBPTR64( abyXLBox );
162 0 : memcpy( &nBoxLength, abyXLBox, 8 );
163 : }
164 : else
165 : {
166 : CPL_MSBPTR32( abyXLBox+4 );
167 : memcpy( &nBoxLength, abyXLBox+4, 4 );
168 : }
169 :
170 0 : nDataOffset = nBoxOffset + 16;
171 : }
172 :
173 402 : if( nBoxLength == 0 )
174 : {
175 50 : VSIFSeekL( fpVSIL, 0, SEEK_END );
176 50 : nBoxLength = VSIFTellL( fpVSIL ) - nBoxOffset;
177 : }
178 :
179 402 : if( EQUAL(szBoxType,"uuid") )
180 : {
181 61 : VSIFReadL( abyUUID, 16, 1, fpVSIL );
182 61 : nDataOffset += 16;
183 : }
184 :
185 402 : return TRUE;
186 : }
187 :
188 : /************************************************************************/
189 : /* IsSuperBox() */
190 : /************************************************************************/
191 :
192 51 : int GDALJP2Box::IsSuperBox()
193 :
194 : {
195 51 : if( EQUAL(GetType(),"asoc") || EQUAL(GetType(),"jp2h") )
196 51 : return TRUE;
197 : else
198 0 : return FALSE;
199 : }
200 :
201 : /************************************************************************/
202 : /* ReadBoxData() */
203 : /************************************************************************/
204 :
205 85 : GByte *GDALJP2Box::ReadBoxData()
206 :
207 : {
208 85 : char *pszData = (char *) CPLMalloc((int)GetDataLength() + 1);
209 :
210 85 : if( (GIntBig) VSIFReadL( pszData, 1, (int)GetDataLength(), fpVSIL )
211 : != GetDataLength() )
212 : {
213 0 : CPLFree( pszData );
214 0 : return NULL;
215 : }
216 :
217 85 : pszData[GetDataLength()] = '\0';
218 :
219 85 : return (GByte *) pszData;
220 : }
221 :
222 : /************************************************************************/
223 : /* GetDataLength() */
224 : /************************************************************************/
225 :
226 583 : GIntBig GDALJP2Box::GetDataLength()
227 : {
228 583 : return nBoxLength - (nDataOffset - nBoxOffset);
229 : }
230 :
231 : /************************************************************************/
232 : /* DumpReadable() */
233 : /************************************************************************/
234 :
235 0 : int GDALJP2Box::DumpReadable( FILE *fpOut )
236 :
237 : {
238 0 : if( fpOut == NULL )
239 0 : fpOut = stdout;
240 :
241 : fprintf( fpOut, " Type=%s, Offset=%d/%d, Data Size=%d",
242 : szBoxType, (int) nBoxOffset, (int) nDataOffset,
243 0 : (int)(nBoxLength - (nDataOffset - nBoxOffset)) );
244 :
245 0 : if( IsSuperBox() )
246 0 : fprintf( fpOut, " (super)" );
247 :
248 0 : fprintf( fpOut, "\n" );
249 0 : if( EQUAL(GetType(),"uuid") )
250 : {
251 0 : char *pszHex = CPLBinaryToHex( 16, GetUUID() );
252 0 : fprintf( fpOut, " UUID=%s", pszHex );
253 :
254 0 : if( EQUAL(pszHex,"B14BF8BD083D4B43A5AE8CD7D5A6CE03") )
255 0 : fprintf( fpOut, " (GeoTIFF)" );
256 0 : if( EQUAL(pszHex,"96A9F1F1DC98402DA7AED68E34451809") )
257 0 : fprintf( fpOut, " (MSI Worldfile)" );
258 0 : CPLFree( pszHex );
259 :
260 0 : fprintf( fpOut, "\n" );
261 : }
262 0 : return 0;
263 : }
264 :
265 : /************************************************************************/
266 : /* SetType() */
267 : /************************************************************************/
268 :
269 92 : void GDALJP2Box::SetType( const char *pszType )
270 :
271 : {
272 : CPLAssert( strlen(pszType) == 4 );
273 :
274 92 : szBoxType[0] = pszType[3];
275 92 : szBoxType[1] = pszType[2];
276 92 : szBoxType[2] = pszType[1];
277 92 : szBoxType[3] = pszType[0];
278 92 : szBoxType[4] = '\0';
279 92 : }
280 :
281 : /************************************************************************/
282 : /* SetWritableData() */
283 : /************************************************************************/
284 :
285 92 : void GDALJP2Box::SetWritableData( int nLength, const GByte *pabyDataIn )
286 :
287 : {
288 92 : CPLFree( pabyData );
289 :
290 92 : pabyData = (GByte *) CPLMalloc(nLength);
291 92 : memcpy( pabyData, pabyDataIn, nLength );
292 :
293 92 : nBoxOffset = -9; // virtual offsets for data length computation.
294 92 : nDataOffset = -1;
295 :
296 92 : nBoxLength = 8 + nLength;
297 92 : }
298 :
299 : /************************************************************************/
300 : /* CreateUUIDBox() */
301 : /************************************************************************/
302 :
303 17 : GDALJP2Box *GDALJP2Box::CreateUUIDBox(
304 : const GByte *pabyUUID, int nDataSize, GByte *pabyData )
305 :
306 : {
307 : GDALJP2Box *poBox;
308 :
309 17 : poBox = new GDALJP2Box();
310 17 : poBox->SetType( "uuid" );
311 17 : memcpy( poBox->abyUUID, pabyUUID, 16 );
312 :
313 17 : GByte *pabyMergedData = (GByte *) CPLMalloc(16+nDataSize);
314 17 : memcpy( pabyMergedData, pabyUUID, 16 );
315 17 : memcpy( pabyMergedData+16, pabyData, nDataSize );
316 :
317 17 : poBox->SetWritableData( 16 + nDataSize, pabyMergedData );
318 :
319 17 : CPLFree( pabyMergedData );
320 :
321 17 : return poBox;
322 : }
323 :
324 : /************************************************************************/
325 : /* CreateAsocBox() */
326 : /************************************************************************/
327 :
328 30 : GDALJP2Box *GDALJP2Box::CreateAsocBox( int nCount, GDALJP2Box **papoBoxes )
329 :
330 :
331 : {
332 30 : int nDataSize=0, iBox;
333 : GByte *pabyCompositeData, *pabyNext;
334 :
335 : /* -------------------------------------------------------------------- */
336 : /* Compute size of data area of asoc box. */
337 : /* -------------------------------------------------------------------- */
338 90 : for( iBox = 0; iBox < nCount; iBox++ )
339 60 : nDataSize += 8 + (int) papoBoxes[iBox]->GetDataLength();
340 :
341 30 : pabyNext = pabyCompositeData = (GByte *) CPLMalloc(nDataSize);
342 :
343 : /* -------------------------------------------------------------------- */
344 : /* Copy subboxes headers and data into buffer. */
345 : /* -------------------------------------------------------------------- */
346 90 : for( iBox = 0; iBox < nCount; iBox++ )
347 : {
348 : GUInt32 nLBox, nTBox;
349 :
350 60 : nLBox = CPL_MSBWORD32(papoBoxes[iBox]->nBoxLength);
351 60 : memcpy( pabyNext, &nLBox, 4 );
352 60 : pabyNext += 4;
353 :
354 60 : memcpy( &nTBox, papoBoxes[iBox]->szBoxType, 4 );
355 60 : nTBox = CPL_MSBWORD32( nTBox );
356 60 : memcpy( pabyNext, &nTBox, 4 );
357 60 : pabyNext += 4;
358 :
359 60 : memcpy( pabyNext, papoBoxes[iBox]->pabyData,
360 120 : (int) papoBoxes[iBox]->GetDataLength() );
361 60 : pabyNext += papoBoxes[iBox]->GetDataLength();
362 : }
363 :
364 : /* -------------------------------------------------------------------- */
365 : /* Create asoc box. */
366 : /* -------------------------------------------------------------------- */
367 30 : GDALJP2Box *poAsoc = new GDALJP2Box();
368 :
369 30 : poAsoc->SetType( "asoc" );
370 30 : poAsoc->SetWritableData( nDataSize, pabyCompositeData );
371 :
372 30 : CPLFree( pabyCompositeData );
373 :
374 30 : return poAsoc;
375 : }
376 :
377 : /************************************************************************/
378 : /* CreateLblBox() */
379 : /************************************************************************/
380 :
381 15 : GDALJP2Box *GDALJP2Box::CreateLblBox( const char *pszLabel )
382 :
383 : {
384 : GDALJP2Box *poBox;
385 :
386 15 : poBox = new GDALJP2Box();
387 15 : poBox->SetType( "lbl " );
388 15 : poBox->SetWritableData( strlen(pszLabel)+1, (const GByte *) pszLabel );
389 :
390 15 : return poBox;
391 : }
392 :
393 : /************************************************************************/
394 : /* CreateLabelledXMLAssoc() */
395 : /************************************************************************/
396 :
397 15 : GDALJP2Box *GDALJP2Box::CreateLabelledXMLAssoc( const char *pszLabel,
398 : const char *pszXML )
399 :
400 : {
401 15 : GDALJP2Box oLabel, oXML;
402 : GDALJP2Box *aoList[2];
403 :
404 15 : oLabel.SetType( "lbl " );
405 15 : oLabel.SetWritableData( strlen(pszLabel)+1, (const GByte *) pszLabel );
406 :
407 15 : oXML.SetType( "xml " );
408 15 : oXML.SetWritableData( strlen(pszXML)+1, (const GByte *) pszXML );
409 :
410 15 : aoList[0] = &oLabel;
411 15 : aoList[1] = &oXML;
412 :
413 15 : return CreateAsocBox( 2, aoList );
414 : }
415 :
|