/src/gdal/ogr/ogrsf_frmts/mitab/mitab_mapheaderblock.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /********************************************************************** |
2 | | * |
3 | | * Name: mitab_mapheaderblock.cpp |
4 | | * Project: MapInfo TAB Read/Write library |
5 | | * Language: C++ |
6 | | * Purpose: Implementation of the TABHeaderBlock class used to handle |
7 | | * reading/writing of the .MAP files' header block |
8 | | * Author: Daniel Morissette, dmorissette@dmsolutions.ca |
9 | | * |
10 | | ********************************************************************** |
11 | | * Copyright (c) 1999-2002, Daniel Morissette |
12 | | * Copyright (c) 2014, Even Rouault <even.rouault at spatialys.com> |
13 | | * |
14 | | * SPDX-License-Identifier: MIT |
15 | | **********************************************************************/ |
16 | | |
17 | | #include "cpl_port.h" |
18 | | #include "mitab.h" |
19 | | |
20 | | #include <cmath> |
21 | | #include <cstddef> |
22 | | |
23 | | #include "cpl_conv.h" |
24 | | #include "cpl_error.h" |
25 | | #include "cpl_vsi.h" |
26 | | #include "mitab_priv.h" |
27 | | |
28 | | /*--------------------------------------------------------------------- |
29 | | * Set various constants used in generating the header block. |
30 | | *--------------------------------------------------------------------*/ |
31 | | constexpr GInt32 HDR_MAGIC_COOKIE = 42424242; |
32 | | constexpr GInt16 HDR_VERSION_NUMBER = 500; |
33 | | |
34 | | constexpr GByte HDR_DEF_ORG_QUADRANT = 1; // N-E Quadrant |
35 | | constexpr GByte HDR_DEF_REFLECTXAXIS = 0; |
36 | | |
37 | | /*--------------------------------------------------------------------- |
38 | | * The header block starts with an array of map object length constants. |
39 | | *--------------------------------------------------------------------*/ |
40 | | constexpr GByte HDR_OBJ_LEN_ARRAY_SIZE = 73; |
41 | | constexpr GByte gabyObjLenArray[HDR_OBJ_LEN_ARRAY_SIZE] = { |
42 | | 0x00, 0x0a, 0x0e, 0x15, 0x0e, 0x16, 0x1b, 0xa2, 0xa6, 0xab, 0x1a, |
43 | | 0x2a, 0x2f, 0xa5, 0xa9, 0xb5, 0xa7, 0xb5, 0xd9, 0x0f, 0x17, 0x23, |
44 | | 0x13, 0x1f, 0x2b, 0x0f, 0x17, 0x23, 0x4f, 0x57, 0x63, 0x9c, 0xa4, |
45 | | 0xa9, 0xa0, 0xa8, 0xad, 0xa4, 0xa8, 0xad, 0x16, 0x1a, 0x39, 0x0d, |
46 | | 0x11, 0x37, 0xa5, 0xa9, 0xb5, 0xa4, 0xa8, 0xad, 0xb2, 0xb6, 0xdc, |
47 | | 0xbd, 0xbd, 0xf4, 0x2b, 0x2f, 0x55, 0xc8, 0xcc, 0xd8, 0xc7, 0xcb, |
48 | | 0xd0, 0xd3, 0xd7, 0xfd, 0xc2, 0xc2, 0xf9}; |
49 | | |
50 | | /*===================================================================== |
51 | | * class TABMAPHeaderBlock |
52 | | *====================================================================*/ |
53 | | |
54 | | /********************************************************************** |
55 | | * TABMAPHeaderBlock::TABMAPHeaderBlock() |
56 | | * |
57 | | * Constructor. |
58 | | **********************************************************************/ |
59 | | TABMAPHeaderBlock::TABMAPHeaderBlock(TABAccess eAccessMode /*= TABRead*/) |
60 | 897 | : TABRawBinBlock(eAccessMode, TRUE) |
61 | 897 | { |
62 | | // TODO(schwehr): Consider using initializer list for most values. |
63 | 897 | InitMembersWithDefaultValues(); |
64 | | |
65 | | // We don't want to reset it once it is set. |
66 | 897 | m_bIntBoundsOverflow = FALSE; |
67 | 897 | } |
68 | | |
69 | | /********************************************************************** |
70 | | * TABMAPHeaderBlock::~TABMAPHeaderBlock() |
71 | | * |
72 | | * Destructor. |
73 | | **********************************************************************/ |
74 | | TABMAPHeaderBlock::~TABMAPHeaderBlock() |
75 | 897 | { |
76 | 897 | } |
77 | | |
78 | | /********************************************************************** |
79 | | * TABMAPHeaderBlock::InitMembersWithDefaultValues() |
80 | | **********************************************************************/ |
81 | | void TABMAPHeaderBlock::InitMembersWithDefaultValues() |
82 | 1.36k | { |
83 | | /*----------------------------------------------------------------- |
84 | | * Set acceptable default values for member vars. |
85 | | *----------------------------------------------------------------*/ |
86 | 1.36k | m_nMAPVersionNumber = HDR_VERSION_NUMBER; |
87 | 1.36k | m_nRegularBlockSize = TAB_MIN_BLOCK_SIZE; |
88 | | |
89 | 1.36k | m_dCoordsys2DistUnits = 1.0; |
90 | 1.36k | m_nXMin = -1000000000; |
91 | 1.36k | m_nYMin = -1000000000; |
92 | 1.36k | m_nXMax = 1000000000; |
93 | 1.36k | m_nYMax = 1000000000; |
94 | 1.36k | m_bIntBoundsOverflow = FALSE; |
95 | | |
96 | 1.36k | m_nFirstIndexBlock = 0; |
97 | 1.36k | m_nFirstGarbageBlock = 0; |
98 | 1.36k | m_nFirstToolBlock = 0; |
99 | | |
100 | 1.36k | m_numPointObjects = 0; |
101 | 1.36k | m_numLineObjects = 0; |
102 | 1.36k | m_numRegionObjects = 0; |
103 | 1.36k | m_numTextObjects = 0; |
104 | 1.36k | m_nMaxCoordBufSize = 0; |
105 | | |
106 | 1.36k | m_nDistUnitsCode = 7; // Meters |
107 | 1.36k | m_nMaxSpIndexDepth = 0; |
108 | 1.36k | m_nCoordPrecision = 3; // ??? 3 Digits of precision |
109 | 1.36k | m_nCoordOriginQuadrant = HDR_DEF_ORG_QUADRANT; // ??? N-E quadrant |
110 | 1.36k | m_nReflectXAxisCoord = HDR_DEF_REFLECTXAXIS; |
111 | 1.36k | m_nMaxObjLenArrayId = HDR_OBJ_LEN_ARRAY_SIZE - 1; // See gabyObjLenArray[] |
112 | 1.36k | m_numPenDefs = 0; |
113 | 1.36k | m_numBrushDefs = 0; |
114 | 1.36k | m_numSymbolDefs = 0; |
115 | 1.36k | m_numFontDefs = 0; |
116 | 1.36k | m_numMapToolBlocks = 0; |
117 | | |
118 | 1.36k | m_sProj.nProjId = 0; |
119 | 1.36k | m_sProj.nEllipsoidId = 0; |
120 | 1.36k | m_sProj.nUnitsId = 7; |
121 | 1.36k | m_sProj.nDatumId = 0; |
122 | 1.36k | m_XScale = 1000.0; // Default coord range (before SetCoordSysBounds()) |
123 | 1.36k | m_YScale = 1000.0; // will be [-1000000.000 .. 1000000.000] |
124 | 1.36k | m_XDispl = 0.0; |
125 | 1.36k | m_YDispl = 0.0; |
126 | 1.36k | m_XPrecision = 0.0; // not specified |
127 | 1.36k | m_YPrecision = 0.0; // not specified |
128 | | |
129 | 9.54k | for (int i = 0; i < 6; i++) |
130 | 8.18k | m_sProj.adProjParams[i] = 0.0; |
131 | | |
132 | 1.36k | m_sProj.dDatumShiftX = 0.0; |
133 | 1.36k | m_sProj.dDatumShiftY = 0.0; |
134 | 1.36k | m_sProj.dDatumShiftZ = 0.0; |
135 | 8.18k | for (int i = 0; i < 5; i++) |
136 | 6.82k | m_sProj.adDatumParams[i] = 0.0; |
137 | | |
138 | 1.36k | m_sProj.nAffineFlag = 0; // Only in version 500 and up |
139 | 1.36k | m_sProj.nAffineUnits = 7; |
140 | 1.36k | m_sProj.dAffineParamA = 0.0; |
141 | 1.36k | m_sProj.dAffineParamB = 0.0; |
142 | 1.36k | m_sProj.dAffineParamC = 0.0; |
143 | 1.36k | m_sProj.dAffineParamD = 0.0; |
144 | 1.36k | m_sProj.dAffineParamE = 0.0; |
145 | 1.36k | m_sProj.dAffineParamF = 0.0; |
146 | 1.36k | } |
147 | | |
148 | | /********************************************************************** |
149 | | * TABMAPHeaderBlock::InitBlockFromData() |
150 | | * |
151 | | * Perform some initialization on the block after its binary data has |
152 | | * been set or changed (or loaded from a file). |
153 | | * |
154 | | * Returns 0 if successful or -1 if an error happened, in which case |
155 | | * CPLError() will have been called. |
156 | | **********************************************************************/ |
157 | | int TABMAPHeaderBlock::InitBlockFromData(GByte *pabyBuf, int nBlockSize, |
158 | | int nSizeUsed, |
159 | | GBool bMakeCopy /* = TRUE */, |
160 | | VSILFILE *fpSrc /* = NULL */, |
161 | | int nOffset /* = 0 */) |
162 | 430 | { |
163 | | /*----------------------------------------------------------------- |
164 | | * First of all, we must call the base class' InitBlockFromData() |
165 | | *----------------------------------------------------------------*/ |
166 | 430 | const int nStatus = TABRawBinBlock::InitBlockFromData( |
167 | 430 | pabyBuf, nBlockSize, nSizeUsed, bMakeCopy, fpSrc, nOffset); |
168 | 430 | if (nStatus != 0) |
169 | 0 | return nStatus; |
170 | | |
171 | | /*----------------------------------------------------------------- |
172 | | * Validate block type |
173 | | * Header blocks have a magic cookie at byte 0x100 |
174 | | *----------------------------------------------------------------*/ |
175 | 430 | GotoByteInBlock(0x100); |
176 | 430 | const GInt32 nMagicCookie = ReadInt32(); |
177 | 430 | if (nMagicCookie != HDR_MAGIC_COOKIE) |
178 | 6 | { |
179 | 6 | CPLError(CE_Failure, CPLE_FileIO, |
180 | 6 | "ReadFromFile(): Invalid Magic Cookie: got %d expected %d", |
181 | 6 | nMagicCookie, HDR_MAGIC_COOKIE); |
182 | 6 | CPLFree(m_pabyBuf); |
183 | 6 | m_pabyBuf = nullptr; |
184 | 6 | return -1; |
185 | 6 | } |
186 | | |
187 | | /*----------------------------------------------------------------- |
188 | | * Init member variables |
189 | | * Instead of having over 30 get/set methods, we'll make all data |
190 | | * members public and we will initialize them here. |
191 | | * For this reason, this class should be used with care. |
192 | | *----------------------------------------------------------------*/ |
193 | 424 | GotoByteInBlock(0x104); |
194 | 424 | m_nMAPVersionNumber = ReadInt16(); |
195 | 424 | m_nRegularBlockSize = ReadInt16(); |
196 | 424 | if (m_nRegularBlockSize < TAB_MIN_BLOCK_SIZE) |
197 | 1 | { |
198 | 1 | CPLError(CE_Failure, CPLE_FileIO, |
199 | 1 | "ReadFromFile(): Invalid block size %d", m_nRegularBlockSize); |
200 | 1 | CPLFree(m_pabyBuf); |
201 | 1 | m_pabyBuf = nullptr; |
202 | 1 | return -1; |
203 | 1 | } |
204 | | |
205 | 423 | m_dCoordsys2DistUnits = ReadDouble(); |
206 | 423 | m_nXMin = ReadInt32(); |
207 | 423 | m_nYMin = ReadInt32(); |
208 | 423 | m_nXMax = ReadInt32(); |
209 | 423 | m_nYMax = ReadInt32(); |
210 | 423 | if (m_nXMin > m_nXMax || m_nYMin > m_nYMax) |
211 | 63 | { |
212 | 63 | CPLError(CE_Warning, CPLE_AppDefined, |
213 | 63 | "Reading corrupted MBR from .map header"); |
214 | 63 | CPLErrorReset(); |
215 | 63 | } |
216 | | |
217 | 423 | GotoByteInBlock(0x130); // Skip 16 unknown bytes |
218 | | |
219 | 423 | m_nFirstIndexBlock = ReadInt32(); |
220 | 423 | m_nFirstGarbageBlock = ReadInt32(); |
221 | 423 | m_nFirstToolBlock = ReadInt32(); |
222 | | |
223 | 423 | m_numPointObjects = ReadInt32(); |
224 | 423 | m_numLineObjects = ReadInt32(); |
225 | 423 | m_numRegionObjects = ReadInt32(); |
226 | 423 | m_numTextObjects = ReadInt32(); |
227 | 423 | m_nMaxCoordBufSize = ReadInt32(); |
228 | | |
229 | 423 | GotoByteInBlock(0x15e); // Skip 14 unknown bytes |
230 | | |
231 | 423 | m_nDistUnitsCode = ReadByte(); |
232 | 423 | m_nMaxSpIndexDepth = ReadByte(); |
233 | 423 | m_nCoordPrecision = ReadByte(); |
234 | 423 | m_nCoordOriginQuadrant = ReadByte(); |
235 | 423 | m_nReflectXAxisCoord = ReadByte(); |
236 | 423 | m_nMaxObjLenArrayId = ReadByte(); // See gabyObjLenArray[] |
237 | 423 | m_numPenDefs = ReadByte(); |
238 | 423 | m_numBrushDefs = ReadByte(); |
239 | 423 | m_numSymbolDefs = ReadByte(); |
240 | 423 | m_numFontDefs = ReadByte(); |
241 | 423 | m_numMapToolBlocks = ReadByte(); |
242 | | |
243 | 423 | ReadByte(); // skip unused byte |
244 | | |
245 | | /* DatumId was never set (always 0) until MapInfo 7.8. See bug 910 |
246 | | * MAP Version Number is 500 in this case. |
247 | | */ |
248 | 423 | if (m_nMAPVersionNumber >= 500) |
249 | 421 | m_sProj.nDatumId = ReadInt16(); |
250 | 2 | else |
251 | 2 | { |
252 | 2 | ReadInt16(); // Skip. |
253 | 2 | m_sProj.nDatumId = 0; |
254 | 2 | } |
255 | 423 | ReadByte(); // Skip unknown byte |
256 | 423 | m_sProj.nProjId = ReadByte(); |
257 | 423 | m_sProj.nEllipsoidId = ReadByte(); |
258 | 423 | m_sProj.nUnitsId = ReadByte(); |
259 | 423 | m_XScale = ReadDouble(); |
260 | 423 | m_YScale = ReadDouble(); |
261 | 423 | if (m_XScale == 0.0 || m_YScale == 0.0) |
262 | 5 | { |
263 | 5 | CPLError(CE_Failure, CPLE_FileIO, |
264 | 5 | "ReadFromFile(): Null xscale and/or yscale"); |
265 | 5 | CPLFree(m_pabyBuf); |
266 | 5 | m_pabyBuf = nullptr; |
267 | 5 | return -1; |
268 | 5 | } |
269 | 418 | m_XDispl = ReadDouble(); |
270 | 418 | m_YDispl = ReadDouble(); |
271 | | |
272 | | /* In V.100 files, the scale and displacement do not appear to be set. |
273 | | * we'll use m_nCoordPrecision to define the scale factor instead. |
274 | | */ |
275 | 418 | if (m_nMAPVersionNumber <= 100) |
276 | 1 | { |
277 | 1 | m_XScale = pow(10.0, m_nCoordPrecision); |
278 | 1 | m_YScale = m_XScale; |
279 | 1 | m_XDispl = 0.0; |
280 | 1 | m_YDispl = 0.0; |
281 | 1 | } |
282 | | |
283 | 2.92k | for (int i = 0; i < 6; i++) |
284 | 2.50k | m_sProj.adProjParams[i] = ReadDouble(); |
285 | | |
286 | 418 | m_sProj.dDatumShiftX = ReadDouble(); |
287 | 418 | m_sProj.dDatumShiftY = ReadDouble(); |
288 | 418 | m_sProj.dDatumShiftZ = ReadDouble(); |
289 | 2.50k | for (int i = 0; i < 5; i++) |
290 | 2.09k | { |
291 | | /* In V.200 files, the next 5 datum params are unused and they |
292 | | * sometimes contain junk bytes... in this case we set adDatumParams[] |
293 | | * to 0 for the rest of the lib to be happy. |
294 | | */ |
295 | 2.09k | m_sProj.adDatumParams[i] = ReadDouble(); |
296 | 2.09k | if (m_nMAPVersionNumber <= 200) |
297 | 5 | m_sProj.adDatumParams[i] = 0.0; |
298 | 2.09k | } |
299 | | |
300 | 418 | m_sProj.nAffineFlag = 0; |
301 | 418 | if (m_nMAPVersionNumber >= 500 && m_nSizeUsed > TAB_MIN_BLOCK_SIZE) |
302 | 207 | { |
303 | | // Read Affine parameters A,B,C,D,E,F |
304 | | // only if version 500+ and block is larger than TAB_MIN_BLOCK_SIZE |
305 | | // bytes |
306 | 207 | int nInUse = ReadByte(); |
307 | 207 | if (nInUse) |
308 | 48 | { |
309 | 48 | m_sProj.nAffineFlag = 1; |
310 | 48 | m_sProj.nAffineUnits = ReadByte(); |
311 | 48 | GotoByteInBlock(0x0208); // Skip unused bytes |
312 | 48 | m_sProj.dAffineParamA = ReadDouble(); |
313 | 48 | m_sProj.dAffineParamB = ReadDouble(); |
314 | 48 | m_sProj.dAffineParamC = ReadDouble(); |
315 | 48 | m_sProj.dAffineParamD = ReadDouble(); |
316 | 48 | m_sProj.dAffineParamE = ReadDouble(); |
317 | 48 | m_sProj.dAffineParamF = ReadDouble(); |
318 | 48 | } |
319 | 207 | } |
320 | | |
321 | 418 | if (m_sProj.nProjId == 35 && m_nMAPVersionNumber >= 500 && |
322 | 418 | m_nSizeUsed >= 0x0268 + 8) |
323 | 0 | { |
324 | 0 | GotoByteInBlock(0x0268); |
325 | 0 | m_sProj.adProjParams[6] = ReadDouble(); |
326 | 0 | } |
327 | | |
328 | 418 | UpdatePrecision(); |
329 | | |
330 | 418 | return 0; |
331 | 423 | } |
332 | | |
333 | | /********************************************************************** |
334 | | * TABMAPHeaderBlock::Int2Coordsys() |
335 | | * |
336 | | * Convert from long integer (internal) to coordinates system units |
337 | | * as defined in the file's coordsys clause. |
338 | | * |
339 | | * Note that the false easting/northing and the conversion factor from |
340 | | * datum to coordsys units are not included in the calculation. |
341 | | * |
342 | | * Returns 0 on success, -1 on error. |
343 | | **********************************************************************/ |
344 | | int TABMAPHeaderBlock::Int2Coordsys(GInt32 nX, GInt32 nY, double &dX, |
345 | | double &dY) |
346 | 2.63k | { |
347 | 2.63k | if (m_pabyBuf == nullptr) |
348 | 0 | return -1; |
349 | | |
350 | | // For some obscure reason, some guy decided that it would be |
351 | | // more fun to be able to define our own origin quadrant! |
352 | | // |
353 | | // In version 100 .tab files (version 400 .map), it is possible to have |
354 | | // a quadrant 0 and it should be treated the same way as quadrant 3 |
355 | | |
356 | 2.63k | if (m_nCoordOriginQuadrant == 2 || m_nCoordOriginQuadrant == 3 || |
357 | 2.63k | m_nCoordOriginQuadrant == 0) |
358 | 580 | dX = -1.0 * (nX + m_XDispl) / m_XScale; |
359 | 2.05k | else |
360 | 2.05k | dX = (nX - m_XDispl) / m_XScale; |
361 | | |
362 | 2.63k | if (m_nCoordOriginQuadrant == 3 || m_nCoordOriginQuadrant == 4 || |
363 | 2.63k | m_nCoordOriginQuadrant == 0) |
364 | 446 | dY = -1.0 * (nY + m_YDispl) / m_YScale; |
365 | 2.19k | else |
366 | 2.19k | dY = (nY - m_YDispl) / m_YScale; |
367 | | |
368 | | // Round coordinates to the desired precision |
369 | 2.63k | if (m_XPrecision > 0 && m_YPrecision > 0) |
370 | 2.55k | { |
371 | 2.55k | dX = round(dX * m_XPrecision) / m_XPrecision; |
372 | 2.55k | dY = round(dY * m_YPrecision) / m_YPrecision; |
373 | 2.55k | } |
374 | | // printf("Int2Coordsys: (%d, %d) -> (%.10g, %.10g)\n", nX, nY, dX, dY); |
375 | | |
376 | 2.63k | return 0; |
377 | 2.63k | } |
378 | | |
379 | | /********************************************************************** |
380 | | * TABMAPHeaderBlock::Coordsys2Int() |
381 | | * |
382 | | * Convert from coordinates system units as defined in the file's |
383 | | * coordsys clause to long integer (internal) coordinates. |
384 | | * |
385 | | * Note that the false easting/northing and the conversion factor from |
386 | | * datum to coordsys units are not included in the calculation. |
387 | | * |
388 | | * Returns 0 on success, -1 on error. |
389 | | **********************************************************************/ |
390 | | int TABMAPHeaderBlock::Coordsys2Int(double dX, double dY, GInt32 &nX, |
391 | | GInt32 &nY, |
392 | | GBool bIgnoreOverflow /*=FALSE*/) |
393 | 2.83k | { |
394 | 2.83k | if (m_pabyBuf == nullptr) |
395 | 0 | return -1; |
396 | | |
397 | | // For some obscure reason, some guy decided that it would be |
398 | | // more fun to be able to define our own origin quadrant! |
399 | | // |
400 | | // In version 100 .tab files (version 400 .map), it is possible to have |
401 | | // a quadrant 0 and it should be treated the same way as quadrant 3 |
402 | | |
403 | | /*----------------------------------------------------------------- |
404 | | * NOTE: double values must be used here, the limit of integer value |
405 | | * have been reached some times due to the very big numbers used here. |
406 | | *----------------------------------------------------------------*/ |
407 | 2.83k | double dTempX = 0.0; |
408 | 2.83k | double dTempY = 0.0; |
409 | | |
410 | 2.83k | if (m_nCoordOriginQuadrant == 2 || m_nCoordOriginQuadrant == 3 || |
411 | 2.83k | m_nCoordOriginQuadrant == 0) |
412 | 0 | dTempX = -1.0 * dX * m_XScale - m_XDispl; |
413 | 2.83k | else |
414 | 2.83k | dTempX = dX * m_XScale + m_XDispl; |
415 | | |
416 | 2.83k | if (m_nCoordOriginQuadrant == 3 || m_nCoordOriginQuadrant == 4 || |
417 | 2.83k | m_nCoordOriginQuadrant == 0) |
418 | 0 | dTempY = -1.0 * dY * m_YScale - m_YDispl; |
419 | 2.83k | else |
420 | 2.83k | dTempY = dY * m_YScale + m_YDispl; |
421 | | |
422 | | /*----------------------------------------------------------------- |
423 | | * Make sure we'll never output coordinates outside of the valid |
424 | | * integer coordinates range: (-1e9, -1e9) - (1e9, 1e9) |
425 | | * Integer coordinates outside of that range will confuse MapInfo. |
426 | | *----------------------------------------------------------------*/ |
427 | 2.83k | GBool bIntBoundsOverflow = FALSE; |
428 | 2.83k | if (dTempX < -1000000000) |
429 | 67 | { |
430 | 67 | dTempX = -1000000000; |
431 | 67 | bIntBoundsOverflow = TRUE; |
432 | 67 | } |
433 | 2.83k | if (dTempX > 1000000000) |
434 | 80 | { |
435 | 80 | dTempX = 1000000000; |
436 | 80 | bIntBoundsOverflow = TRUE; |
437 | 80 | } |
438 | 2.83k | if (dTempY < -1000000000) |
439 | 116 | { |
440 | 116 | dTempY = -1000000000; |
441 | 116 | bIntBoundsOverflow = TRUE; |
442 | 116 | } |
443 | 2.83k | if (dTempY > 1000000000) |
444 | 87 | { |
445 | 87 | dTempY = 1000000000; |
446 | 87 | bIntBoundsOverflow = TRUE; |
447 | 87 | } |
448 | | |
449 | 2.83k | nX = static_cast<GInt32>(ROUND_INT(dTempX)); |
450 | 2.83k | nY = static_cast<GInt32>(ROUND_INT(dTempY)); |
451 | | |
452 | 2.83k | if (bIntBoundsOverflow && !bIgnoreOverflow) |
453 | 290 | { |
454 | 290 | m_bIntBoundsOverflow = TRUE; |
455 | | #ifdef DEBUG |
456 | | CPLError( |
457 | | CE_Warning, static_cast<CPLErrorNum>(TAB_WarningBoundsOverflow), |
458 | | "Integer bounds overflow: (%f, %f) -> (%d, %d)\n", dX, dY, nX, nY); |
459 | | #endif |
460 | 290 | } |
461 | | |
462 | 2.83k | return 0; |
463 | 2.83k | } |
464 | | |
465 | | /********************************************************************** |
466 | | * TABMAPHeaderBlock::ComprInt2Coordsys() |
467 | | * |
468 | | * Convert from compressed integer (internal) to coordinates system units |
469 | | * as defined in the file's coordsys clause. |
470 | | * The difference between long integer and compressed integer coords is |
471 | | * that compressed coordinates are scaled displacement relative to an |
472 | | * object centroid. |
473 | | * |
474 | | * Note that the false easting/northing and the conversion factor from |
475 | | * datum to coordsys units are not included in the calculation. |
476 | | * |
477 | | * Returns 0 on success, -1 on error. |
478 | | **********************************************************************/ |
479 | | int TABMAPHeaderBlock::ComprInt2Coordsys(GInt32 nCenterX, GInt32 nCenterY, |
480 | | int nDeltaX, int nDeltaY, double &dX, |
481 | | double &dY) |
482 | 0 | { |
483 | 0 | if (m_pabyBuf == nullptr) |
484 | 0 | return -1; |
485 | | |
486 | 0 | return Int2Coordsys(nCenterX + nDeltaX, nCenterY + nDeltaY, dX, dY); |
487 | 0 | } |
488 | | |
489 | | /********************************************************************** |
490 | | * TABMAPHeaderBlock::Int2CoordsysDist() |
491 | | * |
492 | | * Convert a pair of X and Y size (or distance) value from long integer |
493 | | * (internal) to coordinates system units as defined in the file's |
494 | | * coordsys clause. |
495 | | * |
496 | | * The difference with Int2Coordsys() is that this function only applies |
497 | | * the scaling factor: it does not apply the displacement. |
498 | | * |
499 | | * Since the calculations on the X and Y values are independent, either |
500 | | * one can be omitted (i.e. passed as 0) |
501 | | * |
502 | | * Returns 0 on success, -1 on error. |
503 | | **********************************************************************/ |
504 | | int TABMAPHeaderBlock::Int2CoordsysDist(GInt32 nX, GInt32 nY, double &dX, |
505 | | double &dY) |
506 | 62 | { |
507 | 62 | if (m_pabyBuf == nullptr) |
508 | 0 | return -1; |
509 | | |
510 | 62 | dX = nX / m_XScale; |
511 | 62 | dY = nY / m_YScale; |
512 | | |
513 | 62 | return 0; |
514 | 62 | } |
515 | | |
516 | | /********************************************************************** |
517 | | * TABMAPHeaderBlock::Coordsys2IntDist() |
518 | | * |
519 | | * Convert a pair of X and Y size (or distance) values from coordinates |
520 | | * system units as defined in the file's coordsys clause to long integer |
521 | | * (internal) coordinates. |
522 | | * |
523 | | * The difference with Coordsys2Int() is that this function only applies |
524 | | * the scaling factor: it does not apply the displacement. |
525 | | * |
526 | | * Since the calculations on the X and Y values are independent, either |
527 | | * one can be omitted (i.e. passed as 0) |
528 | | * |
529 | | * Returns 0 on success, -1 on error. |
530 | | **********************************************************************/ |
531 | | int TABMAPHeaderBlock::Coordsys2IntDist(double dX, double dY, GInt32 &nX, |
532 | | GInt32 &nY) |
533 | 0 | { |
534 | 0 | if (m_pabyBuf == nullptr) |
535 | 0 | return -1; |
536 | | |
537 | 0 | nX = static_cast<GInt32>(dX * m_XScale); |
538 | 0 | nY = static_cast<GInt32>(dY * m_YScale); |
539 | |
|
540 | 0 | return 0; |
541 | 0 | } |
542 | | |
543 | | /********************************************************************** |
544 | | * TABMAPHeaderBlock::SetCoordsysBounds() |
545 | | * |
546 | | * Take projection coordinates bounds of the newly created dataset and |
547 | | * compute new values for the X/Y Scales and X/Y displacement. |
548 | | * |
549 | | * This function must be called after creating a new dataset and before any |
550 | | * of the coordinates conversion functions can be used. |
551 | | * |
552 | | * Returns 0 on success, -1 on error. |
553 | | **********************************************************************/ |
554 | | int TABMAPHeaderBlock::SetCoordsysBounds(double dXMin, double dYMin, |
555 | | double dXMax, double dYMax) |
556 | 28 | { |
557 | | // printf("SetCoordsysBounds(%10g, %10g, %10g, %10g)\n", dXMin, dYMin, |
558 | | // dXMax, dYMax); |
559 | | /*----------------------------------------------------------------- |
560 | | * Check for 0-width or 0-height bounds |
561 | | *----------------------------------------------------------------*/ |
562 | 28 | if (dXMax == dXMin) |
563 | 0 | { |
564 | 0 | dXMin -= 1.0; |
565 | 0 | dXMax += 1.0; |
566 | 0 | } |
567 | | |
568 | 28 | if (dYMax == dYMin) |
569 | 0 | { |
570 | 0 | dYMin -= 1.0; |
571 | 0 | dYMax += 1.0; |
572 | 0 | } |
573 | | |
574 | | /*----------------------------------------------------------------- |
575 | | * X and Y scales are used to map coordsys coordinates to integer |
576 | | * internal coordinates. We want to find the scale and displacement |
577 | | * values that will result in an integer coordinate range of |
578 | | * (-1e9, -1e9) - (1e9, 1e9) |
579 | | * |
580 | | * Note that we ALWAYS generate datasets with the OriginQuadrant = 1 |
581 | | * so that we avoid reverted X/Y axis complications, etc. |
582 | | *----------------------------------------------------------------*/ |
583 | 28 | m_XScale = 2e9 / (dXMax - dXMin); |
584 | 28 | m_YScale = 2e9 / (dYMax - dYMin); |
585 | | |
586 | 28 | m_XDispl = -1.0 * m_XScale * (dXMax + dXMin) / 2; |
587 | 28 | m_YDispl = -1.0 * m_YScale * (dYMax + dYMin) / 2; |
588 | | |
589 | 28 | m_nXMin = -1000000000; |
590 | 28 | m_nYMin = -1000000000; |
591 | 28 | m_nXMax = 1000000000; |
592 | 28 | m_nYMax = 1000000000; |
593 | | |
594 | 28 | UpdatePrecision(); |
595 | | |
596 | 28 | return 0; |
597 | 28 | } |
598 | | |
599 | | /********************************************************************** |
600 | | * TABMAPHeaderBlock::GetMapObjectSize() |
601 | | * |
602 | | * Return the size of the object body for the specified object type. |
603 | | * The value is looked up in the first 256 bytes of the header. |
604 | | **********************************************************************/ |
605 | | int TABMAPHeaderBlock::GetMapObjectSize(int nObjType) |
606 | 784 | { |
607 | 784 | if (m_pabyBuf == nullptr) |
608 | 0 | { |
609 | 0 | CPLError(CE_Failure, CPLE_AssertionFailed, |
610 | 0 | "Block has not been initialized yet!"); |
611 | 0 | return -1; |
612 | 0 | } |
613 | | |
614 | 784 | if (nObjType < 0 || nObjType > 255) |
615 | 0 | { |
616 | 0 | CPLError(CE_Failure, CPLE_IllegalArg, "Invalid object type %d", |
617 | 0 | nObjType); |
618 | 0 | return -1; |
619 | 0 | } |
620 | | |
621 | | // Byte 0x80 is set for objects that have coordinates inside type 3 blocks |
622 | 784 | return m_pabyBuf[nObjType] & 0x7f; |
623 | 784 | } |
624 | | |
625 | | /********************************************************************** |
626 | | * TABMAPHeaderBlock::MapObjectUsesCoordBlock() |
627 | | * |
628 | | * Return TRUE if the specified map object type has coordinates stored |
629 | | * inside type 3 coordinate blocks. |
630 | | * The info is looked up in the first 256 bytes of the header. |
631 | | **********************************************************************/ |
632 | | GBool TABMAPHeaderBlock::MapObjectUsesCoordBlock(int nObjType) |
633 | 784 | { |
634 | 784 | if (m_pabyBuf == nullptr) |
635 | 0 | { |
636 | 0 | CPLError(CE_Failure, CPLE_AssertionFailed, |
637 | 0 | "Block has not been initialized yet!"); |
638 | 0 | return FALSE; |
639 | 0 | } |
640 | | |
641 | 784 | if (nObjType < 0 || nObjType > 255) |
642 | 0 | { |
643 | 0 | CPLError(CE_Failure, CPLE_IllegalArg, "Invalid object type %d", |
644 | 0 | nObjType); |
645 | 0 | return FALSE; |
646 | 0 | } |
647 | | |
648 | | // Byte 0x80 is set for objects that have coordinates inside type 3 blocks |
649 | | |
650 | 784 | return ((m_pabyBuf[nObjType] & 0x80) != 0) ? TRUE : FALSE; |
651 | 784 | } |
652 | | |
653 | | /********************************************************************** |
654 | | * TABMAPHeaderBlock::GetProjInfo() |
655 | | * |
656 | | * Fill the psProjInfo structure with the projection parameters previously |
657 | | * read from this header block. |
658 | | * |
659 | | * Returns 0 on success, -1 on error. |
660 | | **********************************************************************/ |
661 | | int TABMAPHeaderBlock::GetProjInfo(TABProjInfo *psProjInfo) |
662 | 173 | { |
663 | 173 | if (m_pabyBuf == nullptr) |
664 | 0 | { |
665 | 0 | CPLError(CE_Failure, CPLE_AssertionFailed, |
666 | 0 | "Block has not been initialized yet!"); |
667 | 0 | return -1; |
668 | 0 | } |
669 | | |
670 | 173 | if (psProjInfo) |
671 | 173 | *psProjInfo = m_sProj; |
672 | | |
673 | 173 | return 0; |
674 | 173 | } |
675 | | |
676 | | /********************************************************************** |
677 | | * TABMAPHeaderBlock::SetProjInfo() |
678 | | * |
679 | | * Set the projection parameters for this dataset. |
680 | | * |
681 | | * Returns 0 on success, -1 on error. |
682 | | **********************************************************************/ |
683 | | int TABMAPHeaderBlock::SetProjInfo(TABProjInfo *psProjInfo) |
684 | 2 | { |
685 | 2 | if (m_pabyBuf == nullptr) |
686 | 0 | { |
687 | 0 | CPLError(CE_Failure, CPLE_AssertionFailed, |
688 | 0 | "Block has not been initialized yet!"); |
689 | 0 | return -1; |
690 | 0 | } |
691 | | |
692 | 2 | if (psProjInfo) |
693 | 2 | m_sProj = *psProjInfo; |
694 | | |
695 | 2 | return 0; |
696 | 2 | } |
697 | | |
698 | | /********************************************************************** |
699 | | * TABMAPHeaderBlock::CommitToFile() |
700 | | * |
701 | | * Commit the current state of the binary block to the file to which |
702 | | * it has been previously attached. |
703 | | * |
704 | | * This method makes sure all values are properly set in the header |
705 | | * block buffer and then calls TABRawBinBlock::CommitToFile() to do |
706 | | * the actual writing to disk. |
707 | | * |
708 | | * Returns 0 if successful or -1 if an error happened, in which case |
709 | | * CPLError() will have been called. |
710 | | **********************************************************************/ |
711 | | int TABMAPHeaderBlock::CommitToFile() |
712 | 28 | { |
713 | 28 | int i; |
714 | | |
715 | 28 | if (m_pabyBuf == nullptr || m_nRegularBlockSize == 0) |
716 | 0 | { |
717 | 0 | CPLError(CE_Failure, CPLE_AssertionFailed, |
718 | 0 | "TABRawBinBlock::CommitToFile(): Block has not been " |
719 | 0 | "initialized yet!"); |
720 | 0 | return -1; |
721 | 0 | } |
722 | | |
723 | | /*----------------------------------------------------------------- |
724 | | * Reconstruct header to make sure it is in sync with members variables. |
725 | | *----------------------------------------------------------------*/ |
726 | 28 | GotoByteInBlock(0x000); |
727 | 28 | WriteBytes(HDR_OBJ_LEN_ARRAY_SIZE, gabyObjLenArray); |
728 | 28 | m_nMaxObjLenArrayId = HDR_OBJ_LEN_ARRAY_SIZE - 1; |
729 | | |
730 | 28 | GotoByteInBlock(0x100); |
731 | 28 | WriteInt32(HDR_MAGIC_COOKIE); |
732 | | |
733 | 28 | if (m_sProj.nAffineFlag && m_nMAPVersionNumber < 500) |
734 | 0 | { |
735 | | // Must be at least version 500 to support affine params |
736 | | // Default value for HDR_VERSION_NUMBER is 500 so this error should |
737 | | // never happen unless the caller changed the value, in which case they |
738 | | // deserve to get a failure |
739 | 0 | CPLError(CE_Failure, CPLE_AssertionFailed, |
740 | 0 | "TABRawBinBlock::CommitToFile(): .MAP version 500 or more is " |
741 | 0 | "required for affine projection parameter support."); |
742 | 0 | return -1; |
743 | 0 | } |
744 | | |
745 | 28 | WriteInt16(m_nMAPVersionNumber); |
746 | | |
747 | 28 | WriteInt16(m_nRegularBlockSize); |
748 | | |
749 | 28 | WriteDouble(m_dCoordsys2DistUnits); |
750 | 28 | WriteInt32(m_nXMin); |
751 | 28 | WriteInt32(m_nYMin); |
752 | 28 | WriteInt32(m_nXMax); |
753 | 28 | WriteInt32(m_nYMax); |
754 | 28 | if (m_nXMin > m_nXMax || m_nYMin > m_nYMax) |
755 | 0 | { |
756 | 0 | CPLError(CE_Warning, CPLE_AppDefined, |
757 | 0 | "Writing corrupted MBR into .map header"); |
758 | 0 | } |
759 | | |
760 | 28 | WriteZeros(16); // ??? |
761 | | |
762 | 28 | WriteInt32(m_nFirstIndexBlock); |
763 | 28 | WriteInt32(m_nFirstGarbageBlock); |
764 | 28 | WriteInt32(m_nFirstToolBlock); |
765 | | |
766 | 28 | WriteInt32(m_numPointObjects); |
767 | 28 | WriteInt32(m_numLineObjects); |
768 | 28 | WriteInt32(m_numRegionObjects); |
769 | 28 | WriteInt32(m_numTextObjects); |
770 | 28 | WriteInt32(m_nMaxCoordBufSize); |
771 | | |
772 | 28 | WriteZeros(14); // ??? |
773 | | |
774 | 28 | WriteByte(m_nDistUnitsCode); |
775 | 28 | WriteByte(m_nMaxSpIndexDepth); |
776 | 28 | WriteByte(m_nCoordPrecision); |
777 | 28 | WriteByte(m_nCoordOriginQuadrant); |
778 | 28 | WriteByte(m_nReflectXAxisCoord); |
779 | 28 | WriteByte(m_nMaxObjLenArrayId); // See gabyObjLenArray[] |
780 | 28 | WriteByte(m_numPenDefs); |
781 | 28 | WriteByte(m_numBrushDefs); |
782 | 28 | WriteByte(m_numSymbolDefs); |
783 | 28 | WriteByte(m_numFontDefs); |
784 | 28 | CPLAssert(m_numMapToolBlocks >= 0 && m_numMapToolBlocks <= 255); |
785 | 28 | WriteByte(static_cast<GByte>(m_numMapToolBlocks)); |
786 | | |
787 | 28 | WriteZeros(1); // unused byte |
788 | 28 | WriteInt16(m_sProj.nDatumId); |
789 | 28 | WriteZeros(1); // unused byte |
790 | | |
791 | 28 | WriteByte(m_sProj.nProjId); |
792 | 28 | WriteByte(m_sProj.nEllipsoidId); |
793 | 28 | WriteByte(m_sProj.nUnitsId); |
794 | 28 | WriteDouble(m_XScale); |
795 | 28 | WriteDouble(m_YScale); |
796 | 28 | WriteDouble(m_XDispl); |
797 | 28 | WriteDouble(m_YDispl); |
798 | | |
799 | 196 | for (i = 0; i < 6; i++) |
800 | 168 | WriteDouble(m_sProj.adProjParams[i]); |
801 | | |
802 | 28 | WriteDouble(m_sProj.dDatumShiftX); |
803 | 28 | WriteDouble(m_sProj.dDatumShiftY); |
804 | 28 | WriteDouble(m_sProj.dDatumShiftZ); |
805 | 168 | for (i = 0; i < 5; i++) |
806 | 140 | WriteDouble(m_sProj.adDatumParams[i]); |
807 | | |
808 | 28 | if (m_sProj.nAffineFlag) |
809 | 0 | { |
810 | 0 | WriteByte(1); // In Use Flag |
811 | 0 | WriteByte(m_sProj.nAffineUnits); |
812 | 0 | WriteZeros(6); |
813 | 0 | WriteDouble(m_sProj.dAffineParamA); |
814 | 0 | WriteDouble(m_sProj.dAffineParamB); |
815 | 0 | WriteDouble(m_sProj.dAffineParamC); |
816 | 0 | WriteDouble(m_sProj.dAffineParamD); |
817 | 0 | WriteDouble(m_sProj.dAffineParamE); |
818 | 0 | WriteDouble(m_sProj.dAffineParamF); |
819 | |
|
820 | 0 | WriteZeros(456); // Pad rest of block with zeros (Bounds info here ?) |
821 | 0 | } |
822 | | |
823 | 28 | if (m_nMAPVersionNumber >= 500 && m_nBlockSize == 1024 && |
824 | 28 | m_sProj.nProjId == 35) |
825 | 0 | { |
826 | 0 | const auto nCurPosBak = m_nCurPos; |
827 | 0 | if (m_nCurPos == 512) |
828 | 0 | WriteZeros(512); |
829 | 0 | m_nCurPos = 0x0268; |
830 | 0 | WriteDouble(m_sProj.adProjParams[6]); |
831 | 0 | m_nCurPos = nCurPosBak; |
832 | 0 | } |
833 | | |
834 | | /*----------------------------------------------------------------- |
835 | | * OK, call the base class to write the block to disk. |
836 | | *----------------------------------------------------------------*/ |
837 | | #ifdef DEBUG_VERBOSE |
838 | | CPLDebug("MITAB", "Committing HEADER block to offset %d", m_nFileOffset); |
839 | | #endif |
840 | 28 | return TABRawBinBlock::CommitToFile(); |
841 | 28 | } |
842 | | |
843 | | /********************************************************************** |
844 | | * TABMAPHeaderBlock::InitNewBlock() |
845 | | * |
846 | | * Initialize a newly created block so that it knows to which file it |
847 | | * is attached, its block size, etc . and then perform any specific |
848 | | * initialization for this block type, including writing a default |
849 | | * block header, etc. and leave the block ready to receive data. |
850 | | * |
851 | | * This is an alternative to calling ReadFromFile() or InitBlockFromData() |
852 | | * that puts the block in a stable state without loading any initial |
853 | | * data in it. |
854 | | * |
855 | | * Returns 0 if successful or -1 if an error happened, in which case |
856 | | * CPLError() will have been called. |
857 | | **********************************************************************/ |
858 | | int TABMAPHeaderBlock::InitNewBlock(VSILFILE *fpSrc, int nBlockSize, |
859 | | int nFileOffset /* = 0*/) |
860 | 467 | { |
861 | | /*----------------------------------------------------------------- |
862 | | * Start with the default initialization |
863 | | *----------------------------------------------------------------*/ |
864 | | |
865 | | /* .MAP files of Version 500 and up appear to have a 1024 bytes |
866 | | * header. The last 512 bytes are usually all zeros. */ |
867 | 467 | if (TABRawBinBlock::InitNewBlock(fpSrc, 1024, nFileOffset) != 0) |
868 | 0 | return -1; |
869 | | |
870 | | /*----------------------------------------------------------------- |
871 | | * Set acceptable default values for member vars. |
872 | | *----------------------------------------------------------------*/ |
873 | 467 | InitMembersWithDefaultValues(); |
874 | | |
875 | 467 | CPLAssert(nBlockSize >= 0 && nBlockSize <= 32767); |
876 | 467 | m_nRegularBlockSize = static_cast<GInt16>(nBlockSize); |
877 | | |
878 | | /*----------------------------------------------------------------- |
879 | | * And Set the map object length array in the buffer... |
880 | | *----------------------------------------------------------------*/ |
881 | 467 | if (m_eAccess != TABRead) |
882 | 28 | { |
883 | 28 | GotoByteInBlock(0x000); |
884 | 28 | WriteBytes(HDR_OBJ_LEN_ARRAY_SIZE, gabyObjLenArray); |
885 | 28 | } |
886 | | |
887 | 467 | if (CPLGetLastErrorType() == CE_Failure) |
888 | 0 | return -1; |
889 | | |
890 | 467 | return 0; |
891 | 467 | } |
892 | | |
893 | | /********************************************************************** |
894 | | * TABMAPHeaderBlock::UpdatePrecision() |
895 | | * |
896 | | * Update x and y maximum achievable precision given current scales |
897 | | * (m_XScale and m_YScale) |
898 | | **********************************************************************/ |
899 | | void TABMAPHeaderBlock::UpdatePrecision() |
900 | 446 | { |
901 | 446 | m_XPrecision = pow(10.0, round(log10(m_XScale))); |
902 | 446 | m_YPrecision = pow(10.0, round(log10(m_YScale))); |
903 | 446 | } |
904 | | |
905 | | /********************************************************************** |
906 | | * TABMAPHeaderBlock::Dump() |
907 | | * |
908 | | * Dump block contents... available only in DEBUG mode. |
909 | | **********************************************************************/ |
910 | | #ifdef DEBUG |
911 | | |
912 | | void TABMAPHeaderBlock::Dump(FILE *fpOut /*=NULL*/) |
913 | | { |
914 | | if (fpOut == nullptr) |
915 | | fpOut = stdout; |
916 | | |
917 | | fprintf(fpOut, "----- TABMAPHeaderBlock::Dump() -----\n"); |
918 | | |
919 | | if (m_pabyBuf == nullptr) |
920 | | { |
921 | | fprintf(fpOut, "Block has not been initialized yet."); |
922 | | } |
923 | | else |
924 | | { |
925 | | fprintf(fpOut, "Version %d header block.\n", m_nMAPVersionNumber); |
926 | | fprintf(fpOut, " m_nRegularBlockSize = %d\n", |
927 | | m_nRegularBlockSize); |
928 | | fprintf(fpOut, " m_nFirstIndexBlock = %d\n", m_nFirstIndexBlock); |
929 | | fprintf(fpOut, " m_nFirstGarbageBlock = %d\n", m_nFirstGarbageBlock); |
930 | | fprintf(fpOut, " m_nFirstToolBlock = %d\n", m_nFirstToolBlock); |
931 | | fprintf(fpOut, " m_numPointObjects = %d\n", m_numPointObjects); |
932 | | fprintf(fpOut, " m_numLineObjects = %d\n", m_numLineObjects); |
933 | | fprintf(fpOut, " m_numRegionObjects = %d\n", m_numRegionObjects); |
934 | | fprintf(fpOut, " m_numTextObjects = %d\n", m_numTextObjects); |
935 | | fprintf(fpOut, " m_nMaxCoordBufSize = %d\n", m_nMaxCoordBufSize); |
936 | | |
937 | | fprintf(fpOut, "\n"); |
938 | | fprintf(fpOut, " m_dCoordsys2DistUnits = %g\n", m_dCoordsys2DistUnits); |
939 | | fprintf(fpOut, " m_nXMin = %d\n", m_nXMin); |
940 | | fprintf(fpOut, " m_nYMin = %d\n", m_nYMin); |
941 | | fprintf(fpOut, " m_nXMax = %d\n", m_nXMax); |
942 | | fprintf(fpOut, " m_nYMax = %d\n", m_nYMax); |
943 | | fprintf(fpOut, " m_XScale = %g\n", m_XScale); |
944 | | fprintf(fpOut, " m_YScale = %g\n", m_YScale); |
945 | | fprintf(fpOut, " m_XDispl = %g\n", m_XDispl); |
946 | | fprintf(fpOut, " m_YDispl = %g\n", m_YDispl); |
947 | | |
948 | | fprintf(fpOut, "\n"); |
949 | | fprintf(fpOut, " m_nDistUnistCode = %d\n", m_nDistUnitsCode); |
950 | | fprintf(fpOut, " m_nMaxSpIndexDepth = %d\n", m_nMaxSpIndexDepth); |
951 | | fprintf(fpOut, " m_nCoordPrecision = %d\n", m_nCoordPrecision); |
952 | | fprintf(fpOut, " m_nCoordOriginQuadrant= %d\n", |
953 | | m_nCoordOriginQuadrant); |
954 | | fprintf(fpOut, " m_nReflecXAxisCoord = %d\n", m_nReflectXAxisCoord); |
955 | | fprintf(fpOut, " m_nMaxObjLenArrayId = %d\n", m_nMaxObjLenArrayId); |
956 | | fprintf(fpOut, " m_numPenDefs = %d\n", m_numPenDefs); |
957 | | fprintf(fpOut, " m_numBrushDefs = %d\n", m_numBrushDefs); |
958 | | fprintf(fpOut, " m_numSymbolDefs = %d\n", m_numSymbolDefs); |
959 | | fprintf(fpOut, " m_numFontDefs = %d\n", m_numFontDefs); |
960 | | fprintf(fpOut, " m_numMapToolBlocks = %d\n", m_numMapToolBlocks); |
961 | | |
962 | | fprintf(fpOut, "\n"); |
963 | | fprintf(fpOut, " m_sProj.nDatumId = %d\n", m_sProj.nDatumId); |
964 | | fprintf(fpOut, " m_sProj.nProjId = %d\n", |
965 | | static_cast<int>(m_sProj.nProjId)); |
966 | | fprintf(fpOut, " m_sProj.nEllipsoidId = %d\n", |
967 | | static_cast<int>(m_sProj.nEllipsoidId)); |
968 | | fprintf(fpOut, " m_sProj.nUnitsId = %d\n", |
969 | | static_cast<int>(m_sProj.nUnitsId)); |
970 | | fprintf(fpOut, " m_sProj.adProjParams ="); |
971 | | for (int i = 0; i < 6; i++) |
972 | | fprintf(fpOut, " %g", m_sProj.adProjParams[i]); |
973 | | fprintf(fpOut, "\n"); |
974 | | |
975 | | fprintf(fpOut, " m_sProj.dDatumShiftX = %.15g\n", |
976 | | m_sProj.dDatumShiftX); |
977 | | fprintf(fpOut, " m_sProj.dDatumShiftY = %.15g\n", |
978 | | m_sProj.dDatumShiftY); |
979 | | fprintf(fpOut, " m_sProj.dDatumShiftZ = %.15g\n", |
980 | | m_sProj.dDatumShiftZ); |
981 | | fprintf(fpOut, " m_sProj.adDatumParams ="); |
982 | | for (int i = 0; i < 5; i++) |
983 | | fprintf(fpOut, " %.15g", m_sProj.adDatumParams[i]); |
984 | | fprintf(fpOut, "\n"); |
985 | | |
986 | | // Dump array of map object lengths... optional |
987 | | if (FALSE) |
988 | | { |
989 | | fprintf(fpOut, |
990 | | "-- Header bytes 00-FF: Array of map object lengths --\n"); |
991 | | for (int i = 0; i < 256; i++) |
992 | | { |
993 | | fprintf(fpOut, "0x%2.2x", static_cast<int>(m_pabyBuf[i])); |
994 | | if (i != 255) |
995 | | fprintf(fpOut, ","); |
996 | | if ((i + 1) % 16 == 0) |
997 | | fprintf(fpOut, "\n"); |
998 | | } |
999 | | } |
1000 | | } |
1001 | | |
1002 | | fflush(fpOut); |
1003 | | } |
1004 | | |
1005 | | #endif // DEBUG |