1 /******************************************************************************
2  * $Id: hfa_p.h 085ace6b956265eaf2405b298048c59e7a9027cd 2019-10-19 23:19:13 +0200 Even Rouault $
3  *
4  * Project:  Erdas Imagine (.img) Translator
5  * Purpose:  Private class declarations for the HFA classes used to read
6  *           Erdas Imagine (.img) files.  Public (C callable) declarations
7  *           are in hfa.h.
8  * Author:   Frank Warmerdam, warmerdam@pobox.com
9  *
10  ******************************************************************************
11  * Copyright (c) 1999, Intergraph Corporation
12  *
13  * Permission is hereby granted, free of charge, to any person obtaining a
14  * copy of this software and associated documentation files (the "Software"),
15  * to deal in the Software without restriction, including without limitation
16  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
17  * and/or sell copies of the Software, and to permit persons to whom the
18  * Software is furnished to do so, subject to the following conditions:
19  *
20  * The above copyright notice and this permission notice shall be included
21  * in all copies or substantial portions of the Software.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29  * DEALINGS IN THE SOFTWARE.
30  ****************************************************************************/
31 
32 #ifndef HFA_P_H_INCLUDED
33 #define HFA_P_H_INCLUDED
34 
35 #include "cpl_port.h"
36 #include "hfa.h"
37 
38 #include <cstdio>
39 #include <memory>
40 #include <vector>
41 #include <set>
42 
43 #include "cpl_error.h"
44 #include "cpl_vsi.h"
45 
46 #ifdef CPL_LSB
47 #  define HFAStandard(n,p) {}
48 #else
49    void HFAStandard( int, void *);
50 #endif
51 
52 #include "hfa.h"
53 
54 class HFABand;
55 class HFADictionary;
56 class HFAEntry;
57 class HFASpillFile;
58 class HFAType;
59 
60 /************************************************************************/
61 /*      Flag indicating read/write, or read-only access to data.        */
62 /************************************************************************/
63 typedef enum {
64     /*! Read only (no update) access */ HFA_ReadOnly = 0,
65     /*! Read/write access. */           HFA_Update = 1
66 } HFAAccess;
67 
68 /************************************************************************/
69 /*                              HFAInfo_t                               */
70 /*                                                                      */
71 /*      This is just a structure, and used hold info about the whole    */
72 /*      dataset within hfaopen.cpp                                      */
73 /************************************************************************/
74 struct hfainfo {
75     VSILFILE    *fp;
76 
77     char        *pszPath;
78     char        *pszFilename;  // Sans path.
79     char        *pszIGEFilename;  // Sans path.
80 
81     HFAAccess   eAccess;
82 
83     GUInt32     nEndOfFile;
84     GUInt32     nRootPos;
85     GUInt32     nDictionaryPos;
86 
87     GInt16      nEntryHeaderLength;
88     GInt32      nVersion;
89 
90     bool        bTreeDirty;
91     HFAEntry    *poRoot;
92 
93     HFADictionary *poDictionary;
94     char        *pszDictionary;
95 
96     int         nXSize;
97     int         nYSize;
98 
99     int         nBands;
100     HFABand     **papoBand;
101 
102     void        *pMapInfo;
103     void        *pDatum;
104     void        *pProParameters;
105 
106     struct hfainfo *psDependent;
107 };
108 
109 typedef struct hfainfo HFAInfo_t;
110 
111 GUInt32 HFAAllocateSpace( HFAInfo_t *, GUInt32 );
112 CPLErr  HFAParseBandInfo( HFAInfo_t * );
113 HFAInfo_t *HFAGetDependent( HFAInfo_t *, const char * );
114 HFAInfo_t *HFACreateDependent( HFAInfo_t *psBase );
115 bool HFACreateSpillStack( HFAInfo_t *, int nXSize, int nYSize, int nLayers,
116                           int nBlockSize, EPTType eDataType,
117                           GIntBig *pnValidFlagsOffset,
118                           GIntBig *pnDataOffset );
119 
120 const char * const * GetHFAAuxMetaDataList();
121 
122 double *HFAReadBFUniqueBins( HFAEntry *poBinFunc, int nPCTColors );
123 
124 int CPL_DLL
125 HFACreateLayer( HFAHandle psInfo, HFAEntry *poParent,
126                 const char *pszLayerName,
127                 int bOverview, int nBlockSize,
128                 int bCreateCompressed, int bCreateLargeRaster,
129                 int bDependentLayer,
130                 int nXSize, int nYSize, EPTType eDataType,
131                 char **papszOptions,
132 
133                 // These are only related to external (large) files.
134                 GIntBig nStackValidFlagsOffset,
135                 GIntBig nStackDataOffset,
136                 int nStackCount, int nStackIndex );
137 
138 char *
139 HFAPCSStructToWKT( const Eprj_Datum *psDatum,
140                    const Eprj_ProParameters *psPro,
141                    const Eprj_MapInfo *psMapInfo,
142                    HFAEntry *poMapInformation );
143 
144 /************************************************************************/
145 /*                               HFABand                                */
146 /************************************************************************/
147 
148 class HFABand
149 {
150     int         nBlocks;
151 
152     // Used for single-file modification.
153     vsi_l_offset *panBlockStart;
154     int         *panBlockSize;
155     int         *panBlockFlag;
156 
157     // Used for spill-file modification.
158     vsi_l_offset nBlockStart;
159     vsi_l_offset nBlockSize;
160     int         nLayerStackCount;
161     int         nLayerStackIndex;
162 
163 #define BFLG_VALID      0x01
164 #define BFLG_COMPRESSED 0x02
165 
166     int         nPCTColors;
167     double      *apadfPCT[4];
168     double      *padfPCTBins;
169 
170     CPLErr      LoadBlockInfo();
171     CPLErr      LoadExternalBlockInfo();
172 
173     void ReAllocBlock( int iBlock, int nSize );
174     void NullBlock( void * );
175 
176     CPLString   osOverName;
177 
178   public:
179                 HFABand( HFAInfo_t *, HFAEntry * );
180                 ~HFABand();
181 
182     HFAInfo_t   *psInfo;
183 
184     VSILFILE    *fpExternal;
185 
186     EPTType     eDataType;
187     HFAEntry    *poNode;
188 
189     int         nBlockXSize;
190     int         nBlockYSize;
191 
192     int         nWidth;
193     int         nHeight;
194 
195     int         nBlocksPerRow;
196     int         nBlocksPerColumn;
197 
198     bool        bNoDataSet;
199     double      dfNoData;
200 
201     bool        bOverviewsPending;
202     int         nOverviews;
203     HFABand     **papoOverviews;
204 
205     CPLErr      GetRasterBlock( int nXBlock, int nYBlock, void * pData,
206                                 int nDataSize );
207     CPLErr      SetRasterBlock( int nXBlock, int nYBlock, void * pData );
208 
209     const char * GetBandName();
210     void SetBandName(const char *pszName);
211 
212     CPLErr  SetNoDataValue( double dfValue );
213 
214     CPLErr      GetPCT( int *, double **, double **, double **, double **,
215                         double ** );
216     CPLErr      SetPCT( int, double *, double *, double *, double * );
217 
218     int         CreateOverview( int nOverviewLevel, const char *pszResampling );
219     CPLErr      CleanOverviews();
220 
221     CPLErr      LoadOverviews();
222 };
223 
224 /************************************************************************/
225 /*                               HFAEntry                               */
226 /*                                                                      */
227 /*      Base class for all entry types.  Most entry types do not        */
228 /*      have a subclass, and are just handled generically with this     */
229 /*      class.                                                          */
230 /************************************************************************/
231 class HFAEntry
232 {
233     bool        bDirty;
234     GUInt32     nFilePos;
235 
236     HFAInfo_t   *psHFA;
237     HFAEntry    *poParent;
238     HFAEntry    *poPrev;
239 
240     GUInt32     nNextPos;
241     HFAEntry    *poNext;
242 
243     GUInt32     nChildPos;
244     HFAEntry    *poChild;
245 
246     char        szName[64];
247     char        szType[32];
248 
249     HFAType     *poType;
250 
251     GUInt32     nDataPos;
252     GUInt32     nDataSize;
253     GByte      *pabyData;
254 
255     void        LoadData();
256 
257     bool        GetFieldValue( const char *, char, void *,
258                                int *pnRemainingDataSize );
259     CPLErr      SetFieldValue( const char *, char, void * );
260 
261     bool        bIsMIFObject;
262 
263                 HFAEntry();
264                 HFAEntry( const char * pszDictionary,
265                           const char * pszTypeName,
266                           int nDataSizeIn,
267                           GByte* pabyDataIn );
268     std::vector<HFAEntry*> FindChildren( const char *pszName,
269                                          const char *pszType,
270                                          int nRecLevel,
271                                          int* pbErrorDetected);
272 
273 public:
274     static HFAEntry* New( HFAInfo_t * psHFA, GUInt32 nPos,
275                           HFAEntry * poParent,
276                           HFAEntry *poPrev) CPL_WARN_UNUSED_RESULT;
277 
278                 HFAEntry( HFAInfo_t *psHFA,
279                           const char *pszNodeName,
280                           const char *pszTypeName,
281                           HFAEntry *poParent );
282 
283     static HFAEntry* New( HFAInfo_t *psHFA,
284                           const char *pszNodeName,
285                           const char *pszTypeName,
286                           HFAEntry *poParent ) CPL_WARN_UNUSED_RESULT;
287 
288     virtual     ~HFAEntry();
289 
290     static HFAEntry*  BuildEntryFromMIFObject(
291                           HFAEntry *poContainer,
292                           const char *pszMIFObjectPath ) CPL_WARN_UNUSED_RESULT;
293 
294     CPLErr      RemoveAndDestroy();
295 
GetFilePos()296     GUInt32     GetFilePos() const CPL_WARN_UNUSED_RESULT { return nFilePos; }
297 
GetName()298     const char  *GetName() const CPL_WARN_UNUSED_RESULT { return szName; }
299     void SetName( const char *pszNodeName );
300 
GetType()301     const char  *GetType() const CPL_WARN_UNUSED_RESULT { return szType; }
302     HFAType     *GetTypeObject() CPL_WARN_UNUSED_RESULT;
303 
GetData()304     GByte      *GetData() CPL_WARN_UNUSED_RESULT { LoadData(); return pabyData; }
GetDataPos()305     GUInt32     GetDataPos() const CPL_WARN_UNUSED_RESULT { return nDataPos; }
GetDataSize()306     GUInt32     GetDataSize() const CPL_WARN_UNUSED_RESULT { return nDataSize; }
307 
308     HFAEntry    *GetChild() CPL_WARN_UNUSED_RESULT;
309     HFAEntry    *GetNext() CPL_WARN_UNUSED_RESULT;
310     HFAEntry    *GetNamedChild( const char * ) CPL_WARN_UNUSED_RESULT;
311     std::vector<HFAEntry*> FindChildren( const char *pszName,
312                                          const char *pszType) CPL_WARN_UNUSED_RESULT;
313 
314     GInt32      GetIntField( const char *, CPLErr * = nullptr ) CPL_WARN_UNUSED_RESULT;
315     double      GetDoubleField( const char *, CPLErr * = nullptr ) CPL_WARN_UNUSED_RESULT;
316     const char  *GetStringField( const char *, CPLErr * = nullptr, int *pnRemainingDataSize = nullptr ) CPL_WARN_UNUSED_RESULT;
317     GIntBig     GetBigIntField( const char *, CPLErr * = nullptr ) CPL_WARN_UNUSED_RESULT;
318     int         GetFieldCount( const char *, CPLErr * = nullptr ) CPL_WARN_UNUSED_RESULT;
319 
320     CPLErr      SetIntField( const char *, int );
321     CPLErr      SetDoubleField( const char *, double );
322     CPLErr      SetStringField( const char *, const char * );
323 
324     void        DumpFieldValues( FILE *, const char * = nullptr );
325 
326     void        SetPosition();
327     CPLErr      FlushToDisk();
328 
329     void        MarkDirty();
330     GByte      *MakeData( int nSize = 0 );
331 };
332 
333 /************************************************************************/
334 /*                               HFAField                               */
335 /*                                                                      */
336 /*      A field in a HFAType in the dictionary.                         */
337 /************************************************************************/
338 
339 class HFAField
340 {
341   public:
342     int         nBytes;
343 
344     int         nItemCount;
345     // TODO(schwehr): Rename chPointer to something more meaningful.
346     // It's not a pointer.
347     char        chPointer;      // '\0', '*' or 'p'
348     char        chItemType;     // 1|2|4|e|...
349 
350     char        *pszItemObjectType;  // if chItemType == 'o'
351     HFAType     *poItemObjectType;
352 
353     char        **papszEnumNames;  // Normally NULL if not an enum.
354 
355     char        *pszFieldName;
356 
357     char        szNumberString[36];  // Buffer used to return int as a string.
358 
359                 HFAField();
360                 ~HFAField();
361 
362     const char *Initialize( const char * );
363 
364     bool        CompleteDefn( HFADictionary * );
365 
366     void        Dump( FILE * );
367 
368     bool        ExtractInstValue( const char * pszField, int nIndexValue,
369                                   GByte *pabyData, GUInt32 nDataOffset,
370                                   int nDataSize, char chReqType,
371                                   void *pReqReturn,
372                                   int *pnRemainingDataSize = nullptr );
373 
374     CPLErr      SetInstValue( const char * pszField, int nIndexValue,
375                               GByte *pabyData, GUInt32 nDataOffset,
376                               int nDataSize,
377                               char chReqType, void *pValue );
378 
379     void        DumpInstValue( FILE *fpOut, GByte *pabyData,
380                                GUInt32 nDataOffset, int nDataSize,
381                                const char *pszPrefix = nullptr );
382 
383     int         GetInstBytes( GByte *, int, std::set<HFAField*>& oVisitedFields );
384     int         GetInstCount( GByte * pabyData, int nDataSize ) const;
385 };
386 
387 /************************************************************************/
388 /*                               HFAType                                */
389 /*                                                                      */
390 /*      A type in the dictionary.                                       */
391 /************************************************************************/
392 
393 class HFAType
394 {
395     bool bInCompleteDefn;
396 
397   public:
398     int         nBytes;
399 
400     std::vector<std::unique_ptr<HFAField>> apoFields;
401 
402     char        *pszTypeName;
403 
404                 HFAType();
405                 ~HFAType();
406 
407     const char *Initialize( const char * );
408 
409     bool        CompleteDefn( HFADictionary * );
410 
411     void        Dump( FILE * );
412 
413     int         GetInstBytes( GByte *, int, std::set<HFAField*>& oVisitedFields ) const;
414     int         GetInstCount( const char *pszField, GByte *pabyData,
415                               GUInt32 nDataOffset, int nDataSize );
416     bool        ExtractInstValue( const char * pszField,
417                                   GByte *pabyData, GUInt32 nDataOffset,
418                                   int nDataSize, char chReqType,
419                                   void *pReqReturn, int *pnRemainingDataSize );
420     CPLErr      SetInstValue( const char * pszField, GByte *pabyData,
421                               GUInt32 nDataOffset, int nDataSize,
422                               char chReqType, void * pValue );
423     void        DumpInstValue( FILE *fpOut, GByte *pabyData,
424                                GUInt32 nDataOffset, int nDataSize,
425                                const char *pszPrefix = nullptr ) const;
426 };
427 
428 /************************************************************************/
429 /*                            HFADictionary                             */
430 /************************************************************************/
431 
432 class HFADictionary
433 {
434   public:
435     explicit     HFADictionary( const char *pszDict );
436                 ~HFADictionary();
437 
438     HFAType     *FindType( const char * );
439     void        AddType( HFAType * );
440 
441     static int  GetItemSize( char );
442 
443     void        Dump( FILE * );
444 
445   private:
446     int         nTypes;
447     int         nTypesMax;
448     HFAType     **papoTypes;
449 
450   public:
451     // TODO(schwehr): Make these members private.
452     CPLString   osDictionaryText;
453     bool        bDictionaryTextDirty;
454 };
455 
456 /************************************************************************/
457 /*                             HFACompress                              */
458 /*                                                                      */
459 /*      Class that given a block of memory compresses the contents      */
460 /*      using run length encoding (RLE) as used by Imagine.             */
461 /************************************************************************/
462 
463 class HFACompress
464 {
465 public:
466   HFACompress( void *pData, GUInt32 nBlockSize, EPTType eDataType );
467   ~HFACompress();
468 
469   // This is the method that does the work.
470   bool compressBlock();
471 
472   // Static method to allow us to query whether HFA type supported.
473   static bool QueryDataTypeSupported( EPTType eHFADataType );
474 
475   // Get methods - only valid after compressBlock has been called.
getCounts()476   GByte*  getCounts() const { return m_pCounts; }
getCountSize()477   GUInt32 getCountSize() const { return m_nSizeCounts; }
getValues()478   GByte*  getValues() const { return m_pValues; }
getValueSize()479   GUInt32 getValueSize() const { return m_nSizeValues; }
getMin()480   GUInt32 getMin() const { return m_nMin; }
getNumRuns()481   GUInt32 getNumRuns() const { return m_nNumRuns; }
getNumBits()482   GByte   getNumBits() const { return m_nNumBits; }
483 
484 private:
485   static void makeCount( GUInt32 count, GByte *pCounter, GUInt32 *pnSizeCount );
486   GUInt32 findMin( GByte *pNumBits );
487   GUInt32 valueAsUInt32( GUInt32 index );
488   void encodeValue( GUInt32 val, GUInt32 repeat );
489 
490   void *m_pData;
491   GUInt32 m_nBlockSize;
492   GUInt32 m_nBlockCount;
493   EPTType m_eDataType;
494   // The number of bits the datatype we are trying to compress takes.
495   int m_nDataTypeNumBits;
496 
497   GByte   *m_pCounts;
498   GByte   *m_pCurrCount;
499   GUInt32  m_nSizeCounts;
500 
501   GByte   *m_pValues;
502   GByte   *m_pCurrValues;
503   GUInt32  m_nSizeValues;
504 
505   GUInt32  m_nMin;
506   GUInt32  m_nNumRuns;
507   // The number of bits needed to compress the range of values in the block.
508   GByte    m_nNumBits;
509 };
510 
511 #endif /* ndef HFA_P_H_INCLUDED */
512