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