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 465 : GDALJP2Box::GDALJP2Box( VSILFILE *fpIn )
40 :
41 : {
42 465 : fpVSIL = fpIn;
43 465 : szBoxType[0] = '\0';
44 465 : nBoxOffset = -1;
45 465 : nDataOffset = -1;
46 465 : nBoxLength = 0;
47 :
48 465 : pabyData = NULL;
49 465 : }
50 :
51 : /************************************************************************/
52 : /* ~GDALJP2Box() */
53 : /************************************************************************/
54 :
55 465 : GDALJP2Box::~GDALJP2Box()
56 :
57 : {
58 465 : CPLFree( pabyData );
59 465 : }
60 :
61 : /************************************************************************/
62 : /* SetOffset() */
63 : /************************************************************************/
64 :
65 1165 : int GDALJP2Box::SetOffset( GIntBig nNewOffset )
66 :
67 : {
68 1165 : szBoxType[0] = '\0';
69 1165 : return VSIFSeekL( fpVSIL, nNewOffset, SEEK_SET ) == 0;
70 : }
71 :
72 : /************************************************************************/
73 : /* ReadFirst() */
74 : /************************************************************************/
75 :
76 142 : int GDALJP2Box::ReadFirst()
77 :
78 : {
79 142 : return SetOffset(0) && ReadBox();
80 : }
81 :
82 : /************************************************************************/
83 : /* ReadNext() */
84 : /************************************************************************/
85 :
86 840 : int GDALJP2Box::ReadNext()
87 :
88 : {
89 840 : return SetOffset( nBoxOffset + nBoxLength ) && ReadBox();
90 : }
91 :
92 : /************************************************************************/
93 : /* ReadFirstChild() */
94 : /************************************************************************/
95 :
96 183 : int GDALJP2Box::ReadFirstChild( GDALJP2Box *poSuperBox )
97 :
98 : {
99 183 : szBoxType[0] = '\0';
100 183 : if( !poSuperBox->IsSuperBox() )
101 0 : return FALSE;
102 :
103 183 : return SetOffset( poSuperBox->nDataOffset ) && ReadBox();
104 : }
105 :
106 : /************************************************************************/
107 : /* ReadNextChild() */
108 : /************************************************************************/
109 :
110 347 : int GDALJP2Box::ReadNextChild( GDALJP2Box *poSuperBox )
111 :
112 : {
113 347 : if( !ReadNext() )
114 0 : return FALSE;
115 :
116 347 : if( nBoxOffset >= poSuperBox->nBoxOffset + poSuperBox->nBoxLength )
117 : {
118 151 : szBoxType[0] = '\0';
119 151 : return FALSE;
120 : }
121 :
122 196 : return TRUE;
123 : }
124 :
125 : /************************************************************************/
126 : /* ReadBox() */
127 : /************************************************************************/
128 :
129 1165 : int GDALJP2Box::ReadBox()
130 :
131 : {
132 : GUInt32 nLBox;
133 : GUInt32 nTBox;
134 :
135 1165 : nBoxOffset = VSIFTellL( fpVSIL );
136 :
137 1165 : if( VSIFReadL( &nLBox, 4, 1, fpVSIL ) != 1
138 : || VSIFReadL( &nTBox, 4, 1, fpVSIL ) != 1 )
139 : {
140 95 : return FALSE;
141 : }
142 :
143 1070 : memcpy( szBoxType, &nTBox, 4 );
144 1070 : szBoxType[4] = '\0';
145 :
146 1070 : nLBox = CPL_MSBWORD32( nLBox );
147 :
148 1070 : if( nLBox != 1 )
149 : {
150 1070 : nBoxLength = nLBox;
151 1070 : 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 1070 : if( nBoxLength == 0 )
175 : {
176 92 : VSIFSeekL( fpVSIL, 0, SEEK_END );
177 92 : nBoxLength = VSIFTellL( fpVSIL ) - nBoxOffset;
178 : }
179 :
180 1070 : if( EQUAL(szBoxType,"uuid") )
181 : {
182 172 : VSIFReadL( abyUUID, 16, 1, fpVSIL );
183 172 : nDataOffset += 16;
184 : }
185 :
186 1070 : if( GetDataLength() < 0 )
187 : {
188 0 : CPLDebug("GDALJP2", "Invalid length for box %s", szBoxType);
189 0 : return FALSE;
190 : }
191 :
192 1070 : return TRUE;
193 : }
194 :
195 : /************************************************************************/
196 : /* IsSuperBox() */
197 : /************************************************************************/
198 :
199 183 : int GDALJP2Box::IsSuperBox()
200 :
201 : {
202 183 : if( EQUAL(GetType(),"asoc") || EQUAL(GetType(),"jp2h")
203 : || EQUAL(GetType(),"res ") )
204 183 : return TRUE;
205 : else
206 0 : return FALSE;
207 : }
208 :
209 : /************************************************************************/
210 : /* ReadBoxData() */
211 : /************************************************************************/
212 :
213 173 : GByte *GDALJP2Box::ReadBoxData()
214 :
215 : {
216 173 : char *pszData = (char *) CPLMalloc((int)GetDataLength() + 1);
217 :
218 173 : if( (GIntBig) VSIFReadL( pszData, 1, (int)GetDataLength(), fpVSIL )
219 : != GetDataLength() )
220 : {
221 0 : CPLFree( pszData );
222 0 : return NULL;
223 : }
224 :
225 173 : pszData[GetDataLength()] = '\0';
226 :
227 173 : 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 142 : void GDALJP2Box::SetType( const char *pszType )
301 :
302 : {
303 142 : CPLAssert( strlen(pszType) == 4 );
304 :
305 142 : memcpy(szBoxType, pszType, 4);
306 142 : szBoxType[4] = '\0';
307 142 : }
308 :
309 : /************************************************************************/
310 : /* SetWritableData() */
311 : /************************************************************************/
312 :
313 140 : void GDALJP2Box::SetWritableData( int nLength, const GByte *pabyDataIn )
314 :
315 : {
316 140 : CPLFree( pabyData );
317 :
318 140 : pabyData = (GByte *) CPLMalloc(nLength);
319 140 : memcpy( pabyData, pabyDataIn, nLength );
320 :
321 140 : nBoxOffset = -9; // virtual offsets for data length computation.
322 140 : nDataOffset = -1;
323 :
324 140 : nBoxLength = 8 + nLength;
325 140 : }
326 :
327 : /************************************************************************/
328 : /* CreateUUIDBox() */
329 : /************************************************************************/
330 :
331 30 : GDALJP2Box *GDALJP2Box::CreateUUIDBox(
332 : const GByte *pabyUUID, int nDataSize, GByte *pabyData )
333 :
334 : {
335 : GDALJP2Box *poBox;
336 :
337 30 : poBox = new GDALJP2Box();
338 30 : poBox->SetType( "uuid" );
339 30 : memcpy( poBox->abyUUID, pabyUUID, 16 );
340 :
341 30 : GByte *pabyMergedData = (GByte *) CPLMalloc(16+nDataSize);
342 30 : memcpy( pabyMergedData, pabyUUID, 16 );
343 30 : memcpy( pabyMergedData+16, pabyData, nDataSize );
344 :
345 30 : poBox->SetWritableData( 16 + nDataSize, pabyMergedData );
346 :
347 30 : CPLFree( pabyMergedData );
348 :
349 30 : return poBox;
350 : }
351 :
352 : /************************************************************************/
353 : /* CreateAsocBox() */
354 : /************************************************************************/
355 :
356 44 : GDALJP2Box *GDALJP2Box::CreateAsocBox( int nCount, GDALJP2Box **papoBoxes )
357 :
358 :
359 : {
360 44 : int nDataSize=0, iBox;
361 : GByte *pabyCompositeData, *pabyNext;
362 :
363 : /* -------------------------------------------------------------------- */
364 : /* Compute size of data area of asoc box. */
365 : /* -------------------------------------------------------------------- */
366 132 : for( iBox = 0; iBox < nCount; iBox++ )
367 88 : nDataSize += 8 + (int) papoBoxes[iBox]->GetDataLength();
368 :
369 44 : pabyNext = pabyCompositeData = (GByte *) CPLMalloc(nDataSize);
370 :
371 : /* -------------------------------------------------------------------- */
372 : /* Copy subboxes headers and data into buffer. */
373 : /* -------------------------------------------------------------------- */
374 132 : for( iBox = 0; iBox < nCount; iBox++ )
375 : {
376 : GUInt32 nLBox;
377 :
378 88 : nLBox = CPL_MSBWORD32(papoBoxes[iBox]->nBoxLength);
379 88 : memcpy( pabyNext, &nLBox, 4 );
380 88 : pabyNext += 4;
381 :
382 88 : memcpy( pabyNext, papoBoxes[iBox]->szBoxType, 4 );
383 88 : pabyNext += 4;
384 :
385 88 : memcpy( pabyNext, papoBoxes[iBox]->pabyData,
386 176 : (int) papoBoxes[iBox]->GetDataLength() );
387 88 : pabyNext += papoBoxes[iBox]->GetDataLength();
388 : }
389 :
390 : /* -------------------------------------------------------------------- */
391 : /* Create asoc box. */
392 : /* -------------------------------------------------------------------- */
393 44 : GDALJP2Box *poAsoc = new GDALJP2Box();
394 :
395 44 : poAsoc->SetType( "asoc" );
396 44 : poAsoc->SetWritableData( nDataSize, pabyCompositeData );
397 :
398 44 : CPLFree( pabyCompositeData );
399 :
400 44 : return poAsoc;
401 : }
402 :
403 : /************************************************************************/
404 : /* CreateLblBox() */
405 : /************************************************************************/
406 :
407 20 : GDALJP2Box *GDALJP2Box::CreateLblBox( const char *pszLabel )
408 :
409 : {
410 : GDALJP2Box *poBox;
411 :
412 20 : poBox = new GDALJP2Box();
413 20 : poBox->SetType( "lbl " );
414 20 : poBox->SetWritableData( strlen(pszLabel)+1, (const GByte *) pszLabel );
415 :
416 20 : return poBox;
417 : }
418 :
419 : /************************************************************************/
420 : /* CreateLabelledXMLAssoc() */
421 : /************************************************************************/
422 :
423 22 : GDALJP2Box *GDALJP2Box::CreateLabelledXMLAssoc( const char *pszLabel,
424 : const char *pszXML )
425 :
426 : {
427 22 : GDALJP2Box oLabel, oXML;
428 : GDALJP2Box *aoList[2];
429 :
430 22 : oLabel.SetType( "lbl " );
431 22 : oLabel.SetWritableData( strlen(pszLabel)+1, (const GByte *) pszLabel );
432 :
433 22 : oXML.SetType( "xml " );
434 22 : oXML.SetWritableData( strlen(pszXML)+1, (const GByte *) pszXML );
435 :
436 22 : aoList[0] = &oLabel;
437 22 : aoList[1] = &oXML;
438 :
439 22 : return CreateAsocBox( 2, aoList );
440 : }
441 :
|