1 : /******************************************************************************
2 : * $Id: gdaljp2box.cpp 24227 2012-04-13 20:55:20Z rouault $
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 24227 2012-04-13 20:55:20Z rouault $");
34 :
35 : /************************************************************************/
36 : /* GDALJP2Box() */
37 : /************************************************************************/
38 :
39 475 : GDALJP2Box::GDALJP2Box( VSILFILE *fpIn )
40 :
41 : {
42 475 : fpVSIL = fpIn;
43 475 : szBoxType[0] = '\0';
44 475 : nBoxOffset = -1;
45 475 : nDataOffset = -1;
46 475 : nBoxLength = 0;
47 :
48 475 : pabyData = NULL;
49 475 : }
50 :
51 : /************************************************************************/
52 : /* ~GDALJP2Box() */
53 : /************************************************************************/
54 :
55 475 : GDALJP2Box::~GDALJP2Box()
56 :
57 : {
58 475 : CPLFree( pabyData );
59 475 : }
60 :
61 : /************************************************************************/
62 : /* SetOffset() */
63 : /************************************************************************/
64 :
65 1150 : int GDALJP2Box::SetOffset( GIntBig nNewOffset )
66 :
67 : {
68 1150 : szBoxType[0] = '\0';
69 1150 : return VSIFSeekL( fpVSIL, nNewOffset, SEEK_SET ) == 0;
70 : }
71 :
72 : /************************************************************************/
73 : /* ReadFirst() */
74 : /************************************************************************/
75 :
76 143 : int GDALJP2Box::ReadFirst()
77 :
78 : {
79 143 : return SetOffset(0) && ReadBox();
80 : }
81 :
82 : /************************************************************************/
83 : /* ReadNext() */
84 : /************************************************************************/
85 :
86 828 : int GDALJP2Box::ReadNext()
87 :
88 : {
89 828 : return SetOffset( nBoxOffset + nBoxLength ) && ReadBox();
90 : }
91 :
92 : /************************************************************************/
93 : /* ReadFirstChild() */
94 : /************************************************************************/
95 :
96 179 : int GDALJP2Box::ReadFirstChild( GDALJP2Box *poSuperBox )
97 :
98 : {
99 179 : szBoxType[0] = '\0';
100 179 : if( !poSuperBox->IsSuperBox() )
101 0 : return FALSE;
102 :
103 179 : return SetOffset( poSuperBox->nDataOffset ) && ReadBox();
104 : }
105 :
106 : /************************************************************************/
107 : /* ReadNextChild() */
108 : /************************************************************************/
109 :
110 341 : int GDALJP2Box::ReadNextChild( GDALJP2Box *poSuperBox )
111 :
112 : {
113 341 : if( !ReadNext() )
114 0 : return FALSE;
115 :
116 341 : if( nBoxOffset >= poSuperBox->nBoxOffset + poSuperBox->nBoxLength )
117 : {
118 148 : szBoxType[0] = '\0';
119 148 : return FALSE;
120 : }
121 :
122 193 : return TRUE;
123 : }
124 :
125 : /************************************************************************/
126 : /* ReadBox() */
127 : /************************************************************************/
128 :
129 1150 : int GDALJP2Box::ReadBox()
130 :
131 : {
132 : GUInt32 nLBox;
133 : GUInt32 nTBox;
134 :
135 1150 : nBoxOffset = VSIFTellL( fpVSIL );
136 :
137 1150 : if( VSIFReadL( &nLBox, 4, 1, fpVSIL ) != 1
138 : || VSIFReadL( &nTBox, 4, 1, fpVSIL ) != 1 )
139 : {
140 94 : return FALSE;
141 : }
142 :
143 1056 : memcpy( szBoxType, &nTBox, 4 );
144 1056 : szBoxType[4] = '\0';
145 :
146 1056 : nLBox = CPL_MSBWORD32( nLBox );
147 :
148 1056 : if( nLBox != 1 )
149 : {
150 1056 : nBoxLength = nLBox;
151 1056 : nDataOffset = nBoxOffset + 8;
152 : }
153 : else
154 : {
155 : GByte abyXLBox[8];
156 0 : if( VSIFReadL( abyXLBox, 8, 1, fpVSIL ) != 1 )
157 0 : return FALSE;
158 :
159 :
160 : if( sizeof(nBoxLength) == 8 )
161 : {
162 0 : CPL_MSBPTR64( abyXLBox );
163 0 : memcpy( &nBoxLength, abyXLBox, 8 );
164 : }
165 : else
166 : {
167 : CPL_MSBPTR32( abyXLBox+4 );
168 : memcpy( &nBoxLength, abyXLBox+4, 4 );
169 : }
170 :
171 0 : nDataOffset = nBoxOffset + 16;
172 : }
173 :
174 1056 : if( nBoxLength == 0 )
175 : {
176 92 : VSIFSeekL( fpVSIL, 0, SEEK_END );
177 92 : nBoxLength = VSIFTellL( fpVSIL ) - nBoxOffset;
178 : }
179 :
180 1056 : if( EQUAL(szBoxType,"uuid") )
181 : {
182 169 : VSIFReadL( abyUUID, 16, 1, fpVSIL );
183 169 : nDataOffset += 16;
184 : }
185 :
186 1056 : if( GetDataLength() < 0 )
187 : {
188 0 : CPLDebug("GDALJP2", "Invalid length for box %s", szBoxType);
189 0 : return FALSE;
190 : }
191 :
192 1056 : return TRUE;
193 : }
194 :
195 : /************************************************************************/
196 : /* IsSuperBox() */
197 : /************************************************************************/
198 :
199 179 : int GDALJP2Box::IsSuperBox()
200 :
201 : {
202 179 : if( EQUAL(GetType(),"asoc") || EQUAL(GetType(),"jp2h")
203 : || EQUAL(GetType(),"res ") )
204 179 : return TRUE;
205 : else
206 0 : return FALSE;
207 : }
208 :
209 : /************************************************************************/
210 : /* ReadBoxData() */
211 : /************************************************************************/
212 :
213 169 : GByte *GDALJP2Box::ReadBoxData()
214 :
215 : {
216 169 : char *pszData = (char *) CPLMalloc((int)GetDataLength() + 1);
217 :
218 169 : if( (GIntBig) VSIFReadL( pszData, 1, (int)GetDataLength(), fpVSIL )
219 : != GetDataLength() )
220 : {
221 0 : CPLFree( pszData );
222 0 : return NULL;
223 : }
224 :
225 169 : pszData[GetDataLength()] = '\0';
226 :
227 169 : return (GByte *) pszData;
228 : }
229 :
230 : /************************************************************************/
231 : /* GetDataLength() */
232 : /************************************************************************/
233 :
234 2185 : GIntBig GDALJP2Box::GetDataLength()
235 : {
236 2185 : return nBoxLength - (nDataOffset - nBoxOffset);
237 : }
238 :
239 : /************************************************************************/
240 : /* DumpReadable() */
241 : /************************************************************************/
242 :
243 0 : int GDALJP2Box::DumpReadable( FILE *fpOut, int nIndentLevel )
244 :
245 : {
246 0 : if( fpOut == NULL )
247 0 : fpOut = stdout;
248 :
249 : int i;
250 0 : for(i=0;i<nIndentLevel;i++)
251 0 : fprintf( fpOut, " " );
252 :
253 : fprintf( fpOut, " Type=%s, Offset=%d/%d, Data Size=%d",
254 : szBoxType, (int) nBoxOffset, (int) nDataOffset,
255 0 : (int)(nBoxLength - (nDataOffset - nBoxOffset)) );
256 :
257 0 : if( IsSuperBox() )
258 : {
259 0 : fprintf( fpOut, " (super)" );
260 : }
261 :
262 0 : fprintf( fpOut, "\n" );
263 :
264 0 : if( IsSuperBox() )
265 : {
266 0 : GDALJP2Box oSubBox( GetFILE() );
267 :
268 0 : for( oSubBox.ReadFirstChild( this );
269 : strlen(oSubBox.GetType()) > 0;
270 : oSubBox.ReadNextChild( this ) )
271 : {
272 0 : oSubBox.DumpReadable( fpOut, nIndentLevel + 1 );
273 0 : }
274 : }
275 :
276 0 : if( EQUAL(GetType(),"uuid") )
277 : {
278 0 : char *pszHex = CPLBinaryToHex( 16, GetUUID() );
279 0 : for(i=0;i<nIndentLevel;i++)
280 0 : fprintf( fpOut, " " );
281 :
282 0 : fprintf( fpOut, " UUID=%s", pszHex );
283 :
284 0 : if( EQUAL(pszHex,"B14BF8BD083D4B43A5AE8CD7D5A6CE03") )
285 0 : fprintf( fpOut, " (GeoTIFF)" );
286 0 : if( EQUAL(pszHex,"96A9F1F1DC98402DA7AED68E34451809") )
287 0 : fprintf( fpOut, " (MSI Worldfile)" );
288 0 : CPLFree( pszHex );
289 :
290 0 : fprintf( fpOut, "\n" );
291 : }
292 :
293 0 : return 0;
294 : }
295 :
296 : /************************************************************************/
297 : /* SetType() */
298 : /************************************************************************/
299 :
300 155 : void GDALJP2Box::SetType( const char *pszType )
301 :
302 : {
303 155 : CPLAssert( strlen(pszType) == 4 );
304 :
305 155 : memcpy(szBoxType, pszType, 4);
306 155 : szBoxType[4] = '\0';
307 155 : }
308 :
309 : /************************************************************************/
310 : /* SetWritableData() */
311 : /************************************************************************/
312 :
313 153 : void GDALJP2Box::SetWritableData( int nLength, const GByte *pabyDataIn )
314 :
315 : {
316 153 : CPLFree( pabyData );
317 :
318 153 : pabyData = (GByte *) CPLMalloc(nLength);
319 153 : memcpy( pabyData, pabyDataIn, nLength );
320 :
321 153 : nBoxOffset = -9; // virtual offsets for data length computation.
322 153 : nDataOffset = -1;
323 :
324 153 : nBoxLength = 8 + nLength;
325 153 : }
326 :
327 : /************************************************************************/
328 : /* CreateUUIDBox() */
329 : /************************************************************************/
330 :
331 32 : GDALJP2Box *GDALJP2Box::CreateUUIDBox(
332 : const GByte *pabyUUID, int nDataSize, GByte *pabyData )
333 :
334 : {
335 : GDALJP2Box *poBox;
336 :
337 32 : poBox = new GDALJP2Box();
338 32 : poBox->SetType( "uuid" );
339 32 : memcpy( poBox->abyUUID, pabyUUID, 16 );
340 :
341 32 : GByte *pabyMergedData = (GByte *) CPLMalloc(16+nDataSize);
342 32 : memcpy( pabyMergedData, pabyUUID, 16 );
343 32 : memcpy( pabyMergedData+16, pabyData, nDataSize );
344 :
345 32 : poBox->SetWritableData( 16 + nDataSize, pabyMergedData );
346 :
347 32 : CPLFree( pabyMergedData );
348 :
349 32 : return poBox;
350 : }
351 :
352 : /************************************************************************/
353 : /* CreateAsocBox() */
354 : /************************************************************************/
355 :
356 48 : GDALJP2Box *GDALJP2Box::CreateAsocBox( int nCount, GDALJP2Box **papoBoxes )
357 :
358 :
359 : {
360 48 : int nDataSize=0, iBox;
361 : GByte *pabyCompositeData, *pabyNext;
362 :
363 : /* -------------------------------------------------------------------- */
364 : /* Compute size of data area of asoc box. */
365 : /* -------------------------------------------------------------------- */
366 146 : for( iBox = 0; iBox < nCount; iBox++ )
367 98 : nDataSize += 8 + (int) papoBoxes[iBox]->GetDataLength();
368 :
369 48 : pabyNext = pabyCompositeData = (GByte *) CPLMalloc(nDataSize);
370 :
371 : /* -------------------------------------------------------------------- */
372 : /* Copy subboxes headers and data into buffer. */
373 : /* -------------------------------------------------------------------- */
374 146 : for( iBox = 0; iBox < nCount; iBox++ )
375 : {
376 : GUInt32 nLBox;
377 :
378 98 : nLBox = CPL_MSBWORD32(papoBoxes[iBox]->nBoxLength);
379 98 : memcpy( pabyNext, &nLBox, 4 );
380 98 : pabyNext += 4;
381 :
382 98 : memcpy( pabyNext, papoBoxes[iBox]->szBoxType, 4 );
383 98 : pabyNext += 4;
384 :
385 98 : memcpy( pabyNext, papoBoxes[iBox]->pabyData,
386 196 : (int) papoBoxes[iBox]->GetDataLength() );
387 98 : pabyNext += papoBoxes[iBox]->GetDataLength();
388 : }
389 :
390 : /* -------------------------------------------------------------------- */
391 : /* Create asoc box. */
392 : /* -------------------------------------------------------------------- */
393 48 : GDALJP2Box *poAsoc = new GDALJP2Box();
394 :
395 48 : poAsoc->SetType( "asoc" );
396 48 : poAsoc->SetWritableData( nDataSize, pabyCompositeData );
397 :
398 48 : CPLFree( pabyCompositeData );
399 :
400 48 : return poAsoc;
401 : }
402 :
403 : /************************************************************************/
404 : /* CreateLblBox() */
405 : /************************************************************************/
406 :
407 21 : GDALJP2Box *GDALJP2Box::CreateLblBox( const char *pszLabel )
408 :
409 : {
410 : GDALJP2Box *poBox;
411 :
412 21 : poBox = new GDALJP2Box();
413 21 : poBox->SetType( "lbl " );
414 21 : poBox->SetWritableData( strlen(pszLabel)+1, (const GByte *) pszLabel );
415 :
416 21 : return poBox;
417 : }
418 :
419 : /************************************************************************/
420 : /* CreateLabelledXMLAssoc() */
421 : /************************************************************************/
422 :
423 25 : GDALJP2Box *GDALJP2Box::CreateLabelledXMLAssoc( const char *pszLabel,
424 : const char *pszXML )
425 :
426 : {
427 25 : GDALJP2Box oLabel, oXML;
428 : GDALJP2Box *aoList[2];
429 :
430 25 : oLabel.SetType( "lbl " );
431 25 : oLabel.SetWritableData( strlen(pszLabel)+1, (const GByte *) pszLabel );
432 :
433 25 : oXML.SetType( "xml " );
434 25 : oXML.SetWritableData( strlen(pszXML)+1, (const GByte *) pszXML );
435 :
436 25 : aoList[0] = &oLabel;
437 25 : aoList[1] = &oXML;
438 :
439 25 : return CreateAsocBox( 2, aoList );
440 : }
441 :
|