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