1 /******************************************************************************
2 * $Id: gdaljp2structure.cpp 28766 2015-03-24 23:32:21Z rouault $
3 *
4 * Project: GDAL
5 * Purpose: GDALJP2Stucture - Dump structure of a JP2/J2K file
6 * Author: Even Rouault, <even dot rouault at spatialys dot com>
7 *
8 ******************************************************************************
9 * Copyright (c) 2015, European Union (European Environment Agency)
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
AddField(CPLXMLNode * psParent,const char * pszFieldName,int nFieldSize,const char * pszValue,const char * pszDescription=NULL)32 static void AddField(CPLXMLNode* psParent, const char* pszFieldName,
33 int nFieldSize, const char* pszValue,
34 const char* pszDescription = NULL)
35 {
36 CPLXMLNode* psField = CPLCreateXMLElementAndValue(
37 psParent, "Field", pszValue );
38 CPLAddXMLAttributeAndValue(psField, "name", pszFieldName );
39 CPLAddXMLAttributeAndValue(psField, "type", "string" );
40 CPLAddXMLAttributeAndValue(psField, "size", CPLSPrintf("%d", nFieldSize ) );
41 if( pszDescription )
42 CPLAddXMLAttributeAndValue(psField, "description", pszDescription );
43 }
44
AddHexField(CPLXMLNode * psParent,const char * pszFieldName,int nFieldSize,const char * pszValue,const char * pszDescription=NULL)45 static void AddHexField(CPLXMLNode* psParent, const char* pszFieldName,
46 int nFieldSize, const char* pszValue,
47 const char* pszDescription = NULL)
48 {
49 CPLXMLNode* psField = CPLCreateXMLElementAndValue(
50 psParent, "Field", pszValue );
51 CPLAddXMLAttributeAndValue(psField, "name", pszFieldName );
52 CPLAddXMLAttributeAndValue(psField, "type", "hexint" );
53 CPLAddXMLAttributeAndValue(psField, "size", CPLSPrintf("%d", nFieldSize ) );
54 if( pszDescription )
55 CPLAddXMLAttributeAndValue(psField, "description", pszDescription );
56 }
57
AddField(CPLXMLNode * psParent,const char * pszFieldName,GByte nVal,const char * pszDescription=NULL)58 static void AddField(CPLXMLNode* psParent, const char* pszFieldName, GByte nVal,
59 const char* pszDescription = NULL)
60 {
61 CPLXMLNode* psField = CPLCreateXMLElementAndValue(
62 psParent, "Field", CPLSPrintf("%d", nVal) );
63 CPLAddXMLAttributeAndValue(psField, "name", pszFieldName );
64 CPLAddXMLAttributeAndValue(psField, "type", "uint8" );
65 if( pszDescription )
66 CPLAddXMLAttributeAndValue(psField, "description", pszDescription );
67 }
68
AddField(CPLXMLNode * psParent,const char * pszFieldName,GUInt16 nVal,const char * pszDescription=NULL)69 static void AddField(CPLXMLNode* psParent, const char* pszFieldName, GUInt16 nVal,
70 const char* pszDescription = NULL)
71 {
72 CPLXMLNode* psField = CPLCreateXMLElementAndValue(
73 psParent, "Field", CPLSPrintf("%d", nVal) );
74 CPLAddXMLAttributeAndValue(psField, "name", pszFieldName );
75 CPLAddXMLAttributeAndValue(psField, "type", "uint16" );
76 if( pszDescription )
77 CPLAddXMLAttributeAndValue(psField, "description", pszDescription );
78 }
79
AddField(CPLXMLNode * psParent,const char * pszFieldName,GUInt32 nVal,const char * pszDescription=NULL)80 static void AddField(CPLXMLNode* psParent, const char* pszFieldName, GUInt32 nVal,
81 const char* pszDescription = NULL)
82 {
83 CPLXMLNode* psField = CPLCreateXMLElementAndValue(
84 psParent, "Field", CPLSPrintf("%u", nVal) );
85 CPLAddXMLAttributeAndValue(psField, "name", pszFieldName );
86 CPLAddXMLAttributeAndValue(psField, "type", "uint32" );
87 if( pszDescription )
88 CPLAddXMLAttributeAndValue(psField, "description", pszDescription );
89 }
90
GetInterpretationOfBPC(GByte bpc)91 static const char* GetInterpretationOfBPC(GByte bpc)
92 {
93 if( bpc == 255 )
94 return NULL;
95 if( (bpc & 0x80) )
96 return CPLSPrintf("Signed %d bits", 1 + (bpc & 0x7F));
97 else
98 return CPLSPrintf("Unsigned %d bits", 1 + bpc);
99 }
100
GetStandardFieldString(GUInt16 nVal)101 static const char* GetStandardFieldString(GUInt16 nVal)
102 {
103 switch(nVal)
104 {
105 case 1: return "Codestream contains no extensions";
106 case 2: return "Contains multiple composition layers";
107 case 3: return "Codestream is compressed using JPEG 2000 and requires at least a Profile 0 decoder";
108 case 4: return "Codestream is compressed using JPEG 2000 and requires at least a Profile 1 decoder";
109 case 5: return "Codestream is compressed using JPEG 2000 unrestricted";
110 case 35: return "Contains IPR metadata";
111 case 67: return "Contains GMLJP2 metadata";
112 default: return NULL;
113 }
114 }
115
DumpGeoTIFFBox(CPLXMLNode * psBox,GDALJP2Box & oBox)116 static void DumpGeoTIFFBox(CPLXMLNode* psBox,
117 GDALJP2Box& oBox)
118 {
119 GIntBig nBoxDataLength = oBox.GetDataLength();
120 GByte* pabyBoxData = oBox.ReadBoxData();
121 GDALDriver* poVRTDriver = (GDALDriver*) GDALGetDriverByName("VRT");
122 if( pabyBoxData && poVRTDriver)
123 {
124 CPLString osTmpFilename(CPLSPrintf("/vsimem/tmp_%p.tif", oBox.GetFILE()));
125 VSIFCloseL(VSIFileFromMemBuffer(
126 osTmpFilename, pabyBoxData, nBoxDataLength, TRUE) );
127 CPLPushErrorHandler(CPLQuietErrorHandler);
128 GDALDataset* poDS = (GDALDataset*) GDALOpen(osTmpFilename, GA_ReadOnly);
129 CPLPopErrorHandler();
130 if( poDS )
131 {
132 CPLString osTmpVRTFilename(CPLSPrintf("/vsimem/tmp_%p.vrt", oBox.GetFILE()));
133 GDALDataset* poVRTDS = poVRTDriver->CreateCopy(osTmpVRTFilename, poDS, FALSE, NULL, NULL, NULL);
134 GDALClose(poVRTDS);
135 GByte* pabyXML = VSIGetMemFileBuffer( osTmpVRTFilename, NULL, FALSE );
136 CPLXMLNode* psXMLVRT = CPLParseXMLString((const char*)pabyXML);
137 if( psXMLVRT )
138 {
139 CPLXMLNode* psXMLContentNode =
140 CPLCreateXMLNode( psBox, CXT_Element, "DecodedGeoTIFF" );
141 psXMLContentNode->psChild = psXMLVRT;
142 CPLXMLNode* psPrev = NULL;
143 for(CPLXMLNode* psIter = psXMLVRT->psChild; psIter; psIter = psIter->psNext)
144 {
145 if( psIter->eType == CXT_Element &&
146 strcmp(psIter->pszValue, "VRTRasterBand") == 0 )
147 {
148 CPLXMLNode* psNext = psIter->psNext;
149 psIter->psNext = NULL;
150 CPLDestroyXMLNode(psIter);
151 if( psPrev )
152 psPrev->psNext = psNext;
153 else
154 break;
155 psIter = psPrev;
156 }
157 psPrev = psIter;
158 }
159 CPLCreateXMLNode(psXMLVRT, CXT_Element, "VRTRasterBand");
160 }
161
162 VSIUnlink(osTmpVRTFilename);
163 GDALClose(poDS);
164 }
165 VSIUnlink(osTmpFilename);
166 }
167 }
168
DumpFTYPBox(CPLXMLNode * psBox,GDALJP2Box & oBox)169 static void DumpFTYPBox(CPLXMLNode* psBox, GDALJP2Box& oBox)
170 {
171 GIntBig nBoxDataLength = oBox.GetDataLength();
172 GByte* pabyBoxData = oBox.ReadBoxData();
173 if( pabyBoxData )
174 {
175 CPLXMLNode* psDecodedContent =
176 CPLCreateXMLNode( psBox, CXT_Element, "DecodedContent" );
177 GIntBig nRemainingLength = nBoxDataLength;
178 GByte* pabyIter = pabyBoxData;
179 if( nRemainingLength >= 4 )
180 {
181 char szBranding[5];
182 memcpy(szBranding, pabyIter, 4);
183 szBranding[4] = 0;
184 AddField(psDecodedContent, "BR", 4, szBranding);
185 pabyIter += 4;
186 nRemainingLength -= 4;
187 }
188 if( nRemainingLength >= 4 )
189 {
190 GUInt32 nVal;
191 memcpy(&nVal, pabyIter, 4);
192 CPL_MSBPTR32(&nVal);
193 AddField(psDecodedContent, "MinV", nVal);
194 pabyIter += 4;
195 nRemainingLength -= 4;
196 }
197 int nCLIndex = 0;
198 while( nRemainingLength >= 4 )
199 {
200 char szBranding[5];
201 memcpy(szBranding, pabyIter, 4);
202 szBranding[4] = 0;
203 AddField(psDecodedContent,
204 CPLSPrintf("CL%d", nCLIndex),
205 4, szBranding);
206 pabyIter += 4;
207 nRemainingLength -= 4;
208 nCLIndex ++;
209 }
210 if( nRemainingLength > 0 )
211 CPLCreateXMLElementAndValue(
212 psDecodedContent, "RemainingBytes",
213 CPLSPrintf("%d", (int)nRemainingLength ));
214 }
215 CPLFree(pabyBoxData);
216 }
217
DumpIHDRBox(CPLXMLNode * psBox,GDALJP2Box & oBox)218 static void DumpIHDRBox(CPLXMLNode* psBox, GDALJP2Box& oBox)
219 {
220 GIntBig nBoxDataLength = oBox.GetDataLength();
221 GByte* pabyBoxData = oBox.ReadBoxData();
222 if( pabyBoxData )
223 {
224 CPLXMLNode* psDecodedContent =
225 CPLCreateXMLNode( psBox, CXT_Element, "DecodedContent" );
226 GIntBig nRemainingLength = nBoxDataLength;
227 GByte* pabyIter = pabyBoxData;
228 if( nRemainingLength >= 4 )
229 {
230 GUInt32 nVal;
231 memcpy(&nVal, pabyIter, 4);
232 CPL_MSBPTR32(&nVal);
233 AddField(psDecodedContent, "HEIGHT", nVal);
234 pabyIter += 4;
235 nRemainingLength -= 4;
236 }
237 if( nRemainingLength >= 4 )
238 {
239 GUInt32 nVal;
240 memcpy(&nVal, pabyIter, 4);
241 CPL_MSBPTR32(&nVal);
242 AddField(psDecodedContent, "WIDTH", nVal);
243 pabyIter += 4;
244 nRemainingLength -= 4;
245 }
246 if( nRemainingLength >= 2 )
247 {
248 GUInt16 nVal;
249 memcpy(&nVal, pabyIter, 2);
250 CPL_MSBPTR16(&nVal);
251 AddField(psDecodedContent, "NC", nVal);
252 pabyIter += 2;
253 nRemainingLength -= 2;
254 }
255 if( nRemainingLength >= 1 )
256 {
257 AddField(psDecodedContent, "BPC", *pabyIter,
258 GetInterpretationOfBPC(*pabyIter));
259 pabyIter += 1;
260 nRemainingLength -= 1;
261 }
262 if( nRemainingLength >= 1 )
263 {
264 AddField(psDecodedContent, "C", *pabyIter);
265 pabyIter += 1;
266 nRemainingLength -= 1;
267 }
268 if( nRemainingLength >= 1 )
269 {
270 AddField(psDecodedContent, "UnkC", *pabyIter);
271 pabyIter += 1;
272 nRemainingLength -= 1;
273 }
274 if( nRemainingLength >= 1 )
275 {
276 AddField(psDecodedContent, "IPR", *pabyIter);
277 pabyIter += 1;
278 nRemainingLength -= 1;
279 }
280 if( nRemainingLength > 0 )
281 CPLCreateXMLElementAndValue(
282 psDecodedContent, "RemainingBytes",
283 CPLSPrintf("%d", (int)nRemainingLength ));
284 }
285 CPLFree(pabyBoxData);
286 }
287
DumpBPCCBox(CPLXMLNode * psBox,GDALJP2Box & oBox)288 static void DumpBPCCBox(CPLXMLNode* psBox, GDALJP2Box& oBox)
289 {
290 GIntBig nBoxDataLength = oBox.GetDataLength();
291 GByte* pabyBoxData = oBox.ReadBoxData();
292 if( pabyBoxData )
293 {
294 CPLXMLNode* psDecodedContent =
295 CPLCreateXMLNode( psBox, CXT_Element, "DecodedContent" );
296 GIntBig nRemainingLength = nBoxDataLength;
297 GByte* pabyIter = pabyBoxData;
298 int nBPCIndex = 0;
299 while( nRemainingLength >= 1 )
300 {
301 AddField(psDecodedContent,
302 CPLSPrintf("BPC%d", nBPCIndex),
303 *pabyIter,
304 GetInterpretationOfBPC(*pabyIter));
305 nBPCIndex ++;
306 pabyIter += 1;
307 nRemainingLength -= 1;
308 }
309 }
310 CPLFree(pabyBoxData);
311 }
312
DumpCOLRBox(CPLXMLNode * psBox,GDALJP2Box & oBox)313 static void DumpCOLRBox(CPLXMLNode* psBox, GDALJP2Box& oBox)
314 {
315 GIntBig nBoxDataLength = oBox.GetDataLength();
316 GByte* pabyBoxData = oBox.ReadBoxData();
317 if( pabyBoxData )
318 {
319 CPLXMLNode* psDecodedContent =
320 CPLCreateXMLNode( psBox, CXT_Element, "DecodedContent" );
321 GIntBig nRemainingLength = nBoxDataLength;
322 GByte* pabyIter = pabyBoxData;
323 GByte nMeth;
324 if( nRemainingLength >= 1 )
325 {
326 nMeth = *pabyIter;
327 AddField(psDecodedContent, "METH", nMeth,
328 (nMeth == 0) ? "Enumerated Colourspace":
329 (nMeth == 0) ? "Restricted ICC profile": NULL);
330 pabyIter += 1;
331 nRemainingLength -= 1;
332 }
333 if( nRemainingLength >= 1 )
334 {
335 AddField(psDecodedContent, "PREC", *pabyIter);
336 pabyIter += 1;
337 nRemainingLength -= 1;
338 }
339 if( nRemainingLength >= 1 )
340 {
341 AddField(psDecodedContent, "APPROX", *pabyIter);
342 pabyIter += 1;
343 nRemainingLength -= 1;
344 }
345 if( nRemainingLength >= 4 )
346 {
347 GUInt32 nVal;
348 memcpy(&nVal, pabyIter, 4);
349 CPL_MSBPTR32(&nVal);
350 AddField(psDecodedContent, "EnumCS", nVal,
351 (nVal == 16) ? "sRGB" :
352 (nVal == 17) ? "greyscale":
353 (nVal == 18) ? "sYCC" : NULL);
354 pabyIter += 4;
355 nRemainingLength -= 4;
356 }
357 if( nRemainingLength > 0 )
358 CPLCreateXMLElementAndValue(
359 psDecodedContent, "RemainingBytes",
360 CPLSPrintf("%d", (int)nRemainingLength ));
361 }
362 CPLFree(pabyBoxData);
363 }
364
DumpPCLRBox(CPLXMLNode * psBox,GDALJP2Box & oBox)365 static void DumpPCLRBox(CPLXMLNode* psBox, GDALJP2Box& oBox)
366 {
367 GIntBig nBoxDataLength = oBox.GetDataLength();
368 GByte* pabyBoxData = oBox.ReadBoxData();
369 if( pabyBoxData )
370 {
371 CPLXMLNode* psDecodedContent =
372 CPLCreateXMLNode( psBox, CXT_Element, "DecodedContent" );
373 GIntBig nRemainingLength = nBoxDataLength;
374 GByte* pabyIter = pabyBoxData;
375 GUInt16 NE = 0;
376 if( nRemainingLength >= 2 )
377 {
378 GUInt16 nVal;
379 memcpy(&nVal, pabyIter, 2);
380 CPL_MSBPTR16(&nVal);
381 NE = nVal;
382 AddField(psDecodedContent, "NE", nVal);
383 pabyIter += 2;
384 nRemainingLength -= 2;
385 }
386 GByte NPC = 0;
387 if( nRemainingLength >= 1 )
388 {
389 NPC = *pabyIter;
390 AddField(psDecodedContent, "NPC", NPC);
391 pabyIter += 1;
392 nRemainingLength -= 1;
393 }
394 int b8BitOnly = TRUE;
395 for(int i=0;i<NPC;i++)
396 {
397 if( nRemainingLength >= 1 )
398 {
399 b8BitOnly &= (*pabyIter <= 7);
400 AddField(psDecodedContent,
401 CPLSPrintf("B%d", i),
402 *pabyIter,
403 GetInterpretationOfBPC(*pabyIter));
404 pabyIter += 1;
405 nRemainingLength -= 1;
406 }
407 }
408 if( b8BitOnly )
409 {
410 for(int j=0;j<NE;j++)
411 {
412 for(int i=0;i<NPC;i++)
413 {
414 if( nRemainingLength >= 1 )
415 {
416 AddField(psDecodedContent,
417 CPLSPrintf("C_%d_%d", j, i),
418 *pabyIter);
419 pabyIter += 1;
420 nRemainingLength -= 1;
421 }
422 }
423 }
424 }
425 if( nRemainingLength > 0 )
426 CPLCreateXMLElementAndValue(
427 psDecodedContent, "RemainingBytes",
428 CPLSPrintf("%d", (int)nRemainingLength ));
429 }
430 CPLFree(pabyBoxData);
431 }
432
DumpCMAPBox(CPLXMLNode * psBox,GDALJP2Box & oBox)433 static void DumpCMAPBox(CPLXMLNode* psBox, GDALJP2Box& oBox)
434 {
435 GIntBig nBoxDataLength = oBox.GetDataLength();
436 GByte* pabyBoxData = oBox.ReadBoxData();
437 if( pabyBoxData )
438 {
439 CPLXMLNode* psDecodedContent =
440 CPLCreateXMLNode( psBox, CXT_Element, "DecodedContent" );
441 GIntBig nRemainingLength = nBoxDataLength;
442 GByte* pabyIter = pabyBoxData;
443 int nIndex = 0;
444 while( nRemainingLength >= 2 + 1 + 1 )
445 {
446 GUInt16 nVal;
447 memcpy(&nVal, pabyIter, 2);
448 CPL_MSBPTR16(&nVal);
449 AddField(psDecodedContent,
450 CPLSPrintf("CMP%d", nIndex),
451 nVal);
452 pabyIter += 2;
453 nRemainingLength -= 2;
454
455 AddField(psDecodedContent,
456 CPLSPrintf("MTYP%d", nIndex),
457 *pabyIter,
458 (*pabyIter == 0) ? "Direct use":
459 (*pabyIter == 1) ? "Palette mapping": NULL);
460 pabyIter += 1;
461 nRemainingLength -= 1;
462
463 AddField(psDecodedContent,
464 CPLSPrintf("PCOL%d", nIndex),
465 *pabyIter);
466 pabyIter += 1;
467 nRemainingLength -= 1;
468
469 nIndex ++;
470 }
471 if( nRemainingLength > 0 )
472 CPLCreateXMLElementAndValue(
473 psDecodedContent, "RemainingBytes",
474 CPLSPrintf("%d", (int)nRemainingLength ));
475 }
476 CPLFree(pabyBoxData);
477 }
478
DumpCDEFBox(CPLXMLNode * psBox,GDALJP2Box & oBox)479 static void DumpCDEFBox(CPLXMLNode* psBox, GDALJP2Box& oBox)
480 {
481 GIntBig nBoxDataLength = oBox.GetDataLength();
482 GByte* pabyBoxData = oBox.ReadBoxData();
483 if( pabyBoxData )
484 {
485 CPLXMLNode* psDecodedContent =
486 CPLCreateXMLNode( psBox, CXT_Element, "DecodedContent" );
487 GIntBig nRemainingLength = nBoxDataLength;
488 GByte* pabyIter = pabyBoxData;
489 GUInt16 nChannels = 0;
490 if( nRemainingLength >= 2 )
491 {
492 GUInt16 nVal;
493 memcpy(&nVal, pabyIter, 2);
494 nChannels = nVal;
495 CPL_MSBPTR16(&nVal);
496 AddField(psDecodedContent, "N", nVal);
497 pabyIter += 2;
498 nRemainingLength -= 2;
499 }
500 for( int i=0; i < nChannels; i++ )
501 {
502 if( nRemainingLength >= 2 )
503 {
504 GUInt16 nVal;
505 memcpy(&nVal, pabyIter, 2);
506 CPL_MSBPTR16(&nVal);
507 AddField(psDecodedContent,
508 CPLSPrintf("Cn%d", i),
509 nVal);
510 pabyIter += 2;
511 nRemainingLength -= 2;
512 }
513 if( nRemainingLength >= 2 )
514 {
515 GUInt16 nVal;
516 memcpy(&nVal, pabyIter, 2);
517 CPL_MSBPTR16(&nVal);
518 AddField(psDecodedContent,
519 CPLSPrintf("Typ%d", i),
520 nVal,
521 (nVal == 0) ? "Colour channel":
522 (nVal == 1) ? "Opacity channel":
523 (nVal == 2) ? "Premultiplied opacity":
524 (nVal == 65535) ? "Not specified" : NULL);
525 pabyIter += 2;
526 nRemainingLength -= 2;
527 }
528 if( nRemainingLength >= 2 )
529 {
530 GUInt16 nVal;
531 memcpy(&nVal, pabyIter, 2);
532 CPL_MSBPTR16(&nVal);
533 AddField(psDecodedContent,
534 CPLSPrintf("Asoc%d", i),
535 nVal,
536 (nVal == 0) ? "Associated to the whole image":
537 (nVal == 65535) ? "Not associated with a particular colour":
538 "Associated with a particular colour");
539 pabyIter += 2;
540 nRemainingLength -= 2;
541 }
542 }
543 if( nRemainingLength > 0 )
544 CPLCreateXMLElementAndValue(
545 psDecodedContent, "RemainingBytes",
546 CPLSPrintf("%d", (int)nRemainingLength ));
547 }
548 CPLFree(pabyBoxData);
549 }
550
DumpRESxBox(CPLXMLNode * psBox,GDALJP2Box & oBox)551 static void DumpRESxBox(CPLXMLNode* psBox, GDALJP2Box& oBox)
552 {
553 GIntBig nBoxDataLength = oBox.GetDataLength();
554 GByte* pabyBoxData = oBox.ReadBoxData();
555 char chC = oBox.GetType()[3];
556 if( pabyBoxData )
557 {
558 CPLXMLNode* psDecodedContent =
559 CPLCreateXMLNode( psBox, CXT_Element, "DecodedContent" );
560 GIntBig nRemainingLength = nBoxDataLength;
561 GByte* pabyIter = pabyBoxData;
562 GUInt16 nNumV = 0, nNumH = 0, nDenomV = 1, nDenomH = 1, nExpV = 0, nExpH = 0;
563 if( nRemainingLength >= 2 )
564 {
565 GUInt16 nVal;
566 memcpy(&nVal, pabyIter, 2);
567 CPL_MSBPTR16(&nVal);
568 nNumV = nVal;
569 AddField(psDecodedContent, CPLSPrintf("VR%cN", chC), nVal);
570 pabyIter += 2;
571 nRemainingLength -= 2;
572 }
573 if( nRemainingLength >= 2 )
574 {
575 GUInt16 nVal;
576 memcpy(&nVal, pabyIter, 2);
577 CPL_MSBPTR16(&nVal);
578 nDenomV = nVal;
579 AddField(psDecodedContent, CPLSPrintf("VR%cD", chC), nVal);
580 pabyIter += 2;
581 nRemainingLength -= 2;
582 }
583 if( nRemainingLength >= 2 )
584 {
585 GUInt16 nVal;
586 memcpy(&nVal, pabyIter, 2);
587 CPL_MSBPTR16(&nVal);
588 nNumH = nVal;
589 AddField(psDecodedContent, CPLSPrintf("HR%cN", chC), nVal);
590 pabyIter += 2;
591 nRemainingLength -= 2;
592 }
593 if( nRemainingLength >= 2 )
594 {
595 GUInt16 nVal;
596 memcpy(&nVal, pabyIter, 2);
597 CPL_MSBPTR16(&nVal);
598 nDenomH = nVal;
599 AddField(psDecodedContent, CPLSPrintf("HR%cD", chC), nVal);
600 pabyIter += 2;
601 nRemainingLength -= 2;
602 }
603 if( nRemainingLength >= 1 )
604 {
605 AddField(psDecodedContent, CPLSPrintf("VR%cE", chC), *pabyIter);
606 nExpV = *pabyIter;
607 pabyIter += 1;
608 nRemainingLength -= 1;
609 }
610 if( nRemainingLength >= 1 )
611 {
612 AddField(psDecodedContent, CPLSPrintf("HR%cE", chC), *pabyIter);
613 nExpH = *pabyIter;
614 pabyIter += 1;
615 nRemainingLength -= 1;
616 }
617 if( nRemainingLength == 0 )
618 {
619 CPLCreateXMLElementAndValue(psDecodedContent, "VRes",
620 CPLSPrintf("%.03f", 1.0 * nNumV / nDenomV * pow(10.0, nExpV)));
621 CPLCreateXMLElementAndValue(psDecodedContent, "HRes",
622 CPLSPrintf("%.03f", 1.0 * nNumH / nDenomH * pow(10.0, nExpH)));
623 }
624 else if( nRemainingLength > 0 )
625 CPLCreateXMLElementAndValue(
626 psDecodedContent, "RemainingBytes",
627 CPLSPrintf("%d", (int)nRemainingLength ));
628 }
629 CPLFree(pabyBoxData);
630 }
631
DumpRREQBox(CPLXMLNode * psBox,GDALJP2Box & oBox)632 static void DumpRREQBox(CPLXMLNode* psBox, GDALJP2Box& oBox)
633 {
634 GIntBig nBoxDataLength = oBox.GetDataLength();
635 GByte* pabyBoxData = oBox.ReadBoxData();
636 if( pabyBoxData )
637 {
638 CPLXMLNode* psDecodedContent =
639 CPLCreateXMLNode( psBox, CXT_Element, "DecodedContent" );
640 GIntBig nRemainingLength = nBoxDataLength;
641 GByte* pabyIter = pabyBoxData;
642 GByte ML = 0;
643 if( nRemainingLength >= 1 )
644 {
645 ML = *pabyIter;
646 AddField(psDecodedContent, "ML", *pabyIter);
647 pabyIter += 1;
648 nRemainingLength -= 1;
649 }
650 if( nRemainingLength >= ML )
651 {
652 CPLString osHex("0x");
653 for(int i=0;i<ML;i++)
654 {
655 osHex += CPLSPrintf("%02X", *pabyIter);
656 pabyIter += 1;
657 nRemainingLength -= 1;
658 }
659 AddHexField(psDecodedContent, "FUAM", (int)ML, osHex.c_str());
660 }
661 if( nRemainingLength >= ML )
662 {
663 CPLString osHex("0x");
664 for(int i=0;i<ML;i++)
665 {
666 osHex += CPLSPrintf("%02X", *pabyIter);
667 pabyIter += 1;
668 nRemainingLength -= 1;
669 }
670 AddHexField(psDecodedContent, "DCM", (int)ML, osHex.c_str());
671 }
672 GUInt16 NSF = 0;
673 if( nRemainingLength >= 2 )
674 {
675 GUInt16 nVal;
676 memcpy(&nVal, pabyIter, 2);
677 CPL_MSBPTR16(&nVal);
678 NSF = nVal;
679 AddField(psDecodedContent, "NSF", nVal);
680 pabyIter += 2;
681 nRemainingLength -= 2;
682 }
683 for(int iNSF=0;iNSF<NSF;iNSF++)
684 {
685 if( nRemainingLength >= 2 )
686 {
687 GUInt16 nVal;
688 memcpy(&nVal, pabyIter, 2);
689 CPL_MSBPTR16(&nVal);
690 AddField(psDecodedContent,
691 CPLSPrintf("SF%d", iNSF), nVal,
692 GetStandardFieldString(nVal));
693 pabyIter += 2;
694 nRemainingLength -= 2;
695 }
696 if( nRemainingLength >= ML )
697 {
698 CPLString osHex("0x");
699 for(int i=0;i<ML;i++)
700 {
701 osHex += CPLSPrintf("%02X", *pabyIter);
702 pabyIter += 1;
703 nRemainingLength -= 1;
704 }
705 AddHexField(psDecodedContent,
706 CPLSPrintf("SM%d", iNSF),
707 (int)ML, osHex.c_str());
708 }
709 }
710 GUInt16 NVF = 0;
711 if( nRemainingLength >= 2 )
712 {
713 GUInt16 nVal;
714 memcpy(&nVal, pabyIter, 2);
715 CPL_MSBPTR16(&nVal);
716 NVF = nVal;
717 AddField(psDecodedContent, "NVF", nVal);
718 pabyIter += 2;
719 nRemainingLength -= 2;
720 }
721 for(int iNVF=0;iNVF<NVF;iNVF++)
722 {
723 if( nRemainingLength >= 16 )
724 {
725 CPLString osHex("0x");
726 for(int i=0;i<16;i++)
727 {
728 osHex += CPLSPrintf("%02X", *pabyIter);
729 pabyIter += 1;
730 nRemainingLength -= 1;
731 }
732 AddHexField(psDecodedContent,
733 CPLSPrintf("VF%d", iNVF),
734 (int)ML, osHex.c_str());
735 }
736 if( nRemainingLength >= ML )
737 {
738 CPLString osHex("0x");
739 for(int i=0;i<ML;i++)
740 {
741 osHex += CPLSPrintf("%02X", *pabyIter);
742 pabyIter += 1;
743 nRemainingLength -= 1;
744 }
745 AddHexField(psDecodedContent,
746 CPLSPrintf("VM%d", iNVF),
747 (int)ML, osHex.c_str());
748 }
749 }
750 if( nRemainingLength > 0 )
751 CPLCreateXMLElementAndValue(
752 psDecodedContent, "RemainingBytes",
753 CPLSPrintf("%d", (int)nRemainingLength ));
754 }
755 CPLFree(pabyBoxData);
756 }
757
CreateMarker(CPLXMLNode * psCSBox,const char * pszName,GIntBig nOffset,GIntBig nLength)758 static CPLXMLNode* CreateMarker(CPLXMLNode* psCSBox, const char* pszName,
759 GIntBig nOffset, GIntBig nLength)
760 {
761 CPLXMLNode* psMarker = CPLCreateXMLNode( psCSBox, CXT_Element, "Marker" );
762 CPLAddXMLAttributeAndValue(psMarker, "name", pszName );
763 CPLAddXMLAttributeAndValue(psMarker, "offset",
764 CPLSPrintf(CPL_FRMT_GIB, nOffset ) );
765 CPLAddXMLAttributeAndValue(psMarker, "length",
766 CPLSPrintf(CPL_FRMT_GIB, 2 + nLength ) );
767 return psMarker;
768 }
769
AddError(CPLXMLNode * psParent,const char * pszErrorMsg,GIntBig nOffset=0)770 static void AddError(CPLXMLNode* psParent, const char* pszErrorMsg,
771 GIntBig nOffset = 0)
772 {
773 CPLXMLNode* psError = CPLCreateXMLNode( psParent, CXT_Element, "Error" );
774 CPLAddXMLAttributeAndValue(psError, "message", pszErrorMsg );
775 if( nOffset )
776 {
777 CPLAddXMLAttributeAndValue(psError, "offset",
778 CPLSPrintf(CPL_FRMT_GIB, nOffset ) );
779 }
780 }
781
GetMarkerName(GByte byVal)782 static const char* GetMarkerName(GByte byVal)
783 {
784 switch(byVal)
785 {
786 case 0x90: return "SOT";
787 case 0x51: return "SIZ";
788 case 0x52: return "COD";
789 case 0x53: return "COC";
790 case 0x55: return "TLM";
791 case 0x57: return "PLM";
792 case 0x58: return "PLT";
793 case 0x5C: return "QCD";
794 case 0x5D: return "QCC";
795 case 0x5E: return "RGN";
796 case 0x5F: return "POC";
797 case 0x60: return "PPM";
798 case 0x61: return "PPT";
799 case 0x63: return "CRG";
800 case 0x64: return "COM";
801 default: return CPLSPrintf("Unknown 0xFF%02X", byVal);
802 }
803 }
804
805 /************************************************************************/
806 /* DumpJPK2CodeStream() */
807 /************************************************************************/
808
DumpJPK2CodeStream(CPLXMLNode * psBox,VSILFILE * fp,GIntBig nBoxDataOffset,GIntBig nBoxDataLength)809 static CPLXMLNode* DumpJPK2CodeStream(CPLXMLNode* psBox,
810 VSILFILE* fp,
811 GIntBig nBoxDataOffset,
812 GIntBig nBoxDataLength)
813 {
814 VSIFSeekL(fp, nBoxDataOffset, SEEK_SET);
815 GByte abyMarker[2];
816 CPLXMLNode* psCSBox = CPLCreateXMLNode( psBox, CXT_Element, "JP2KCodeStream" );
817 GByte* pabyMarkerData = (GByte*)CPLMalloc(65535+1);
818 GIntBig nNextTileOffset = 0;
819 while( TRUE )
820 {
821 GIntBig nOffset = (GIntBig)VSIFTellL(fp);
822 if( nOffset == nBoxDataOffset + nBoxDataLength )
823 break;
824 if( VSIFReadL(abyMarker, 2, 1, fp) != 1 )
825 {
826 AddError(psCSBox, "Cannot read marker", nOffset);
827 break;
828 }
829 if( abyMarker[0] != 0xFF )
830 {
831 AddError(psCSBox, "Not a marker", nOffset);
832 break;
833 }
834 if( abyMarker[1] == 0x4F )
835 {
836 CreateMarker( psCSBox, "SOC", nOffset, 0 );
837 continue;
838 }
839 if( abyMarker[1] == 0x93 )
840 {
841 GIntBig nMarkerSize = 0;
842 int bBreak = FALSE;
843 if( nNextTileOffset == 0 )
844 {
845 nMarkerSize = (nBoxDataOffset + nBoxDataLength - 2) - nOffset - 2;
846 VSIFSeekL(fp, nBoxDataOffset + nBoxDataLength - 2, SEEK_SET);
847 if( VSIFReadL(abyMarker, 2, 1, fp) != 1 ||
848 abyMarker[0] != 0xFF || abyMarker[1] != 0xD9 )
849 {
850 /* autotest/gdrivers/data/rgb16_ecwsdk.jp2 does not end */
851 /* with a EOC... */
852 nMarkerSize += 2;
853 bBreak = TRUE;
854 }
855 }
856 else if( nNextTileOffset >= nOffset + 2 )
857 nMarkerSize = nNextTileOffset - nOffset - 2;
858
859 CreateMarker( psCSBox, "SOD", nOffset, nMarkerSize );
860 if( bBreak )
861 break;
862
863 if( nNextTileOffset && nNextTileOffset == nOffset )
864 {
865 /* Found with Pleiades images. openjpeg doesn't like it either */
866 nNextTileOffset = 0;
867 }
868 else if( nNextTileOffset && nNextTileOffset >= nOffset + 2 )
869 {
870 VSIFSeekL(fp, nNextTileOffset, SEEK_SET);
871 nNextTileOffset = 0;
872 }
873 else
874 {
875 /* We have seek and check before we hit a EOC */
876 CreateMarker( psCSBox, "EOC", nOffset, 0 );
877 }
878 continue;
879 }
880 if( abyMarker[1] == 0xD9 )
881 {
882 CreateMarker( psCSBox, "EOC", nOffset, 0 );
883 continue;
884 }
885 /* Reserved markers */
886 if( abyMarker[1] >= 0x30 && abyMarker[1] <= 0x3F )
887 {
888 CreateMarker( psCSBox, CPLSPrintf("Unknown 0xFF%02X", abyMarker[1]), nOffset, 0 );
889 continue;
890 }
891
892 GUInt16 nMarkerSize;
893 if( VSIFReadL(&nMarkerSize, 2, 1, fp) != 1 )
894 {
895 AddError(psCSBox, CPLSPrintf("Cannot read marker size of %s", GetMarkerName(abyMarker[1])), nOffset);
896 break;
897 }
898 CPL_MSBPTR16(&nMarkerSize);
899 if( nMarkerSize < 2 )
900 {
901 AddError(psCSBox, CPLSPrintf("Invalid marker size of %s", GetMarkerName(abyMarker[1])), nOffset);
902 break;
903 }
904
905 CPLXMLNode* psMarker = CreateMarker( psCSBox, GetMarkerName(abyMarker[1]), nOffset, nMarkerSize );
906 if( VSIFReadL(pabyMarkerData, nMarkerSize - 2, 1, fp) != 1 )
907 {
908 AddError(psMarker, "Cannot read marker data", nOffset);
909 break;
910 }
911 GByte* pabyMarkerDataIter = pabyMarkerData;
912 GUInt16 nRemainingMarkerSize = nMarkerSize - 2;
913 GUInt32 nLastVal = 0;
914
915
916 #define READ_MARKER_FIELD_UINT8_COMMENT(name, comment) \
917 do { if( nRemainingMarkerSize >= 1 ) { \
918 nLastVal = *pabyMarkerDataIter; \
919 AddField(psMarker, name, *pabyMarkerDataIter, comment); \
920 pabyMarkerDataIter += 1; \
921 nRemainingMarkerSize -= 1; \
922 } \
923 else { \
924 AddError(psMarker, CPLSPrintf("Cannot read field %s", name)); \
925 nLastVal = 0; \
926 } \
927 } while(0)
928
929 #define READ_MARKER_FIELD_UINT8(name) \
930 READ_MARKER_FIELD_UINT8_COMMENT(name, NULL)
931
932 #define READ_MARKER_FIELD_UINT16_COMMENT(name, comment) \
933 do { if( nRemainingMarkerSize >= 2 ) { \
934 GUInt16 nVal; \
935 memcpy(&nVal, pabyMarkerDataIter, 2); \
936 CPL_MSBPTR16(&nVal); \
937 nLastVal = nVal; \
938 AddField(psMarker, name, nVal, comment); \
939 pabyMarkerDataIter += 2; \
940 nRemainingMarkerSize -= 2; \
941 } \
942 else { \
943 AddError(psMarker, CPLSPrintf("Cannot read field %s", name)); \
944 nLastVal = 0; \
945 } \
946 } while(0)
947
948 #define READ_MARKER_FIELD_UINT16(name) \
949 READ_MARKER_FIELD_UINT16_COMMENT(name, NULL)
950
951 #define READ_MARKER_FIELD_UINT32_COMMENT(name, comment) \
952 do { if( nRemainingMarkerSize >= 4 ) { \
953 GUInt32 nVal; \
954 memcpy(&nVal, pabyMarkerDataIter, 4); \
955 CPL_MSBPTR32(&nVal); \
956 AddField(psMarker, name, nVal, comment); \
957 nLastVal = nVal; \
958 pabyMarkerDataIter += 4; \
959 nRemainingMarkerSize -= 4; \
960 } \
961 else { \
962 AddError(psMarker, CPLSPrintf("Cannot read field %s", name)); \
963 nLastVal = 0; \
964 } \
965 } while(0)
966
967 #define READ_MARKER_FIELD_UINT32(name) \
968 READ_MARKER_FIELD_UINT32_COMMENT(name, NULL)
969
970 if( abyMarker[1] == 0x90 ) /* SOT */
971 {
972 READ_MARKER_FIELD_UINT16("Isot");
973 READ_MARKER_FIELD_UINT32("Psot");
974 GUInt32 PSOT = nLastVal;
975 READ_MARKER_FIELD_UINT8("TPsot");
976 READ_MARKER_FIELD_UINT8("TNsot");
977 if( nRemainingMarkerSize > 0 )
978 CPLCreateXMLElementAndValue(
979 psMarker, "RemainingBytes",
980 CPLSPrintf("%d", (int)nRemainingMarkerSize ));
981
982 if( PSOT )
983 nNextTileOffset = nOffset + PSOT;
984 }
985 else if( abyMarker[1] == 0x51 ) /* SIZ */
986 {
987 READ_MARKER_FIELD_UINT16_COMMENT("Rsiz",
988 (nLastVal == 0) ? "Unrestricted profile":
989 (nLastVal == 1) ? "Profile 0":
990 (nLastVal == 2) ? "Profile 1": NULL);
991 READ_MARKER_FIELD_UINT32("Xsiz");
992 READ_MARKER_FIELD_UINT32("Ysiz");
993 READ_MARKER_FIELD_UINT32("XOsiz");
994 READ_MARKER_FIELD_UINT32("YOsiz");
995 READ_MARKER_FIELD_UINT32("XTsiz");
996 READ_MARKER_FIELD_UINT32("YTsiz");
997 READ_MARKER_FIELD_UINT32("XTOSiz");
998 READ_MARKER_FIELD_UINT32("YTOSiz");
999 READ_MARKER_FIELD_UINT16("Csiz");
1000 int CSiz = nLastVal;
1001 for(int i=0;i<CSiz;i++)
1002 {
1003 READ_MARKER_FIELD_UINT8_COMMENT(CPLSPrintf("Ssiz%d", i),
1004 GetInterpretationOfBPC(nLastVal));
1005 READ_MARKER_FIELD_UINT8(CPLSPrintf("XRsiz%d", i));
1006 READ_MARKER_FIELD_UINT8(CPLSPrintf("YRsiz%d", i));
1007 }
1008 if( nRemainingMarkerSize > 0 )
1009 CPLCreateXMLElementAndValue(
1010 psMarker, "RemainingBytes",
1011 CPLSPrintf("%d", (int)nRemainingMarkerSize ));
1012 }
1013 else if( abyMarker[1] == 0x52 ) /* COD */
1014 {
1015 int bHasPrecincts = TRUE;
1016 if( nRemainingMarkerSize >= 1 ) {
1017 nLastVal = *pabyMarkerDataIter;
1018 CPLString osInterp;
1019 if( nLastVal & 0x1 )
1020 {
1021 bHasPrecincts = TRUE;
1022 osInterp += "User defined precincts";
1023 }
1024 else
1025 osInterp += "Standard precincts";
1026 osInterp += ", ";
1027 if( nLastVal & 0x2 )
1028 osInterp += "SOP marker segments may be used";
1029 else
1030 osInterp += "No SOP marker segments";
1031 osInterp += ", ";
1032 if( nLastVal & 0x4 )
1033 osInterp += "EPH marker segments may be used";
1034 else
1035 osInterp += "No EPH marker segments";
1036 AddField(psMarker, "Scod", (GByte)nLastVal, osInterp.c_str());
1037 pabyMarkerDataIter += 1;
1038 nRemainingMarkerSize -= 1;
1039 }
1040 else {
1041 AddError(psMarker, CPLSPrintf("Cannot read field %s", "Scod"));
1042 nLastVal = 0;
1043 }
1044 READ_MARKER_FIELD_UINT8_COMMENT("SGcod_Progress",
1045 (nLastVal == 0) ? "LRCP" :
1046 (nLastVal == 1) ? "RLCP" :
1047 (nLastVal == 2) ? "RPCL" :
1048 (nLastVal == 3) ? "PCRL" :
1049 (nLastVal == 4) ? "CPRL" : NULL);
1050 READ_MARKER_FIELD_UINT16("SGcod_NumLayers");
1051 READ_MARKER_FIELD_UINT8("SGcod_MCT");
1052 READ_MARKER_FIELD_UINT8("SPcod_NumDecompositions");
1053 READ_MARKER_FIELD_UINT8_COMMENT("SPcod_xcb_minus_2", CPLSPrintf("%d", 1 << (2+nLastVal)));
1054 READ_MARKER_FIELD_UINT8_COMMENT("SPcod_ycb_minus_2", CPLSPrintf("%d", 1 << (2+nLastVal)));
1055 if( nRemainingMarkerSize >= 1 ) {
1056 nLastVal = *pabyMarkerDataIter;
1057 CPLString osInterp;
1058 if( nLastVal & 0x1 )
1059 osInterp += "Selective arithmetic coding bypass";
1060 else
1061 osInterp += "No selective arithmetic coding bypass";
1062 osInterp += ", ";
1063 if( nLastVal & 0x2 )
1064 osInterp += "Reset context probabilities on coding pass boundaries";
1065 else
1066 osInterp += "No reset of context probabilities on coding pass boundaries";
1067 osInterp += ", ";
1068 if( nLastVal & 0x4 )
1069 osInterp += "Termination on each coding pass";
1070 else
1071 osInterp += "No termination on each coding pass";
1072 osInterp += ", ";
1073 if( nLastVal & 0x8 )
1074 osInterp += "Vertically causal context";
1075 else
1076 osInterp += "No vertically causal context";
1077 osInterp += ", ";
1078 if( nLastVal & 0x10 )
1079 osInterp += "Predictable termination";
1080 else
1081 osInterp += "No predictable termination";
1082 osInterp += ", ";
1083 if( nLastVal & 0x20 )
1084 osInterp += "Segmentation symbols are used";
1085 else
1086 osInterp += "No segmentation symbols are used";
1087 AddField(psMarker, "SPcod_cbstyle", (GByte)nLastVal, osInterp.c_str());
1088 pabyMarkerDataIter += 1;
1089 nRemainingMarkerSize -= 1;
1090 }
1091 else {
1092 AddError(psMarker, CPLSPrintf("Cannot read field %s", "SPcod_cbstyle"));
1093 nLastVal = 0;
1094 }
1095 READ_MARKER_FIELD_UINT8_COMMENT("SPcod_transformation",
1096 (nLastVal == 0) ? "9-7 irreversible":
1097 (nLastVal == 1) ? "5-3 reversible": NULL);
1098 if( bHasPrecincts )
1099 {
1100 int i = 0;
1101 while( nRemainingMarkerSize >= 1 )
1102 {
1103 nLastVal = *pabyMarkerDataIter;
1104 AddField(psMarker, CPLSPrintf("SPcod_Precincts%d", i), *pabyMarkerDataIter,
1105 CPLSPrintf("PPx=%d PPy=%d: %dx%d",
1106 nLastVal & 0xf, nLastVal >> 4,
1107 1 << (nLastVal & 0xf), 1 << (nLastVal >> 4)));
1108 pabyMarkerDataIter += 1;
1109 nRemainingMarkerSize -= 1;
1110 i ++;
1111 }
1112 }
1113 if( nRemainingMarkerSize > 0 )
1114 CPLCreateXMLElementAndValue(
1115 psMarker, "RemainingBytes",
1116 CPLSPrintf("%d", (int)nRemainingMarkerSize ));
1117 }
1118 else if( abyMarker[1] == 0x53 ) /* COC */
1119 {
1120 }
1121 else if( abyMarker[1] == 0x55 ) /* TLM */
1122 {
1123 CPLXMLNode* psMarker = CreateMarker( psCSBox, "TLM", nOffset, nMarkerSize );
1124 READ_MARKER_FIELD_UINT8("Ztlm");
1125 int ST = 0, SP = 0;
1126 READ_MARKER_FIELD_UINT8_COMMENT("Stlm",
1127 CPLSPrintf("ST=%d SP=%d",
1128 (ST = (nLastVal >> 4) & 3),
1129 (SP = ((nLastVal >> 6) & 1))));
1130 int nTilePartDescLength = ST + ((SP == 0) ? 2 : 4);
1131 int i = 0;
1132 while( nRemainingMarkerSize >= nTilePartDescLength )
1133 {
1134 if( ST == 1 )
1135 READ_MARKER_FIELD_UINT8(CPLSPrintf("Ttlm%d", i));
1136 else if( ST == 2 )
1137 READ_MARKER_FIELD_UINT16(CPLSPrintf("Ttlm%d", i));
1138 if( SP == 0 )
1139 READ_MARKER_FIELD_UINT16(CPLSPrintf("Ptlm%d", i));
1140 else
1141 READ_MARKER_FIELD_UINT32(CPLSPrintf("Ptlm%d", i));
1142 i ++;
1143 }
1144 if( nRemainingMarkerSize > 0 )
1145 CPLCreateXMLElementAndValue(
1146 psMarker, "RemainingBytes",
1147 CPLSPrintf("%d", (int)nRemainingMarkerSize ));
1148 }
1149 else if( abyMarker[1] == 0x57 ) /* PLM */
1150 {
1151 }
1152 else if( abyMarker[1] == 0x58 ) /* PLT */
1153 {
1154 }
1155 else if( abyMarker[1] == 0x5C ) /* QCD */
1156 {
1157 }
1158 else if( abyMarker[1] == 0x5D ) /* QCC */
1159 {
1160 }
1161 else if( abyMarker[1] == 0x5E ) /* RGN */
1162 {
1163 }
1164 else if( abyMarker[1] == 0x5F ) /* POC */
1165 {
1166 }
1167 else if( abyMarker[1] == 0x60 ) /* PPM */
1168 {
1169 }
1170 else if( abyMarker[1] == 0x61 ) /* PPT */
1171 {
1172 }
1173 else if( abyMarker[1] == 0x63 ) /* CRG */
1174 {
1175 }
1176 else if( abyMarker[1] == 0x64 ) /* COM */
1177 {
1178 READ_MARKER_FIELD_UINT16_COMMENT("Rcom", (nLastVal == 0 ) ? "Binary" : (nLastVal == 1) ? "LATIN1" : NULL);
1179 if( nLastVal == 1 )
1180 {
1181 GByte abyBackup = pabyMarkerDataIter[nRemainingMarkerSize];
1182 pabyMarkerDataIter[nRemainingMarkerSize] = 0;
1183 AddField(psMarker, "COM", (int)nRemainingMarkerSize, (const char*)pabyMarkerDataIter);
1184 pabyMarkerDataIter[nRemainingMarkerSize] = abyBackup;
1185 }
1186 }
1187
1188 VSIFSeekL(fp, nOffset + 2 + nMarkerSize, SEEK_SET);
1189 }
1190 CPLFree(pabyMarkerData);
1191 return psCSBox;
1192 }
1193
1194 /************************************************************************/
1195 /* GDALGetJPEG2000StructureInternal() */
1196 /************************************************************************/
1197
1198 static
GDALGetJPEG2000StructureInternal(CPLXMLNode * psParent,VSILFILE * fp,GDALJP2Box * poParentBox,char ** papszOptions)1199 void GDALGetJPEG2000StructureInternal(CPLXMLNode* psParent,
1200 VSILFILE* fp,
1201 GDALJP2Box* poParentBox,
1202 char** papszOptions)
1203 {
1204 static const char* szHex = "0123456789ABCDEF";
1205 GDALJP2Box oBox( fp );
1206 if( oBox.ReadFirstChild(poParentBox) )
1207 {
1208 while( strlen(oBox.GetType()) > 0 )
1209 {
1210 GIntBig nBoxDataLength = oBox.GetDataLength();
1211 const char* pszBoxType = oBox.GetType();
1212
1213 CPLXMLNode* psBox = CPLCreateXMLNode( psParent, CXT_Element, "JP2Box" );
1214 CPLAddXMLAttributeAndValue(psBox, "name", pszBoxType );
1215 CPLAddXMLAttributeAndValue(psBox, "box_offset",
1216 CPLSPrintf(CPL_FRMT_GIB, oBox.GetBoxOffset() ) );
1217 CPLAddXMLAttributeAndValue(psBox, "box_length",
1218 CPLSPrintf(CPL_FRMT_GIB, oBox.GetBoxLength() ) );
1219 CPLAddXMLAttributeAndValue(psBox, "data_offset",
1220 CPLSPrintf(CPL_FRMT_GIB, oBox.GetDataOffset() ) );
1221 CPLAddXMLAttributeAndValue(psBox, "data_length",
1222 CPLSPrintf(CPL_FRMT_GIB, nBoxDataLength ) );
1223
1224 if( oBox.IsSuperBox() )
1225 {
1226 GDALGetJPEG2000StructureInternal(psBox, fp, &oBox, papszOptions);
1227 }
1228 else
1229 {
1230 if( strcmp(pszBoxType, "uuid") == 0 )
1231 {
1232 char* pszBinaryContent = (char*)VSIMalloc( 2 * 16 + 1 );
1233 const GByte* pabyUUID = oBox.GetUUID();
1234 for(int i=0;i<16;i++)
1235 {
1236 pszBinaryContent[2*i] = szHex[pabyUUID[i] >> 4];
1237 pszBinaryContent[2*i+1] = szHex[pabyUUID[i] & 0xf];
1238 }
1239 pszBinaryContent[2*16] = '\0';
1240 CPLXMLNode* psUUIDNode =
1241 CPLCreateXMLNode( psBox, CXT_Element, "UUID" );
1242 if( GDALJP2Metadata::IsUUID_MSI(pabyUUID) )
1243 CPLAddXMLAttributeAndValue(psUUIDNode, "description", "GeoTIFF" );
1244 else if( GDALJP2Metadata::IsUUID_XMP(pabyUUID) )
1245 CPLAddXMLAttributeAndValue(psUUIDNode, "description", "XMP" );
1246 CPLCreateXMLNode( psUUIDNode, CXT_Text, pszBinaryContent);
1247 VSIFree(pszBinaryContent);
1248 }
1249
1250 if( (CSLFetchBoolean(papszOptions, "BINARY_CONTENT", FALSE) ||
1251 CSLFetchBoolean(papszOptions, "ALL", FALSE) ) &&
1252 strcmp(pszBoxType, "jp2c") != 0 &&
1253 nBoxDataLength < 100 * 1024 )
1254 {
1255 CPLXMLNode* psBinaryContent = CPLCreateXMLNode( psBox, CXT_Element, "BinaryContent" );
1256 GByte* pabyBoxData = oBox.ReadBoxData();
1257 int nBoxLength = (int)nBoxDataLength;
1258 char* pszBinaryContent = (char*)VSIMalloc( 2 * nBoxLength + 1 );
1259 if( pabyBoxData && pszBinaryContent )
1260 {
1261 for(int i=0;i<nBoxLength;i++)
1262 {
1263 pszBinaryContent[2*i] = szHex[pabyBoxData[i] >> 4];
1264 pszBinaryContent[2*i+1] = szHex[pabyBoxData[i] & 0xf];
1265 }
1266 pszBinaryContent[2*nBoxLength] = '\0';
1267 CPLCreateXMLNode( psBinaryContent, CXT_Text, pszBinaryContent );
1268 }
1269 CPLFree(pabyBoxData);
1270 VSIFree(pszBinaryContent);
1271 }
1272
1273 if( (CSLFetchBoolean(papszOptions, "TEXT_CONTENT", FALSE) ||
1274 CSLFetchBoolean(papszOptions, "ALL", FALSE) ) &&
1275 strcmp(pszBoxType, "jp2c") != 0 &&
1276 nBoxDataLength < 100 * 1024 )
1277 {
1278 GByte* pabyBoxData = oBox.ReadBoxData();
1279 if( pabyBoxData )
1280 {
1281 if( CPLIsUTF8((const char*)pabyBoxData, -1) &&
1282 (int)strlen((const char*)pabyBoxData) + 2 >= nBoxDataLength )
1283 {
1284 CPLXMLNode* psXMLContentBox = NULL;
1285 if( ((const char*)pabyBoxData)[0] == '<' )
1286 {
1287 CPLPushErrorHandler(CPLQuietErrorHandler);
1288 psXMLContentBox = CPLParseXMLString((const char*)pabyBoxData);
1289 CPLPopErrorHandler();
1290 }
1291 if( psXMLContentBox )
1292 {
1293 CPLXMLNode* psXMLContentNode =
1294 CPLCreateXMLNode( psBox, CXT_Element, "XMLContent" );
1295 psXMLContentNode->psChild = psXMLContentBox;
1296 }
1297 else
1298 {
1299 CPLCreateXMLNode(
1300 CPLCreateXMLNode( psBox, CXT_Element, "TextContent" ),
1301 CXT_Text, (const char*)pabyBoxData);
1302 }
1303 }
1304 }
1305 CPLFree(pabyBoxData);
1306 }
1307
1308 if( strcmp(pszBoxType, "jp2c") == 0 )
1309 {
1310 if( CSLFetchBoolean(papszOptions, "CODESTREAM", FALSE) ||
1311 CSLFetchBoolean(papszOptions, "ALL", FALSE) )
1312 {
1313 DumpJPK2CodeStream(psBox, fp,
1314 oBox.GetDataOffset(), nBoxDataLength);
1315 }
1316 }
1317 else if( strcmp(pszBoxType, "uuid") == 0 &&
1318 GDALJP2Metadata::IsUUID_MSI(oBox.GetUUID()) )
1319 {
1320 DumpGeoTIFFBox(psBox, oBox);
1321 }
1322 else if( strcmp(pszBoxType, "ftyp") == 0 )
1323 {
1324 DumpFTYPBox(psBox, oBox);
1325 }
1326 else if( strcmp(pszBoxType, "ihdr") == 0 )
1327 {
1328 DumpIHDRBox(psBox, oBox);
1329 }
1330 else if( strcmp(pszBoxType, "bpcc") == 0 )
1331 {
1332 DumpBPCCBox(psBox, oBox);
1333 }
1334 else if( strcmp(pszBoxType, "colr") == 0 )
1335 {
1336 DumpCOLRBox(psBox, oBox);
1337 }
1338 else if( strcmp(pszBoxType, "pclr") == 0 )
1339 {
1340 DumpPCLRBox(psBox, oBox);
1341 }
1342 else if( strcmp(pszBoxType, "cmap") == 0 )
1343 {
1344 DumpCMAPBox(psBox, oBox);
1345 }
1346 else if( strcmp(pszBoxType, "cdef") == 0 )
1347 {
1348 DumpCDEFBox(psBox, oBox);
1349 }
1350 else if( strcmp(pszBoxType, "resc") == 0 ||
1351 strcmp(pszBoxType, "resd") == 0)
1352 {
1353 DumpRESxBox(psBox, oBox);
1354 }
1355 else if( strcmp(pszBoxType, "rreq") == 0 )
1356 {
1357 DumpRREQBox(psBox, oBox);
1358 }
1359 }
1360
1361 if (!oBox.ReadNextChild(poParentBox))
1362 break;
1363 }
1364 }
1365 }
1366
1367 /************************************************************************/
1368 /* GDALGetJPEG2000Structure() */
1369 /************************************************************************/
1370
1371 static const unsigned char jpc_header[] = {0xff,0x4f};
1372 static const unsigned char jp2_box_jp[] = {0x6a,0x50,0x20,0x20}; /* 'jP ' */
1373
1374 /** Dump the structure of a JPEG2000 file as a XML tree.
1375 *
1376 * @param pszFilename filename.
1377 * @param papszOptions NULL terminated list of options, or NULL.
1378 * Allowed options are BINARY_CONTENT=YES, TEXT_CONTENT=YES,
1379 * CODESTREAM=YES, ALL=YES.
1380 * @return XML tree (to be freed with CPLDestroyXMLNode()) or NULL in case
1381 * of error
1382 * @since GDAL 2.0
1383 */
1384
GDALGetJPEG2000Structure(const char * pszFilename,char ** papszOptions)1385 CPLXMLNode* GDALGetJPEG2000Structure(const char* pszFilename,
1386 char** papszOptions)
1387 {
1388 VSILFILE* fp = VSIFOpenL(pszFilename, "rb");
1389 if( fp == NULL )
1390 {
1391 CPLError(CE_Failure, CPLE_AppDefined, "Cannot open %s", pszFilename);
1392 return NULL;
1393 }
1394 GByte abyHeader[16];
1395 if( VSIFReadL(abyHeader, 16, 1, fp) != 1 ||
1396 (memcmp(abyHeader, jpc_header, sizeof(jpc_header)) != 0 &&
1397 memcmp(abyHeader + 4, jp2_box_jp, sizeof(jp2_box_jp)) != 0) )
1398 {
1399 CPLError(CE_Failure, CPLE_AppDefined, "%s is not a JPEG2000 file", pszFilename);
1400 VSIFCloseL(fp);
1401 return NULL;
1402 }
1403
1404 CPLXMLNode* psParent = NULL;
1405 if( memcmp(abyHeader, jpc_header, sizeof(jpc_header)) == 0 )
1406 {
1407 if( CSLFetchBoolean(papszOptions, "CODESTREAM", FALSE) ||
1408 CSLFetchBoolean(papszOptions, "ALL", FALSE) )
1409 {
1410 VSIFSeekL(fp, 0, SEEK_END);
1411 GIntBig nBoxDataLength = (GIntBig)VSIFTellL(fp);
1412 psParent = DumpJPK2CodeStream(NULL, fp, 0, nBoxDataLength);
1413 CPLAddXMLAttributeAndValue(psParent, "filename", pszFilename );
1414 }
1415 }
1416 else
1417 {
1418 psParent = CPLCreateXMLNode( NULL, CXT_Element, "JP2File" );
1419 CPLAddXMLAttributeAndValue(psParent, "filename", pszFilename );
1420 GDALGetJPEG2000StructureInternal(psParent, fp, NULL, papszOptions );
1421 }
1422
1423 VSIFCloseL(fp);
1424 return psParent;
1425 }
1426