OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
ossimJp2Info.cpp
Go to the documentation of this file.
1 //----------------------------------------------------------------------------
2 //
3 // License: LGPL
4 //
5 // See LICENSE.txt file in the top level directory for more details.
6 //
7 // Author: David Burken
8 //
9 // Description: JP2 Info object.
10 //
11 //----------------------------------------------------------------------------
12 // $Id: ossimJp2Info.cpp 23222 2015-04-05 15:44:57Z dburken $
13 
15 #include <ossim/base/ossimCommon.h>
16 #include <ossim/base/ossimEndian.h>
19 #include <ossim/base/ossimTrace.h>
20 // #include <ossim/support_data/ossimJ2kCommon.h>
22 #include <fstream>
23 #include <istream>
24 #include <iostream>
25 
26 static ossimTrace traceDebug("ossimJp2Info:debug");
27 
29  : ossimJ2kInfo()
30 {
31 }
32 
34 {
35 }
36 
38 {
39  bool result = false;
40 
41  std::ifstream str;
42  str.open( file.c_str(), std::ios_base::in | std::ios_base::binary);
43 
44  if ( str.is_open() )
45  {
46  const ossim_uint8 J2K_SIGNATURE_BOX[SIGNATURE_BOX_SIZE] =
47  {0x00,0x00,0x00,0x0c,0x6a,0x50,0x20,0x20,0x0d,0x0a,0x87,0x0a};
48 
50 
51  // Read in the box.
52  str.read((char*)box, SIGNATURE_BOX_SIZE);
53 
54  result = true;
55  for (ossim_uint32 i = 0; i < SIGNATURE_BOX_SIZE; ++i)
56  {
57  if (box[i] != J2K_SIGNATURE_BOX[i])
58  {
59  result = false;
60  break;
61  }
62  }
63 
64  str.close();
65  }
66 
67  if ( result )
68  {
69  m_file = file; // Capture file name.
70  }
71 
72  return result;
73 }
74 
76 {
77  if ( m_file.size() )
78  {
79  // Open the file.
80  std::ifstream str( m_file.c_str(), std::ios_base::in | std::ios_base::binary );
81  if (str.good())
82  {
83  //---
84  // ISO/IEC 15444-1:2004 (E)
85  // LBox, Box Length. This field specifies the length of the box, stored
86  // as a 4-byte big endian unsigned integer. This value includes all of
87  // the fields of the box, including the length and type. If the value
88  // of this field is 1, then the XLBox field shall exist and the value
89  // of that field shall be the actual length of the box. If the value
90  // of this field is 0, then the length of the box was not known when
91  // the LBox field was written. In this case, this box contains all
92  // bytes up to the end of the file. If a box of length 0 is contained
93  // within another box (its superbox), then the length of that superbox
94  // shall also be 0. This means that this box is the last box in the
95  // file. The values 2-7 are reserved for ISO use.
96  //---
97  ossim_uint32 lbox = 0;
98  ossim_uint32 tbox = 0;
99  ossim_uint64 xlbox = 0;
100 
101  const ossim_uint32 UUID_TYPE = 0x75756964;
102  const ossim_uint8 GEOTIFF_UUID[GEOTIFF_UUID_SIZE] =
103  {
104  0xb1, 0x4b, 0xf8, 0xbd,
105  0x08, 0x3d, 0x4b, 0x43,
106  0xa5, 0xae, 0x8c, 0xd7,
107  0xd5, 0xa6, 0xce, 0x03
108  };
109 
110  while ( str.good() )
111  {
112  std::streamoff boxPos = str.tellg();
113 
114  readUInt32( lbox, str );
115  readUInt32( tbox, str );
116 
117  if ( 1 == lbox )
118  {
119  readUInt64( xlbox, str );
120  }
121 
122  if ( traceDebug() )
123  {
125  << "jp2.lbox: " << std::dec << lbox << "\n"
126  << "jp2.tbox: " << std::hex << tbox << std::dec << "\n";
128 
129  if ( 1 == lbox )
130  {
131  ossimNotify(ossimNotifyLevel_DEBUG) << "jp2.xlbox: " << xlbox << std::endl;
132  }
133  }
134 
135  if (tbox == UUID_TYPE)
136  {
137  // Check for GeoTIFF box.
138 
139  ossim_uint8 geotiffUuid[GEOTIFF_UUID_SIZE];
140 
141  // Read in the id.
142  str.read((char*)geotiffUuid, GEOTIFF_UUID_SIZE);
143 
144 #if 0
145  bool foundIt = true;
146  for (ossim_uint32 i = 0; i < GEOTIFF_UUID_SIZE; ++i)
147  {
148  if (geotiffUuid[i] != GEOTIFF_UUID[i])
149  {
150  foundIt = false;
151  break;
152  }
153  }
154 #endif
155 
156  if( memcmp( (char*)geotiffUuid, GEOTIFF_UUID, GEOTIFF_UUID_SIZE) == 0)
157  {
158  //---
159  // Feed the stream to the tiff info object to get a keyword
160  // list with geometry/projection info.
161  //---
162  ossimTiffInfo info;
163 
164  //---
165  // Have geotiff boxes with badly terminated geotiffs. So to keep
166  // the tag parser from walking past the first image file directory
167  // (IFD) into garbage we will set the process overview flag to false.
168  //
169  // Note if we ever get multiple entries we will need to take this out.
170  //---
171  info.setProcessOverviewFlag(false);
172 
173  // Do a print to a memory stream.
175  info.print(str, os);
176 
177  // Open an input stream to pass to the keyword list.
178  std::istringstream in( os.str() );
179 
180  ossimKeywordlist kwl;
181  if ( kwl.parseStream(in) )
182  {
183  kwl.addPrefixToAll( ossimString("jp2.") );
184 
185  // Print it:
186  out << kwl << std::endl;
187  }
188 
189  // Get out of while loop.
190  // break;
191  }
192  }
193 
194  if (lbox == 0) // last box?
195  {
196  break;
197  }
198 
199  // Seek to the next box. If xlbox is 1
200  if (lbox == 1)
201  {
202  boxPos += (std::streamoff)xlbox;
203  }
204  else
205  {
206  boxPos += (std::streamoff)lbox;
207  }
208 
209  // Go to next box:
210  str.seekg(boxPos, std::ios_base::beg);
211 
212  } // matches: while ( str.good() )
213 
214  // Close the stream.
215  str.close();
216 
217  } // matches: if ( str.is_open() )
218 
219  } // matches: if ( m_file.size() )
220 
221  return out;
222 }
223 
225 {
226  str.read((char*)&i, 4);
227  if (m_endian)
228  {
229  m_endian->swap(i);
230  }
231 }
232 
234 {
235  str.read((char*)&i, 8);
236  if (m_endian)
237  {
238  m_endian->swap(i);
239  }
240 }
241 
242 std::streamoff ossimJp2Info::findBoxData( const ossim_uint32& type,
243  std::ifstream& str,
244  ossim_uint32& length ) const
245 {
246  std::streamoff boxPos = 0;
247  std::streamoff dataPosOfType = 0;
248 
249  if ( str.good() )
250  {
251  ossim_uint32 lbox = 0;
252  ossim_uint32 tbox = 0;
253  ossim_uint64 xlbox = 0;
254  std::streamoff offsetToDbox = 0;
255 
256  while ( str.good() )
257  {
258  boxPos = str.tellg();
259 
260  readUInt32( lbox, str );
261  readUInt32( tbox, str );
262 
263  if ( lbox == 1 )
264  {
265  readUInt64( xlbox, str );
266  offsetToDbox = 16;
267  }
268  else
269  {
270  offsetToDbox = 8;
271  }
272 
273  if ( traceDebug() )
274  {
276  << "jp2.lbox: " << std::dec << lbox << "\n"
277  << "jp2.tbox: " << std::hex << tbox << std::dec << "\n";
279 
280  if ( lbox == 1 )
281  {
282  ossimNotify(ossimNotifyLevel_DEBUG) << "jp2.xlbox: " << xlbox << std::endl;
283  }
284  }
285 
286  if ( tbox == type )
287  {
288  dataPosOfType = boxPos + offsetToDbox; // set up return value
289  length = lbox;
290  break; // done...
291  }
292 
293  if ( lbox == 0 ) // last box?
294  {
295  break;
296  }
297 
298  // Seek to the next box.
299  std::streamoff nextBoxPos = boxPos;
300  if (lbox == 1)
301  {
302  nextBoxPos+= (std::streamoff)xlbox;
303  }
304  else
305  {
306  nextBoxPos+= (std::streamoff)lbox;
307  }
308 
309  // Go to next box:
310  str.seekg(nextBoxPos, std::ios_base::beg);
311 
312  } // matches: while ( str.good() )
313 
314  } // matches: if ( str.good() )
315 
316  return dataPosOfType;
317 }
318 
319 std::streamoff ossimJp2Info::getBox( const ossim_uint32 type,
320  bool includeAll,
321  std::vector<ossim_uint8>& box ) const
322 {
323  std::streamoff boxPos = 0;
324 
325  if ( m_file.size() )
326  {
327  // Open the file.
328  std::ifstream str( m_file.c_str(), std::ios_base::in | std::ios_base::binary );
329  if (str.good())
330  {
331  boxPos = getBox( type, includeAll, str, box ) ;
332 
333  } // matches: if ( str.is_open() )
334 
335  } // matches: if ( m_file.size() )
336 
337  return boxPos;
338 
339 } // End: ossimJp2Info::getBox( type, includeAll, box ) const
340 
341 std::streamoff ossimJp2Info::getBox( const ossim_uint32& type,
342  bool includeAll,
343  std::ifstream& str,
344  std::vector<ossim_uint8>& box ) const
345 {
346  std::streamoff boxPos = 0;
347  std::streamoff boxPosOfType = 0;
348  box.clear();
349 
350  if ( str.good() )
351  {
352  ossim_uint32 lbox = 0;
353  ossim_uint32 tbox = 0;
354  ossim_uint64 xlbox = 0;
355  std::streamoff offsetToDbox = 0;
356 
357  while ( str.good() )
358  {
359  boxPos = str.tellg();
360 
361  readUInt32( lbox, str );
362  readUInt32( tbox, str );
363 
364  if ( lbox == 1 )
365  {
366  readUInt64( xlbox, str );
367  offsetToDbox = 16;
368  }
369 
370  if ( !includeAll )
371  {
372  if ( lbox == 1 )
373  {
374  offsetToDbox = 16;
375  }
376  else
377  {
378  offsetToDbox = 8;
379  }
380  }
381 
382  if ( traceDebug() )
383  {
385  << "jp2.lbox: " << std::dec << lbox << "\n"
386  << "jp2.tbox: " << std::hex << tbox << std::dec << "\n";
388 
389  if ( 1 == lbox )
390  {
391  ossimNotify(ossimNotifyLevel_DEBUG) << "jp2.xlbox: " << xlbox << std::endl;
392  }
393  }
394 
395 
396  if ( tbox == type )
397  {
398  //---
399  // This is our box, copy it to box.
400  // Not copying the lbox,tbox or xlbox
401  std::streamoff boxSize = 0;
402  if ( lbox == 0 )
403  {
404  // Last box, goes to end of file.
405  str.seekg( 0, std::ios_base::end );
406  boxSize = str.tellg() - boxPos;
407  }
408  else if ( lbox == 1 )
409  {
410  boxSize = xlbox;
411  }
412  else
413  {
414  boxSize = lbox;
415  }
416  boxSize -= offsetToDbox;
417 
418  // Seek to box data start
419  str.seekg( boxPos + offsetToDbox, std::ios_base::beg );
420 
421  // std::vector::resize can throw a std::bad_alloc so wrap it...
422  try
423  {
424  box.resize( boxSize );
425  str.read( (char*)&box.front(), boxSize );
426  }
427  catch( std::exception& e )
428  {
429  std::ostringstream errMsg;
430  errMsg << "ossimJp2Info::getBox caught exception on resize:\n"
431  << "Buffer size in bytes: " << boxSize
432  << "\n" << e.what() << std::endl;
433  throw ossimException( errMsg.str() );
434  }
435 
436  boxPosOfType = boxPos; // set up return value
437  break; // done...
438  }
439 
440  if (lbox == 0) // last box?
441  {
442  break;
443  }
444 
445  // Seek to the next box.
446  std::streamoff nextBoxPos = boxPos;
447  if (lbox == 1)
448  {
449  nextBoxPos+= (std::streamoff)xlbox;
450  }
451  else
452  {
453  nextBoxPos+= (std::streamoff)lbox;
454  }
455 
456  // Go to next box:
457  str.seekg(nextBoxPos, std::ios_base::beg);
458 
459  } // matches: while ( str.good() )
460 
461  } // matches: if ( str.good() )
462 
463  return boxPosOfType;
464 
465 } // End: ossimJp2Info::getBox( type, includeAll, str, box ) const
466 
468  std::ifstream& str, std::vector<ossim_uint8>& box ) const
469 {
470  std::streamoff boxPos = 0;
471  if ( str.good() )
472  {
473  const ossim_uint32 UUID_TYPE = 0x75756964;
474 
475  boxPos = getBox( UUID_TYPE, false, str, box );
476  if ( boxPos && ( box.size() >= GEOTIFF_UUID_SIZE) )
477  {
478  const ossim_uint8 GEOTIFF_UUID[GEOTIFF_UUID_SIZE] =
479  {
480  0xb1, 0x4b, 0xf8, 0xbd,
481  0x08, 0x3d, 0x4b, 0x43,
482  0xa5, 0xae, 0x8c, 0xd7,
483  0xd5, 0xa6, 0xce, 0x03
484  };
485 
486  if( memcmp( (char*)&box.front(), GEOTIFF_UUID, GEOTIFF_UUID_SIZE) != 0)
487  {
488  boxPos = 0;
489  box.clear();
490  }
491  }
492  }
493  return boxPos;
494 }
495 
496 std::streamoff ossimJp2Info::getGmlBox(
497  std::ifstream& str, std::vector<ossim_uint8>& box ) const
498 {
499  std::streamoff boxPos = 0;
500  if ( str.good() )
501  {
502  const ossim_uint32 ASOC_TBOX_ID = 0x61736F63;
503  const ossim_uint32 LBL_TBOX_ID = 0x6C626C20;
504  const ossim_uint32 XML_TBOX_ID = 0x786D6C20;
505 
506  ossim_uint32 asoc0_data_length = 0;
507  std::streamoff dataPosAsoc0 = findBoxData( ASOC_TBOX_ID, str, asoc0_data_length );
508 
509  if ( dataPosAsoc0 > 0 && asoc0_data_length > 0 )
510  {
511  ossim_uint32 lbl0_data_length = 0;
512  std::streamoff dataPosLbl0 = findBoxData( LBL_TBOX_ID, str, lbl0_data_length );
513 
514  if ( dataPosLbl0 > 0 && lbl0_data_length > 0 )
515  {
516  std::string gmlDataStr;
517  gmlDataStr.resize( lbl0_data_length );
518 
519  // Removed c++ 11 call for portablility...
520  // str.read( (char*)&gmlDataStr.front(), lbl0_data_length );
521  str.read( (char*)&gmlDataStr[0], lbl0_data_length );
522 
523  // Do we have a GML data asoc ?
524  if ( gmlDataStr.compare( 0, 8, "gml.data" ) == 0 )
525  {
526  // Seek to asoc 0 start of data
527  str.seekg( dataPosAsoc0, std::ios_base::beg );
528 
529  ossim_uint32 asoc1_data_length = 0;
530  std::streamoff dataPosAsoc1 = findBoxData( ASOC_TBOX_ID, str, asoc1_data_length );
531 
532  if ( dataPosAsoc1 > 0 && asoc1_data_length > 0 )
533  {
534  ossim_uint32 lbl1_data_length = 0;
535  std::streamoff dataPosLbl1 = findBoxData( LBL_TBOX_ID, str, lbl1_data_length );
536 
537  if ( dataPosLbl1 > 0 && lbl1_data_length > 0 )
538  {
539  std::string gmlRootInstanceStr;
540  gmlRootInstanceStr.resize( lbl1_data_length );
541  // Removed c++ 11 call for portablility...
542  // str.read( (char*)&gmlRootInstanceStr.front(), lbl1_data_length );
543  str.read( (char*)&gmlRootInstanceStr[0], lbl1_data_length );
544 
545  // Do we have a GML root-instance asoc ?
546  if ( gmlRootInstanceStr.compare( 0, 17, "gml.root-instance" ) == 0 )
547  {
548  // Seek to asoc 1 start of data
549  str.seekg( dataPosAsoc1, std::ios_base::beg );
550 
551  boxPos = getBox( XML_TBOX_ID, false, str, box );
552  }
553  }
554  }
555  }
556  }
557  }
558  }
559  return boxPos;
560 }
561 
563 {
564  std::string boxType;
565 
566  const ossim_uint32 JP2_ASSOC_TYPE = 0x61736f63;
567  const ossim_uint32 JP2_LABEL_TYPE = 0x6c626c20;
568  const ossim_uint32 JP2_SIG_TYPE = 0x6A502020;
569  const ossim_uint32 FILE_TYPE = 0x66747970;
570  const ossim_uint32 JP2_HDR_TYPE = 0x6A703268;
571  const ossim_uint32 IMG_HDR_TYPE = 0x69686472;
572  const ossim_uint32 BPCC_TYPE = 0x62706363;
573  const ossim_uint32 COLR_TYPE = 0x636F6C72;
574  const ossim_uint32 PCLR_TYPE = 0x70636C72;
575  const ossim_uint32 CMAP_TYPE = 0x636D6170;
576  const ossim_uint32 CDEF_TYPE = 0x63646566;
577  const ossim_uint32 RES_TYPE = 0x72657320;
578  const ossim_uint32 RESC_TYPE = 0x72657363;
579  const ossim_uint32 RESD_TYPE = 0x72657364;
580  const ossim_uint32 JP2C_TYPE = 0x6A703263;
581  const ossim_uint32 JP2I_TYPE = 0x6A703269;
582  const ossim_uint32 XML_TYPE = 0x786D6C20;
583  const ossim_uint32 UUID_TYPE = 0x75756964;
584 
585  switch( tbox )
586  {
587  case JP2_ASSOC_TYPE:
588  {
589  boxType = "jp2_assoc";
590  break;
591  }
592  case JP2_LABEL_TYPE:
593  {
594  boxType = "jp2_label";
595  break;
596  }
597  case JP2_SIG_TYPE:
598  {
599  boxType = "jp2_sig";
600  break;
601  }
602  case FILE_TYPE:
603  {
604  boxType = "ftyp";
605  break;
606  }
607  case JP2_HDR_TYPE:
608  {
609  boxType = "jp2h";
610  break;
611  }
612  case IMG_HDR_TYPE:
613  {
614  boxType = "ihdr";
615  break;
616  }
617  case BPCC_TYPE:
618  {
619  boxType = "bpcc";
620  break;
621  }
622  case COLR_TYPE:
623  {
624  boxType = "colr";
625  break;
626  }
627  case PCLR_TYPE:
628  {
629  boxType = "pclr";
630  break;
631  }
632  case CMAP_TYPE:
633  {
634  boxType = "cmap";
635  break;
636  }
637  case CDEF_TYPE:
638  {
639  boxType = "cdef";
640  break;
641  }
642  case RES_TYPE:
643  {
644  boxType = "res";
645  break;
646  }
647  case RESC_TYPE:
648  {
649  boxType = "resc";
650  break;
651  }
652  case RESD_TYPE:
653  {
654  boxType = "resd";
655  break;
656  }
657  case JP2C_TYPE:
658  {
659  boxType = "jp2c";
660  break;
661  }
662  case JP2I_TYPE:
663  {
664  boxType = "jp2i";
665  break;
666  }
667  case XML_TYPE:
668  {
669  boxType = "xml";
670  break;
671  }
672  case UUID_TYPE:
673  {
674  boxType = "uuid";
675  break;
676  }
677  default:
678  {
679  boxType = "unhandled";
680  break;
681  }
682  }
683 
684  out << "jp2.box_type: " << boxType << "\n";
685 }
ossimFilename m_file
Definition: ossimJ2kInfo.h:120
virtual std::ostream & print(std::ostream &out) const
Print method.
void setProcessOverviewFlag(bool flag)
Sets the overview flag.
std::basic_ostringstream< char > ostringstream
Class for char output memory streams.
Definition: ossimIosFwd.h:35
TIFF info class.
Definition: ossimJ2kInfo.h:27
virtual bool open(const ossimFilename &file)
open method.
Represents serializable keyword/value map.
std::basic_ifstream< char > ifstream
Class for char input file streams.
Definition: ossimIosFwd.h:44
ossimJp2Info()
default constructor
ossimEndian * m_endian
Definition: ossimJ2kInfo.h:121
std::streamoff getBox(const ossim_uint32 type, bool includeAll, std::vector< ossim_uint8 > &box) const
This gets a box of type and stuffs in box.
void readUInt64(ossim_uint64 &i, std::ifstream &str) const
Initializes i reference.
TIFF info class.
Definition: ossimTiffInfo.h:36
virtual ~ossimJp2Info()
virtual destructor
std::string::size_type size() const
Definition: ossimString.h:405
unsigned long long ossim_uint64
unsigned int ossim_uint32
void readUInt32(ossim_uint32 &i, std::ifstream &str) const
Initializes i reference.
void printTboxType(ossim_uint32 tbox, std::ostream &out) const
Print tbox type as string if known.
virtual std::ostream & print(std::ostream &out) const
Print method.
void addPrefixToAll(const ossimString &prefix)
const char * c_str() const
Returns a pointer to a null-terminated array of characters representing the string&#39;s contents...
Definition: ossimString.h:396
std::basic_istringstream< char > istringstream
Class for char input memory streams.
Definition: ossimIosFwd.h:32
std::streamoff getGmlBox(std::ifstream &str, std::vector< ossim_uint8 > &box) const
Method to get the embedded JP2 GML Box.
std::streamoff getGeotiffBox(std::ifstream &str, std::vector< ossim_uint8 > &box) const
Method to get the embedded JP2 GeoTIFF box.
void swap(ossim_sint8 &)
Definition: ossimEndian.h:26
unsigned char ossim_uint8
OSSIMDLLEXPORT std::ostream & ossimNotify(ossimNotifyLevel level=ossimNotifyLevel_WARN)
std::basic_ostream< char > ostream
Base class for char output streams.
Definition: ossimIosFwd.h:23
std::streamoff findBoxData(const ossim_uint32 &type, std::ifstream &str, ossim_uint32 &length) const
This finds a box of type and returns the location of its data.