Coverage Report

Created: 2026-08-11 08:26

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