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