1 /**********************************************************************
2  * $Id: mitab_priv.h a40fc640782d3f2b3889ee92dfcf4aa545733bc8 2020-11-06 21:56:04 +0100 Even Rouault $
3  *
4  * Name:     mitab_priv.h
5  * Project:  MapInfo TAB Read/Write library
6  * Language: C++
7  * Purpose:  Header file containing private definitions for the library.
8  * Author:   Daniel Morissette, dmorissette@dmsolutions.ca
9  *
10  **********************************************************************
11  * Copyright (c) 1999-2003, Daniel Morissette
12  * Copyright (c) 2014, Even Rouault <even.rouault at spatialys.com>
13  *
14  * Permission is hereby granted, free of charge, to any person obtaining a
15  * copy of this software and associated documentation files (the "Software"),
16  * to deal in the Software without restriction, including without limitation
17  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
18  * and/or sell copies of the Software, and to permit persons to whom the
19  * Software is furnished to do so, subject to the following conditions:
20  *
21  * The above copyright notice and this permission notice shall be included
22  * in all copies or substantial portions of the Software.
23  *
24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
27  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30  * DEALINGS IN THE SOFTWARE.
31  **********************************************************************/
32 
33 #ifndef MITAB_PRIV_H_INCLUDED_
34 #define MITAB_PRIV_H_INCLUDED_
35 
36 #include "cpl_conv.h"
37 #include "cpl_string.h"
38 #include "ogr_feature.h"
39 
40 #include <set>
41 
42 class TABFile;
43 class TABFeature;
44 class TABMAPToolBlock;
45 class TABMAPIndexBlock;
46 
47 /*---------------------------------------------------------------------
48  * Access mode: Read or Write
49  *--------------------------------------------------------------------*/
50 typedef enum
51 {
52     TABRead,
53     TABWrite,
54     TABReadWrite
55 } TABAccess;
56 
57 /*---------------------------------------------------------------------
58  * Supported .MAP block types (the first byte at the beginning of a block)
59  *--------------------------------------------------------------------*/
60 #define TAB_RAWBIN_BLOCK        -1
61 #define TABMAP_HEADER_BLOCK     0
62 #define TABMAP_INDEX_BLOCK      1
63 #define TABMAP_OBJECT_BLOCK     2
64 #define TABMAP_COORD_BLOCK      3
65 #define TABMAP_GARB_BLOCK       4
66 #define TABMAP_TOOL_BLOCK       5
67 #define TABMAP_LAST_VALID_BLOCK_TYPE  5
68 
69 /*---------------------------------------------------------------------
70  * Drawing Tool types
71  *--------------------------------------------------------------------*/
72 #define TABMAP_TOOL_PEN         1
73 #define TABMAP_TOOL_BRUSH       2
74 #define TABMAP_TOOL_FONT        3
75 #define TABMAP_TOOL_SYMBOL      4
76 
77 /*---------------------------------------------------------------------
78  * Limits related to .TAB version number.  If we pass any of those limits
79  * then we have to use larger object types
80  *--------------------------------------------------------------------*/
81 #define TAB_REGION_PLINE_300_MAX_VERTICES    32767
82 
83 #define TAB_REGION_PLINE_450_MAX_SEGMENTS       32767
84 #define TAB_REGION_PLINE_450_MAX_VERTICES       1048575
85 
86 #define TAB_MULTIPOINT_650_MAX_VERTICES         1048576
87 
88 /* Use this macro to test whether the number of segments and vertices
89  * in this object exceeds the V450/650 limits and requires a V800 object
90  */
91 #define TAB_REGION_PLINE_REQUIRES_V800(numSegments, numVerticesTotal) \
92     ((numSegments) > TAB_REGION_PLINE_450_MAX_SEGMENTS || \
93      ((numSegments)*3 + numVerticesTotal) > TAB_REGION_PLINE_450_MAX_VERTICES )
94 
95 /*---------------------------------------------------------------------
96  * Codes for the known MapInfo Geometry types
97  *--------------------------------------------------------------------*/
98 typedef enum
99 {
100     TAB_GEOM_UNSET          = -1,
101 
102     TAB_GEOM_NONE           = 0,
103     TAB_GEOM_SYMBOL_C       = 0x01,
104     TAB_GEOM_SYMBOL         = 0x02,
105     TAB_GEOM_LINE_C         = 0x04,
106     TAB_GEOM_LINE           = 0x05,
107     TAB_GEOM_PLINE_C        = 0x07,
108     TAB_GEOM_PLINE          = 0x08,
109     TAB_GEOM_ARC_C          = 0x0a,
110     TAB_GEOM_ARC            = 0x0b,
111     TAB_GEOM_REGION_C       = 0x0d,
112     TAB_GEOM_REGION         = 0x0e,
113     TAB_GEOM_TEXT_C         = 0x10,
114     TAB_GEOM_TEXT           = 0x11,
115     TAB_GEOM_RECT_C         = 0x13,
116     TAB_GEOM_RECT           = 0x14,
117     TAB_GEOM_ROUNDRECT_C    = 0x16,
118     TAB_GEOM_ROUNDRECT      = 0x17,
119     TAB_GEOM_ELLIPSE_C      = 0x19,
120     TAB_GEOM_ELLIPSE        = 0x1a,
121     TAB_GEOM_MULTIPLINE_C   = 0x25,
122     TAB_GEOM_MULTIPLINE     = 0x26,
123     TAB_GEOM_FONTSYMBOL_C   = 0x28,
124     TAB_GEOM_FONTSYMBOL     = 0x29,
125     TAB_GEOM_CUSTOMSYMBOL_C = 0x2b,
126     TAB_GEOM_CUSTOMSYMBOL   = 0x2c,
127 /* Version 450 object types: */
128     TAB_GEOM_V450_REGION_C  = 0x2e,
129     TAB_GEOM_V450_REGION    = 0x2f,
130     TAB_GEOM_V450_MULTIPLINE_C = 0x31,
131     TAB_GEOM_V450_MULTIPLINE   = 0x32,
132 /* Version 650 object types: */
133     TAB_GEOM_MULTIPOINT_C   = 0x34,
134     TAB_GEOM_MULTIPOINT     = 0x35,
135     TAB_GEOM_COLLECTION_C   = 0x37,
136     TAB_GEOM_COLLECTION     = 0x38,
137 /* Version 800 object types: */
138     TAB_GEOM_UNKNOWN1_C     = 0x3a,    // ???
139     TAB_GEOM_UNKNOWN1       = 0x3b,    // ???
140     TAB_GEOM_V800_REGION_C  = 0x3d,
141     TAB_GEOM_V800_REGION    = 0x3e,
142     TAB_GEOM_V800_MULTIPLINE_C = 0x40,
143     TAB_GEOM_V800_MULTIPLINE   = 0x41,
144     TAB_GEOM_V800_MULTIPOINT_C = 0x43,
145     TAB_GEOM_V800_MULTIPOINT   = 0x44,
146     TAB_GEOM_V800_COLLECTION_C = 0x46,
147     TAB_GEOM_V800_COLLECTION   = 0x47,
148     TAB_GEOM_MAX_TYPE /* TODo: Does this need to be 0x80? */
149 } TABGeomType;
150 
151 #define TAB_GEOM_GET_VERSION(nGeomType)                     \
152     (((nGeomType) < TAB_GEOM_V450_REGION_C)  ? 300:         \
153      ((nGeomType) < TAB_GEOM_MULTIPOINT_C)   ? 450:         \
154      ((nGeomType) < TAB_GEOM_UNKNOWN1_C)     ? 650: 800 )
155 
156 /*---------------------------------------------------------------------
157  * struct TABMAPIndexEntry - Entries found in type 1 blocks of .MAP files
158  *
159  * We will use this struct to rebuild the geographic index in memory
160  *--------------------------------------------------------------------*/
161 typedef struct TABMAPIndexEntry_t
162 {
163     // These members refer to the info we find in the file
164     GInt32      XMin;
165     GInt32      YMin;
166     GInt32      XMax;
167     GInt32      YMax;
168     GInt32      nBlockPtr;
169 }TABMAPIndexEntry;
170 
171 #define TAB_MIN_BLOCK_SIZE              512
172 #define TAB_MAX_BLOCK_SIZE              (32768-512)
173 
174 #define TAB_MAX_ENTRIES_INDEX_BLOCK     ((TAB_MAX_BLOCK_SIZE-4)/20)
175 
176 /*---------------------------------------------------------------------
177  * TABVertex
178  *--------------------------------------------------------------------*/
179 typedef struct TABVertex_t
180 {
181     double x{};
182     double y{};
183 } TABVertex;
184 
185 /*---------------------------------------------------------------------
186  * TABTableType - Attribute table format
187  *--------------------------------------------------------------------*/
188 typedef enum
189 {
190     TABTableNative,     // The default
191     TABTableDBF,
192     TABTableAccess
193 } TABTableType;
194 
195 /*---------------------------------------------------------------------
196  * TABFieldType - Native MapInfo attribute field types
197  *--------------------------------------------------------------------*/
198 typedef enum
199 {
200     TABFUnknown = 0,
201     TABFChar,
202     TABFInteger,
203     TABFSmallInt,
204     TABFDecimal,
205     TABFFloat,
206     TABFDate,
207     TABFLogical,
208     TABFTime,
209     TABFDateTime
210 } TABFieldType;
211 
212 #define TABFIELDTYPE_2_STRING(type)     \
213    (type == TABFChar ? "Char" :         \
214     type == TABFInteger ? "Integer" :   \
215     type == TABFSmallInt ? "SmallInt" : \
216     type == TABFDecimal ? "Decimal" :   \
217     type == TABFFloat ? "Float" :       \
218     type == TABFDate ? "Date" :         \
219     type == TABFLogical ? "Logical" :   \
220     type == TABFTime ? "Time" :         \
221     type == TABFDateTime ? "DateTime" : \
222     "Unknown field type"   )
223 
224 /*---------------------------------------------------------------------
225  * TABDATFieldDef
226  *--------------------------------------------------------------------*/
227 typedef struct TABDATFieldDef_t
228 {
229     char        szName[11];
230     char        cType;
231     GByte       byLength;
232     GByte       byDecimals;
233 
234     TABFieldType eTABType;
235 } TABDATFieldDef;
236 
237 /*---------------------------------------------------------------------
238  * TABMAPCoordSecHdr
239  * struct used in the TABMAPCoordBlock to store info about the coordinates
240  * for a section of a PLINE MULTIPLE or a REGION.
241  *--------------------------------------------------------------------*/
242 typedef struct TABMAPCoordSecHdr_t
243 {
244     GInt32      numVertices;
245     GInt32      numHoles;
246     GInt32      nXMin;
247     GInt32      nYMin;
248     GInt32      nXMax;
249     GInt32      nYMax;
250 
251     GInt32      nDataOffset;
252     int         nVertexOffset;
253 } TABMAPCoordSecHdr;
254 
255 /*---------------------------------------------------------------------
256  * TABProjInfo
257  * struct used to store the projection parameters from the .MAP header
258  *--------------------------------------------------------------------*/
259 typedef struct TABProjInfo_t
260 {
261     GByte       nProjId;           // See MapInfo Ref. Manual, App. F and G
262     GByte       nEllipsoidId;
263     GByte       nUnitsId;
264     double      adProjParams[6];   // params in same order as in .MIF COORDSYS
265 
266     GInt16      nDatumId;       // Datum Id added in MapInfo 7.8+ (.map V500)
267     double      dDatumShiftX;   // Before that, we had to always lookup datum
268     double      dDatumShiftY;   // parameters to establish datum id
269     double      dDatumShiftZ;
270     double      adDatumParams[5];
271 
272     // Affine parameters only in .map version 500 and up
273     GByte       nAffineFlag;    // 0=No affine param, 1=Affine params
274     GByte       nAffineUnits;
275     double      dAffineParamA;  // Affine params
276     double      dAffineParamB;
277     double      dAffineParamC;
278     double      dAffineParamD;
279     double      dAffineParamE;
280     double      dAffineParamF;
281 } TABProjInfo;
282 
283 /*---------------------------------------------------------------------
284  * TABPenDef - Pen definition information
285  *--------------------------------------------------------------------*/
286 typedef struct TABPenDef_t
287 {
288     GInt32      nRefCount;
289     GByte       nPixelWidth;
290     GByte       nLinePattern;
291     int         nPointWidth;
292     GInt32      rgbColor;
293 } TABPenDef;
294 
295 /* MI Default = PEN(1,2,0) */
296 #define MITAB_PEN_DEFAULT {0, 1, 2, 0, 0x000000}
297 
298 /*---------------------------------------------------------------------
299  * TABBrushDef - Brush definition information
300  *--------------------------------------------------------------------*/
301 typedef struct TABBrushDef_t
302 {
303     GInt32      nRefCount;
304     GByte       nFillPattern;
305     GByte       bTransparentFill; // 1 = Transparent
306     GInt32      rgbFGColor;
307     GInt32      rgbBGColor;
308 } TABBrushDef;
309 
310 /* MI Default = BRUSH(1,0,16777215) */
311 #define MITAB_BRUSH_DEFAULT {0, 1, 0, 0, 0xffffff}
312 
313 /*---------------------------------------------------------------------
314  * TABFontDef - Font Name information
315  *--------------------------------------------------------------------*/
316 typedef struct TABFontDef_t
317 {
318     GInt32      nRefCount;
319     char        szFontName[33];
320 } TABFontDef;
321 
322 /* MI Default = FONT("Arial",0,0,0) */
323 #define MITAB_FONT_DEFAULT {0, "Arial"}
324 
325 /*---------------------------------------------------------------------
326  * TABSymbolDef - Symbol definition information
327  *--------------------------------------------------------------------*/
328 typedef struct TABSymbolDef_t
329 {
330     GInt32      nRefCount;
331     GInt16      nSymbolNo;
332     GInt16      nPointSize;
333     GByte       _nUnknownValue_;// Style???
334     GInt32      rgbColor;
335 } TABSymbolDef;
336 
337 /* MI Default = SYMBOL(35,0,12) */
338 #define MITAB_SYMBOL_DEFAULT {0, 35, 12, 0, 0x000000}
339 
340 /*---------------------------------------------------------------------
341  *                      class TABToolDefTable
342  *
343  * Class to handle the list of Drawing Tool Definitions for a dataset
344  *
345  * This class also contains methods to read tool defs from the file and
346  * write them to the file.
347  *--------------------------------------------------------------------*/
348 
349 class TABToolDefTable
350 {
351     CPL_DISALLOW_COPY_ASSIGN(TABToolDefTable)
352 
353   protected:
354     TABPenDef   **m_papsPen;
355     int         m_numPen;
356     int         m_numAllocatedPen;
357     TABBrushDef **m_papsBrush;
358     int         m_numBrushes;
359     int         m_numAllocatedBrushes;
360     TABFontDef  **m_papsFont;
361     int         m_numFonts;
362     int         m_numAllocatedFonts;
363     TABSymbolDef **m_papsSymbol;
364     int         m_numSymbols;
365     int         m_numAllocatedSymbols;
366 
367   public:
368     TABToolDefTable();
369     ~TABToolDefTable();
370 
371     int         ReadAllToolDefs(TABMAPToolBlock *poToolBlock);
372     int         WriteAllToolDefs(TABMAPToolBlock *poToolBlock);
373 
374     TABPenDef   *GetPenDefRef(int nIndex);
375     int         AddPenDefRef(TABPenDef *poPenDef);
376     int         GetNumPen();
377 
378     TABBrushDef *GetBrushDefRef(int nIndex);
379     int         AddBrushDefRef(TABBrushDef *poBrushDef);
380     int         GetNumBrushes();
381 
382     TABFontDef  *GetFontDefRef(int nIndex);
383     int         AddFontDefRef(TABFontDef *poFontDef);
384     int         GetNumFonts();
385 
386     TABSymbolDef *GetSymbolDefRef(int nIndex);
387     int         AddSymbolDefRef(TABSymbolDef *poSymbolDef);
388     int         GetNumSymbols();
389 
390     int         GetMinVersionNumber();
391 };
392 
393 /*=====================================================================
394           Classes to handle Object Headers inside TABMAPObjectBlocks
395  =====================================================================*/
396 
397 class TABMAPObjectBlock;
398 class TABMAPHeaderBlock;
399 
400 class TABMAPObjHdr
401 {
402   public:
403     TABGeomType m_nType;
404     GInt32      m_nId;
405     GInt32      m_nMinX;  /* Object MBR */
406     GInt32      m_nMinY;
407     GInt32      m_nMaxX;
408     GInt32      m_nMaxY;
409 
TABMAPObjHdr()410     TABMAPObjHdr():
411         m_nType(TAB_GEOM_NONE),
412         m_nId(0),
413         m_nMinX(0),
414         m_nMinY(0),
415         m_nMaxX(0),
416         m_nMaxY(0)
417         {}
~TABMAPObjHdr()418     virtual ~TABMAPObjHdr() {}
419 
420     static TABMAPObjHdr *NewObj(TABGeomType nNewObjType, GInt32 nId=0);
421     static TABMAPObjHdr *ReadNextObj(TABMAPObjectBlock *poObjBlock,
422                                      TABMAPHeaderBlock *poHeader);
423 
424     GBool       IsCompressedType();
425     int         WriteObjTypeAndId(TABMAPObjectBlock *);
426     void        SetMBR(GInt32 nMinX, GInt32 nMinY, GInt32 nMaxX, GInt32 mMaxY);
427 
WriteObj(TABMAPObjectBlock *)428     virtual int WriteObj(TABMAPObjectBlock *) {return -1;}
429 
430 //  protected:
ReadObj(TABMAPObjectBlock *)431     virtual int ReadObj(TABMAPObjectBlock *) {return -1;}
432 };
433 
434 class TABMAPObjHdrWithCoord : public TABMAPObjHdr
435 {
436   public:
437     GInt32      m_nCoordBlockPtr = 0;
438     GInt32      m_nCoordDataSize = 0;
439 
440     /* Eventually this class may have methods to help maintaining refs to
441      * coord. blocks when splitting object blocks.
442      */
443 };
444 
445 class TABMAPObjNone final : public TABMAPObjHdr
446 {
447   public:
448 
TABMAPObjNone()449     TABMAPObjNone() {}
~TABMAPObjNone()450     virtual ~TABMAPObjNone() {}
451 
WriteObj(TABMAPObjectBlock *)452     virtual int WriteObj(TABMAPObjectBlock *) override {return 0;}
453 
454 //  protected:
ReadObj(TABMAPObjectBlock *)455     virtual int ReadObj(TABMAPObjectBlock *) override {return 0;}
456 };
457 
458 class TABMAPObjPoint: public TABMAPObjHdr
459 {
460   public:
461     GInt32      m_nX;
462     GInt32      m_nY;
463     GByte       m_nSymbolId;
464 
TABMAPObjPoint()465     TABMAPObjPoint():
466         m_nX(0), m_nY(0), m_nSymbolId(0) {}
~TABMAPObjPoint()467     virtual ~TABMAPObjPoint() {}
468 
469     virtual int WriteObj(TABMAPObjectBlock *) override;
470 
471 //  protected:
472     virtual int ReadObj(TABMAPObjectBlock *) override;
473 };
474 
475 class TABMAPObjFontPoint: public TABMAPObjPoint
476 {
477   public:
478     GByte       m_nPointSize;
479     GInt16      m_nFontStyle;
480     GByte       m_nR;
481     GByte       m_nG;
482     GByte       m_nB;
483     GInt16      m_nAngle;  /* In tenths of degree */
484     GByte       m_nFontId;
485 
TABMAPObjFontPoint()486     TABMAPObjFontPoint():
487         m_nPointSize(0),
488         m_nFontStyle(0),
489         m_nR(0),
490         m_nG(0),
491         m_nB(0),
492         m_nAngle(0),
493         m_nFontId(0)
494         {}
~TABMAPObjFontPoint()495     virtual ~TABMAPObjFontPoint() {}
496 
497     virtual int WriteObj(TABMAPObjectBlock *) override;
498 
499 //  protected:
500     virtual int ReadObj(TABMAPObjectBlock *) override;
501 };
502 
503 class TABMAPObjCustomPoint final : public TABMAPObjPoint
504 {
505   public:
506     GByte m_nUnknown_;
507     GByte m_nCustomStyle;
508     GByte m_nFontId;
509 
TABMAPObjCustomPoint()510     TABMAPObjCustomPoint():
511         m_nUnknown_(0),
512         m_nCustomStyle(0),
513         m_nFontId(0)
514         {}
~TABMAPObjCustomPoint()515     virtual ~TABMAPObjCustomPoint() {}
516 
517     virtual int WriteObj(TABMAPObjectBlock *) override;
518 
519 //  protected:
520     virtual int ReadObj(TABMAPObjectBlock *) override;
521 };
522 
523 class TABMAPObjLine final : public TABMAPObjHdr
524 {
525   public:
526     GInt32      m_nX1;
527     GInt32      m_nY1;
528     GInt32      m_nX2;
529     GInt32      m_nY2;
530     GByte       m_nPenId;
531 
TABMAPObjLine()532     TABMAPObjLine():
533         m_nX1(0),
534         m_nY1(0),
535         m_nX2(0),
536         m_nY2(0),
537         m_nPenId(0)
538         {}
~TABMAPObjLine()539     virtual ~TABMAPObjLine() {}
540 
541     virtual int WriteObj(TABMAPObjectBlock *) override;
542 
543 //  protected:
544     virtual int ReadObj(TABMAPObjectBlock *) override;
545 };
546 
547 class TABMAPObjPLine final : public TABMAPObjHdrWithCoord
548 {
549   public:
550     GInt32      m_numLineSections;  /* MULTIPLINE/REGION only. Not in PLINE */
551     GInt32      m_nLabelX;      /* Centroid/label location */
552     GInt32      m_nLabelY;
553     GInt32      m_nComprOrgX;   /* Present only in compressed coord. case */
554     GInt32      m_nComprOrgY;
555     GByte       m_nPenId;
556     GByte       m_nBrushId;
557     GBool       m_bSmooth;      /* TRUE if (m_nCoordDataSize & 0x80000000) */
558 
TABMAPObjPLine()559     TABMAPObjPLine():
560         m_numLineSections(0),
561         m_nLabelX(0),
562         m_nLabelY(0),
563         m_nComprOrgX(0),
564         m_nComprOrgY(0),
565         m_nPenId(0),
566         m_nBrushId(0),
567         m_bSmooth(0)
568         {}
~TABMAPObjPLine()569     virtual ~TABMAPObjPLine() {}
570 
571     virtual int WriteObj(TABMAPObjectBlock *) override;
572 
573 //  protected:
574     virtual int ReadObj(TABMAPObjectBlock *) override;
575 };
576 
577 class TABMAPObjRectEllipse final : public TABMAPObjHdr
578 {
579   public:
580     GInt32      m_nCornerWidth;   /* For rounded rect only */
581     GInt32      m_nCornerHeight;
582     GByte       m_nPenId;
583     GByte       m_nBrushId;
584 
TABMAPObjRectEllipse()585     TABMAPObjRectEllipse():
586         m_nCornerWidth(0),
587         m_nCornerHeight(0),
588         m_nPenId(0),
589         m_nBrushId(0)
590         {}
~TABMAPObjRectEllipse()591     virtual ~TABMAPObjRectEllipse() {}
592 
593     virtual int WriteObj(TABMAPObjectBlock *) override;
594 
595 //  protected:
596     virtual int ReadObj(TABMAPObjectBlock *) override;
597 };
598 
599 class TABMAPObjArc final : public TABMAPObjHdr
600 {
601   public:
602     GInt32      m_nStartAngle;
603     GInt32      m_nEndAngle;
604     GInt32      m_nArcEllipseMinX;  /* MBR of the arc defining ellipse */
605     GInt32      m_nArcEllipseMinY;  /* Only present in arcs            */
606     GInt32      m_nArcEllipseMaxX;
607     GInt32      m_nArcEllipseMaxY;
608     GByte       m_nPenId;
609 
TABMAPObjArc()610     TABMAPObjArc():
611         m_nStartAngle(0),
612         m_nEndAngle(0),
613         m_nArcEllipseMinX(0),
614         m_nArcEllipseMinY(0),
615         m_nArcEllipseMaxX(0),
616         m_nArcEllipseMaxY(0),
617         m_nPenId(0)
618         {}
~TABMAPObjArc()619     virtual ~TABMAPObjArc() {}
620 
621     virtual int WriteObj(TABMAPObjectBlock *) override;
622 
623 //  protected:
624     virtual int ReadObj(TABMAPObjectBlock *) override;
625 };
626 
627 class TABMAPObjText final : public TABMAPObjHdrWithCoord
628 {
629   public:
630     /* String and its len stored in the nCoordPtr and nCoordSize */
631 
632     GInt16      m_nTextAlignment;
633     GInt32      m_nAngle;
634     GInt16      m_nFontStyle;
635 
636     GByte       m_nFGColorR;
637     GByte       m_nFGColorG;
638     GByte       m_nFGColorB;
639     GByte       m_nBGColorR;
640     GByte       m_nBGColorG;
641     GByte       m_nBGColorB;
642 
643     GInt32      m_nLineEndX;
644     GInt32      m_nLineEndY;
645 
646     GInt32      m_nHeight;
647     GByte       m_nFontId;
648 
649     GByte       m_nPenId;
650 
TABMAPObjText()651     TABMAPObjText():
652         m_nTextAlignment(0),
653         m_nAngle(0),
654         m_nFontStyle(0),
655         m_nFGColorR(0),
656         m_nFGColorG(0),
657         m_nFGColorB(0),
658         m_nBGColorR(0),
659         m_nBGColorG(0),
660         m_nBGColorB(0),
661         m_nLineEndX(0),
662         m_nLineEndY(0),
663         m_nHeight(0),
664         m_nFontId(0),
665         m_nPenId(0)
666         {}
~TABMAPObjText()667     virtual ~TABMAPObjText() {}
668 
669     virtual int WriteObj(TABMAPObjectBlock *) override;
670 
671 //  protected:
672     virtual int ReadObj(TABMAPObjectBlock *) override;
673 };
674 
675 class TABMAPObjMultiPoint final : public TABMAPObjHdrWithCoord
676 {
677   public:
678     GInt32      m_nNumPoints;
679     GInt32      m_nComprOrgX;   /* Present only in compressed coord. case */
680     GInt32      m_nComprOrgY;
681     GByte       m_nSymbolId;
682     GInt32      m_nLabelX;      /* Not sure if it is a label point, but */
683     GInt32      m_nLabelY;      /* it is similar to what we find in PLINE */
684 
TABMAPObjMultiPoint()685     TABMAPObjMultiPoint():
686         m_nNumPoints(0),
687         m_nComprOrgX(0),
688         m_nComprOrgY(0),
689         m_nSymbolId(0),
690         m_nLabelX(0),
691         m_nLabelY(0)
692         {}
~TABMAPObjMultiPoint()693     virtual ~TABMAPObjMultiPoint() {}
694 
695     virtual int WriteObj(TABMAPObjectBlock *) override;
696 
697 //  protected:
698     virtual int ReadObj(TABMAPObjectBlock *) override;
699 };
700 
701 class TABMAPObjCollection final : public TABMAPObjHdrWithCoord
702 {
703   public:
704     GInt32      m_nRegionDataSize;
705     GInt32      m_nPolylineDataSize;
706     GInt32      m_nMPointDataSize;
707     GInt32      m_nComprOrgX;   /* Present only in compressed coord. case */
708     GInt32      m_nComprOrgY;
709     GInt32      m_nNumMultiPoints;
710     GInt32      m_nNumRegSections;
711     GInt32      m_nNumPLineSections;
712 
713     GByte       m_nMultiPointSymbolId;
714     GByte       m_nRegionPenId;
715     GByte       m_nRegionBrushId;
716     GByte       m_nPolylinePenId;
717 
TABMAPObjCollection()718     TABMAPObjCollection():
719         m_nRegionDataSize(0),
720         m_nPolylineDataSize(0),
721         m_nMPointDataSize(0),
722         m_nComprOrgX(0),
723         m_nComprOrgY(0),
724         m_nNumMultiPoints(0),
725         m_nNumRegSections(0),
726         m_nNumPLineSections(0),
727         m_nMultiPointSymbolId(0),
728         m_nRegionPenId(0),
729         m_nRegionBrushId(0),
730         m_nPolylinePenId(0)
731         {}
~TABMAPObjCollection()732     virtual ~TABMAPObjCollection()
733     {}
734 
735     virtual int WriteObj(TABMAPObjectBlock *) override;
736 
737 //  protected:
738     virtual int ReadObj(TABMAPObjectBlock *) override;
739 
740   private:
741     // private copy ctor and assignment operator to prevent shallow copying
742     TABMAPObjCollection& operator=(const TABMAPObjCollection& rhs);
743     TABMAPObjCollection(const TABMAPObjCollection& rhs);
744 };
745 
746 /*=====================================================================
747           Classes to handle .MAP files low-level blocks
748  =====================================================================*/
749 
750 typedef struct TABBlockRef_t
751 {
752     GInt32                nBlockPtr;
753     struct TABBlockRef_t *psPrev;
754     struct TABBlockRef_t *psNext;
755 } TABBlockRef;
756 
757 /*---------------------------------------------------------------------
758  *                      class TABBinBlockManager
759  *
760  * This class is used to keep track of allocated blocks and is used
761  * by various classes that need to allocate a new block in a .MAP file.
762  *--------------------------------------------------------------------*/
763 class TABBinBlockManager
764 {
765     CPL_DISALLOW_COPY_ASSIGN(TABBinBlockManager)
766 
767   protected:
768     int         m_nBlockSize;
769     GInt32      m_nLastAllocatedBlock;
770     TABBlockRef *m_psGarbageBlocksFirst;
771     TABBlockRef *m_psGarbageBlocksLast;
772     char        m_szName[32]; /* for debug purposes */
773 
774   public:
775     TABBinBlockManager();
776     ~TABBinBlockManager();
777 
778     void        SetBlockSize(int nBlockSize);
GetBlockSize()779     int         GetBlockSize() const { return m_nBlockSize; }
780 
781     GInt32      AllocNewBlock(const char* pszReason = "");
782     void        Reset();
SetLastPtr(int nBlockPtr)783     void        SetLastPtr(int nBlockPtr) {m_nLastAllocatedBlock=nBlockPtr; }
784 
785     void        PushGarbageBlockAsFirst(GInt32 nBlockPtr);
786     void        PushGarbageBlockAsLast(GInt32 nBlockPtr);
787     GInt32      GetFirstGarbageBlock();
788     GInt32      PopGarbageBlock();
789 
790     void        SetName(const char* pszName);
791 };
792 
793 /*---------------------------------------------------------------------
794  *                      class TABRawBinBlock
795  *
796  * This is the base class used for all other data block types... it
797  * contains all the base functions to handle binary data.
798  *--------------------------------------------------------------------*/
799 
800 class TABRawBinBlock
801 {
802     CPL_DISALLOW_COPY_ASSIGN(TABRawBinBlock)
803 
804   protected:
805     VSILFILE    *m_fp;          /* Associated file handle               */
806     TABAccess   m_eAccess;      /* Read/Write access mode               */
807 
808     int         m_nBlockType;
809 
810     GByte       *m_pabyBuf;     /* Buffer to contain the block's data    */
811     int         m_nBlockSize;   /* Size of current block (and buffer)    */
812     int         m_nSizeUsed;    /* Number of bytes used in buffer        */
813     GBool       m_bHardBlockSize;/* TRUE=Blocks MUST always be nSize bytes  */
814                                  /* FALSE=last block may be less than nSize */
815     int         m_nFileOffset;  /* Location of current block in the file */
816     int         m_nCurPos;      /* Next byte to read from m_pabyBuf[]    */
817     int         m_nFirstBlockPtr;/* Size of file header when different from */
818                                  /* block size (used by GotoByteInFile())   */
819     int         m_nFileSize;
820 
821     int         m_bModified;     /* Used only to detect changes        */
822 
823   public:
824     TABRawBinBlock(TABAccess eAccessMode = TABRead,
825                    GBool bHardBlockSize = TRUE);
826     virtual ~TABRawBinBlock();
827 
828     virtual int ReadFromFile(VSILFILE *fpSrc, int nOffset, int nSize);
829     virtual int CommitToFile();
830     int         CommitAsDeleted(GInt32 nNextBlockPtr);
831 
832     virtual int InitBlockFromData(GByte *pabyBuf,
833                                   int nBlockSize, int nSizeUsed,
834                                   GBool bMakeCopy = TRUE,
835                                   VSILFILE *fpSrc = nullptr, int nOffset = 0);
836     virtual int InitNewBlock(VSILFILE *fpSrc, int nBlockSize, int nFileOffset=0);
837 
838     int         GetBlockType();
GetBlockClass()839     virtual int GetBlockClass() { return TAB_RAWBIN_BLOCK; }
840 
GetStartAddress()841     GInt32      GetStartAddress() {return m_nFileOffset;}
842 #ifdef DEBUG
843     virtual void Dump(FILE *fpOut = nullptr);
844 #endif
845     static void        DumpBytes(GInt32 nValue, int nOffset=0, FILE *fpOut=nullptr);
846 
847     int         GotoByteRel(int nOffset);
848     int         GotoByteInBlock(int nOffset);
849     int         GotoByteInFile(int nOffset,
850                                GBool bForceReadFromFile = FALSE,
851                                GBool bOffsetIsEndOfData = FALSE);
852     void        SetFirstBlockPtr(int nOffset);
853 
854     int         GetNumUnusedBytes();
855     int         GetFirstUnusedByteOffset();
856     int         GetCurAddress();
857 
858     virtual int ReadBytes(int numBytes, GByte *pabyDstBuf);
859     GByte       ReadByte();
860     // cppcheck-suppress functionStatic
861     GInt16      ReadInt16();
862     // cppcheck-suppress functionStatic
863     GInt32      ReadInt32();
864     // cppcheck-suppress functionStatic
865     float       ReadFloat();
866     // cppcheck-suppress functionStatic
867     double      ReadDouble();
868 
869     virtual int WriteBytes(int nBytesToWrite, const GByte *pBuf);
870     int         WriteByte(GByte byValue);
871     // cppcheck-suppress functionStatic
872     int         WriteInt16(GInt16 n16Value);
873     // cppcheck-suppress functionStatic
874     int         WriteInt32(GInt32 n32Value);
875     // cppcheck-suppress functionStatic
876     int         WriteFloat(float fValue);
877     // cppcheck-suppress functionStatic
878     int         WriteDouble(double dValue);
879     int         WriteZeros(int nBytesToWrite);
880     int         WritePaddedString(int nFieldSize, const char *pszString);
881 
SetModifiedFlag(GBool bModified)882     void        SetModifiedFlag(GBool bModified) {m_bModified=bModified;}
883 
884     // This semi-private method gives a direct access to the internal
885     // buffer... to be used with extreme care!!!!!!!!!
GetCurDataPtr()886     GByte *     GetCurDataPtr() { return (m_pabyBuf + m_nCurPos); }
887 };
888 
889 /*---------------------------------------------------------------------
890  *                      class TABMAPHeaderBlock
891  *
892  * Class to handle Read/Write operation on .MAP Header Blocks
893  *--------------------------------------------------------------------*/
894 
895 class TABMAPHeaderBlock final : public TABRawBinBlock
896 {
897     void        InitMembersWithDefaultValues();
898     void        UpdatePrecision();
899 
900   protected:
901 #if defined(__GNUC__)
902 #pragma GCC diagnostic push
903 #pragma GCC diagnostic ignored "-Wmissing-field-initializers"
904 #endif
905     TABProjInfo m_sProj{};
906 #if defined(__GNUC__)
907 #pragma GCC diagnostic pop
908 #endif
909 
910   public:
911     explicit TABMAPHeaderBlock(TABAccess eAccessMode = TABRead);
912     virtual ~TABMAPHeaderBlock();
913 
914     virtual int CommitToFile() override;
915 
916     virtual int InitBlockFromData(GByte *pabyBuf,
917                                   int nBlockSize, int nSizeUsed,
918                                   GBool bMakeCopy = TRUE,
919                                   VSILFILE *fpSrc = nullptr, int nOffset = 0) override;
920     virtual int InitNewBlock(VSILFILE *fpSrc, int nBlockSize, int nFileOffset=0) override;
921 
GetBlockClass()922     virtual int GetBlockClass() override { return TABMAP_HEADER_BLOCK; }
923 
924     int         Int2Coordsys(GInt32 nX, GInt32 nY, double &dX, double &dY);
925     int         Coordsys2Int(double dX, double dY, GInt32 &nX, GInt32 &nY,
926                              GBool bIgnoreOverflow=FALSE);
927     int         ComprInt2Coordsys(GInt32 nCenterX, GInt32 nCenterY,
928                                   int nDeltaX, int nDeltaY,
929                                   double &dX, double &dY);
930     int         Int2CoordsysDist(GInt32 nX, GInt32 nY, double &dX, double &dY);
931     int         Coordsys2IntDist(double dX, double dY, GInt32 &nX, GInt32 &nY);
932     int         SetCoordsysBounds(double dXMin, double dYMin,
933                                   double dXMax, double dYMax);
934 
935     int         GetMapObjectSize(int nObjType);
936     GBool       MapObjectUsesCoordBlock(int nObjType);
937 
938     int         GetProjInfo(TABProjInfo *psProjInfo);
939     int         SetProjInfo(TABProjInfo *psProjInfo);
940 
941 #ifdef DEBUG
942     virtual void Dump(FILE *fpOut = nullptr) override;
943 #endif
944 
945     // Instead of having over 30 get/set methods, we'll make all data
946     // members public and we will initialize them in the overloaded
947     // LoadFromFile().  For this reason, this class should be used with care.
948 
949     GInt16      m_nMAPVersionNumber{};
950     GInt16      m_nRegularBlockSize{};
951 
952     double      m_dCoordsys2DistUnits{};
953     GInt32      m_nXMin{};
954     GInt32      m_nYMin{};
955     GInt32      m_nXMax{};
956     GInt32      m_nYMax{};
957     GBool       m_bIntBoundsOverflow{};  // Set to TRUE if coordinates
958                                        // outside of bounds were written
959 
960     GInt32      m_nFirstIndexBlock{};
961     GInt32      m_nFirstGarbageBlock{};
962     GInt32      m_nFirstToolBlock{};
963     GInt32      m_numPointObjects{};
964     GInt32      m_numLineObjects{};
965     GInt32      m_numRegionObjects{};
966     GInt32      m_numTextObjects{};
967     GInt32      m_nMaxCoordBufSize{};
968 
969     GByte       m_nDistUnitsCode{};       // See Appendix F
970     GByte       m_nMaxSpIndexDepth{};
971     GByte       m_nCoordPrecision{};      // Num. decimal places on coord.
972     GByte       m_nCoordOriginQuadrant{};
973     GByte       m_nReflectXAxisCoord{};
974     GByte       m_nMaxObjLenArrayId{};     // See gabyObjLenArray[]
975     GByte       m_numPenDefs{};
976     GByte       m_numBrushDefs{};
977     GByte       m_numSymbolDefs{};
978     GByte       m_numFontDefs{};
979     GInt16      m_numMapToolBlocks{};
980 
981     double      m_XScale{};
982     double      m_YScale{};
983     double      m_XDispl{};
984     double      m_YDispl{};
985     double      m_XPrecision{}; // maximum achievable precision along X axis depending on bounds extent
986     double      m_YPrecision{}; // maximum achievable precision along Y axis depending on bounds extent
987 };
988 
989 /*---------------------------------------------------------------------
990  *                      class TABMAPIndexBlock
991  *
992  * Class to handle Read/Write operation on .MAP Index Blocks (Type 01)
993  *--------------------------------------------------------------------*/
994 
995 class TABMAPIndexBlock final : public TABRawBinBlock
996 {
997     CPL_DISALLOW_COPY_ASSIGN(TABMAPIndexBlock)
998 
999   protected:
1000     int         m_numEntries;
1001     TABMAPIndexEntry m_asEntries[TAB_MAX_ENTRIES_INDEX_BLOCK];
1002 
1003     int         ReadNextEntry(TABMAPIndexEntry *psEntry);
1004     int         WriteNextEntry(TABMAPIndexEntry *psEntry);
1005 
1006     // Use these to keep track of current block's MBR
1007     GInt32      m_nMinX;
1008     GInt32      m_nMinY;
1009     GInt32      m_nMaxX;
1010     GInt32      m_nMaxY;
1011 
1012     TABBinBlockManager *m_poBlockManagerRef;
1013 
1014     // Info about child currently loaded
1015     TABMAPIndexBlock *m_poCurChild;
1016     int         m_nCurChildIndex;
1017     // Also need to know about its parent
1018     TABMAPIndexBlock *m_poParentRef;
1019 
1020     int         ReadAllEntries();
1021 
GetMaxEntries()1022     int         GetMaxEntries() const { return ((m_nBlockSize-4)/20); }
1023 
1024   public:
1025     explicit TABMAPIndexBlock(TABAccess eAccessMode = TABRead);
1026     virtual ~TABMAPIndexBlock();
1027 
1028     virtual int InitBlockFromData(GByte *pabyBuf,
1029                                   int nBlockSize, int nSizeUsed,
1030                                   GBool bMakeCopy = TRUE,
1031                                   VSILFILE *fpSrc = nullptr, int nOffset = 0) override;
1032     virtual int InitNewBlock(VSILFILE *fpSrc, int nBlockSize, int nFileOffset=0) override;
1033     virtual int CommitToFile() override;
1034 
GetBlockClass()1035     virtual int GetBlockClass() override { return TABMAP_INDEX_BLOCK; }
1036 
1037     void        UnsetCurChild();
1038 
1039     int         GetNumFreeEntries();
GetNumEntries()1040     int         GetNumEntries()         {return m_numEntries;}
1041     TABMAPIndexEntry *GetEntry( int iIndex );
1042     int         AddEntry(GInt32 XMin, GInt32 YMin,
1043                          GInt32 XMax, GInt32 YMax,
1044                          GInt32 nBlockPtr,
1045                          GBool bAddInThisNodeOnly=FALSE);
1046     int         GetCurMaxDepth();
1047     void        GetMBR(GInt32 &nXMin, GInt32 &nYMin,
1048                        GInt32 &nXMax, GInt32 &nYMax);
1049     void        SetMBR(GInt32 nXMin, GInt32 nYMin,
1050                        GInt32 nXMax, GInt32 nYMax);
1051 
GetNodeBlockPtr()1052     GInt32      GetNodeBlockPtr() { return GetStartAddress();}
1053 
1054     void        SetMAPBlockManagerRef(TABBinBlockManager *poBlockMgr);
1055     void        SetParentRef(TABMAPIndexBlock *poParent);
1056     void        SetCurChildRef(TABMAPIndexBlock *poChild, int nChildIndex);
1057 
GetCurChildIndex()1058     int         GetCurChildIndex() { return m_nCurChildIndex; }
GetCurChild()1059     TABMAPIndexBlock *GetCurChild() { return m_poCurChild; }
GetParentRef()1060     TABMAPIndexBlock *GetParentRef() { return m_poParentRef; }
1061 
1062     int         SplitNode(GInt32 nNewEntryXMin, GInt32 nNewEntryYMin,
1063                           GInt32 nNewEntryXMax, GInt32 nNewEntryYMax);
1064     int         SplitRootNode(GInt32 nNewEntryXMin, GInt32 nNewEntryYMin,
1065                               GInt32 nNewEntryXMax, GInt32 nNewEntryYMax);
1066     void        UpdateCurChildMBR(GInt32 nXMin, GInt32 nYMin,
1067                                   GInt32 nXMax, GInt32 nYMax,
1068                                   GInt32 nBlockPtr);
1069     void        RecomputeMBR();
1070     int         InsertEntry(GInt32 XMin, GInt32 YMin,
1071                             GInt32 XMax, GInt32 YMax, GInt32 nBlockPtr);
1072     int         ChooseSubEntryForInsert(GInt32 nXMin, GInt32 nYMin,
1073                                         GInt32 nXMax, GInt32 nYMax);
1074     GInt32      ChooseLeafForInsert(GInt32 nXMin, GInt32 nYMin,
1075                                     GInt32 nXMax, GInt32 nYMax);
1076     int         UpdateLeafEntry(GInt32 nBlockPtr,
1077                                 GInt32 nXMin, GInt32 nYMin,
1078                                 GInt32 nXMax, GInt32 nYMax);
1079     int         GetCurLeafEntryMBR(GInt32 nBlockPtr,
1080                                    GInt32 &nXMin, GInt32 &nYMin,
1081                                    GInt32 &nXMax, GInt32 &nYMax);
1082 
1083     // Static utility functions for node splitting, also used by
1084     // the TABMAPObjectBlock class.
1085     static double ComputeAreaDiff(GInt32 nNodeXMin, GInt32 nNodeYMin,
1086                                   GInt32 nNodeXMax, GInt32 nNodeYMax,
1087                                   GInt32 nEntryXMin, GInt32 nEntryYMin,
1088                                   GInt32 nEntryXMax, GInt32 nEntryYMax);
1089     static int    PickSeedsForSplit(TABMAPIndexEntry *pasEntries,
1090                                     int numEntries,
1091                                     int nSrcCurChildIndex,
1092                                     GInt32 nNewEntryXMin,
1093                                     GInt32 nNewEntryYMin,
1094                                     GInt32 nNewEntryXMax,
1095                                     GInt32 nNewEntryYMax,
1096                                     int &nSeed1, int &nSeed2);
1097 #ifdef DEBUG
1098     virtual void Dump(FILE *fpOut = nullptr) override;
1099 #endif
1100 
1101 };
1102 
1103 /*---------------------------------------------------------------------
1104  *                      class TABMAPObjectBlock
1105  *
1106  * Class to handle Read/Write operation on .MAP Object data Blocks (Type 02)
1107  *--------------------------------------------------------------------*/
1108 
1109 class TABMAPObjectBlock final : public TABRawBinBlock
1110 {
1111     CPL_DISALLOW_COPY_ASSIGN(TABMAPObjectBlock)
1112 
1113   protected:
1114     int         m_numDataBytes; /* Excluding first 4 bytes header */
1115     GInt32      m_nFirstCoordBlock;
1116     GInt32      m_nLastCoordBlock;
1117     GInt32      m_nCenterX;
1118     GInt32      m_nCenterY;
1119 
1120     // In order to compute block center, we need to keep track of MBR
1121     GInt32      m_nMinX;
1122     GInt32      m_nMinY;
1123     GInt32      m_nMaxX;
1124     GInt32      m_nMaxY;
1125 
1126     // Keep track of current object either in read or read/write mode
1127     int         m_nCurObjectOffset; // -1 if there is no current object.
1128     int         m_nCurObjectId;     // -1 if there is no current object.
1129     TABGeomType m_nCurObjectType;   // TAB_GEOM_UNSET if there is no current object.
1130 
1131     int         m_bLockCenter;
1132 
1133   public:
1134     explicit TABMAPObjectBlock(TABAccess eAccessMode = TABRead);
1135     virtual ~TABMAPObjectBlock();
1136 
1137     virtual int CommitToFile() override;
1138     virtual int InitBlockFromData(GByte *pabyBuf,
1139                                   int nBlockSize, int nSizeUsed,
1140                                   GBool bMakeCopy = TRUE,
1141                                   VSILFILE *fpSrc = nullptr, int nOffset = 0) override;
1142     virtual int InitNewBlock(VSILFILE *fpSrc, int nBlockSize, int nFileOffset=0) override;
1143 
GetBlockClass()1144     virtual int GetBlockClass() override { return TABMAP_OBJECT_BLOCK; }
1145 
1146     virtual int ReadIntCoord(GBool bCompressed, GInt32 &nX, GInt32 &nY);
1147     int         WriteIntCoord(GInt32 nX, GInt32 nY, GBool bCompressed);
1148     int         WriteIntMBRCoord(GInt32 nXMin, GInt32 nYMin,
1149                                  GInt32 nXMax, GInt32 nYMax,
1150                                  GBool bCompressed);
1151     int         UpdateMBR(GInt32 nX, GInt32 nY);
1152 
1153     int         PrepareNewObject(TABMAPObjHdr *poObjHdr);
1154     int         CommitNewObject(TABMAPObjHdr *poObjHdr);
1155 
1156     void        AddCoordBlockRef(GInt32 nCoordBlockAddress);
GetFirstCoordBlockAddress()1157     GInt32      GetFirstCoordBlockAddress() { return m_nFirstCoordBlock; }
GetLastCoordBlockAddress()1158     GInt32      GetLastCoordBlockAddress() { return m_nLastCoordBlock; }
1159 
1160     void        GetMBR(GInt32 &nXMin, GInt32 &nYMin,
1161                        GInt32 &nXMax, GInt32 &nYMax);
1162     void        SetMBR(GInt32 nXMin, GInt32 nYMin,
1163                        GInt32 nXMax, GInt32 nYMax);
1164 
1165     void        Rewind();
1166     void        ClearObjects();
1167     void        LockCenter();
1168     void        SetCenterFromOtherBlock(TABMAPObjectBlock* poOtherObjBlock);
1169     int         AdvanceToNextObject( TABMAPHeaderBlock * );
GetCurObjectOffset()1170     int         GetCurObjectOffset() { return m_nCurObjectOffset; }
GetCurObjectId()1171     int         GetCurObjectId() { return m_nCurObjectId; }
GetCurObjectType()1172     TABGeomType GetCurObjectType() { return m_nCurObjectType; }
1173 
1174 #ifdef DEBUG
1175     virtual void Dump(FILE *fpOut = nullptr) override { Dump(fpOut, FALSE); }
1176     void Dump(FILE *fpOut, GBool bDetails);
1177 #endif
1178 };
1179 
1180 /*---------------------------------------------------------------------
1181  *                      class TABMAPCoordBlock
1182  *
1183  * Class to handle Read/Write operation on .MAP Coordinate Blocks (Type 03)
1184  *--------------------------------------------------------------------*/
1185 
1186 class TABMAPCoordBlock final : public TABRawBinBlock
1187 {
1188     CPL_DISALLOW_COPY_ASSIGN(TABMAPCoordBlock)
1189 
1190   protected:
1191     int         m_numDataBytes; /* Excluding first 8 bytes header */
1192     GInt32      m_nNextCoordBlock;
1193     int         m_numBlocksInChain;
1194 
1195     GInt32      m_nComprOrgX;
1196     GInt32      m_nComprOrgY;
1197 
1198     // In order to compute block center, we need to keep track of MBR
1199     GInt32      m_nMinX;
1200     GInt32      m_nMinY;
1201     GInt32      m_nMaxX;
1202     GInt32      m_nMaxY;
1203 
1204     TABBinBlockManager *m_poBlockManagerRef;
1205 
1206     int         m_nTotalDataSize;       // Num bytes in whole chain of blocks
1207     int         m_nFeatureDataSize;     // Num bytes for current feature coords
1208 
1209     GInt32      m_nFeatureXMin;         // Used to keep track of current
1210     GInt32      m_nFeatureYMin;         // feature MBR.
1211     GInt32      m_nFeatureXMax;
1212     GInt32      m_nFeatureYMax;
1213 
1214   public:
1215     explicit TABMAPCoordBlock(TABAccess eAccessMode = TABRead);
1216     virtual ~TABMAPCoordBlock();
1217 
1218     virtual int InitBlockFromData(GByte *pabyBuf,
1219                                   int nBlockSize, int nSizeUsed,
1220                                   GBool bMakeCopy = TRUE,
1221                                   VSILFILE *fpSrc = nullptr, int nOffset = 0) override;
1222     virtual int InitNewBlock(VSILFILE *fpSrc, int nBlockSize, int nFileOffset=0) override;
1223     virtual int CommitToFile() override;
1224 
GetBlockClass()1225     virtual int GetBlockClass() override { return TABMAP_COORD_BLOCK; }
1226 
1227     void        SetMAPBlockManagerRef(TABBinBlockManager *poBlockManager);
1228     virtual int ReadBytes(int numBytes, GByte *pabyDstBuf) override;
1229     virtual int WriteBytes(int nBytesToWrite, const GByte *pBuf) override;
1230     void        SetComprCoordOrigin(GInt32 nX, GInt32 nY);
1231     int         ReadIntCoord(GBool bCompressed, GInt32 &nX, GInt32 &nY);
1232     int         ReadIntCoords(GBool bCompressed, int numCoords, GInt32 *panXY);
1233     int         ReadCoordSecHdrs(GBool bCompressed, int nVersion,
1234                                  int numSections, TABMAPCoordSecHdr *pasHdrs,
1235                                  GInt32    &numVerticesTotal);
1236     int         WriteCoordSecHdrs(int nVersion, int numSections,
1237                                   TABMAPCoordSecHdr *pasHdrs,
1238                                   GBool bCompressed);
1239 
1240     void        SetNextCoordBlock(GInt32 nNextCoordBlockAddress);
GetNextCoordBlock()1241     GInt32      GetNextCoordBlock()   { return m_nNextCoordBlock; }
1242 
1243     int         WriteIntCoord(GInt32 nX, GInt32 nY, GBool bCompressed);
1244 
GetNumBlocksInChain()1245     int         GetNumBlocksInChain() { return m_numBlocksInChain; }
1246 
ResetTotalDataSize()1247     void        ResetTotalDataSize() {m_nTotalDataSize = 0;}
GetTotalDataSize()1248     int         GetTotalDataSize() {return m_nTotalDataSize;}
1249 
1250     void        SeekEnd();
1251     void        StartNewFeature();
GetFeatureDataSize()1252     int         GetFeatureDataSize() {return m_nFeatureDataSize;}
1253 //__TODO__ Can we flush GetFeatureMBR() and all MBR tracking in this class???
1254     void        GetFeatureMBR(GInt32 &nXMin, GInt32 &nYMin,
1255                               GInt32 &nXMax, GInt32 &nYMax);
1256 
1257 #ifdef DEBUG
1258     virtual void Dump(FILE *fpOut = nullptr) override;
1259 #endif
1260 };
1261 
1262 /*---------------------------------------------------------------------
1263  *                      class TABMAPToolBlock
1264  *
1265  * Class to handle Read/Write operation on .MAP Drawing Tool Blocks (Type 05)
1266  *
1267  * In addition to handling the I/O, this class also maintains the list
1268  * of Tool definitions in memory.
1269  *--------------------------------------------------------------------*/
1270 
1271 class TABMAPToolBlock final : public TABRawBinBlock
1272 {
1273     CPL_DISALLOW_COPY_ASSIGN(TABMAPToolBlock)
1274 
1275   protected:
1276     int         m_numDataBytes; /* Excluding first 8 bytes header */
1277     GInt32      m_nNextToolBlock;
1278     int         m_numBlocksInChain;
1279 
1280     TABBinBlockManager *m_poBlockManagerRef;
1281 
1282   public:
1283     explicit TABMAPToolBlock(TABAccess eAccessMode = TABRead);
1284     virtual ~TABMAPToolBlock();
1285 
1286     virtual int InitBlockFromData(GByte *pabyBuf,
1287                                   int nBlockSize, int nSizeUsed,
1288                                   GBool bMakeCopy = TRUE,
1289                                   VSILFILE *fpSrc = nullptr, int nOffset = 0) override;
1290     virtual int InitNewBlock(VSILFILE *fpSrc, int nBlockSize, int nFileOffset=0) override;
1291     virtual int CommitToFile() override;
1292 
GetBlockClass()1293     virtual int GetBlockClass() override { return TABMAP_TOOL_BLOCK; }
1294 
1295     void        SetMAPBlockManagerRef(TABBinBlockManager *poBlockManager);
1296     virtual int ReadBytes(int numBytes, GByte *pabyDstBuf) override;
1297     virtual int WriteBytes(int nBytesToWrite, const GByte *pBuf) override;
1298 
1299     void        SetNextToolBlock(GInt32 nNextCoordBlockAddress);
1300 
1301     GBool       EndOfChain();
GetNumBlocksInChain()1302     int         GetNumBlocksInChain() { return m_numBlocksInChain; }
1303 
1304     int         CheckAvailableSpace(int nToolType);
1305 
1306 #ifdef DEBUG
1307     virtual void Dump(FILE *fpOut = nullptr) override;
1308 #endif
1309 };
1310 
1311 /*=====================================================================
1312        Classes to deal with .MAP files at the MapInfo object level
1313  =====================================================================*/
1314 
1315 /*---------------------------------------------------------------------
1316  *                      class TABIDFile
1317  *
1318  * Class to handle Read/Write operation on .ID files... the .ID file
1319  * contains an index to the objects in the .MAP file by object id.
1320  *--------------------------------------------------------------------*/
1321 
1322 class TABIDFile
1323 {
1324     CPL_DISALLOW_COPY_ASSIGN(TABIDFile)
1325 
1326   private:
1327     char        *m_pszFname;
1328     VSILFILE    *m_fp;
1329     TABAccess   m_eAccessMode;
1330 
1331     TABRawBinBlock *m_poIDBlock;
1332     int         m_nBlockSize;
1333     GInt32      m_nMaxId;
1334 
1335    public:
1336     TABIDFile();
1337     ~TABIDFile();
1338 
1339     int         Open(const char *pszFname, const char* pszAccess);
1340     int         Open(const char *pszFname, TABAccess eAccess);
1341     int         Close();
1342 
1343     int         SyncToDisk();
1344 
1345     GInt32      GetObjPtr(GInt32 nObjId);
1346     int         SetObjPtr(GInt32 nObjId, GInt32 nObjPtr);
1347     GInt32      GetMaxObjId();
1348 
1349 #ifdef DEBUG
1350     void Dump(FILE *fpOut = nullptr);
1351 #endif
1352 };
1353 
1354 /*---------------------------------------------------------------------
1355  *                      class TABMAPFile
1356  *
1357  * Class to handle Read/Write operation on .MAP files... this class hides
1358  * all the dealings with blocks, indexes, etc.
1359  * Use this class to deal with MapInfo objects directly.
1360  *--------------------------------------------------------------------*/
1361 
1362 class TABMAPFile
1363 {
1364     CPL_DISALLOW_COPY_ASSIGN(TABMAPFile)
1365 
1366   private:
1367     int         m_nMinTABVersion;
1368     char        *m_pszFname;
1369     VSILFILE    *m_fp;
1370     TABAccess   m_eAccessMode;
1371 
1372     TABBinBlockManager m_oBlockManager{};
1373 
1374     TABMAPHeaderBlock   *m_poHeader;
1375 
1376     // Members used to access objects using the spatial index
1377     TABMAPIndexBlock  *m_poSpIndex;
1378 
1379     // Defaults to FALSE, i.e. optimized spatial index
1380     GBool       m_bQuickSpatialIndexMode;
1381 
1382     // Member used to access objects using the object ids (.ID file)
1383     TABIDFile   *m_poIdIndex;
1384 
1385     // Current object data block.
1386     TABMAPObjectBlock *m_poCurObjBlock;
1387     int         m_nCurObjPtr;
1388     TABGeomType m_nCurObjType;
1389     int         m_nCurObjId;
1390     TABMAPCoordBlock *m_poCurCoordBlock;
1391 
1392     // Drawing Tool Def. table (takes care of all drawing tools in memory)
1393     TABToolDefTable *m_poToolDefTable;
1394 
1395     // Coordinates filter... default is MBR of the whole file
1396     TABVertex   m_sMinFilter{};
1397     TABVertex   m_sMaxFilter{};
1398     GInt32      m_XMinFilter;
1399     GInt32      m_YMinFilter;
1400     GInt32      m_XMaxFilter;
1401     GInt32      m_YMaxFilter;
1402 
1403     int         m_bUpdated;
1404     int         m_bLastOpWasRead;
1405     int         m_bLastOpWasWrite;
1406 
1407     int         CommitObjAndCoordBlocks(GBool bDeleteObjects =FALSE);
1408     int         LoadObjAndCoordBlocks(GInt32 nBlockPtr);
1409     TABMAPObjectBlock *SplitObjBlock(TABMAPObjHdr *poObjHdrToAdd,
1410                                      int nSizeOfObjToAdd);
1411     int         MoveObjToBlock(TABMAPObjHdr       *poObjHdr,
1412                                TABMAPCoordBlock   *poSrcCoordBlock,
1413                                TABMAPObjectBlock  *poDstObjBlock,
1414                                TABMAPCoordBlock   **ppoDstCoordBlock);
1415     int         PrepareCoordBlock(int nObjType,
1416                                   TABMAPObjectBlock *poObjBlock,
1417                                   TABMAPCoordBlock  **ppoCoordBlock);
1418 
1419     int         InitDrawingTools();
1420     int         CommitDrawingTools();
1421 
1422     int         CommitSpatialIndex();
1423 
1424     // Stuff related to traversing spatial index.
1425     TABMAPIndexBlock *m_poSpIndexLeaf;
1426 
1427     //Strings encoding
1428     CPLString   m_osEncoding;
1429 
1430     int         LoadNextMatchingObjectBlock(int bFirstObject);
1431     TABRawBinBlock *PushBlock( int nFileOffset );
1432 
1433     int         ReOpenReadWrite();
1434 
1435   public:
1436     explicit TABMAPFile(const char* pszEncoding);
1437     ~TABMAPFile();
1438 
1439     int         Open(const char *pszFname, const char* pszAccess,
1440                      GBool bNoErrorMsg = FALSE,
1441                      int nBlockSizeForCreate = 512 );
1442     int         Open(const char *pszFname, TABAccess eAccess,
1443                      GBool bNoErrorMsg = FALSE,
1444                      int nBlockSizeForCreate = 512 );
1445     int         Close();
1446 
1447     GUInt32     GetFileSize();
1448 
1449     int         SyncToDisk();
1450 
1451     int         SetQuickSpatialIndexMode(GBool bQuickSpatialIndexMode = TRUE);
1452 
1453     int         Int2Coordsys(GInt32 nX, GInt32 nY, double &dX, double &dY);
1454     int         Coordsys2Int(double dX, double dY, GInt32 &nX, GInt32 &nY,
1455                              GBool bIgnoreOverflow=FALSE);
1456     int         Int2CoordsysDist(GInt32 nX, GInt32 nY, double &dX, double &dY);
1457     int         Coordsys2IntDist(double dX, double dY, GInt32 &nX, GInt32 &nY);
1458     void        SetCoordFilter(TABVertex sMin, TABVertex sMax);
1459     // cppcheck-suppress functionStatic
1460     void        GetCoordFilter(TABVertex &sMin, TABVertex &sMax) const;
1461     void        ResetCoordFilter();
1462     int         SetCoordsysBounds(double dXMin, double dYMin,
1463                                   double dXMax, double dYMax);
1464 
1465     GInt32      GetMaxObjId();
1466     int         MoveToObjId(int nObjId);
1467     void        UpdateMapHeaderInfo(TABGeomType nObjType);
1468     int         PrepareNewObj(TABMAPObjHdr *poObjHdr);
1469     int         PrepareNewObjViaSpatialIndex(TABMAPObjHdr *poObjHdr);
1470     int         PrepareNewObjViaObjBlock(TABMAPObjHdr *poObjHdr);
1471     int         CommitNewObj(TABMAPObjHdr *poObjHdr);
1472 
1473     void        ResetReading();
1474     int         GetNextFeatureId( int nPrevId );
1475 
1476     int         MarkAsDeleted();
1477 
1478     TABGeomType GetCurObjType();
1479     int         GetCurObjId();
1480     TABMAPObjectBlock *GetCurObjBlock();
1481     TABMAPCoordBlock  *GetCurCoordBlock();
1482     TABMAPCoordBlock  *GetCoordBlock(int nFileOffset);
1483     TABMAPHeaderBlock *GetHeaderBlock();
1484     TABIDFile         *GetIDFileRef();
1485     TABRawBinBlock    *GetIndexObjectBlock(int nFileOffset);
1486 
1487     int         ReadPenDef(int nPenIndex, TABPenDef *psDef);
1488     int         ReadBrushDef(int nBrushIndex, TABBrushDef *psDef);
1489     int         ReadFontDef(int nFontIndex, TABFontDef *psDef);
1490     int         ReadSymbolDef(int nSymbolIndex, TABSymbolDef *psDef);
1491     int         WritePenDef(TABPenDef *psDef);
1492     int         WriteBrushDef(TABBrushDef *psDef);
1493     int         WriteFontDef(TABFontDef *psDef);
1494     int         WriteSymbolDef(TABSymbolDef *psDef);
1495 
1496     int         GetMinTABFileVersion();
1497 
1498     const CPLString& GetEncoding() const;
1499     void SetEncoding( const CPLString& );
1500 
1501     static bool IsValidObjType(int nObjType);
1502 
1503 #ifdef DEBUG
1504     void Dump(FILE *fpOut = nullptr);
1505     void DumpSpatialIndexToMIF(TABMAPIndexBlock *poNode,
1506                                FILE *fpMIF, FILE *fpMID,
1507                                int nParentId=-1,
1508                                int nIndexInNode=-1,
1509                                int nCurDepth=0,
1510                                int nMaxDepth=-1);
1511 #endif
1512 };
1513 
1514 /*---------------------------------------------------------------------
1515  *                      class TABINDNode
1516  *
1517  * An index node in a .IND file.
1518  *
1519  * This class takes care of reading child nodes as necessary when looking
1520  * for a given key value in the index tree.
1521  *--------------------------------------------------------------------*/
1522 
1523 class TABINDNode
1524 {
1525     CPL_DISALLOW_COPY_ASSIGN(TABINDNode)
1526 
1527   private:
1528     VSILFILE    *m_fp;
1529     TABAccess   m_eAccessMode;
1530     TABINDNode *m_poCurChildNode;
1531     TABINDNode *m_poParentNodeRef;
1532 
1533     TABBinBlockManager *m_poBlockManagerRef;
1534 
1535     int         m_nSubTreeDepth;
1536     int         m_nKeyLength;
1537     TABFieldType m_eFieldType;
1538     GBool       m_bUnique;
1539 
1540     GInt32      m_nCurDataBlockPtr;
1541     int         m_nCurIndexEntry;
1542     TABRawBinBlock *m_poDataBlock;
1543     int         m_numEntriesInNode;
1544     GInt32      m_nPrevNodePtr;
1545     GInt32      m_nNextNodePtr;
1546 
1547     int         GotoNodePtr(GInt32 nNewNodePtr);
1548     GInt32      ReadIndexEntry(int nEntryNo, GByte *pKeyValue);
1549     int         IndexKeyCmp(const GByte *pKeyValue, int nEntryNo);
1550 
1551     int         InsertEntry(GByte *pKeyValue, GInt32 nRecordNo,
1552                             GBool bInsertAfterCurChild=FALSE,
1553                             GBool bMakeNewEntryCurChild=FALSE);
1554     int         SetNodeBufferDirectly(int numEntries, GByte *pBuf,
1555                                       int nCurIndexEntry=0,
1556                                       TABINDNode *poCurChild=nullptr);
1557     GInt32      FindFirst(const GByte *pKeyValue,
1558                           std::set<int>& oSetVisitedNodePtr);
1559 
1560    public:
1561     explicit TABINDNode(TABAccess eAccessMode = TABRead);
1562     ~TABINDNode();
1563 
1564     int         InitNode(VSILFILE *fp, int nBlockPtr,
1565                          int nKeyLength, int nSubTreeDepth, GBool bUnique,
1566                          TABBinBlockManager *poBlockMgr=nullptr,
1567                          TABINDNode *poParentNode=nullptr,
1568                          int nPrevNodePtr=0, int nNextNodePtr=0);
1569 
1570     int         SetFieldType(TABFieldType eType);
GetFieldType()1571     TABFieldType GetFieldType()         {return m_eFieldType;}
1572 
SetUnique(GBool bUnique)1573     void        SetUnique(GBool bUnique){m_bUnique = bUnique;}
IsUnique()1574     GBool       IsUnique()              {return m_bUnique;}
1575 
GetKeyLength()1576     int         GetKeyLength()          {return m_nKeyLength;}
GetSubTreeDepth()1577     int         GetSubTreeDepth()       {return m_nSubTreeDepth;}
GetNodeBlockPtr()1578     GInt32      GetNodeBlockPtr()       {return m_nCurDataBlockPtr;}
GetNumEntries()1579     int         GetNumEntries()         {return m_numEntriesInNode;}
GetMaxNumEntries()1580     int         GetMaxNumEntries()      {return (512-12)/(m_nKeyLength+4);}
1581 
1582     GInt32      FindFirst(const GByte *pKeyValue);
1583     GInt32      FindNext(GByte *pKeyValue);
1584 
1585     int         CommitToFile();
1586 
1587     int         AddEntry(GByte *pKeyValue, GInt32 nRecordNo,
1588                          GBool bAddInThisNodeOnly=FALSE,
1589                          GBool bInsertAfterCurChild=FALSE,
1590                          GBool bMakeNewEntryCurChild=FALSE);
1591     int         SplitNode();
1592     int         SplitRootNode();
1593     GByte*      GetNodeKey();
1594     int         UpdateCurChildEntry(GByte *pKeyValue, GInt32 nRecordNo);
1595     int         UpdateSplitChild(GByte *pKeyValue1, GInt32 nRecordNo1,
1596                                  GByte *pKeyValue2, GInt32 nRecordNo2,
1597                                  int nNewCurChildNo /* 1 or 2 */);
1598 
1599     int         SetNodeBlockPtr(GInt32 nThisNodePtr);
1600     int         SetPrevNodePtr(GInt32 nPrevNodePtr);
1601     int         SetNextNodePtr(GInt32 nNextNodePtr);
1602 
1603 #ifdef DEBUG
1604     void Dump(FILE *fpOut = nullptr);
1605 #endif
1606 };
1607 
1608 /*---------------------------------------------------------------------
1609  *                      class TABINDFile
1610  *
1611  * Class to handle table field index (.IND) files... we use this
1612  * class as the main entry point to open and search the table field indexes.
1613  * Note that .IND files are supported for read access only.
1614  *--------------------------------------------------------------------*/
1615 
1616 class TABINDFile
1617 {
1618     CPL_DISALLOW_COPY_ASSIGN(TABINDFile)
1619 
1620   private:
1621     char        *m_pszFname;
1622     VSILFILE    *m_fp;
1623     TABAccess   m_eAccessMode;
1624 
1625     TABBinBlockManager m_oBlockManager{};
1626 
1627     int         m_numIndexes;
1628     TABINDNode  **m_papoIndexRootNodes;
1629     GByte       **m_papbyKeyBuffers;
1630 
1631     int         ValidateIndexNo(int nIndexNumber);
1632     int         ReadHeader();
1633     int         WriteHeader();
1634 
1635    public:
1636     TABINDFile();
1637     ~TABINDFile();
1638 
1639     int         Open(const char *pszFname, const char *pszAccess,
1640                      GBool bTestOpenNoError=FALSE);
1641     int         Close();
1642 
GetNumIndexes()1643     int         GetNumIndexes() {return m_numIndexes;}
1644     int         SetIndexFieldType(int nIndexNumber, TABFieldType eType);
1645     int         SetIndexUnique(int nIndexNumber, GBool bUnique=TRUE);
1646     GByte      *BuildKey(int nIndexNumber, GInt32 nValue);
1647     GByte      *BuildKey(int nIndexNumber, const char *pszStr);
1648     GByte      *BuildKey(int nIndexNumber, double dValue);
1649     GInt32      FindFirst(int nIndexNumber, GByte *pKeyValue);
1650     GInt32      FindNext(int nIndexNumber, GByte *pKeyValue);
1651 
1652     int         CreateIndex(TABFieldType eType, int nFieldSize);
1653     int         AddEntry(int nIndexNumber, GByte *pKeyValue, GInt32 nRecordNo);
1654 
1655 #ifdef DEBUG
1656     void Dump(FILE *fpOut = nullptr);
1657 #endif
1658 };
1659 
1660 /*---------------------------------------------------------------------
1661  *                      class TABDATFile
1662  *
1663  * Class to handle Read/Write operation on .DAT files... the .DAT file
1664  * contains the table of attribute field values.
1665  *--------------------------------------------------------------------*/
1666 
1667 class TABDATFile
1668 {
1669     CPL_DISALLOW_COPY_ASSIGN(TABDATFile)
1670 
1671   private:
1672     char        *m_pszFname;
1673     VSILFILE    *m_fp;
1674     TABAccess   m_eAccessMode;
1675     TABTableType m_eTableType;
1676 
1677     TABRawBinBlock *m_poHeaderBlock;
1678     int         m_numFields;
1679     TABDATFieldDef *m_pasFieldDef;
1680 
1681     TABRawBinBlock *m_poRecordBlock;
1682     int         m_nBlockSize;
1683     int         m_nRecordSize;
1684     int         m_nCurRecordId;
1685     GBool       m_bCurRecordDeletedFlag;
1686 
1687     GInt32      m_numRecords;
1688     GInt32      m_nFirstRecordPtr;
1689     GBool       m_bWriteHeaderInitialized;
1690     GBool       m_bWriteEOF;
1691 
1692     int         m_bUpdated;
1693     CPLString   m_osEncoding;
1694 
1695     int         InitWriteHeader();
1696     int         WriteHeader();
1697 
1698     // We know that character strings are limited to 254 chars in MapInfo
1699     // Using a buffer pr. class instance to avoid threading issues with the library
1700     char        m_szBuffer[256];
1701 
1702    public:
1703     explicit TABDATFile( const char* pszEncoding );
1704     ~TABDATFile();
1705 
1706     int         Open(const char *pszFname, const char* pszAccess,
1707                      TABTableType eTableType =TABTableNative);
1708     int         Open(const char *pszFname, TABAccess eAccess,
1709                      TABTableType eTableType =TABTableNative);
1710     int         Close();
1711 
1712     int         GetNumFields();
1713     TABFieldType GetFieldType(int nFieldId);
1714     int         GetFieldWidth(int nFieldId);
1715     int         GetFieldPrecision(int nFieldId);
1716     int         ValidateFieldInfoFromTAB(int iField, const char *pszName,
1717                                          TABFieldType eType,
1718                                          int nWidth, int nPrecision);
1719 
1720     int         AddField(const char *pszName, TABFieldType eType,
1721                          int nWidth, int nPrecision=0);
1722 
1723     int         DeleteField( int iField );
1724     int         ReorderFields( int* panMap );
1725     int         AlterFieldDefn( int iField, OGRFieldDefn* poNewFieldDefn, int nFlags );
1726 
1727     int         SyncToDisk();
1728 
1729     GInt32      GetNumRecords();
1730     TABRawBinBlock *GetRecordBlock(int nRecordId);
IsCurrentRecordDeleted()1731     GBool       IsCurrentRecordDeleted() { return m_bCurRecordDeletedFlag;}
1732     int         CommitRecordToFile();
1733 
1734     int         MarkAsDeleted();
1735     int         MarkRecordAsExisting();
1736 
1737     const char  *ReadCharField(int nWidth);
1738     GInt32      ReadIntegerField(int nWidth);
1739     GInt16      ReadSmallIntField(int nWidth);
1740     double      ReadFloatField(int nWidth);
1741     double      ReadDecimalField(int nWidth);
1742     const char  *ReadLogicalField(int nWidth);
1743     const char  *ReadDateField(int nWidth);
1744     int         ReadDateField(int nWidth, int *nYear, int *nMonth, int *nDay);
1745     const char  *ReadTimeField(int nWidth);
1746     int         ReadTimeField(int nWidth, int *nHour, int *nMinute,
1747                               int *nSecond, int *nMS);
1748     const char  *ReadDateTimeField(int nWidth);
1749     int         ReadDateTimeField(int nWidth, int *nYear, int *nMonth, int *nDay,
1750                                  int *nHour, int *nMinute, int *nSecond, int *nMS);
1751 
1752     int         WriteCharField(const char *pszValue, int nWidth,
1753                                TABINDFile *poINDFile, int nIndexNo);
1754     int         WriteIntegerField(GInt32 nValue,
1755                                   TABINDFile *poINDFile, int nIndexNo);
1756     int         WriteSmallIntField(GInt16 nValue,
1757                                    TABINDFile *poINDFile, int nIndexNo);
1758     int         WriteFloatField(double dValue,
1759                                 TABINDFile *poINDFile, int nIndexNo);
1760     int         WriteDecimalField(double dValue, int nWidth, int nPrecision,
1761                                   TABINDFile *poINDFile, int nIndexNo);
1762     int         WriteLogicalField(const char *pszValue,
1763                                   TABINDFile *poINDFile, int nIndexNo);
1764     int         WriteDateField(const char *pszValue,
1765                                TABINDFile *poINDFile, int nIndexNo);
1766     int         WriteDateField(int nYear, int nMonth, int nDay,
1767                                TABINDFile *poINDFile, int nIndexNo);
1768     int         WriteTimeField(const char *pszValue,
1769                                TABINDFile *poINDFile, int nIndexNo);
1770     int         WriteTimeField(int nHour, int nMinute, int nSecond, int nMS,
1771                                TABINDFile *poINDFile, int nIndexNo);
1772     int         WriteDateTimeField(const char *pszValue,
1773                                TABINDFile *poINDFile, int nIndexNo);
1774     int         WriteDateTimeField(int nYear, int nMonth, int nDay,
1775                                    int nHour, int nMinute, int nSecond, int nMS,
1776                                    TABINDFile *poINDFile, int nIndexNo);
1777 
1778     const CPLString& GetEncoding() const;
1779     void SetEncoding( const CPLString& );
1780 
1781 #ifdef DEBUG
1782     void Dump(FILE *fpOut = nullptr);
1783 #endif
1784 };
1785 
1786 /*---------------------------------------------------------------------
1787  *                      class TABRelation
1788  *
1789  * Class that maintains a relation between 2 tables through a field
1790  * in each table (the SQL "where table1.field1=table2.field2" found in
1791  * TABView datasets).
1792  *
1793  * An instance of this class is used to read data records from the
1794  * combined tables as if they were a single one.
1795  *--------------------------------------------------------------------*/
1796 
1797 class TABRelation
1798 {
1799     CPL_DISALLOW_COPY_ASSIGN(TABRelation)
1800 
1801   private:
1802     /* Information about the main table.
1803      */
1804     TABFile     *m_poMainTable;
1805     char        *m_pszMainFieldName;
1806     int         m_nMainFieldNo;
1807 
1808     /* Information about the related table.
1809      * NOTE: The related field MUST be indexed.
1810      */
1811     TABFile     *m_poRelTable;
1812     char        *m_pszRelFieldName;
1813     int         m_nRelFieldNo;
1814 
1815     TABINDFile  *m_poRelINDFileRef;
1816     int         m_nRelFieldIndexNo;
1817 
1818     int         m_nUniqueRecordNo;
1819 
1820     /* Main and Rel table field map:
1821      * For each field in the source tables, -1 means that the field is not
1822      * selected, and a value >=0 is the index of this field in the combined
1823      * FeatureDefn
1824      */
1825     int         *m_panMainTableFieldMap;
1826     int         *m_panRelTableFieldMap;
1827 
1828     OGRFeatureDefn *m_poDefn;
1829 
1830     void        ResetAllMembers();
1831     GByte       *BuildFieldKey(TABFeature *poFeature, int nFieldNo,
1832                                   TABFieldType eType, int nIndexNo);
1833 
1834    public:
1835     TABRelation();
1836     ~TABRelation();
1837 
1838     int         Init(const char *pszViewName,
1839                      TABFile *poMainTable, TABFile *poRelTable,
1840                      const char *pszMainFieldName,
1841                      const char *pszRelFieldName,
1842                      char **papszSelectedFields);
1843     int         CreateRelFields();
1844 
GetFeatureDefn()1845     OGRFeatureDefn *GetFeatureDefn()  {return m_poDefn;}
1846     TABFieldType    GetNativeFieldType(int nFieldId);
1847     TABFeature     *GetFeature(int nFeatureId);
1848 
1849     int         WriteFeature(TABFeature *poFeature, int nFeatureId=-1);
1850 
1851     int         SetFeatureDefn(OGRFeatureDefn *poFeatureDefn,
1852                            TABFieldType *paeMapInfoNativeFieldTypes=nullptr);
1853     int         AddFieldNative(const char *pszName, TABFieldType eMapInfoType,
1854                                int nWidth=0, int nPrecision=0,
1855                                GBool bIndexed=FALSE, GBool bUnique=FALSE, int bApproxOK=TRUE);
1856 
1857     int         SetFieldIndexed(int nFieldId);
1858     GBool       IsFieldIndexed(int nFieldId);
1859     GBool       IsFieldUnique(int nFieldId);
1860 
GetMainFieldName()1861     const char *GetMainFieldName()      {return m_pszMainFieldName;}
GetRelFieldName()1862     const char *GetRelFieldName()       {return m_pszRelFieldName;}
1863 };
1864 
1865 /*---------------------------------------------------------------------
1866  *                      class MIDDATAFile
1867  *
1868  * Class to handle a file pointer with a copy of the latest read line.
1869  *
1870  *--------------------------------------------------------------------*/
1871 
1872 class MIDDATAFile
1873 {
1874     CPL_DISALLOW_COPY_ASSIGN(MIDDATAFile)
1875 
1876    public:
1877       explicit MIDDATAFile( const char* pszEncoding );
1878      ~MIDDATAFile();
1879 
1880      int         Open(const char *pszFname, const char *pszAccess);
1881      int         Close();
1882 
1883      const char *GetLine();
1884      const char *GetLastLine();
1885      int Rewind();
1886      void SaveLine(const char *pszLine);
1887      const char *GetSavedLine();
1888      void WriteLine(const char*, ...) CPL_PRINT_FUNC_FORMAT (2, 3);
1889      static GBool IsValidFeature(const char *pszString);
1890 
1891 //  Translation information
1892      void SetTranslation(double, double, double, double);
1893      double GetXTrans(double);
1894      double GetYTrans(double);
GetXMultiplier()1895      double GetXMultiplier(){return m_dfXMultiplier;}
GetDelimiter()1896      const char *GetDelimiter(){return m_pszDelimiter;}
SetDelimiter(const char * pszDelimiter)1897      void SetDelimiter(const char *pszDelimiter){m_pszDelimiter=pszDelimiter;}
1898 
1899      void SetEof(GBool bEof);
1900      GBool GetEof();
1901 
1902     const CPLString& GetEncoding() const;
1903     void SetEncoding( const CPLString& );
1904 
1905      private:
1906        VSILFILE *m_fp;
1907        const char *m_pszDelimiter;
1908 
1909        // Set limit for the length of a line
1910 #define MIDMAXCHAR 10000
1911        char m_szLastRead[MIDMAXCHAR];
1912        char m_szSavedLine[MIDMAXCHAR];
1913 
1914        char        *m_pszFname;
1915        TABAccess   m_eAccessMode;
1916        double      m_dfXMultiplier;
1917        double      m_dfYMultiplier;
1918        double      m_dfXDisplacement;
1919        double      m_dfYDisplacement;
1920        GBool       m_bEof;
1921        CPLString   m_osEncoding;
1922 };
1923 
1924 /*=====================================================================
1925                         Function prototypes
1926  =====================================================================*/
1927 
1928 TABRawBinBlock *TABCreateMAPBlockFromFile(VSILFILE *fpSrc, int nOffset,
1929                                           int nSize,
1930                                           GBool bHardBlockSize = TRUE,
1931                                           TABAccess eAccessMode = TABRead);
1932 
1933 #endif /* MITAB_PRIV_H_INCLUDED_ */
1934