/src/gdal/frmts/hfa/hfadictionary.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /****************************************************************************** |
2 | | * |
3 | | * Project: Erdas Imagine (.img) Translator |
4 | | * Purpose: Implementation of the HFADictionary class for managing the |
5 | | * dictionary read from the HFA file. Most work done by the |
6 | | * HFAType, and HFAField classes. |
7 | | * Author: Frank Warmerdam, warmerdam@pobox.com |
8 | | * |
9 | | ****************************************************************************** |
10 | | * Copyright (c) 1999, Intergraph Corporation |
11 | | * |
12 | | * SPDX-License-Identifier: MIT |
13 | | ****************************************************************************/ |
14 | | |
15 | | #include "cpl_port.h" |
16 | | #include "hfa_p.h" |
17 | | |
18 | | #include <cstdio> |
19 | | #include <cstring> |
20 | | #include <string> |
21 | | |
22 | | #include "cpl_conv.h" |
23 | | #include "cpl_error.h" |
24 | | #include "cpl_string.h" |
25 | | #include "cpl_vsi.h" |
26 | | |
27 | | static const char *const apszDefDefn[] = { |
28 | | "Edsc_Table", |
29 | | "{1:lnumrows,}Edsc_Table", |
30 | | |
31 | | "Edsc_Column", |
32 | | "{1:lnumRows,1:LcolumnDataPtr,1:e4:integer,real,complex,string,dataType,1:" |
33 | | "lmaxNumChars,}Edsc_Column", |
34 | | |
35 | | "Eprj_Size", |
36 | | "{1:dwidth,1:dheight,}Eprj_Size", |
37 | | |
38 | | "Eprj_Coordinate", |
39 | | "{1:dx,1:dy,}Eprj_Coordinate", |
40 | | |
41 | | "Eprj_MapInfo", |
42 | | "{0:pcproName,1:*oEprj_Coordinate,upperLeftCenter,1:*oEprj_Coordinate," |
43 | | "lowerRightCenter,1:*oEprj_Size,pixelSize,0:pcunits,}Eprj_MapInfo", |
44 | | |
45 | | "Eimg_StatisticsParameters830", |
46 | | "{0:poEmif_String,LayerNames,1:*bExcludedValues,1:oEmif_String,AOIname,1:" |
47 | | "lSkipFactorX,1:lSkipFactorY,1:*oEdsc_BinFunction,BinFunction,}Eimg_" |
48 | | "StatisticsParameters830", |
49 | | |
50 | | "Esta_Statistics", |
51 | | "{1:dminimum,1:dmaximum,1:dmean,1:dmedian,1:dmode,1:dstddev,}Esta_" |
52 | | "Statistics", |
53 | | |
54 | | "Edsc_BinFunction", |
55 | | "{1:lnumBins,1:e4:direct,linear,logarithmic,explicit,binFunctionType,1:" |
56 | | "dminLimit,1:dmaxLimit,1:*bbinLimits,}Edsc_BinFunction", |
57 | | |
58 | | "Eimg_NonInitializedValue", |
59 | | "{1:*bvalueBD,}Eimg_NonInitializedValue", |
60 | | |
61 | | "Eprj_MapProjection842", |
62 | | "{1:x{1:x{0:pcstring,}Emif_String,type,1:x{0:pcstring,}Emif_String," |
63 | | "MIFDictionary,0:pCMIFObject,}Emif_MIFObject,projection,1:x{0:pcstring,}" |
64 | | "Emif_String,title,}Eprj_MapProjection842", |
65 | | |
66 | | "Emif_MIFObject", |
67 | | "{1:x{0:pcstring,}Emif_String,type,1:x{0:pcstring,}Emif_String," |
68 | | "MIFDictionary,0:pCMIFObject,}Emif_MIFObject", |
69 | | |
70 | | "Eprj_ProParameters", |
71 | | "{1:e2:EPRJ_INTERNAL,EPRJ_EXTERNAL,proType,1:lproNumber,0:pcproExeName,0:" |
72 | | "pcproName,1:lproZone,0:pdproParams,1:*oEprj_Spheroid,proSpheroid,}Eprj_" |
73 | | "ProParameters", |
74 | | |
75 | | "Eprj_Datum", |
76 | | "{0:pcdatumname,1:e3:EPRJ_DATUM_PARAMETRIC,EPRJ_DATUM_GRID,EPRJ_DATUM_" |
77 | | "REGRESSION,type,0:pdparams,0:pcgridname,}Eprj_Datum", |
78 | | |
79 | | "Eprj_Spheroid", |
80 | | "{0:pcsphereName,1:da,1:db,1:deSquared,1:dradius,}Eprj_Spheroid", |
81 | | |
82 | | nullptr, |
83 | | nullptr}; |
84 | | |
85 | | /************************************************************************/ |
86 | | /* ==================================================================== */ |
87 | | /* HFADictionary */ |
88 | | /* ==================================================================== */ |
89 | | /************************************************************************/ |
90 | | |
91 | | /************************************************************************/ |
92 | | /* HFADictionary() */ |
93 | | /************************************************************************/ |
94 | | |
95 | | HFADictionary::HFADictionary(const char *pszString) |
96 | 15.1k | : nTypes(0), nTypesMax(0), papoTypes(nullptr), osDictionaryText(pszString), |
97 | 15.1k | bDictionaryTextDirty(false) |
98 | 15.1k | { |
99 | | // Read all the types. |
100 | | // TODO(schwehr): Refactor this approach to be more obvious. |
101 | 635k | while (pszString != nullptr && *pszString != '.') |
102 | 620k | { |
103 | 620k | HFAType *poNewType = new HFAType(); |
104 | 620k | pszString = poNewType->Initialize(pszString); |
105 | | |
106 | 620k | if (pszString != nullptr) |
107 | 608k | AddType(poNewType); |
108 | 11.8k | else |
109 | 11.8k | delete poNewType; |
110 | 620k | } |
111 | | |
112 | | // Complete the definitions. |
113 | 624k | for (int i = 0; i < nTypes; i++) |
114 | 608k | { |
115 | 608k | papoTypes[i]->CompleteDefn(this); |
116 | 608k | } |
117 | 15.1k | } |
118 | | |
119 | | /************************************************************************/ |
120 | | /* ~HFADictionary() */ |
121 | | /************************************************************************/ |
122 | | |
123 | | HFADictionary::~HFADictionary() |
124 | | |
125 | 15.1k | { |
126 | 642k | for (int i = 0; i < nTypes; i++) |
127 | 627k | delete papoTypes[i]; |
128 | | |
129 | 15.1k | CPLFree(papoTypes); |
130 | 15.1k | } |
131 | | |
132 | | /************************************************************************/ |
133 | | /* AddType() */ |
134 | | /************************************************************************/ |
135 | | |
136 | | void HFADictionary::AddType(HFAType *poType) |
137 | | |
138 | 627k | { |
139 | 627k | if (nTypes == nTypesMax |
140 | | #ifdef DEBUG |
141 | | // To please Coverity. |
142 | | || papoTypes == nullptr |
143 | | #endif |
144 | 627k | ) |
145 | 25.1k | { |
146 | 25.1k | nTypesMax = nTypes * 2 + 10; |
147 | 25.1k | papoTypes = static_cast<HFAType **>( |
148 | 25.1k | CPLRealloc(papoTypes, sizeof(void *) * nTypesMax)); |
149 | 25.1k | } |
150 | | |
151 | 627k | papoTypes[nTypes++] = poType; |
152 | 627k | } |
153 | | |
154 | | /************************************************************************/ |
155 | | /* FindType() */ |
156 | | /************************************************************************/ |
157 | | |
158 | | HFAType *HFADictionary::FindType(const char *pszName) |
159 | | |
160 | 1.13M | { |
161 | 864M | for (int i = 0; i < nTypes; i++) |
162 | 864M | { |
163 | 864M | if (papoTypes[i]->pszTypeName != nullptr && |
164 | 864M | strcmp(pszName, papoTypes[i]->pszTypeName) == 0) |
165 | 963k | return papoTypes[i]; |
166 | 864M | } |
167 | | |
168 | | // Check if this is a type have other knowledge of. If so, add |
169 | | // it to the dictionary now. I'm not sure how some files end |
170 | | // up being distributed using types not in the dictionary. |
171 | 2.36M | for (int i = 0; apszDefDefn[i] != nullptr; i += 2) |
172 | 2.22M | { |
173 | 2.22M | if (strcmp(pszName, apszDefDefn[i]) == 0) |
174 | 24.1k | { |
175 | 24.1k | HFAType *poNewType = new HFAType(); |
176 | | |
177 | 24.1k | poNewType->Initialize(apszDefDefn[i + 1]); |
178 | 24.1k | if (!poNewType->CompleteDefn(this)) |
179 | 5.21k | { |
180 | 5.21k | delete poNewType; |
181 | 5.21k | return nullptr; |
182 | 5.21k | } |
183 | 18.9k | AddType(poNewType); |
184 | | |
185 | 18.9k | if (!osDictionaryText.empty()) |
186 | 18.9k | osDictionaryText.erase(osDictionaryText.size() - 1, 1); |
187 | 18.9k | osDictionaryText += apszDefDefn[i + 1]; |
188 | 18.9k | osDictionaryText += ",."; |
189 | | |
190 | 18.9k | bDictionaryTextDirty = true; |
191 | | |
192 | 18.9k | return poNewType; |
193 | 24.1k | } |
194 | 2.22M | } |
195 | | |
196 | 143k | return nullptr; |
197 | 167k | } |
198 | | |
199 | | /************************************************************************/ |
200 | | /* GetItemSize() */ |
201 | | /* */ |
202 | | /* Get the size of a basic (atomic) item. */ |
203 | | /************************************************************************/ |
204 | | |
205 | | int HFADictionary::GetItemSize(char chType) |
206 | | |
207 | 5.56M | { |
208 | 5.56M | switch (chType) |
209 | 5.56M | { |
210 | 24.0k | case '1': |
211 | 32.1k | case '2': |
212 | 33.9k | case '4': |
213 | 3.55M | case 'c': |
214 | 3.59M | case 'C': |
215 | 3.59M | return 1; |
216 | | |
217 | 121k | case 'e': |
218 | 144k | case 's': |
219 | 213k | case 'S': |
220 | 213k | return 2; |
221 | | |
222 | 23.1k | case 't': |
223 | 264k | case 'l': |
224 | 404k | case 'L': |
225 | 419k | case 'f': |
226 | 419k | return 4; |
227 | | |
228 | 264k | case 'd': |
229 | 287k | case 'm': |
230 | 287k | return 8; |
231 | | |
232 | 5.61k | case 'M': |
233 | 5.61k | return 16; |
234 | | |
235 | 870k | case 'b': |
236 | 870k | return -1; |
237 | | |
238 | 151k | case 'o': |
239 | 172k | case 'x': |
240 | 172k | return 0; |
241 | | |
242 | 0 | default: |
243 | 0 | CPLAssert(false); |
244 | 5.56M | } |
245 | | |
246 | 0 | return 0; |
247 | 5.56M | } |
248 | | |
249 | | /************************************************************************/ |
250 | | /* Dump() */ |
251 | | /************************************************************************/ |
252 | | |
253 | | void HFADictionary::Dump(FILE *fp) |
254 | | |
255 | 0 | { |
256 | 0 | CPL_IGNORE_RET_VAL(VSIFPrintf(fp, "\nHFADictionary:\n")); |
257 | |
|
258 | 0 | for (int i = 0; i < nTypes; i++) |
259 | 0 | { |
260 | 0 | papoTypes[i]->Dump(fp); |
261 | 0 | } |
262 | 0 | } |