• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

geographika / mapserver / 17709373190

14 Sep 2025 09:32AM UTC coverage: 41.466% (+0.09%) from 41.375%
17709373190

push

github

geographika
Add index templates

62086 of 149729 relevant lines covered (41.47%)

25036.08 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

59.35
/src/mapshape.c
1
/******************************************************************************
2
 * $Id$
3
 *
4
 * Project:  MapServer
5
 * Purpose:  Implements support for shapefile access.
6
 * Authors:  Steve Lime and Frank Warmerdam
7
 *
8
 * Note:
9
 * This code is entirely based on the previous work of Frank Warmerdam. It is
10
 * essentially shapelib 1.1.5. However, there were enough changes that it was
11
 * incorporated into the MapServer source to avoid confusion. Relicensed with
12
 * permission of Frank Warmerdam (shapelib author). See the README
13
 * for licence details.
14
 *
15
 ******************************************************************************
16
 * Copyright (c) 1996-2005 Regents of the University of Minnesota.
17
 *
18
 * Permission is hereby granted, free of charge, to any person obtaining a
19
 * copy of this software and associated documentation files (the "Software"),
20
 * to deal in the Software without restriction, including without limitation
21
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
22
 * and/or sell copies of the Software, and to permit persons to whom the
23
 * Software is furnished to do so, subject to the following conditions:
24
 *
25
 * The above copyright notice and this permission notice shall be included in
26
 * all copies of this Software or works derived from this Software.
27
 *
28
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
29
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
31
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
32
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
33
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
34
 * DEALINGS IN THE SOFTWARE.
35
 ****************************************************************************/
36

37
#define NEED_IGNORE_RET_VAL
38

39
#include <limits.h>
40
#include <assert.h>
41
#include <stdbool.h>
42
#include "mapserver.h"
43
#include "mapows.h"
44

45
#include <cpl_conv.h>
46
#include <ogr_srs_api.h>
47

48
/* Only use this macro on 32-bit integers! */
49
#define SWAP_FOUR_BYTES(data) CPL_SWAP32(data)
50

51
#define ByteCopy(a, b, c) memcpy(b, a, c)
52

53
#ifdef __BYTE_ORDER__
54
/* GCC/clang predefined macro */
55
#define bBigEndian (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
56
#elif defined(_MSC_VER)
57
/* MSVC doesn't support the C99 trick below, but all Microsoft
58
   platforms are little-endian */
59
#define bBigEndian false
60
#else
61
/* generic check */
62
#define bBigEndian                                                             \
63
  (((union {                                                                   \
64
     int in;                                                                   \
65
     char out;                                                                 \
66
   }){1})                                                                      \
67
       .out)
68
#endif
69

70
/* SHX reading */
71
static int msSHXLoadAll(SHPHandle psSHP);
72
static int msSHXReadOffset(SHPHandle psSHP, int hEntity);
73
static int msSHXReadSize(SHPHandle psSHP, int hEntity);
74

75
/************************************************************************/
76
/*                              SwapWord()                              */
77
/*                                                                      */
78
/*      Swap a 2, 4 or 8 byte word.                                     */
79
/************************************************************************/
80
static void SwapWord(int length, void *wordP) {
81
  int i;
82
  uchar temp;
83

84
  for (i = 0; i < length / 2; i++) {
17,640✔
85
    temp = ((uchar *)wordP)[i];
11,760✔
86
    ((uchar *)wordP)[i] = ((uchar *)wordP)[length - i - 1];
11,760✔
87
    ((uchar *)wordP)[length - i - 1] = temp;
11,760✔
88
  }
89
}
90

91
/************************************************************************/
92
/*                             SfRealloc()                              */
93
/*                                                                      */
94
/*      A realloc cover function that will access a NULL pointer as     */
95
/*      a valid input.                                                  */
96
/************************************************************************/
97
static void *SfRealloc(void *pMem, int nNewSize) {
98
  return realloc(pMem, nNewSize);
4,934✔
99
}
100

101
/************************************************************************/
102
/*                          writeHeader()                               */
103
/*                                                                      */
104
/*      Write out a header for the .shp and .shx files as well as the */
105
/*  contents of the index (.shx) file.        */
106
/************************************************************************/
107
static void writeHeader(SHPHandle psSHP) {
1✔
108
  uchar abyHeader[100];
109
  int i;
110
  ms_int32 i32;
111
  double dValue;
112
  ms_int32 *panSHX;
113

114
  /* -------------------------------------------------------------------- */
115
  /*      Prepare header block for .shp file.                             */
116
  /* -------------------------------------------------------------------- */
117
  for (i = 0; i < 100; i++)
101✔
118
    abyHeader[i] = 0;
100✔
119

120
  abyHeader[2] = 0x27; /* magic cookie */
1✔
121
  abyHeader[3] = 0x0a;
1✔
122

123
  i32 = psSHP->nFileSize / 2; /* file size */
1✔
124
  ByteCopy(&i32, abyHeader + 24, 4);
125
  if (!bBigEndian)
126
    SwapWord(4, abyHeader + 24);
127

128
  i32 = 1000; /* version */
129
  ByteCopy(&i32, abyHeader + 28, 4);
130
  if (bBigEndian)
131
    SwapWord(4, abyHeader + 28);
132

133
  i32 = psSHP->nShapeType; /* shape type */
1✔
134
  ByteCopy(&i32, abyHeader + 32, 4);
135
  if (bBigEndian)
136
    SwapWord(4, abyHeader + 32);
137

138
  dValue = psSHP->adBoundsMin[0]; /* set bounds */
1✔
139
  ByteCopy(&dValue, abyHeader + 36, 8);
140
  if (bBigEndian)
141
    SwapWord(8, abyHeader + 36);
142

143
  dValue = psSHP->adBoundsMin[1];
1✔
144
  ByteCopy(&dValue, abyHeader + 44, 8);
145
  if (bBigEndian)
146
    SwapWord(8, abyHeader + 44);
147

148
  dValue = psSHP->adBoundsMax[0];
1✔
149
  ByteCopy(&dValue, abyHeader + 52, 8);
150
  if (bBigEndian)
151
    SwapWord(8, abyHeader + 52);
152

153
  dValue = psSHP->adBoundsMax[1];
1✔
154
  ByteCopy(&dValue, abyHeader + 60, 8);
155
  if (bBigEndian)
156
    SwapWord(8, abyHeader + 60);
157

158
  dValue = psSHP->adBoundsMin[2]; /* z */
1✔
159
  ByteCopy(&dValue, abyHeader + 68, 8);
160
  if (bBigEndian)
161
    SwapWord(8, abyHeader + 68);
162

163
  dValue = psSHP->adBoundsMax[2];
1✔
164
  ByteCopy(&dValue, abyHeader + 76, 8);
165
  if (bBigEndian)
166
    SwapWord(8, abyHeader + 76);
167

168
  dValue = psSHP->adBoundsMin[3]; /* m */
1✔
169
  ByteCopy(&dValue, abyHeader + 84, 8);
170
  if (bBigEndian)
171
    SwapWord(8, abyHeader + 84);
172

173
  dValue = psSHP->adBoundsMax[3];
1✔
174
  ByteCopy(&dValue, abyHeader + 92, 8);
175
  if (bBigEndian)
176
    SwapWord(8, abyHeader + 92);
177

178
  /* -------------------------------------------------------------------- */
179
  /*      Write .shp file header.                                         */
180
  /* -------------------------------------------------------------------- */
181
  VSIFSeekL(psSHP->fpSHP, 0, 0);
1✔
182
  VSIFWriteL(abyHeader, 100, 1, psSHP->fpSHP);
1✔
183

184
  /* -------------------------------------------------------------------- */
185
  /*      Prepare, and write .shx file header.                            */
186
  /* -------------------------------------------------------------------- */
187
  i32 = (psSHP->nRecords * 2 * sizeof(ms_int32) + 100) / 2; /* file size */
1✔
188
  ByteCopy(&i32, abyHeader + 24, 4);
189
  if (!bBigEndian)
190
    SwapWord(4, abyHeader + 24);
191

192
  VSIFSeekL(psSHP->fpSHX, 0, 0);
1✔
193
  VSIFWriteL(abyHeader, 100, 1, psSHP->fpSHX);
1✔
194

195
  /* -------------------------------------------------------------------- */
196
  /*      Write out the .shx contents.                                    */
197
  /* -------------------------------------------------------------------- */
198
  panSHX = (ms_int32 *)msSmallMalloc(sizeof(ms_int32) * 2 * psSHP->nRecords);
1✔
199

200
  for (i = 0; i < psSHP->nRecords; i++) {
2✔
201
    panSHX[i * 2] = psSHP->panRecOffset[i] / 2;
1✔
202
    panSHX[i * 2 + 1] = psSHP->panRecSize[i] / 2;
1✔
203
    if (!bBigEndian) {
204
      *(panSHX + i * 2) = SWAP_FOUR_BYTES(*(panSHX + i * 2));
1✔
205
      *(panSHX + i * 2 + 1) = SWAP_FOUR_BYTES(*(panSHX + i * 2 + 1));
1✔
206
    }
207
  }
208

209
  VSIFWriteL(panSHX, sizeof(ms_int32) * 2, psSHP->nRecords, psSHP->fpSHX);
1✔
210

211
  free(panSHX);
1✔
212
}
1✔
213

214
SHPHandle msSHPOpenVirtualFile(VSILFILE *fpSHP, VSILFILE *fpSHX) {
2,937✔
215
  /* -------------------------------------------------------------------- */
216
  /*  Initialize the info structure.              */
217
  /* -------------------------------------------------------------------- */
218
  SHPHandle psSHP = (SHPHandle)msSmallMalloc(sizeof(SHPInfo));
2,937✔
219

220
  psSHP->bUpdated = MS_FALSE;
2,937✔
221

222
  psSHP->pabyRec = NULL;
2,937✔
223
  psSHP->panParts = NULL;
2,937✔
224
  psSHP->nBufSize = psSHP->nPartMax = 0;
2,937✔
225

226
  psSHP->fpSHP = fpSHP;
2,937✔
227
  psSHP->fpSHX = fpSHX;
2,937✔
228

229
  /* -------------------------------------------------------------------- */
230
  /*   Read the file size from the SHP file.            */
231
  /* -------------------------------------------------------------------- */
232
  uchar *pabyBuf = (uchar *)msSmallMalloc(100);
2,937✔
233
  if (1 != VSIFReadL(pabyBuf, 100, 1, psSHP->fpSHP)) {
2,937✔
234
    VSIFCloseL(psSHP->fpSHP);
×
235
    VSIFCloseL(psSHP->fpSHX);
×
236
    free(psSHP);
×
237
    free(pabyBuf);
×
238
    return (NULL);
×
239
  }
240

241
  if (!bBigEndian)
242
    SwapWord(4, pabyBuf + 24);
2,937✔
243
  memcpy(&psSHP->nFileSize, pabyBuf + 24, 4);
2,937✔
244
  if (psSHP->nFileSize < 0 || psSHP->nFileSize > INT_MAX / 2) {
2,937✔
245
    msDebug("Invalid / unsupported nFileSize = %d value. Got it from actual "
×
246
            "file length",
247
            psSHP->nFileSize);
248
    VSIFSeekL(psSHP->fpSHP, 0, SEEK_END);
×
249
    vsi_l_offset nSize = VSIFTellL(psSHP->fpSHP);
×
250
    if (nSize > (vsi_l_offset)INT_MAX) {
×
251
      msDebug("Actual .shp size is larger than 2 GB. Not supported. "
×
252
              "Invalidating nFileSize");
253
      psSHP->nFileSize = 0;
×
254
    } else
255
      psSHP->nFileSize = (int)nSize;
×
256
  } else {
257
    psSHP->nFileSize *= 2;
2,937✔
258
  }
259

260
  /* -------------------------------------------------------------------- */
261
  /*  Read SHX file Header info                                           */
262
  /* -------------------------------------------------------------------- */
263
  if (1 != VSIFReadL(pabyBuf, 100, 1, psSHP->fpSHX)) {
2,937✔
264
    msSetError(MS_SHPERR, "Corrupted .shx file", "msSHPOpen()");
×
265
    VSIFCloseL(psSHP->fpSHP);
×
266
    VSIFCloseL(psSHP->fpSHX);
×
267
    free(psSHP);
×
268
    free(pabyBuf);
×
269
    return (NULL);
×
270
  }
271

272
  if (pabyBuf[0] != 0 || pabyBuf[1] != 0 || pabyBuf[2] != 0x27 ||
2,937✔
273
      (pabyBuf[3] != 0x0a && pabyBuf[3] != 0x0d)) {
2,937✔
274
    msSetError(MS_SHPERR, "Corrupted .shx file", "msSHPOpen()");
×
275
    VSIFCloseL(psSHP->fpSHP);
×
276
    VSIFCloseL(psSHP->fpSHX);
×
277
    free(psSHP);
×
278
    free(pabyBuf);
×
279

280
    return (NULL);
×
281
  }
282

283
  int nSHXHalfFileSize;
284
  if (!bBigEndian)
285
    SwapWord(4, pabyBuf + 24);
286
  memcpy(&nSHXHalfFileSize, pabyBuf + 24, 4);
287
  if (nSHXHalfFileSize >= 50)
2,937✔
288
    psSHP->nRecords = (nSHXHalfFileSize - 50) / 4; // (nSHXFileSize - 100) / 8
2,937✔
289
  else
290
    psSHP->nRecords = -1;
×
291

292
  if (psSHP->nRecords < 0 || psSHP->nRecords > 256000000) {
2,937✔
293
    msSetError(MS_SHPERR, "Corrupted .shx file : nRecords = %d.", "msSHPOpen()",
×
294
               psSHP->nRecords);
295
    VSIFCloseL(psSHP->fpSHP);
×
296
    VSIFCloseL(psSHP->fpSHX);
×
297
    free(psSHP);
×
298
    free(pabyBuf);
×
299
    return (NULL);
×
300
  }
301

302
  psSHP->nShapeType = pabyBuf[32];
2,937✔
303

304
  if (bBigEndian)
305
    SwapWord(8, pabyBuf + 36);
306
  double dValue;
307
  memcpy(&dValue, pabyBuf + 36, 8);
308
  psSHP->adBoundsMin[0] = dValue;
2,937✔
309

310
  if (bBigEndian)
311
    SwapWord(8, pabyBuf + 44);
312
  memcpy(&dValue, pabyBuf + 44, 8);
313
  psSHP->adBoundsMin[1] = dValue;
2,937✔
314

315
  if (bBigEndian)
316
    SwapWord(8, pabyBuf + 52);
317
  memcpy(&dValue, pabyBuf + 52, 8);
318
  psSHP->adBoundsMax[0] = dValue;
2,937✔
319

320
  if (bBigEndian)
321
    SwapWord(8, pabyBuf + 60);
322
  memcpy(&dValue, pabyBuf + 60, 8);
323
  psSHP->adBoundsMax[1] = dValue;
2,937✔
324

325
  if (bBigEndian)
326
    SwapWord(8, pabyBuf + 68); /* z */
327
  memcpy(&dValue, pabyBuf + 68, 8);
328
  psSHP->adBoundsMin[2] = dValue;
2,937✔
329

330
  if (bBigEndian)
331
    SwapWord(8, pabyBuf + 76);
332
  memcpy(&dValue, pabyBuf + 76, 8);
333
  psSHP->adBoundsMax[2] = dValue;
2,937✔
334

335
  if (bBigEndian)
336
    SwapWord(8, pabyBuf + 84); /* m */
337
  memcpy(&dValue, pabyBuf + 84, 8);
338
  psSHP->adBoundsMin[3] = dValue;
2,937✔
339

340
  if (bBigEndian)
341
    SwapWord(8, pabyBuf + 92);
342
  memcpy(&dValue, pabyBuf + 92, 8);
343
  psSHP->adBoundsMax[3] = dValue;
2,937✔
344
  free(pabyBuf);
2,937✔
345

346
  /* -------------------------------------------------------------------- */
347
  /*  Read the .shx file to get the offsets to each record in       */
348
  /*  the .shp file.                  */
349
  /* -------------------------------------------------------------------- */
350
  psSHP->nMaxRecords = psSHP->nRecords;
2,937✔
351

352
  /* Our in-memory cache of offset information */
353
  psSHP->panRecOffset = (int *)malloc(sizeof(int) * psSHP->nMaxRecords);
2,937✔
354
  /* Our in-memory cache of size information */
355
  psSHP->panRecSize = (int *)malloc(sizeof(int) * psSHP->nMaxRecords);
2,937✔
356
  /* The completeness information for our in-memory cache */
357
  psSHP->panRecLoaded =
2,937✔
358
      msAllocBitArray(1 + (psSHP->nMaxRecords / SHX_BUFFER_PAGE));
2,937✔
359
  /* Is our in-memory cache completely populated? */
360
  psSHP->panRecAllLoaded = 0;
2,937✔
361

362
  /* malloc failed? clean up and shut down */
363
  if (psSHP->panRecOffset == NULL || psSHP->panRecSize == NULL ||
2,937✔
364
      psSHP->panRecLoaded == NULL) {
365
    free(psSHP->panRecOffset);
×
366
    free(psSHP->panRecSize);
×
367
    free(psSHP->panRecLoaded);
×
368
    VSIFCloseL(psSHP->fpSHP);
×
369
    VSIFCloseL(psSHP->fpSHX);
×
370
    free(psSHP);
×
371
    msSetError(MS_MEMERR, "Out of memory", "msSHPOpen()");
×
372
    return (NULL);
×
373
  }
374

375
  return (psSHP);
376
}
377

378
/************************************************************************/
379
/*                              msSHPOpen()                             */
380
/*                                                                      */
381
/*      Open the .shp and .shx files based on the basename of the       */
382
/*      files or either file name.                                      */
383
/************************************************************************/
384
SHPHandle msSHPOpen(const char *pszLayer, const char *pszAccess) {
2,955✔
385
  char *pszFullname, *pszBasename;
386

387
  int i;
388

389
  /* -------------------------------------------------------------------- */
390
  /*      Ensure the access string is one of the legal ones.  We          */
391
  /*      ensure the result string indicates binary to avoid common       */
392
  /*      problems on Windows.                                            */
393
  /* -------------------------------------------------------------------- */
394
  if (strcmp(pszAccess, "rb+") == 0 || strcmp(pszAccess, "r+b") == 0 ||
2,955✔
395
      strcmp(pszAccess, "r+") == 0)
2,950✔
396
    pszAccess = "r+b";
397
  else
398
    pszAccess = "rb";
399

400
  /* -------------------------------------------------------------------- */
401
  /*  Compute the base (layer) name.  If there is any extension     */
402
  /*  on the passed in filename we will strip it off.         */
403
  /* -------------------------------------------------------------------- */
404
  pszBasename = (char *)msSmallMalloc(strlen(pszLayer) + 5);
2,955✔
405
  strcpy(pszBasename, pszLayer);
406
  for (i = strlen(pszBasename) - 1;
2,955✔
407
       i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/' &&
22,716✔
408
       pszBasename[i] != '\\';
409
       i--) {
19,761✔
410
  }
411

412
  if (pszBasename[i] == '.')
2,955✔
413
    pszBasename[i] = '\0';
565✔
414

415
  /* -------------------------------------------------------------------- */
416
  /*  Open the .shp and .shx files.  Note that files pulled from      */
417
  /*  a PC to Unix with upper case filenames won't work!        */
418
  /* -------------------------------------------------------------------- */
419
  pszFullname = (char *)msSmallMalloc(strlen(pszBasename) + 5);
2,955✔
420
  sprintf(pszFullname, "%s.shp", pszBasename);
421
  VSILFILE *fpSHP = VSIFOpenL(pszFullname, pszAccess);
2,955✔
422
  if (fpSHP == NULL) {
2,955✔
423
    sprintf(pszFullname, "%s.SHP", pszBasename);
424
    fpSHP = VSIFOpenL(pszFullname, pszAccess);
19✔
425
  }
426
  if (fpSHP == NULL) {
19✔
427
    msFree(pszBasename);
18✔
428
    msFree(pszFullname);
18✔
429
    return (NULL);
18✔
430
  }
431

432
  sprintf(pszFullname, "%s.shx", pszBasename);
433
  VSILFILE *fpSHX = VSIFOpenL(pszFullname, pszAccess);
2,937✔
434
  if (fpSHX == NULL) {
2,937✔
435
    sprintf(pszFullname, "%s.SHX", pszBasename);
436
    fpSHX = VSIFOpenL(pszFullname, pszAccess);
1✔
437
  }
438
  if (fpSHX == NULL) {
1✔
439
    VSIFCloseL(fpSHP);
×
440
    msFree(pszBasename);
×
441
    msFree(pszFullname);
×
442
    return (NULL);
×
443
  }
444

445
  free(pszFullname);
2,937✔
446
  free(pszBasename);
2,937✔
447

448
  return msSHPOpenVirtualFile(fpSHP, fpSHX);
2,937✔
449
}
450

451
/************************************************************************/
452
/*                              msSHPClose()                            */
453
/*                        */
454
/*  Close the .shp and .shx files.          */
455
/************************************************************************/
456
void msSHPClose(SHPHandle psSHP) {
2,937✔
457
  /* -------------------------------------------------------------------- */
458
  /*  Update the header if we have modified anything.           */
459
  /* -------------------------------------------------------------------- */
460
  if (psSHP->bUpdated)
2,937✔
461
    writeHeader(psSHP);
1✔
462

463
  /* -------------------------------------------------------------------- */
464
  /*      Free all resources, and close files.                            */
465
  /* -------------------------------------------------------------------- */
466
  free(psSHP->panRecOffset);
2,937✔
467
  free(psSHP->panRecSize);
2,937✔
468
  free(psSHP->panRecLoaded);
2,937✔
469

470
  free(psSHP->pabyRec);
2,937✔
471
  free(psSHP->panParts);
2,937✔
472

473
  VSIFCloseL(psSHP->fpSHX);
2,937✔
474
  VSIFCloseL(psSHP->fpSHP);
2,937✔
475

476
  free(psSHP);
2,937✔
477
}
2,937✔
478

479
/************************************************************************/
480
/*                             msSHPGetInfo()                           */
481
/*                                                                      */
482
/*      Fetch general information about the shape file.                 */
483
/************************************************************************/
484
void msSHPGetInfo(SHPHandle psSHP, int *pnEntities, int *pnShapeType) {
2,937✔
485
  if (pnEntities)
2,937✔
486
    *pnEntities = psSHP->nRecords;
2,937✔
487

488
  if (pnShapeType)
2,937✔
489
    *pnShapeType = psSHP->nShapeType;
2,937✔
490
}
2,937✔
491

492
/************************************************************************/
493
/*                             msSHPCreate()                            */
494
/*                                                                      */
495
/*      Create a new shape file and return a handle to the open         */
496
/*      shape file with read/write access.                              */
497
/************************************************************************/
498
SHPHandle msSHPCreate(const char *pszLayer, int nShapeType) {
2✔
499
  char *pszBasename, *pszFullname;
500
  int i;
501
  VSILFILE *fpSHP, *fpSHX;
502
  uchar abyHeader[100];
503
  ms_int32 i32;
504
  double dValue;
505

506
  /* -------------------------------------------------------------------- */
507
  /*  Compute the base (layer) name.  If there is any extension       */
508
  /*  on the passed in filename we will strip it off.         */
509
  /* -------------------------------------------------------------------- */
510
  pszBasename = (char *)msSmallMalloc(strlen(pszLayer) + 5);
2✔
511
  strcpy(pszBasename, pszLayer);
512
  for (i = strlen(pszBasename) - 1;
2✔
513
       i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/' &&
9✔
514
       pszBasename[i] != '\\';
515
       i--) {
7✔
516
  }
517

518
  if (pszBasename[i] == '.')
2✔
519
    pszBasename[i] = '\0';
1✔
520

521
  /* -------------------------------------------------------------------- */
522
  /*      Open the two files so we can write their headers.               */
523
  /* -------------------------------------------------------------------- */
524
  pszFullname = (char *)msSmallMalloc(strlen(pszBasename) + 5);
2✔
525
  sprintf(pszFullname, "%s.shp", pszBasename);
526
  fpSHP = VSIFOpenL(pszFullname, "wb");
2✔
527
  if (fpSHP == NULL) {
2✔
528
    free(pszFullname);
×
529
    free(pszBasename);
×
530
    return (NULL);
×
531
  }
532

533
  sprintf(pszFullname, "%s.shx", pszBasename);
534
  fpSHX = VSIFOpenL(pszFullname, "wb");
2✔
535
  if (fpSHX == NULL) {
2✔
536
    VSIFCloseL(fpSHP);
×
537
    free(pszFullname);
×
538
    free(pszBasename);
×
539
    return (NULL);
×
540
  }
541

542
  free(pszFullname);
2✔
543
  free(pszBasename);
2✔
544

545
  /* -------------------------------------------------------------------- */
546
  /*      Prepare header block for .shp file.                             */
547
  /* -------------------------------------------------------------------- */
548
  for (i = 0; i < 100; i++)
202✔
549
    abyHeader[i] = 0;
200✔
550

551
  abyHeader[2] = 0x27; /* magic cookie */
2✔
552
  abyHeader[3] = 0x0a;
2✔
553

554
  i32 = 50; /* file size */
555
  ByteCopy(&i32, abyHeader + 24, 4);
556
  if (!bBigEndian)
557
    SwapWord(4, abyHeader + 24);
558

559
  i32 = 1000; /* version */
560
  ByteCopy(&i32, abyHeader + 28, 4);
561
  if (bBigEndian)
562
    SwapWord(4, abyHeader + 28);
563

564
  i32 = nShapeType; /* shape type */
565
  ByteCopy(&i32, abyHeader + 32, 4);
566
  if (bBigEndian)
567
    SwapWord(4, abyHeader + 32);
568

569
  dValue = 0.0; /* set bounds */
570
  ByteCopy(&dValue, abyHeader + 36, 8);
571
  ByteCopy(&dValue, abyHeader + 44, 8);
572
  ByteCopy(&dValue, abyHeader + 52, 8);
573
  ByteCopy(&dValue, abyHeader + 60, 8);
574

575
  /* -------------------------------------------------------------------- */
576
  /*      Write .shp file header.                                         */
577
  /* -------------------------------------------------------------------- */
578
  VSIFWriteL(abyHeader, 100, 1, fpSHP);
2✔
579

580
  /* -------------------------------------------------------------------- */
581
  /*      Prepare, and write .shx file header.                            */
582
  /* -------------------------------------------------------------------- */
583
  i32 = 50; /* file size */
584
  ByteCopy(&i32, abyHeader + 24, 4);
585
  if (!bBigEndian)
586
    SwapWord(4, abyHeader + 24);
587

588
  VSIFWriteL(abyHeader, 100, 1, fpSHX);
2✔
589

590
  /* -------------------------------------------------------------------- */
591
  /*      Close the files, and then open them as regular existing files.  */
592
  /* -------------------------------------------------------------------- */
593
  VSIFCloseL(fpSHP);
2✔
594
  VSIFCloseL(fpSHX);
2✔
595

596
  return (msSHPOpen(pszLayer, "rb+"));
2✔
597
}
598

599
/************************************************************************/
600
/*                           writeBounds()                              */
601
/*                                                                      */
602
/*      Compute a bounds rectangle for a shape, and set it into the     */
603
/*      indicated location in the record.                               */
604
/************************************************************************/
605
static void writeBounds(uchar *pabyRec, shapeObj *shape, int nVCount) {
×
606
  double dXMin, dXMax, dYMin, dYMax;
607
  int i, j;
608

609
  if (nVCount == 0) {
×
610
    dXMin = dYMin = dXMax = dYMax = 0.0;
×
611
  } else {
612
    dXMin = dXMax = shape->line[0].point[0].x;
×
613
    dYMin = dYMax = shape->line[0].point[0].y;
×
614

615
    for (i = 0; i < shape->numlines; i++) {
×
616
      for (j = 0; j < shape->line[i].numpoints; j++) {
×
617
        dXMin = MS_MIN(dXMin, shape->line[i].point[j].x);
×
618
        dXMax = MS_MAX(dXMax, shape->line[i].point[j].x);
×
619
        dYMin = MS_MIN(dYMin, shape->line[i].point[j].y);
×
620
        dYMax = MS_MAX(dYMax, shape->line[i].point[j].y);
×
621
      }
622
    }
623
  }
624

625
  if (bBigEndian) {
626
    SwapWord(8, &dXMin);
627
    SwapWord(8, &dYMin);
628
    SwapWord(8, &dXMax);
629
    SwapWord(8, &dYMax);
630
  }
631

632
  ByteCopy(&dXMin, pabyRec + 0, 8);
633
  ByteCopy(&dYMin, pabyRec + 8, 8);
×
634
  ByteCopy(&dXMax, pabyRec + 16, 8);
×
635
  ByteCopy(&dYMax, pabyRec + 24, 8);
×
636
}
×
637

638
int msSHPWritePoint(SHPHandle psSHP, pointObj *point) {
×
639
  int nRecordOffset, nRecordSize = 0;
640
  uchar *pabyRec;
641
  ms_int32 i32, nPoints, nParts;
642

643
  if (psSHP->nShapeType != SHP_POINT)
×
644
    return (-1);
645
  if (psSHP->nFileSize == 0)
×
646
    return -1;
647

648
  psSHP->bUpdated = MS_TRUE;
×
649

650
  /* Fill the SHX buffer if it is not already full. */
651
  if (!psSHP->panRecAllLoaded)
×
652
    msSHXLoadAll(psSHP);
×
653

654
  /* -------------------------------------------------------------------- */
655
  /*      Add the new entity to the in memory index.                      */
656
  /* -------------------------------------------------------------------- */
657
  psSHP->nRecords++;
×
658
  if (psSHP->nRecords > psSHP->nMaxRecords) {
×
659
    psSHP->nMaxRecords = (int)(psSHP->nMaxRecords * 1.3 + 100);
×
660

661
    psSHP->panRecOffset =
×
662
        (int *)SfRealloc(psSHP->panRecOffset, sizeof(int) * psSHP->nMaxRecords);
×
663
    psSHP->panRecSize =
×
664
        (int *)SfRealloc(psSHP->panRecSize, sizeof(int) * psSHP->nMaxRecords);
×
665
  }
666

667
  /* -------------------------------------------------------------------- */
668
  /*      Compute a few things.                                           */
669
  /* -------------------------------------------------------------------- */
670
  nPoints = 1;
671
  nParts = 1;
672

673
  /* -------------------------------------------------------------------- */
674
  /*      Initialize record.                                              */
675
  /* -------------------------------------------------------------------- */
676
  psSHP->panRecOffset[psSHP->nRecords - 1] = nRecordOffset = psSHP->nFileSize;
×
677

678
  pabyRec =
679
      (uchar *)msSmallMalloc(nPoints * 2 * sizeof(double) + nParts * 4 + 128);
×
680

681
  /* -------------------------------------------------------------------- */
682
  /*      Write vertices for a point.                                     */
683
  /* -------------------------------------------------------------------- */
684
  ByteCopy(&(point->x), pabyRec + 12, 8);
×
685
  ByteCopy(&(point->y), pabyRec + 20, 8);
×
686

687
  if (bBigEndian) {
688
    SwapWord(8, pabyRec + 12);
689
    SwapWord(8, pabyRec + 20);
690
  }
691

692
  nRecordSize = 20;
693

694
  /* -------------------------------------------------------------------- */
695
  /*      Set the shape type, record number, and record size.             */
696
  /* -------------------------------------------------------------------- */
697
  i32 = psSHP->nRecords - 1 + 1; /* record # */
×
698
  if (!bBigEndian)
699
    i32 = SWAP_FOUR_BYTES(i32);
×
700
  ByteCopy(&i32, pabyRec, 4);
701

702
  i32 = nRecordSize / 2; /* record size */
703
  if (!bBigEndian)
704
    i32 = SWAP_FOUR_BYTES(i32);
×
705
  ByteCopy(&i32, pabyRec + 4, 4);
×
706

707
  i32 = psSHP->nShapeType; /* shape type */
×
708
  if (bBigEndian)
709
    i32 = SWAP_FOUR_BYTES(i32);
710
  ByteCopy(&i32, pabyRec + 8, 4);
×
711

712
  /* -------------------------------------------------------------------- */
713
  /*      Write out record.                                               */
714
  /* -------------------------------------------------------------------- */
715
  if (VSIFSeekL(psSHP->fpSHP, nRecordOffset, 0) == 0) {
×
716
    VSIFWriteL(pabyRec, nRecordSize + 8, 1, psSHP->fpSHP);
×
717

718
    psSHP->panRecSize[psSHP->nRecords - 1] = nRecordSize;
×
719
    psSHP->nFileSize += nRecordSize + 8;
×
720

721
    /* -------------------------------------------------------------------- */
722
    /*  Expand file wide bounds based on this shape.        */
723
    /* -------------------------------------------------------------------- */
724
    if (psSHP->nRecords == 1) {
×
725
      psSHP->adBoundsMin[0] = psSHP->adBoundsMax[0] = point->x;
×
726
      psSHP->adBoundsMin[1] = psSHP->adBoundsMax[1] = point->y;
×
727
    } else {
728
      psSHP->adBoundsMin[0] = MS_MIN(psSHP->adBoundsMin[0], point->x);
×
729
      psSHP->adBoundsMin[1] = MS_MIN(psSHP->adBoundsMin[1], point->y);
×
730
      psSHP->adBoundsMax[0] = MS_MAX(psSHP->adBoundsMax[0], point->x);
×
731
      psSHP->adBoundsMax[1] = MS_MAX(psSHP->adBoundsMax[1], point->y);
×
732
    }
733
  } else {
734
    psSHP->nRecords--;
×
735
  }
736
  free(pabyRec);
×
737
  return (psSHP->nRecords - 1);
×
738
}
739

740
int msSHPWriteShape(SHPHandle psSHP, shapeObj *shape) {
1✔
741
  int nRecordOffset, i, j, k, nRecordSize = 0;
742
  uchar *pabyRec;
743
  int nShapeType;
744

745
  ms_int32 i32, nPoints, nParts;
746

747
  if (psSHP->nFileSize == 0)
1✔
748
    return -1;
749

750
  psSHP->bUpdated = MS_TRUE;
1✔
751

752
  /* Fill the SHX buffer if it is not already full. */
753
  if (!psSHP->panRecAllLoaded)
1✔
754
    msSHXLoadAll(psSHP);
1✔
755

756
  /* -------------------------------------------------------------------- */
757
  /*      Add the new entity to the in memory index.                      */
758
  /* -------------------------------------------------------------------- */
759
  psSHP->nRecords++;
1✔
760
  if (psSHP->nRecords > psSHP->nMaxRecords) {
1✔
761
    psSHP->nMaxRecords = (int)(psSHP->nMaxRecords * 1.3 + 100);
1✔
762

763
    psSHP->panRecOffset =
1✔
764
        (int *)SfRealloc(psSHP->panRecOffset, sizeof(int) * psSHP->nMaxRecords);
1✔
765
    psSHP->panRecSize =
1✔
766
        (int *)SfRealloc(psSHP->panRecSize, sizeof(int) * psSHP->nMaxRecords);
1✔
767
  }
768

769
  /* -------------------------------------------------------------------- */
770
  /*      Compute a few things.                                           */
771
  /* -------------------------------------------------------------------- */
772
  nPoints = 0;
1✔
773
  for (i = 0; i < shape->numlines; i++)
2✔
774
    nPoints += shape->line[i].numpoints;
1✔
775

776
  nParts = shape->numlines;
1✔
777

778
  /* -------------------------------------------------------------------- */
779
  /*      Initialize record.                                              */
780
  /* -------------------------------------------------------------------- */
781
  psSHP->panRecOffset[psSHP->nRecords - 1] = nRecordOffset = psSHP->nFileSize;
1✔
782

783
  pabyRec =
784
      (uchar *)msSmallMalloc(nPoints * 4 * sizeof(double) + nParts * 8 + 128);
1✔
785
  nShapeType = psSHP->nShapeType;
1✔
786

787
  if (shape->type == MS_SHAPE_NULL) {
1✔
788
    nShapeType = 0;
789
    nRecordSize = 12;
790
  }
791
  /* -------------------------------------------------------------------- */
792
  /*  Write vertices for a Polygon or Arc.            */
793
  /* -------------------------------------------------------------------- */
794
  else if (psSHP->nShapeType == SHP_POLYGON || psSHP->nShapeType == SHP_ARC ||
×
795
           psSHP->nShapeType == SHP_POLYGONM || psSHP->nShapeType == SHP_ARCM ||
796
           psSHP->nShapeType == SHP_ARCZ || psSHP->nShapeType == SHP_POLYGONZ) {
×
797
    ms_int32 t_nParts, t_nPoints, partSize;
798

799
    t_nParts = nParts;
800
    t_nPoints = nPoints;
801

802
    writeBounds(pabyRec + 12, shape, t_nPoints);
×
803

804
    if (bBigEndian) {
805
      nPoints = SWAP_FOUR_BYTES(nPoints);
806
      nParts = SWAP_FOUR_BYTES(nParts);
807
    }
808

809
    ByteCopy(&nPoints, pabyRec + 40 + 8, 4);
×
810
    ByteCopy(&nParts, pabyRec + 36 + 8, 4);
×
811

812
    partSize = 0; /* first part always starts at 0 */
×
813
    ByteCopy(&partSize, pabyRec + 44 + 8 + 4 * 0, 4);
×
814
    if (bBigEndian)
815
      SwapWord(4, pabyRec + 44 + 8 + 4 * 0);
816

817
    for (i = 1; i < t_nParts; i++) {
×
818
      partSize += shape->line[i - 1].numpoints;
×
819
      ByteCopy(&partSize, pabyRec + 44 + 8 + 4 * i, 4);
×
820
      if (bBigEndian)
821
        SwapWord(4, pabyRec + 44 + 8 + 4 * i);
822
    }
823

824
    k = 0; /* overall point counter */
825
    for (i = 0; i < shape->numlines; i++) {
×
826
      for (j = 0; j < shape->line[i].numpoints; j++) {
×
827
        ByteCopy(&(shape->line[i].point[j].x),
×
828
                 pabyRec + 44 + 4 * t_nParts + 8 + k * 16, 8);
829
        ByteCopy(&(shape->line[i].point[j].y),
×
830
                 pabyRec + 44 + 4 * t_nParts + 8 + k * 16 + 8, 8);
831

832
        if (bBigEndian) {
833
          SwapWord(8, pabyRec + 44 + 4 * t_nParts + 8 + k * 16);
834
          SwapWord(8, pabyRec + 44 + 4 * t_nParts + 8 + k * 16 + 8);
835
        }
836

837
        k++;
×
838
      }
839
    }
840

841
    nRecordSize = 44 + 4 * t_nParts + 16 * t_nPoints;
×
842

843
    /* -------------------------------------------------------------------- */
844
    /*      measured shape : polygon and arc.                               */
845
    /* -------------------------------------------------------------------- */
846
    if (psSHP->nShapeType == SHP_POLYGONM || psSHP->nShapeType == SHP_ARCM) {
×
847
      const double dfMMin = shape->line[0].point[0].m;
×
848
      const double dfMMax =
×
849
          shape->line[shape->numlines - 1]
×
850
              .point[shape->line[shape->numlines - 1].numpoints - 1]
×
851
              .m;
×
852

853
      nRecordSize = 44 + 4 * t_nParts + 8 + (t_nPoints * 16);
×
854

855
      ByteCopy(&(dfMMin), pabyRec + nRecordSize, 8);
×
856
      if (bBigEndian)
857
        SwapWord(8, pabyRec + nRecordSize);
858
      nRecordSize += 8;
×
859

860
      ByteCopy(&(dfMMax), pabyRec + nRecordSize, 8);
×
861
      if (bBigEndian)
862
        SwapWord(8, pabyRec + nRecordSize);
863
      nRecordSize += 8;
×
864

865
      for (i = 0; i < shape->numlines; i++) {
×
866
        for (j = 0; j < shape->line[i].numpoints; j++) {
×
867
          ByteCopy(&(shape->line[i].point[j].m), pabyRec + nRecordSize, 8);
×
868
          if (bBigEndian)
869
            SwapWord(8, pabyRec + nRecordSize);
870
          nRecordSize += 8;
×
871
        }
872
      }
873
    }
874

875
    /* -------------------------------------------------------------------- */
876
    /*      Polygon. Arc with Z                                             */
877
    /* -------------------------------------------------------------------- */
878
    if (psSHP->nShapeType == SHP_POLYGONZ || psSHP->nShapeType == SHP_ARCZ ||
×
879
        psSHP->nShapeType == SHP_POLYGONM || psSHP->nShapeType == SHP_ARCM) {
880
      const double dfMMin = shape->line[0].point[0].z;
×
881
      const double dfMMax =
×
882
          shape->line[shape->numlines - 1]
×
883
              .point[shape->line[shape->numlines - 1].numpoints - 1]
×
884
              .z;
×
885

886
      nRecordSize = 44 + 4 * t_nParts + 8 + (t_nPoints * 16);
×
887

888
      ByteCopy(&(dfMMin), pabyRec + nRecordSize, 8);
×
889
      if (bBigEndian)
890
        SwapWord(8, pabyRec + nRecordSize);
891
      nRecordSize += 8;
×
892

893
      ByteCopy(&(dfMMax), pabyRec + nRecordSize, 8);
×
894
      if (bBigEndian)
895
        SwapWord(8, pabyRec + nRecordSize);
896
      nRecordSize += 8;
×
897

898
      for (i = 0; i < shape->numlines; i++) {
×
899
        for (j = 0; j < shape->line[i].numpoints; j++) {
×
900
          ByteCopy(&(shape->line[i].point[j].z), pabyRec + nRecordSize, 8);
×
901
          if (bBigEndian)
902
            SwapWord(8, pabyRec + nRecordSize);
903
          nRecordSize += 8;
×
904
        }
905
      }
906
    }
907
  }
908

909
  /* -------------------------------------------------------------------- */
910
  /*  Write vertices for a MultiPoint.                                    */
911
  /* -------------------------------------------------------------------- */
912
  else if (psSHP->nShapeType == SHP_MULTIPOINT ||
913
           psSHP->nShapeType == SHP_MULTIPOINTM ||
914
           psSHP->nShapeType == SHP_MULTIPOINTZ) {
915
    ms_int32 t_nPoints;
916

917
    t_nPoints = nPoints;
918

919
    writeBounds(pabyRec + 12, shape, nPoints);
×
920

921
    if (bBigEndian)
922
      nPoints = SWAP_FOUR_BYTES(nPoints);
923
    ByteCopy(&nPoints, pabyRec + 44, 4);
×
924

925
    for (i = 0; i < shape->line[0].numpoints; i++) {
×
926
      ByteCopy(&(shape->line[0].point[i].x), pabyRec + 48 + i * 16, 8);
×
927
      ByteCopy(&(shape->line[0].point[i].y), pabyRec + 48 + i * 16 + 8, 8);
×
928

929
      if (bBigEndian) {
930
        SwapWord(8, pabyRec + 48 + i * 16);
931
        SwapWord(8, pabyRec + 48 + i * 16 + 8);
932
      }
933
    }
934

935
    nRecordSize = 40 + 16 * t_nPoints;
×
936

937
    if (psSHP->nShapeType == SHP_MULTIPOINTM) {
×
938
      const double dfMMin = shape->line[0].point[0].m;
×
939
      const double dfMMax =
×
940
          shape->line[0].point[shape->line[0].numpoints - 1].m;
×
941

942
      ByteCopy(&(dfMMin), pabyRec + nRecordSize, 8);
×
943
      if (bBigEndian)
944
        SwapWord(8, pabyRec + nRecordSize);
945
      nRecordSize += 8;
×
946

947
      ByteCopy(&(dfMMax), pabyRec + nRecordSize, 8);
×
948
      if (bBigEndian)
949
        SwapWord(8, pabyRec + nRecordSize);
950
      nRecordSize += 8;
×
951

952
      for (i = 0; i < shape->line[0].numpoints; i++) {
×
953
        ByteCopy(&(shape->line[0].point[i].m), pabyRec + nRecordSize, 8);
×
954
        if (bBigEndian)
955
          SwapWord(8, pabyRec + nRecordSize);
956
        nRecordSize += 8;
×
957
      }
958
    }
959

960
    if (psSHP->nShapeType == SHP_MULTIPOINTZ) {
×
961
      const double dfMMin = shape->line[0].point[0].z;
×
962
      const double dfMMax =
×
963
          shape->line[0].point[shape->line[0].numpoints - 1].z;
×
964

965
      ByteCopy(&(dfMMin), pabyRec + nRecordSize, 8);
×
966
      if (bBigEndian)
967
        SwapWord(8, pabyRec + nRecordSize);
968
      nRecordSize += 8;
×
969

970
      ByteCopy(&(dfMMax), pabyRec + nRecordSize, 8);
×
971
      if (bBigEndian)
972
        SwapWord(8, pabyRec + nRecordSize);
973
      nRecordSize += 8;
×
974

975
      for (i = 0; i < shape->line[0].numpoints; i++) {
×
976
        ByteCopy(&(shape->line[0].point[i].z), pabyRec + nRecordSize, 8);
×
977
        if (bBigEndian)
978
          SwapWord(8, pabyRec + nRecordSize);
979
        nRecordSize += 8;
×
980
      }
981
    }
982
  }
983

984
  /* -------------------------------------------------------------------- */
985
  /*      Write vertices for a point.                                     */
986
  /* -------------------------------------------------------------------- */
987
  else if (psSHP->nShapeType == SHP_POINT || psSHP->nShapeType == SHP_POINTM ||
988
           psSHP->nShapeType == SHP_POINTZ) {
989
    ByteCopy(&(shape->line[0].point[0].x), pabyRec + 12, 8);
×
990
    ByteCopy(&(shape->line[0].point[0].y), pabyRec + 20, 8);
×
991

992
    if (bBigEndian) {
993
      SwapWord(8, pabyRec + 12);
994
      SwapWord(8, pabyRec + 20);
995
    }
996

997
    nRecordSize = 20;
998

999
    if (psSHP->nShapeType == SHP_POINTM) {
×
1000
      ByteCopy(&(shape->line[0].point[0].m), pabyRec + nRecordSize, 8);
×
1001
      if (bBigEndian)
1002
        SwapWord(8, pabyRec + nRecordSize);
1003
      nRecordSize += 8;
1004
    }
1005

1006
    if (psSHP->nShapeType == SHP_POINTZ) {
×
1007
      ByteCopy(&(shape->line[0].point[0].z), pabyRec + nRecordSize, 8);
×
1008
      if (bBigEndian)
1009
        SwapWord(8, pabyRec + nRecordSize);
1010
      nRecordSize += 8;
×
1011
    }
1012
  }
1013

1014
  /* -------------------------------------------------------------------- */
1015
  /*      Set the shape type, record number, and record size.             */
1016
  /* -------------------------------------------------------------------- */
1017
  i32 = psSHP->nRecords - 1 + 1; /* record # */
1✔
1018
  if (!bBigEndian)
1019
    i32 = SWAP_FOUR_BYTES(i32);
1✔
1020
  ByteCopy(&i32, pabyRec, 4);
1021

1022
  i32 = nRecordSize / 2; /* record size */
1✔
1023
  if (!bBigEndian)
1024
    i32 = SWAP_FOUR_BYTES(i32);
1✔
1025
  ByteCopy(&i32, pabyRec + 4, 4);
1✔
1026

1027
  i32 = nShapeType; /* shape type */
1✔
1028
  if (bBigEndian)
1029
    i32 = SWAP_FOUR_BYTES(i32);
1030
  ByteCopy(&i32, pabyRec + 8, 4);
1✔
1031

1032
  /* -------------------------------------------------------------------- */
1033
  /*      Write out record.                                               */
1034
  /* -------------------------------------------------------------------- */
1035
  if (VSIFSeekL(psSHP->fpSHP, nRecordOffset, 0) == 0) {
1✔
1036
    VSIFWriteL(pabyRec, nRecordSize + 8, 1, psSHP->fpSHP);
1✔
1037

1038
    psSHP->panRecSize[psSHP->nRecords - 1] = nRecordSize;
1✔
1039
    psSHP->nFileSize += nRecordSize + 8;
1✔
1040

1041
    /* -------------------------------------------------------------------- */
1042
    /*  Expand file wide bounds based on this shape.        */
1043
    /* -------------------------------------------------------------------- */
1044
    if (psSHP->nRecords == 1) {
1✔
1045
      psSHP->adBoundsMin[0] = psSHP->adBoundsMax[0] = shape->line[0].point[0].x;
1✔
1046
      psSHP->adBoundsMin[1] = psSHP->adBoundsMax[1] = shape->line[0].point[0].y;
1✔
1047
      psSHP->adBoundsMin[2] = psSHP->adBoundsMax[2] = shape->line[0].point[0].z;
1✔
1048
      psSHP->adBoundsMin[3] = psSHP->adBoundsMax[3] = shape->line[0].point[0].m;
1✔
1049
    }
1050

1051
    for (i = 0; i < shape->numlines; i++) {
2✔
1052
      for (j = 0; j < shape->line[i].numpoints; j++) {
6✔
1053
        psSHP->adBoundsMin[0] =
5✔
1054
            MS_MIN(psSHP->adBoundsMin[0], shape->line[i].point[j].x);
5✔
1055
        psSHP->adBoundsMin[1] =
5✔
1056
            MS_MIN(psSHP->adBoundsMin[1], shape->line[i].point[j].y);
5✔
1057
        psSHP->adBoundsMin[2] =
5✔
1058
            MS_MIN(psSHP->adBoundsMin[2], shape->line[i].point[j].z);
5✔
1059
        psSHP->adBoundsMin[3] =
5✔
1060
            MS_MIN(psSHP->adBoundsMin[3], shape->line[i].point[j].m);
5✔
1061
        psSHP->adBoundsMax[0] =
5✔
1062
            MS_MAX(psSHP->adBoundsMax[0], shape->line[i].point[j].x);
5✔
1063
        psSHP->adBoundsMax[1] =
5✔
1064
            MS_MAX(psSHP->adBoundsMax[1], shape->line[i].point[j].y);
5✔
1065
        psSHP->adBoundsMax[2] =
5✔
1066
            MS_MAX(psSHP->adBoundsMax[2], shape->line[i].point[j].z);
5✔
1067
        psSHP->adBoundsMax[3] =
5✔
1068
            MS_MAX(psSHP->adBoundsMax[3], shape->line[i].point[j].m);
5✔
1069
      }
1070
    }
1071

1072
  } else {
1073
    psSHP->nRecords--;
×
1074
    /* there was an error writing the record */
1075
  }
1076
  free(pabyRec);
1✔
1077
  return (psSHP->nRecords - 1);
1✔
1078
}
1079

1080
/*
1081
 ** msSHPReadAllocateBuffer() - Ensure our record buffer is large enough.
1082
 */
1083
static uchar *msSHPReadAllocateBuffer(SHPHandle psSHP, int hEntity,
31,923✔
1084
                                      const char *pszCallingFunction) {
1085

1086
  int nEntitySize = msSHXReadSize(psSHP, hEntity);
31,923✔
1087
  if (nEntitySize <= 0 || nEntitySize > INT_MAX - 8) {
31,923✔
1088
    msSetError(MS_MEMERR,
×
1089
               "Out of memory. Cannot allocate %d bytes. Probably broken "
1090
               "shapefile at feature %d",
1091
               pszCallingFunction, nEntitySize, hEntity);
1092
    return NULL;
×
1093
  }
1094
  nEntitySize += 8;
31,923✔
1095
  /* -------------------------------------------------------------------- */
1096
  /*      Ensure our record buffer is large enough.                       */
1097
  /* -------------------------------------------------------------------- */
1098

1099
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
1100
  /* when running with libFuzzer, allocate a new buffer for every
1101
     call, to allow AddressSanitizer to detect memory errors */
1102
  free(psSHP->pabyRec);
1103
  psSHP->pabyRec = NULL;
1104
  psSHP->nBufSize = 0;
1105
#endif
1106

1107
  if (nEntitySize > psSHP->nBufSize) {
31,923✔
1108
    uchar *pabyRec = (uchar *)SfRealloc(psSHP->pabyRec, nEntitySize);
3,463✔
1109
    if (pabyRec == NULL) {
3,463✔
1110
      msSetError(MS_MEMERR,
×
1111
                 "Out of memory. Cannot allocate %d bytes. Probably broken "
1112
                 "shapefile at feature %d",
1113
                 pszCallingFunction, nEntitySize, hEntity);
1114
      return NULL;
×
1115
    }
1116
    psSHP->pabyRec = pabyRec;
3,463✔
1117
    psSHP->nBufSize = nEntitySize;
3,463✔
1118
  }
1119
  return psSHP->pabyRec;
31,923✔
1120
}
1121

1122
/*
1123
** msSHPReadPoint() - Reads a single point from a POINT shape file.
1124
*/
1125
int msSHPReadPoint(SHPHandle psSHP, int hEntity, pointObj *point) {
×
1126
  int nEntitySize;
1127

1128
  /* -------------------------------------------------------------------- */
1129
  /*      Only valid for point shapefiles                                 */
1130
  /* -------------------------------------------------------------------- */
1131
  if (psSHP->nShapeType != SHP_POINT) {
×
1132
    msSetError(MS_SHPERR, "msSHPReadPoint only operates on point shapefiles.",
×
1133
               "msSHPReadPoint()");
1134
    return (MS_FAILURE);
×
1135
  }
1136

1137
  /* -------------------------------------------------------------------- */
1138
  /*      Validate the record/entity number.                              */
1139
  /* -------------------------------------------------------------------- */
1140
  if (hEntity < 0 || hEntity >= psSHP->nRecords) {
×
1141
    msSetError(MS_SHPERR, "Record index out of bounds.", "msSHPReadPoint()");
×
1142
    return (MS_FAILURE);
×
1143
  }
1144

1145
  nEntitySize = msSHXReadSize(psSHP, hEntity) + 8;
×
1146

1147
  if (nEntitySize == 12) {
×
1148
    msSetError(MS_SHPERR, "NULL feature encountered.", "msSHPReadPoint()");
×
1149
    return (MS_FAILURE);
×
1150
  } else if (nEntitySize < 28) {
×
1151
    msSetError(MS_SHPERR,
×
1152
               "Corrupted feature encountered.  hEntity=%d, nEntitySize=%d",
1153
               "msSHPReadPoint()", hEntity, nEntitySize);
1154
    return (MS_FAILURE);
×
1155
  }
1156

1157
  uchar *pabyRec = msSHPReadAllocateBuffer(psSHP, hEntity, "msSHPReadPoint()");
×
1158
  if (pabyRec == NULL) {
×
1159
    return MS_FAILURE;
1160
  }
1161

1162
  /* -------------------------------------------------------------------- */
1163
  /*      Read the record.                                                */
1164
  /* -------------------------------------------------------------------- */
1165
  const int offset = msSHXReadOffset(psSHP, hEntity);
×
1166
  if (offset <= 0 || 0 != VSIFSeekL(psSHP->fpSHP, offset, 0)) {
×
1167
    msSetError(MS_IOERR, "failed to seek offset", "msSHPReadPoint()");
×
1168
    return (MS_FAILURE);
×
1169
  }
1170
  if (1 != VSIFReadL(pabyRec, nEntitySize, 1, psSHP->fpSHP)) {
×
1171
    msSetError(MS_IOERR, "failed to fread record", "msSHPReadPoint()");
×
1172
    return (MS_FAILURE);
×
1173
  }
1174

1175
  memcpy(&(point->x), pabyRec + 12, 8);
×
1176
  memcpy(&(point->y), pabyRec + 20, 8);
×
1177

1178
  if (bBigEndian) {
1179
    SwapWord(8, &(point->x));
1180
    SwapWord(8, &(point->y));
1181
  }
1182

1183
  return (MS_SUCCESS);
×
1184
}
1185

1186
/*
1187
** msSHXLoadPage()
1188
**
1189
** The SHX tells us what the byte offsets of the shapes in the SHP file are.
1190
** We read the SHX file in ~8K pages and store those pages in memory for
1191
** successive accesses during the reading cycle (first bounds are read,
1192
** then entire shapes). Each time we read a page, we mark it as read.
1193
*/
1194
static bool msSHXLoadPage(SHPHandle psSHP, int shxBufferPage) {
1,890✔
1195
  int i;
1196

1197
  /* Each SHX record is 8 bytes long (two ints), hence our buffer size. */
1198
  char buffer[SHX_BUFFER_PAGE * 8];
1199

1200
  /*  Validate the page number. */
1201
  if (shxBufferPage < 0)
1,890✔
1202
    return (MS_FAILURE);
1203

1204
  const int nShapesToCache =
1205
      shxBufferPage < psSHP->nRecords / SHX_BUFFER_PAGE
1,890✔
1206
          ? SHX_BUFFER_PAGE
1207
          : psSHP->nRecords - shxBufferPage * SHX_BUFFER_PAGE;
1,890✔
1208

1209
  if (0 !=
1,890✔
1210
      VSIFSeekL(psSHP->fpSHX, 100 + shxBufferPage * SHX_BUFFER_PAGE * 8, 0)) {
1,890✔
1211
    memset(psSHP->panRecOffset + shxBufferPage * SHX_BUFFER_PAGE, 0,
×
1212
           nShapesToCache * sizeof(psSHP->panRecOffset[0]));
1213
    memset(psSHP->panRecSize + shxBufferPage * SHX_BUFFER_PAGE, 0,
×
1214
           nShapesToCache * sizeof(psSHP->panRecSize[0]));
1215
    msSetBit(psSHP->panRecLoaded, shxBufferPage, 1);
×
1216
    msSetError(MS_IOERR, "failed to seek offset", "msSHXLoadPage()");
×
1217
    return false;
×
1218
  }
1219

1220
  if ((size_t)nShapesToCache !=
1,890✔
1221
      VSIFReadL(buffer, 8, nShapesToCache, psSHP->fpSHX)) {
1,890✔
1222
    memset(psSHP->panRecOffset + shxBufferPage * SHX_BUFFER_PAGE, 0,
×
1223
           nShapesToCache * sizeof(psSHP->panRecOffset[0]));
1224
    memset(psSHP->panRecSize + shxBufferPage * SHX_BUFFER_PAGE, 0,
×
1225
           nShapesToCache * sizeof(psSHP->panRecSize[0]));
1226
    msSetBit(psSHP->panRecLoaded, shxBufferPage, 1);
×
1227
    msSetError(MS_IOERR, "failed to fread SHX record", "msSHXLoadPage()");
×
1228
    return false;
×
1229
  }
1230

1231
  /* Copy the buffer contents out into the working arrays. */
1232
  for (i = 0; i < nShapesToCache; i++) {
186,776✔
1233
    int tmpOffset, tmpSize;
1234

1235
    memcpy(&tmpOffset, (buffer + (8 * i)), 4);
184,886✔
1236
    memcpy(&tmpSize, (buffer + (8 * i) + 4), 4);
184,886✔
1237

1238
    /* SHX uses big endian numbers for the offsets, so we have to flip them */
1239
    /* if we are a little endian machine. */
1240
    if (!bBigEndian) {
1241
      tmpOffset = SWAP_FOUR_BYTES(tmpOffset);
184,886✔
1242
      tmpSize = SWAP_FOUR_BYTES(tmpSize);
184,886✔
1243
    }
1244

1245
    /* SHX stores the offsets in 2 byte units, so we double them to get */
1246
    /* an offset in bytes. */
1247
    if (tmpOffset > 0 && tmpOffset < INT_MAX / 2)
184,886✔
1248
      tmpOffset = tmpOffset * 2;
184,886✔
1249
    else
1250
      tmpOffset = 0;
×
1251

1252
    if (tmpSize > 0 && tmpSize < INT_MAX / 2)
184,886✔
1253
      tmpSize = tmpSize * 2;
184,886✔
1254
    else
1255
      tmpSize = 0;
×
1256

1257
    /* Write the answer into the working arrays on the SHPHandle */
1258
    psSHP->panRecOffset[shxBufferPage * SHX_BUFFER_PAGE + i] = tmpOffset;
184,886✔
1259
    psSHP->panRecSize[shxBufferPage * SHX_BUFFER_PAGE + i] = tmpSize;
184,886✔
1260
  }
1261

1262
  msSetBit(psSHP->panRecLoaded, shxBufferPage, 1);
1,890✔
1263

1264
  return (MS_SUCCESS);
1,890✔
1265
}
1266

1267
static int msSHXLoadAll(SHPHandle psSHP) {
1✔
1268

1269
  int i;
1270
  uchar *pabyBuf;
1271

1272
  pabyBuf = (uchar *)malloc(8 * psSHP->nRecords);
1✔
1273
  if (pabyBuf == NULL) {
1✔
1274
    msSetError(MS_IOERR, "failed to allocate memory for SHX buffer",
×
1275
               "msSHXLoadAll()");
1276
    return MS_FAILURE;
×
1277
  }
1278
  if ((size_t)psSHP->nRecords !=
1✔
1279
      VSIFReadL(pabyBuf, 8, psSHP->nRecords, psSHP->fpSHX)) {
1✔
1280
    msSetError(MS_IOERR, "failed to read shx records", "msSHXLoadAll()");
×
1281
    free(pabyBuf);
×
1282
    return MS_FAILURE;
×
1283
  }
1284
  for (i = 0; i < psSHP->nRecords; i++) {
1✔
1285
    ms_int32 nOffset, nLength;
1286

1287
    memcpy(&nOffset, pabyBuf + i * 8, 4);
×
1288
    memcpy(&nLength, pabyBuf + i * 8 + 4, 4);
×
1289

1290
    if (!bBigEndian) {
1291
      nOffset = SWAP_FOUR_BYTES(nOffset);
×
1292
      nLength = SWAP_FOUR_BYTES(nLength);
×
1293
    }
1294

1295
    /* SHX stores the offsets in 2 byte units, so we double them to get */
1296
    /* an offset in bytes. */
1297
    if (nOffset > 0 && nOffset < INT_MAX / 2)
×
1298
      nOffset = nOffset * 2;
×
1299
    else
1300
      nOffset = 0;
×
1301

1302
    if (nLength > 0 && nLength < INT_MAX / 2)
×
1303
      nLength = nLength * 2;
×
1304
    else
1305
      nLength = 0;
×
1306

1307
    psSHP->panRecOffset[i] = nOffset;
×
1308
    psSHP->panRecSize[i] = nLength;
×
1309
  }
1310
  free(pabyBuf);
1✔
1311
  psSHP->panRecAllLoaded = 1;
1✔
1312

1313
  return (MS_SUCCESS);
1✔
1314
}
1315

1316
static int msSHXReadOffset(SHPHandle psSHP, int hEntity) {
190,854✔
1317

1318
  int shxBufferPage = hEntity / SHX_BUFFER_PAGE;
190,854✔
1319

1320
  /*  Validate the record/entity number. */
1321
  if (hEntity < 0 || hEntity >= psSHP->nRecords)
190,854✔
1322
    return 0;
1323

1324
  if (!(psSHP->panRecAllLoaded ||
381,708✔
1325
        msGetBit(psSHP->panRecLoaded, shxBufferPage))) {
190,854✔
1326
    msSHXLoadPage(psSHP, shxBufferPage);
×
1327
  }
1328

1329
  return psSHP->panRecOffset[hEntity];
190,854✔
1330
}
1331

1332
static int msSHXReadSize(SHPHandle psSHP, int hEntity) {
222,777✔
1333

1334
  int shxBufferPage = hEntity / SHX_BUFFER_PAGE;
222,777✔
1335

1336
  /*  Validate the record/entity number. */
1337
  if (hEntity < 0 || hEntity >= psSHP->nRecords)
222,777✔
1338
    return 0;
1339

1340
  if (!(psSHP->panRecAllLoaded ||
445,554✔
1341
        msGetBit(psSHP->panRecLoaded, shxBufferPage))) {
222,777✔
1342
    msSHXLoadPage(psSHP, shxBufferPage);
1,890✔
1343
  }
1344

1345
  return psSHP->panRecSize[hEntity];
222,777✔
1346
}
1347

1348
static void ReadRect(rectObj *r, const uchar *src) {
23,403✔
1349
  memcpy(&r->minx, src, 8);
23,403✔
1350
  memcpy(&r->miny, src + 8, 8);
23,403✔
1351
  memcpy(&r->maxx, src + 16, 8);
23,403✔
1352
  memcpy(&r->maxy, src + 24, 8);
23,403✔
1353

1354
  if (bBigEndian) {
1355
    SwapWord(8, &r->minx);
1356
    SwapWord(8, &r->miny);
1357
    SwapWord(8, &r->maxx);
1358
    SwapWord(8, &r->maxy);
1359
  }
1360
}
23,403✔
1361

1362
/*
1363
** msSHPReadShape() - Reads the vertices for one shape from a shape file.
1364
*/
1365
void msSHPReadShape(SHPHandle psSHP, int hEntity, shapeObj *shape) {
31,923✔
1366
  int i, j, k;
1367
  int nEntitySize, nRequiredSize;
1368

1369
  msInitShape(shape); /* initialize the shape */
31,923✔
1370

1371
  /* -------------------------------------------------------------------- */
1372
  /*      Validate the record/entity number.                              */
1373
  /* -------------------------------------------------------------------- */
1374
  if (hEntity < 0 || hEntity >= psSHP->nRecords)
31,923✔
1375
    return;
1376

1377
  nEntitySize = msSHXReadSize(psSHP, hEntity);
31,923✔
1378
  if (nEntitySize < 4 || nEntitySize > INT_MAX - 8) {
31,923✔
1379
    shape->type = MS_SHAPE_NULL;
×
1380
    msSetError(MS_SHPERR,
×
1381
               "Corrupted feature encountered.  hEntity = %d, nEntitySize=%d",
1382
               "msSHPReadShape()", hEntity, nEntitySize);
1383
    return;
×
1384
  }
1385

1386
  nEntitySize += 8;
31,923✔
1387
  if (nEntitySize == 12) {
31,923✔
1388
    shape->type = MS_SHAPE_NULL;
×
1389
    return;
×
1390
  }
1391

1392
  uchar *pabyRec = msSHPReadAllocateBuffer(psSHP, hEntity, "msSHPReadShape()");
31,923✔
1393
  if (pabyRec == NULL) {
31,923✔
1394
    shape->type = MS_SHAPE_NULL;
×
1395
    return;
×
1396
  }
1397

1398
  /* -------------------------------------------------------------------- */
1399
  /*      Read the record.                                                */
1400
  /* -------------------------------------------------------------------- */
1401
  const int offset = msSHXReadOffset(psSHP, hEntity);
31,923✔
1402
  if (offset <= 0 || 0 != VSIFSeekL(psSHP->fpSHP, offset, 0)) {
31,923✔
1403
    msSetError(MS_IOERR, "failed to seek offset", "msSHPReadShape()");
×
1404
    shape->type = MS_SHAPE_NULL;
×
1405
    return;
×
1406
  }
1407
  if (1 != VSIFReadL(pabyRec, nEntitySize, 1, psSHP->fpSHP)) {
31,923✔
1408
    msSetError(MS_IOERR, "failed to fread record", "msSHPReadPoint()");
×
1409
    shape->type = MS_SHAPE_NULL;
×
1410
    return;
×
1411
  }
1412

1413
  /* -------------------------------------------------------------------- */
1414
  /*  Extract vertices for a Polygon or Arc.            */
1415
  /* -------------------------------------------------------------------- */
1416
  if (psSHP->nShapeType == SHP_POLYGON || psSHP->nShapeType == SHP_ARC ||
31,923✔
1417
      psSHP->nShapeType == SHP_POLYGONM || psSHP->nShapeType == SHP_ARCM ||
1418
      psSHP->nShapeType == SHP_POLYGONZ || psSHP->nShapeType == SHP_ARCZ) {
23,366✔
1419
    ms_int32 nPoints, nParts;
1420

1421
    if (nEntitySize < 40 + 8 + 4) {
23,366✔
1422
      shape->type = MS_SHAPE_NULL;
×
1423
      msSetError(MS_SHPERR,
×
1424
                 "Corrupted feature encountered.  hEntity = %d, nEntitySize=%d",
1425
                 "msSHPReadShape()", hEntity, nEntitySize);
1426
      return;
×
1427
    }
1428

1429
    /* copy the bounding box */
1430
    ReadRect(&shape->bounds, pabyRec + 8 + 4);
23,366✔
1431

1432
    memcpy(&nPoints, pabyRec + 40 + 8, 4);
1433
    memcpy(&nParts, pabyRec + 36 + 8, 4);
1434

1435
    if (bBigEndian) {
1436
      nPoints = SWAP_FOUR_BYTES(nPoints);
1437
      nParts = SWAP_FOUR_BYTES(nParts);
1438
    }
1439

1440
    if (nPoints < 0 || nParts < 0 || nPoints > 50 * 1000 * 1000 ||
23,366✔
1441
        nParts > 10 * 1000 * 1000) {
1442
      shape->type = MS_SHAPE_NULL;
×
1443
      msSetError(MS_SHPERR,
×
1444
                 "Corrupted feature encountered.  hEntity = %d, nPoints =%d, "
1445
                 "nParts = %d",
1446
                 "msSHPReadShape()", hEntity, nPoints, nParts);
1447
      return;
×
1448
    }
1449

1450
    /* -------------------------------------------------------------------- */
1451
    /*      Copy out the part array from the record.                        */
1452
    /* -------------------------------------------------------------------- */
1453

1454
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
1455
    /* when running with libFuzzer, allocate a new buffer for every
1456
       call, to allow AddressSanitizer to detect memory errors */
1457
    free(psSHP->panParts);
1458
    psSHP->panParts = NULL;
1459
    psSHP->nPartMax = 0;
1460
#endif
1461

1462
    if (psSHP->nPartMax < nParts) {
23,366✔
1463
      psSHP->panParts = (int *)SfRealloc(psSHP->panParts, nParts * sizeof(int));
1,470✔
1464
      if (psSHP->panParts == NULL) {
1,470✔
1465
        /* Reallocate previous successful size for following features */
1466
        psSHP->panParts = (int *)msSmallMalloc(psSHP->nPartMax * sizeof(int));
×
1467

1468
        shape->type = MS_SHAPE_NULL;
×
1469
        msSetError(MS_MEMERR,
×
1470
                   "Out of memory. Cannot allocate %d bytes. Probably broken "
1471
                   "shapefile at feature %d",
1472
                   "msSHPReadShape()", (int)(nParts * sizeof(int)), hEntity);
1473
        return;
×
1474
      }
1475
      psSHP->nPartMax = nParts;
1,470✔
1476
    }
1477
    if (psSHP->panParts == NULL) {
23,366✔
1478
      shape->type = MS_SHAPE_NULL;
×
1479
      msSetError(MS_MEMERR, "Out of memory", "msSHPReadShape()");
×
1480
      return;
×
1481
    }
1482

1483
    /* With the previous checks on nPoints and nParts, */
1484
    /* we should not overflow here and after */
1485
    /* since 50 M * (16 + 8 + 8) = 1 600 MB */
1486
    if (44 + 8 + 4 * nParts + 16 * nPoints > nEntitySize) {
23,366✔
1487
      shape->type = MS_SHAPE_NULL;
×
1488
      msSetError(MS_SHPERR,
×
1489
                 "Corrupted .shp file : shape %d, nPoints=%d, nParts=%d.",
1490
                 "msSHPReadShape()", hEntity, nPoints, nParts);
1491
      return;
×
1492
    }
1493

1494
    memcpy(psSHP->panParts, pabyRec + 44 + 8, 4 * nParts);
23,366✔
1495
    if (bBigEndian) {
1496
      for (i = 0; i < nParts; i++) {
1497
        *(psSHP->panParts + i) = SWAP_FOUR_BYTES(*(psSHP->panParts + i));
1498
      }
1499
    }
1500

1501
    /* -------------------------------------------------------------------- */
1502
    /*      Fill the shape structure.                                       */
1503
    /* -------------------------------------------------------------------- */
1504
    shape->line = (lineObj *)malloc(sizeof(lineObj) * nParts);
23,366✔
1505
    MS_CHECK_ALLOC_NO_RET(shape->line, sizeof(lineObj) * nParts);
23,366✔
1506

1507
    shape->numlines = nParts;
23,366✔
1508

1509
    k = 0; /* overall point counter */
1510
    for (i = 0; i < nParts; i++) {
47,212✔
1511
      const ms_int32 end = i == nParts - 1 ? nPoints : psSHP->panParts[i + 1];
23,846✔
1512
      if (psSHP->panParts[i] < 0 || end < 0 || end > nPoints ||
23,846✔
1513
          psSHP->panParts[i] >= end) {
1514
        msSetError(MS_SHPERR,
×
1515
                   "Corrupted .shp file : shape %d, shape->line[%d].start=%d, "
1516
                   "shape->line[%d].end=%d",
1517
                   "msSHPReadShape()", hEntity, i, psSHP->panParts[i], i, end);
1518
        while (--i >= 0)
×
1519
          free(shape->line[i].point);
×
1520
        free(shape->line);
×
1521
        shape->line = NULL;
×
1522
        shape->numlines = 0;
×
1523
        shape->type = MS_SHAPE_NULL;
×
1524
        return;
×
1525
      }
1526

1527
      shape->line[i].numpoints = end - psSHP->panParts[i];
23,846✔
1528
      if ((shape->line[i].point = (pointObj *)malloc(
23,846✔
1529
               sizeof(pointObj) * shape->line[i].numpoints)) == NULL) {
23,846✔
1530
        while (--i >= 0)
×
1531
          free(shape->line[i].point);
×
1532
        free(shape->line);
×
1533
        shape->line = NULL;
×
1534
        shape->numlines = 0;
×
1535
        shape->type = MS_SHAPE_NULL;
×
1536
        msSetError(MS_MEMERR, "Out of memory", "msSHPReadShape()");
×
1537
        return;
×
1538
      }
1539

1540
      /* nOffset = 44 + 8 + 4*nParts; */
1541
      for (j = 0; j < shape->line[i].numpoints; j++) {
7,723,686✔
1542
        memcpy(&(shape->line[i].point[j].x),
7,699,840✔
1543
               pabyRec + 44 + 4 * nParts + 8 + k * 16, 8);
7,699,840✔
1544
        memcpy(&(shape->line[i].point[j].y),
7,699,840✔
1545
               pabyRec + 44 + 4 * nParts + 8 + k * 16 + 8, 8);
7,699,840✔
1546

1547
        if (bBigEndian) {
1548
          SwapWord(8, &(shape->line[i].point[j].x));
1549
          SwapWord(8, &(shape->line[i].point[j].y));
1550
        }
1551

1552
        /* --------------------------------------------------------------------
1553
         */
1554
        /*      Polygon, Arc with Z values. */
1555
        /* --------------------------------------------------------------------
1556
         */
1557
        shape->line[i].point[j].z = 0.0; /* initialize */
7,699,840✔
1558
        if (psSHP->nShapeType == SHP_POLYGONZ ||
7,699,840✔
1559
            psSHP->nShapeType == SHP_ARCZ) {
1560
          const int nOffset = 44 + 8 + (4 * nParts) + (16 * nPoints);
1561
          if (nEntitySize >= nOffset + 16 + 8 * nPoints) {
×
1562
            memcpy(&(shape->line[i].point[j].z), pabyRec + nOffset + 16 + k * 8,
×
1563
                   8);
1564
            if (bBigEndian)
1565
              SwapWord(8, &(shape->line[i].point[j].z));
1566
          }
1567
        }
1568

1569
        /* --------------------------------------------------------------------
1570
         */
1571
        /*      Measured arc and polygon support. */
1572
        /* --------------------------------------------------------------------
1573
         */
1574
        shape->line[i].point[j].m = 0; /* initialize */
7,699,840✔
1575
        if (psSHP->nShapeType == SHP_POLYGONM ||
7,699,840✔
1576
            psSHP->nShapeType == SHP_ARCM) {
1577
          const int nOffset = 44 + 8 + (4 * nParts) + (16 * nPoints);
1578
          if (nEntitySize >= nOffset + 16 + 8 * nPoints) {
×
1579
            memcpy(&(shape->line[i].point[j].m), pabyRec + nOffset + 16 + k * 8,
×
1580
                   8);
1581
            if (bBigEndian)
1582
              SwapWord(8, &(shape->line[i].point[j].m));
1583
          }
1584
        }
1585
        k++;
7,699,840✔
1586
      }
1587
    }
1588

1589
    if (psSHP->nShapeType == SHP_POLYGON || psSHP->nShapeType == SHP_POLYGONZ ||
23,366✔
1590
        psSHP->nShapeType == SHP_POLYGONM)
1591
      shape->type = MS_SHAPE_POLYGON;
16,160✔
1592
    else
1593
      shape->type = MS_SHAPE_LINE;
7,206✔
1594

1595
  }
1596

1597
  /* -------------------------------------------------------------------- */
1598
  /*  Extract a MultiPoint.                                               */
1599
  /* -------------------------------------------------------------------- */
1600
  else if (psSHP->nShapeType == SHP_MULTIPOINT ||
1601
           psSHP->nShapeType == SHP_MULTIPOINTM ||
1602
           psSHP->nShapeType == SHP_MULTIPOINTZ) {
37✔
1603
    ms_int32 nPoints;
1604

1605
    if (nEntitySize < 44 + 4) {
37✔
1606
      shape->type = MS_SHAPE_NULL;
×
1607
      msSetError(MS_SHPERR,
×
1608
                 "Corrupted feature encountered.  recSize of feature %d=%d",
1609
                 "msSHPReadShape()", hEntity, msSHXReadSize(psSHP, hEntity));
1610
      return;
×
1611
    }
1612

1613
    /* copy the bounding box */
1614
    ReadRect(&shape->bounds, pabyRec + 8 + 4);
37✔
1615

1616
    memcpy(&nPoints, pabyRec + 44, 4);
1617
    if (bBigEndian)
1618
      nPoints = SWAP_FOUR_BYTES(nPoints);
1619

1620
    /* -------------------------------------------------------------------- */
1621
    /*      Fill the shape structure.                                       */
1622
    /* -------------------------------------------------------------------- */
1623
    if ((shape->line = (lineObj *)malloc(sizeof(lineObj))) == NULL) {
37✔
1624
      shape->type = MS_SHAPE_NULL;
×
1625
      msSetError(MS_MEMERR, "Out of memory", "msSHPReadShape()");
×
1626
      return;
×
1627
    }
1628

1629
    if (nPoints < 0 || nPoints > 50 * 1000 * 1000) {
37✔
1630
      free(shape->line);
×
1631
      shape->line = NULL;
×
1632
      shape->numlines = 0;
×
1633
      shape->type = MS_SHAPE_NULL;
×
1634
      msSetError(MS_SHPERR, "Corrupted .shp file : shape %d, nPoints=%d.",
×
1635
                 "msSHPReadShape()", hEntity, nPoints);
1636
      return;
×
1637
    }
1638

1639
    nRequiredSize = 48 + nPoints * 16;
37✔
1640
    if (psSHP->nShapeType == SHP_MULTIPOINTZ ||
37✔
1641
        psSHP->nShapeType == SHP_MULTIPOINTM)
1642
      nRequiredSize += 16 + nPoints * 8;
×
1643
    if (nRequiredSize > nEntitySize) {
37✔
1644
      free(shape->line);
×
1645
      shape->line = NULL;
×
1646
      shape->numlines = 0;
×
1647
      shape->type = MS_SHAPE_NULL;
×
1648
      msSetError(
×
1649
          MS_SHPERR,
1650
          "Corrupted .shp file : shape %d : nPoints = %d, nEntitySize = %d",
1651
          "msSHPReadShape()", hEntity, nPoints, nEntitySize);
1652
      return;
×
1653
    }
1654

1655
    shape->numlines = 1;
37✔
1656
    shape->line[0].numpoints = nPoints;
37✔
1657
    shape->line[0].point = (pointObj *)malloc(nPoints * sizeof(pointObj));
37✔
1658
    if (shape->line[0].point == NULL) {
37✔
1659
      free(shape->line);
×
1660
      shape->line = NULL;
×
1661
      shape->numlines = 0;
×
1662
      shape->type = MS_SHAPE_NULL;
×
1663
      msSetError(MS_MEMERR, "Out of memory", "msSHPReadShape()");
×
1664
      return;
×
1665
    }
1666

1667
    for (i = 0; i < nPoints; i++) {
111✔
1668
      memcpy(&(shape->line[0].point[i].x), pabyRec + 48 + 16 * i, 8);
74✔
1669
      memcpy(&(shape->line[0].point[i].y), pabyRec + 48 + 16 * i + 8, 8);
74✔
1670

1671
      if (bBigEndian) {
1672
        SwapWord(8, &(shape->line[0].point[i].x));
1673
        SwapWord(8, &(shape->line[0].point[i].y));
1674
      }
1675

1676
      /* -------------------------------------------------------------------- */
1677
      /*      MulipointZ                                                      */
1678
      /* -------------------------------------------------------------------- */
1679
      shape->line[0].point[i].z = 0; /* initialize */
74✔
1680
      if (psSHP->nShapeType == SHP_MULTIPOINTZ) {
74✔
1681
        const int nOffset = 48 + 16 * nPoints;
1682
        memcpy(&(shape->line[0].point[i].z), pabyRec + nOffset + 16 + i * 8, 8);
×
1683
        if (bBigEndian)
1684
          SwapWord(8, &(shape->line[0].point[i].z));
1685
      }
1686

1687
      /* -------------------------------------------------------------------- */
1688
      /*      Measured shape : multipont.                                     */
1689
      /* -------------------------------------------------------------------- */
1690
      shape->line[0].point[i].m = 0; /* initialize */
74✔
1691
      if (psSHP->nShapeType == SHP_MULTIPOINTM) {
74✔
1692
        const int nOffset = 48 + 16 * nPoints;
1693
        memcpy(&(shape->line[0].point[i].m), pabyRec + nOffset + 16 + i * 8, 8);
×
1694
        if (bBigEndian)
1695
          SwapWord(8, &(shape->line[0].point[i].m));
1696
      }
1697
    }
1698

1699
    shape->type = MS_SHAPE_POINT;
37✔
1700
  }
1701

1702
  /* -------------------------------------------------------------------- */
1703
  /*  Extract a Point.                            */
1704
  /* -------------------------------------------------------------------- */
1705
  else if (psSHP->nShapeType == SHP_POINT || psSHP->nShapeType == SHP_POINTM ||
1706
           psSHP->nShapeType == SHP_POINTZ) {
1707

1708
    if (nEntitySize < 20 + 8) {
8,520✔
1709
      shape->type = MS_SHAPE_NULL;
×
1710
      msSetError(MS_SHPERR,
×
1711
                 "Corrupted feature encountered.  recSize of feature %d=%d",
1712
                 "msSHPReadShape()", hEntity, msSHXReadSize(psSHP, hEntity));
1713
      return;
×
1714
    }
1715

1716
    /* -------------------------------------------------------------------- */
1717
    /*      Fill the shape structure.                                       */
1718
    /* -------------------------------------------------------------------- */
1719
    shape->line = (lineObj *)malloc(sizeof(lineObj));
8,520✔
1720
    MS_CHECK_ALLOC_NO_RET(shape->line, sizeof(lineObj));
8,520✔
1721

1722
    shape->numlines = 1;
8,520✔
1723
    shape->line[0].numpoints = 1;
8,520✔
1724
    shape->line[0].point = (pointObj *)msSmallMalloc(sizeof(pointObj));
8,520✔
1725

1726
    memcpy(&(shape->line[0].point[0].x), pabyRec + 12, 8);
8,520✔
1727
    memcpy(&(shape->line[0].point[0].y), pabyRec + 20, 8);
8,520✔
1728

1729
    if (bBigEndian) {
1730
      SwapWord(8, &(shape->line[0].point[0].x));
1731
      SwapWord(8, &(shape->line[0].point[0].y));
1732
    }
1733

1734
    /* -------------------------------------------------------------------- */
1735
    /*      PointZ                                                          */
1736
    /* -------------------------------------------------------------------- */
1737
    shape->line[0].point[0].z = 0; /* initialize */
8,520✔
1738
    if (psSHP->nShapeType == SHP_POINTZ) {
8,520✔
1739
      const int nOffset = 20 + 8;
1740
      if (nEntitySize >= nOffset + 8) {
×
1741
        memcpy(&(shape->line[0].point[0].z), pabyRec + nOffset, 8);
×
1742
        if (bBigEndian)
1743
          SwapWord(8, &(shape->line[0].point[0].z));
1744
      }
1745
    }
1746

1747
    /* -------------------------------------------------------------------- */
1748
    /*      Measured support : point.                                       */
1749
    /* -------------------------------------------------------------------- */
1750
    shape->line[0].point[0].m = 0; /* initialize */
8,520✔
1751
    if (psSHP->nShapeType == SHP_POINTM) {
8,520✔
1752
      const int nOffset = 20 + 8;
1753
      if (nEntitySize >= nOffset + 8) {
×
1754
        memcpy(&(shape->line[0].point[0].m), pabyRec + nOffset, 8);
×
1755
        if (bBigEndian)
1756
          SwapWord(8, &(shape->line[0].point[0].m));
1757
      }
1758
    }
1759

1760
    /* set the bounding box to the point */
1761
    shape->bounds.minx = shape->bounds.maxx = shape->line[0].point[0].x;
8,520✔
1762
    shape->bounds.miny = shape->bounds.maxy = shape->line[0].point[0].y;
8,520✔
1763

1764
    shape->type = MS_SHAPE_POINT;
8,520✔
1765
  }
1766

1767
  shape->index = hEntity;
31,923✔
1768

1769
  return;
31,923✔
1770
}
1771

1772
int msSHPReadBounds(SHPHandle psSHP, int hEntity, rectObj *padBounds) {
161,868✔
1773
  /* -------------------------------------------------------------------- */
1774
  /*      Validate the record/entity number.                              */
1775
  /* -------------------------------------------------------------------- */
1776
  if (psSHP->nRecords <= 0 || hEntity < -1 || hEntity >= psSHP->nRecords) {
161,868✔
1777
    padBounds->minx = padBounds->miny = padBounds->maxx = padBounds->maxy = 0.0;
2✔
1778
    return MS_FAILURE;
2✔
1779
  }
1780

1781
  /* -------------------------------------------------------------------- */
1782
  /*  If the entity is -1 we fetch the bounds for the whole file.   */
1783
  /* -------------------------------------------------------------------- */
1784
  if (hEntity == -1) {
161,866✔
1785
    padBounds->minx = psSHP->adBoundsMin[0];
2,935✔
1786
    padBounds->miny = psSHP->adBoundsMin[1];
2,935✔
1787
    padBounds->maxx = psSHP->adBoundsMax[0];
2,935✔
1788
    padBounds->maxy = psSHP->adBoundsMax[1];
2,935✔
1789
  } else {
1790

1791
    if (msSHXReadSize(psSHP, hEntity) <= 4) { /* NULL shape */
158,931✔
1792
      padBounds->minx = padBounds->miny = padBounds->maxx = padBounds->maxy =
×
1793
          0.0;
1794
      return MS_FAILURE;
×
1795
    }
1796

1797
    const int offset = msSHXReadOffset(psSHP, hEntity);
158,931✔
1798
    if (offset <= 0 || offset >= INT_MAX - 12 ||
317,862✔
1799
        0 != VSIFSeekL(psSHP->fpSHP, offset + 12, 0)) {
158,931✔
1800
      msSetError(MS_IOERR, "failed to seek offset", "msSHPReadBounds()");
×
1801
      return (MS_FAILURE);
×
1802
    }
1803

1804
    if (psSHP->nShapeType != SHP_POINT && psSHP->nShapeType != SHP_POINTZ &&
158,931✔
1805
        psSHP->nShapeType != SHP_POINTM) {
1806
      if (1 != VSIFReadL(padBounds, sizeof(double) * 4, 1, psSHP->fpSHP)) {
9,257✔
1807
        msSetError(MS_IOERR, "failed to fread record", "msSHPReadBounds()");
×
1808
        return (MS_FAILURE);
×
1809
      }
1810

1811
      if (bBigEndian) {
1812
        SwapWord(8, &(padBounds->minx));
1813
        SwapWord(8, &(padBounds->miny));
1814
        SwapWord(8, &(padBounds->maxx));
1815
        SwapWord(8, &(padBounds->maxy));
1816
      }
1817

1818
      if (msIsNan(padBounds->minx)) { /* empty shape */
9,257✔
1819
        padBounds->minx = padBounds->miny = padBounds->maxx = padBounds->maxy =
×
1820
            0.0;
1821
        return MS_FAILURE;
×
1822
      }
1823
    } else {
1824
      /* -------------------------------------------------------------------- */
1825
      /*      For points we fetch the point, and duplicate it as the          */
1826
      /*      minimum and maximum bound.                                      */
1827
      /* -------------------------------------------------------------------- */
1828
      if (1 != VSIFReadL(padBounds, sizeof(double) * 2, 1, psSHP->fpSHP)) {
149,674✔
1829
        msSetError(MS_IOERR, "failed to fread record", "msSHPReadBounds()");
×
1830
        return (MS_FAILURE);
×
1831
      }
1832

1833
      if (bBigEndian) {
1834
        SwapWord(8, &(padBounds->minx));
1835
        SwapWord(8, &(padBounds->miny));
1836
      }
1837

1838
      padBounds->maxx = padBounds->minx;
149,674✔
1839
      padBounds->maxy = padBounds->miny;
149,674✔
1840
    }
1841
  }
1842

1843
  return MS_SUCCESS;
1844
}
1845

1846
int msShapefileOpenHandle(shapefileObj *shpfile, const char *filename,
2,935✔
1847
                          SHPHandle hSHP, DBFHandle hDBF) {
1848
  assert(filename != NULL);
1849
  assert(hSHP != NULL);
1850
  assert(hDBF != NULL);
1851

1852
  /* initialize a few things */
1853
  shpfile->status = NULL;
2,935✔
1854
  shpfile->lastshape = -1;
2,935✔
1855
  shpfile->isopen = MS_FALSE;
2,935✔
1856

1857
  shpfile->hSHP = hSHP;
2,935✔
1858

1859
  strlcpy(shpfile->source, filename, sizeof(shpfile->source));
2,935✔
1860

1861
  /* load some information about this shapefile */
1862
  msSHPGetInfo(shpfile->hSHP, &shpfile->numshapes, &shpfile->type);
2,935✔
1863

1864
  if (shpfile->numshapes < 0 || shpfile->numshapes > 256000000) {
2,935✔
1865
    msSetError(MS_SHPERR, "Corrupted .shp file : numshapes = %d.",
×
1866
               "msShapefileOpen()", shpfile->numshapes);
1867
    msDBFClose(hDBF);
×
1868
    msSHPClose(hSHP);
×
1869
    return -1;
×
1870
  }
1871

1872
  msSHPReadBounds(shpfile->hSHP, -1, &(shpfile->bounds));
2,935✔
1873

1874
  shpfile->hDBF = hDBF;
2,935✔
1875

1876
  shpfile->isopen = MS_TRUE;
2,935✔
1877
  return (0); /* all o.k. */
2,935✔
1878
}
1879

1880
int msShapefileOpenVirtualFile(shapefileObj *shpfile, const char *filename,
×
1881
                               VSILFILE *fpSHP, VSILFILE *fpSHX,
1882
                               VSILFILE *fpDBF, int log_failures) {
1883
  assert(filename != NULL);
1884
  assert(fpSHP != NULL);
1885
  assert(fpSHX != NULL);
1886
  assert(fpDBF != NULL);
1887

1888
  /* open the shapefile file (appending ok) and get basic info */
1889
  SHPHandle hSHP = msSHPOpenVirtualFile(fpSHP, fpSHX);
×
1890
  if (!hSHP) {
×
1891
    if (log_failures)
×
1892
      msSetError(MS_IOERR, "(%s)", "msShapefileOpen()", filename);
×
1893
    VSIFCloseL(fpDBF);
×
1894
    return (-1);
×
1895
  }
1896

1897
  DBFHandle hDBF = msDBFOpenVirtualFile(fpDBF);
×
1898

1899
  if (!hDBF) {
×
1900
    if (log_failures)
×
1901
      msSetError(MS_IOERR, "(%s)", "msShapefileOpen()", filename);
×
1902
    msSHPClose(hSHP);
×
1903
    return (-1);
×
1904
  }
1905

1906
  return msShapefileOpenHandle(shpfile, filename, hSHP, hDBF);
×
1907
}
1908

1909
int msShapefileOpen(shapefileObj *shpfile, const char *mode,
2,955✔
1910
                    const char *filename, int log_failures) {
1911
  int i;
1912
  char *dbfFilename;
1913
  size_t bufferSize = 0;
1914

1915
  if (!filename) {
2,955✔
1916
    if (log_failures)
2✔
1917
      msSetError(MS_IOERR, "No (NULL) filename provided.", "msShapefileOpen()");
2✔
1918
    return (-1);
2✔
1919
  }
1920

1921
  /* open the shapefile file (appending ok) and get basic info */
1922
  SHPHandle hSHP;
1923
  if (!mode)
2,953✔
1924
    hSHP = msSHPOpen(filename, "rb");
×
1925
  else
1926
    hSHP = msSHPOpen(filename, mode);
2,953✔
1927

1928
  if (!hSHP) {
2,953✔
1929
    if (log_failures)
18✔
1930
      msSetError(MS_IOERR, "(%s)", "msShapefileOpen()", filename);
18✔
1931
    return (-1);
18✔
1932
  }
1933

1934
  bufferSize = strlen(filename) + 5;
2,935✔
1935
  dbfFilename = (char *)msSmallMalloc(bufferSize);
2,935✔
1936
  strcpy(dbfFilename, filename);
1937

1938
  /* clean off any extension the filename might have */
1939
  for (i = strlen(dbfFilename) - 1;
2,935✔
1940
       i > 0 && dbfFilename[i] != '.' && dbfFilename[i] != '/' &&
22,583✔
1941
       dbfFilename[i] != '\\';
1942
       i--) {
19,648✔
1943
  }
1944

1945
  if (dbfFilename[i] == '.')
2,935✔
1946
    dbfFilename[i] = '\0';
560✔
1947

1948
  strlcat(dbfFilename, ".dbf", bufferSize);
1949

1950
  DBFHandle hDBF = msDBFOpen(dbfFilename, "rb");
2,935✔
1951

1952
  if (!hDBF) {
2,935✔
1953
    if (log_failures)
×
1954
      msSetError(MS_IOERR, "(%s)", "msShapefileOpen()", dbfFilename);
×
1955
    free(dbfFilename);
×
1956
    msSHPClose(hSHP);
×
1957
    return (-1);
×
1958
  }
1959
  free(dbfFilename);
2,935✔
1960

1961
  return msShapefileOpenHandle(shpfile, filename, hSHP, hDBF);
2,935✔
1962
}
1963

1964
/* Creates a new shapefile */
1965
int msShapefileCreate(shapefileObj *shpfile, char *filename, int type) {
2✔
1966
  if (type != SHP_POINT && type != SHP_MULTIPOINT && type != SHP_ARC &&
2✔
1967
      type != SHP_POLYGON && type != SHP_POINTM && type != SHP_MULTIPOINTM &&
1✔
1968
      type != SHP_ARCM && type != SHP_POLYGONM && type != SHP_POINTZ &&
×
1969
      type != SHP_MULTIPOINTZ && type != SHP_ARCZ && type != SHP_POLYGONZ) {
×
1970
    msSetError(MS_SHPERR, "Invalid shape type.", "msNewSHPFile()");
×
1971
    return (-1);
×
1972
  }
1973

1974
  /* create the spatial portion */
1975
  shpfile->hSHP = msSHPCreate(filename, type);
2✔
1976
  if (!shpfile->hSHP) {
2✔
1977
    msSetError(MS_IOERR, "(%s)", "msNewSHPFile()", filename);
×
1978
    return (-1);
×
1979
  }
1980

1981
  /* retrieve a few things about this shapefile */
1982
  msSHPGetInfo(shpfile->hSHP, &shpfile->numshapes, &shpfile->type);
2✔
1983
  msSHPReadBounds(shpfile->hSHP, -1, &(shpfile->bounds));
2✔
1984

1985
  /* initialize a few other things */
1986
  shpfile->status = NULL;
2✔
1987
  shpfile->lastshape = -1;
2✔
1988
  shpfile->isopen = MS_TRUE;
2✔
1989

1990
  shpfile->hDBF = NULL; /* XBase file is NOT created here... */
2✔
1991
  return (0);
2✔
1992
}
1993

1994
void msShapefileClose(shapefileObj *shpfile) {
2,939✔
1995
  if (shpfile && shpfile->isopen == MS_TRUE) { /* Silently return if called with
2,939✔
1996
                                                  NULL shpfile by freeLayer() */
1997
    if (shpfile->hSHP)
2,937✔
1998
      msSHPClose(shpfile->hSHP);
2,937✔
1999
    if (shpfile->hDBF)
2,937✔
2000
      msDBFClose(shpfile->hDBF);
2,935✔
2001
    free(shpfile->status);
2,937✔
2002
    shpfile->isopen = MS_FALSE;
2,937✔
2003
  }
2004
}
2,939✔
2005

2006
/* status array lives in the shpfile, can return MS_SUCCESS/MS_FAILURE/MS_DONE
2007
 */
2008
int msShapefileWhichShapes(shapefileObj *shpfile, rectObj rect, int debug) {
1,793✔
2009
  int i;
2010
  rectObj shaperect;
2011
  char *filename;
2012

2013
  free(shpfile->status);
1,793✔
2014
  shpfile->status = NULL;
1,793✔
2015

2016
  /* rect and shapefile DON'T overlap... */
2017
  if (msRectOverlap(&shpfile->bounds, &rect) != MS_TRUE)
1,793✔
2018
    return (MS_DONE);
2019

2020
  if (msRectContained(&shpfile->bounds, &rect) == MS_TRUE) {
1,752✔
2021
    shpfile->status = msAllocBitArray(shpfile->numshapes);
1,218✔
2022
    if (!shpfile->status) {
1,218✔
2023
      msSetError(MS_MEMERR, NULL, "msShapefileWhichShapes()");
×
2024
      return (MS_FAILURE);
×
2025
    }
2026
    msSetAllBits(shpfile->status, shpfile->numshapes, 1);
1,218✔
2027
  } else {
2028

2029
    /* deal with case where sourcename is of the form 'file.shp' */
2030
    char *sourcename =
2031
        msStrdup(shpfile->source); /* shape file source string from map file */
534✔
2032
    char *s = strstr(sourcename, ".shp");
534✔
2033
    if (s)
534✔
2034
      *s = '\0';
283✔
2035
    else {
2036
      s = strstr(sourcename, ".SHP");
251✔
2037
      if (s)
251✔
2038
        *s = '\0';
1✔
2039
    }
2040

2041
    filename =
2042
        (char *)malloc(strlen(sourcename) + strlen(MS_INDEX_EXTENSION) + 1);
534✔
2043
    MS_CHECK_ALLOC(filename,
534✔
2044
                   strlen(sourcename) + strlen(MS_INDEX_EXTENSION) + 1,
2045
                   MS_FAILURE);
2046

2047
    sprintf(filename, "%s%s", sourcename, MS_INDEX_EXTENSION);
2048

2049
    shpfile->status =
534✔
2050
        msSearchDiskTree(filename, rect, debug, shpfile->numshapes);
534✔
2051
    free(filename);
534✔
2052
    free(sourcename);
534✔
2053

2054
    if (shpfile->status) { /* index  */
534✔
2055
      msFilterTreeSearch(shpfile, shpfile->status, rect);
43✔
2056
    } else { /* no index  */
2057
      shpfile->status = msAllocBitArray(shpfile->numshapes);
491✔
2058
      if (!shpfile->status) {
491✔
2059
        msSetError(MS_MEMERR, NULL, "msShapefileWhichShapes()");
×
2060
        return (MS_FAILURE);
×
2061
      }
2062

2063
      for (i = 0; i < shpfile->numshapes; i++) {
159,298✔
2064
        if (msSHPReadBounds(shpfile->hSHP, i, &shaperect) != MS_SUCCESS) {
158,807✔
2065
          if (msSHXReadSize(shpfile->hSHP, i) == 4) { /* handle NULL shape */
×
2066
            continue;
×
2067
          }
2068
          return (MS_FAILURE);
2069
        }
2070

2071
        if (msRectOverlap(&shaperect, &rect) == MS_TRUE)
158,807✔
2072
          msSetBit(shpfile->status, i, 1);
7,015✔
2073
      }
2074
    }
2075
  }
2076

2077
  shpfile->lastshape = -1;
1,752✔
2078

2079
  return (MS_SUCCESS); /* success */
1,752✔
2080
}
2081

2082
/* Return the absolute path to the given layer's tileindex file's directory */
2083
void msTileIndexAbsoluteDir(char *tiFileAbsDir, layerObj *layer) {
15✔
2084
  char tiFileAbsPath[MS_MAXPATHLEN];
2085
  char *tiFileAbsDirTmp = NULL;
2086

2087
  msBuildPath(tiFileAbsPath, layer->map->mappath,
15✔
2088
              layer->tileindex); /* absolute path to tileindex file */
15✔
2089
  tiFileAbsDirTmp = msGetPath(tiFileAbsPath); /* tileindex file's directory */
15✔
2090
  strlcpy(tiFileAbsDir, tiFileAbsDirTmp, MS_MAXPATHLEN);
2091
  free(tiFileAbsDirTmp);
15✔
2092
}
15✔
2093

2094
/*
2095
** Build possible paths we might find the tile file at:
2096
**   map dir + shape path + filename?
2097
**   tile dir + shape path + filename?
2098
**   map dir + filename?
2099
**
2100
** Returns
2101
** MS_SUCCESS - found a file
2102
** MS_FAILURE - no file, and map is configured to fail on missing
2103
** MS_DONE - no file, and map is configured to continue on missing
2104
*/
2105
static int msTiledSHPTryOpen(shapefileObj *shpfile, layerObj *layer,
8✔
2106
                             char *tiFileAbsDir, const char *filename) {
2107
  char szPath[MS_MAXPATHLEN];
2108
  int ignore_missing = msMapIgnoreMissingData(layer->map);
8✔
2109
  int log_failures = MS_TRUE;
2110

2111
  if (ignore_missing == MS_MISSING_DATA_IGNORE)
8✔
2112
    log_failures = MS_FALSE;
2113

2114
  if (msShapefileOpen(shpfile, "rb",
8✔
2115
                      msBuildPath3(szPath, layer->map->mappath,
8✔
2116
                                   layer->map->shapepath, filename),
8✔
2117
                      log_failures) == -1) {
2118
    if (msShapefileOpen(
×
2119
            shpfile, "rb",
2120
            msBuildPath3(szPath, tiFileAbsDir, layer->map->shapepath, filename),
×
2121
            log_failures) == -1) {
2122
      if (msShapefileOpen(shpfile, "rb",
×
2123
                          msBuildPath(szPath, layer->map->mappath, filename),
×
2124
                          log_failures) == -1) {
2125
        if (ignore_missing == MS_MISSING_DATA_FAIL) {
×
2126
          msSetError(
×
2127
              MS_IOERR,
2128
              "Unable to open shapefile '%s' for layer '%s' ... fatal error.",
2129
              "msTiledSHPTryOpen()", filename, layer->name);
2130
          return (MS_FAILURE);
×
2131
        } else if (ignore_missing == MS_MISSING_DATA_LOG) {
×
2132
          if (layer->debug || layer->map->debug) {
×
2133
            msDebug("Unable to open shapefile '%s' for layer '%s' ... ignoring "
×
2134
                    "this missing data.\n",
2135
                    szPath, layer->name);
2136
          }
2137
          return (MS_DONE);
×
2138
        } else if (ignore_missing == MS_MISSING_DATA_IGNORE) {
×
2139
          return (MS_DONE);
2140
        } else {
2141
          /* never get here */
2142
          msSetError(MS_IOERR, "msIgnoreMissingData returned unexpected value.",
×
2143
                     "msTiledSHPTryOpen()");
2144
          return (MS_FAILURE);
×
2145
        }
2146
      }
2147
    }
2148
  }
2149
  return (MS_SUCCESS);
2150
}
2151

2152
static const char *msTiledSHPLoadEntry(layerObj *layer, int i, char *tilename,
11✔
2153
                                       size_t tilenamesize) {
2154
  const char *filename;
2155
  msTiledSHPLayerInfo *tSHP = layer->layerinfo;
11✔
2156

2157
  msProjectDestroyReprojector(tSHP->reprojectorFromTileProjToLayerProj);
11✔
2158
  tSHP->reprojectorFromTileProjToLayerProj = NULL;
11✔
2159

2160
  msFreeProjection(&(tSHP->sTileProj));
11✔
2161
  if (layer->tilesrs != NULL) {
11✔
2162
    int idx = msDBFGetItemIndex(tSHP->tileshpfile->hDBF, layer->tilesrs);
6✔
2163
    const char *pszWKT =
2164
        msDBFReadStringAttribute(tSHP->tileshpfile->hDBF, i, idx);
6✔
2165
    IGNORE_RET_VAL(
6✔
2166
        msOGCWKT2ProjectionObj(pszWKT, &(tSHP->sTileProj), layer->debug));
2167
  }
2168

2169
  if (!layer->data) /* assume whole filename is in attribute field */
11✔
2170
    filename = msDBFReadStringAttribute(tSHP->tileshpfile->hDBF, i,
11✔
2171
                                        layer->tileitemindex);
2172
  else {
2173
    snprintf(tilename, tilenamesize, "%s/%s",
×
2174
             msDBFReadStringAttribute(tSHP->tileshpfile->hDBF, i,
×
2175
                                      layer->tileitemindex),
2176
             layer->data);
2177
    filename = tilename;
2178
  }
2179

2180
  return filename;
11✔
2181
}
2182

2183
static int msTiledSHPOpenFile(layerObj *layer) {
6✔
2184
  int i;
2185
  const char *filename;
2186
  char tilename[MS_MAXPATHLEN], szPath[MS_MAXPATHLEN];
2187
  char tiFileAbsDir[MS_MAXPATHLEN];
2188

2189
  msTiledSHPLayerInfo *tSHP = NULL;
2190

2191
  if (layer->layerinfo != NULL) {
6✔
2192
    return MS_SUCCESS; // Nothing to do... layer is already opened
2193
  }
2194

2195
  if (msCheckParentPointer(layer->map, "map") == MS_FAILURE)
5✔
2196
    return MS_FAILURE;
2197

2198
  /* allocate space for a shapefileObj using layer->layerinfo  */
2199
  tSHP = (msTiledSHPLayerInfo *)calloc(1, sizeof(msTiledSHPLayerInfo));
5✔
2200
  MS_CHECK_ALLOC(tSHP, sizeof(msTiledSHPLayerInfo), MS_FAILURE);
5✔
2201
  msInitProjection(&(tSHP->sTileProj));
5✔
2202
  msProjectionInheritContextFrom(&(tSHP->sTileProj), &layer->projection);
5✔
2203

2204
  tSHP->shpfile = (shapefileObj *)malloc(sizeof(shapefileObj));
5✔
2205
  if (tSHP->shpfile == NULL) {
5✔
2206
    msSetError(MS_MEMERR, "%s: %d: Out of memory allocating %u bytes.\n",
×
2207
               "msTiledSHPOpenFile()", __FILE__, __LINE__,
2208
               (unsigned int)sizeof(shapefileObj));
2209
    msFreeProjection(&(tSHP->sTileProj));
×
2210
    free(tSHP);
×
2211
    return MS_FAILURE;
×
2212
  }
2213

2214
  tSHP->shpfile->isopen =
5✔
2215
      MS_FALSE; /* in case of error: do not try to close the shpfile */
2216
  tSHP->tileshpfile =
5✔
2217
      NULL; /* may need this if not using a tile layer, look for malloc later */
2218
  layer->layerinfo = tSHP;
5✔
2219

2220
  tSHP->tilelayerindex = msGetLayerIndex(layer->map, layer->tileindex);
5✔
2221
  if (tSHP->tilelayerindex !=
5✔
2222
      -1) { /* does the tileindex reference another layer */
2223
    int status;
2224
    layerObj *tlp;
2225

2226
    tlp = (GET_LAYER(layer->map, tSHP->tilelayerindex));
×
2227

2228
    if (tlp->connectiontype != MS_SHAPEFILE) {
×
2229
      msSetError(MS_SHPERR, "Tileindex layer must be a shapefile.",
×
2230
                 "msTiledSHPOpenFile()");
2231
      return (MS_FAILURE);
×
2232
    }
2233

2234
    status = msLayerOpen(tlp);
×
2235
    if (status != MS_SUCCESS)
×
2236
      return (MS_FAILURE);
2237

2238
    /* build item list */
2239
    status = msLayerWhichItems(tlp, MS_FALSE, NULL);
×
2240
    if (status != MS_SUCCESS)
×
2241
      return (MS_FAILURE);
2242

2243
    tSHP->tileshpfile =
×
2244
        (shapefileObj *)tlp->layerinfo; /* shapefiles use layerinfo to point to
×
2245
                                           a shapefileObj */
2246

2247
  } else { /* or reference a shapefile directly */
2248

2249
    /* we need tSHP->tileshpfile if we're not working with a layer */
2250
    tSHP->tileshpfile = (shapefileObj *)malloc(sizeof(shapefileObj));
5✔
2251
    if (tSHP->tileshpfile == NULL) {
5✔
2252
      msSetError(MS_MEMERR, "%s: %d: Out of memory allocating %u bytes.\n",
×
2253
                 "msTiledSHPOpenFile()", __FILE__, __LINE__,
2254
                 (unsigned int)sizeof(shapefileObj));
2255
      free(tSHP->shpfile);
×
2256
      msFreeProjection(&(tSHP->sTileProj));
×
2257
      free(tSHP);
×
2258
      layer->layerinfo = NULL;
×
2259
      return MS_FAILURE;
×
2260
    }
2261

2262
    if (msShapefileOpen(tSHP->tileshpfile, "rb",
5✔
2263
                        msBuildPath3(szPath, layer->map->mappath,
5✔
2264
                                     layer->map->shapepath, layer->tileindex),
5✔
2265
                        MS_TRUE) == -1)
2266
      if (msShapefileOpen(
×
2267
              tSHP->tileshpfile, "rb",
2268
              msBuildPath(szPath, layer->map->mappath, layer->tileindex),
×
2269
              MS_TRUE) == -1)
2270
        return (MS_FAILURE);
2271
  }
2272

2273
  if ((layer->tileitemindex =
5✔
2274
           msDBFGetItemIndex(tSHP->tileshpfile->hDBF, layer->tileitem)) == -1)
5✔
2275
    return (MS_FAILURE);
2276

2277
  if (layer->tilesrs != NULL &&
7✔
2278
      msDBFGetItemIndex(tSHP->tileshpfile->hDBF, layer->tilesrs) < 0) {
2✔
2279
    msSetError(MS_SHPERR, "Cannot identify TILESRS field.",
×
2280
               "msTiledSHPOpenFile()");
2281
    return MS_FAILURE;
×
2282
  }
2283
  if (layer->tilesrs != NULL && layer->projection.numargs == 0) {
5✔
2284
    msSetError(MS_SHPERR,
×
2285
               "A layer with TILESRS set in TILEINDEX `%s' must have a "
2286
               "projection set on itself.",
2287
               "msOGRLayerOpen()", layer->tileindex);
2288
    return MS_FAILURE;
×
2289
  }
2290

2291
  msTileIndexAbsoluteDir(tiFileAbsDir, layer);
5✔
2292

2293
  /* position the source at the FIRST tile to use as a template, this is so the
2294
   * functions that fill the iteminfo array have something to work from */
2295
  for (i = 0; i < tSHP->tileshpfile->numshapes; i++) {
5✔
2296
    int try_open;
2297

2298
    filename = msTiledSHPLoadEntry(layer, i, tilename, sizeof(tilename));
5✔
2299
    if (strlen(filename) == 0)
5✔
2300
      continue; /* check again */
×
2301

2302
    try_open = msTiledSHPTryOpen(tSHP->shpfile, layer, tiFileAbsDir, filename);
5✔
2303
    if (try_open == MS_DONE)
5✔
2304
      continue;
×
2305
    else if (try_open == MS_FAILURE)
5✔
2306
      return (MS_FAILURE);
2307

2308
    return (MS_SUCCESS); /* found a template, ok to proceed */
2309
  }
2310

2311
  msSetError(MS_SHPERR,
×
2312
             "Unable to open a single tile to use as a template in layer %s.",
2313
             "msTiledSHPOpenFile()", layer->name ? layer->name : "(null)");
×
2314
  return (MS_FAILURE);
×
2315
}
2316

2317
static int msTiledSHPWhichShapes(layerObj *layer, rectObj rect, int isQuery) {
2✔
2318
  int i, status;
2319
  const char *filename;
2320
  char tilename[MS_MAXPATHLEN];
2321
  char tiFileAbsDir[MS_MAXPATHLEN];
2322

2323
  msTiledSHPLayerInfo *tSHP = NULL;
2324

2325
  if (msCheckParentPointer(layer->map, "map") == MS_FAILURE)
2✔
2326
    return MS_FAILURE;
2327

2328
  tSHP = layer->layerinfo;
2✔
2329
  if (!tSHP) {
2✔
2330
    msSetError(MS_SHPERR, "Tiled shapefile layer has not been opened.",
×
2331
               "msTiledSHPWhichShapes()");
2332
    return (MS_FAILURE);
×
2333
  }
2334

2335
  msShapefileClose(tSHP->shpfile); /* close previously opened files */
2✔
2336

2337
  tSHP->searchrect = rect; /* save the search extent */
2✔
2338

2339
  if (tSHP->tilelayerindex !=
2✔
2340
      -1) { /* does the tileindex reference another layer */
2341
    layerObj *tlp;
2342
    shapeObj tshape;
2343

2344
    tlp = (GET_LAYER(layer->map, tSHP->tilelayerindex));
×
2345
    status = msLayerWhichShapes(tlp, rect, isQuery);
×
2346
    if (status != MS_SUCCESS)
×
2347
      return (status); /* could be MS_DONE or MS_FAILURE */
2348

2349
    msTileIndexAbsoluteDir(tiFileAbsDir, layer);
×
2350

2351
    msInitShape(&tshape);
×
2352
    while ((status = msLayerNextShape(tlp, &tshape)) == MS_SUCCESS) {
×
2353
      int try_open;
2354
      rectObj rectTile = rect;
×
2355

2356
      filename =
2357
          msTiledSHPLoadEntry(layer, tshape.index, tilename, sizeof(tilename));
×
2358
      if (strlen(filename) == 0)
×
2359
        continue; /* check again */
×
2360

2361
      try_open =
2362
          msTiledSHPTryOpen(tSHP->shpfile, layer, tiFileAbsDir, filename);
×
2363
      if (try_open == MS_DONE)
×
2364
        continue;
×
2365
      else if (try_open == MS_FAILURE)
×
2366
        return (MS_FAILURE);
×
2367

2368
      if (tSHP->sTileProj.numargs > 0) {
×
2369
        msProjectRect(&(layer->projection), &(tSHP->sTileProj), &rectTile);
×
2370
      }
2371

2372
      status = msShapefileWhichShapes(tSHP->shpfile, rectTile, layer->debug);
×
2373
      if (status == MS_DONE) {
×
2374
        /* Close and continue to next tile */
2375
        msShapefileClose(tSHP->shpfile);
×
2376
        continue;
×
2377
      } else if (status != MS_SUCCESS) {
×
2378
        msShapefileClose(tSHP->shpfile);
×
2379
        return (MS_FAILURE);
×
2380
      }
2381

2382
      /* the layer functions keeps track of this */
2383
      /* tSHP->tileshpfile->lastshape = tshape.index; */
2384
      break;
×
2385
    }
2386
    return (status); /* if we reach here we either 1) ran out of tiles or 2) had
×
2387
                        an error reading a tile */
2388

2389
  } else { /* or reference a shapefile directly */
2390
    int try_open;
2391

2392
    status = msShapefileWhichShapes(tSHP->tileshpfile, rect, layer->debug);
2✔
2393
    if (status != MS_SUCCESS)
2✔
2394
      return (status); /* could be MS_DONE or MS_FAILURE */
2395

2396
    msTileIndexAbsoluteDir(tiFileAbsDir, layer);
2✔
2397

2398
    /* position the source at the FIRST shapefile */
2399
    for (i = 0; i < tSHP->tileshpfile->numshapes; i++) {
2✔
2400
      rectObj rectTile = rect;
2✔
2401
      if (msGetBit(tSHP->tileshpfile->status, i)) {
2✔
2402

2403
        filename = msTiledSHPLoadEntry(layer, i, tilename, sizeof(tilename));
2✔
2404
        if (strlen(filename) == 0)
2✔
2405
          continue; /* check again */
×
2406

2407
        try_open =
2408
            msTiledSHPTryOpen(tSHP->shpfile, layer, tiFileAbsDir, filename);
2✔
2409
        if (try_open == MS_DONE)
2✔
2410
          continue;
×
2411
        else if (try_open == MS_FAILURE)
2✔
2412
          return (MS_FAILURE);
×
2413

2414
        if (tSHP->sTileProj.numargs > 0) {
2✔
2415
          msProjectRect(&(layer->projection), &(tSHP->sTileProj), &rectTile);
1✔
2416
        }
2417

2418
        status = msShapefileWhichShapes(tSHP->shpfile, rectTile, layer->debug);
2✔
2419
        if (status == MS_DONE) {
2✔
2420
          /* Close and continue to next tile */
2421
          msShapefileClose(tSHP->shpfile);
×
2422
          continue;
×
2423
        } else if (status != MS_SUCCESS) {
2✔
2424
          msShapefileClose(tSHP->shpfile);
×
2425
          return (MS_FAILURE);
×
2426
        }
2427

2428
        tSHP->tileshpfile->lastshape = i;
2✔
2429
        break;
2✔
2430
      }
2431
    }
2432

2433
    if (i == tSHP->tileshpfile->numshapes)
2✔
2434
      return (MS_DONE); /* no more tiles */
2435
    else
2436
      return (MS_SUCCESS);
2✔
2437
  }
2438

2439
  return (MS_FAILURE); /* should *never* get here */
2440
}
2441

2442
static int msTiledSHPNextShape(layerObj *layer, shapeObj *shape) {
5✔
2443
  int i, status, filter_passed = MS_FALSE;
2444
  const char *filename;
2445
  char tilename[MS_MAXPATHLEN];
2446
  char tiFileAbsDir[MS_MAXPATHLEN];
2447

2448
  msTiledSHPLayerInfo *tSHP = NULL;
2449

2450
  if (msCheckParentPointer(layer->map, "map") == MS_FAILURE)
5✔
2451
    return MS_FAILURE;
2452

2453
  tSHP = layer->layerinfo;
5✔
2454
  if (!tSHP) {
5✔
2455
    msSetError(MS_SHPERR, "Tiled shapefile layer has not been opened.",
×
2456
               "msTiledSHPNextShape()");
2457
    return (MS_FAILURE);
×
2458
  }
2459

2460
  msTileIndexAbsoluteDir(tiFileAbsDir, layer);
5✔
2461

2462
  do {
2463
    i = tSHP->shpfile->lastshape + 1;
6✔
2464
    while (i < tSHP->shpfile->numshapes && !msGetBit(tSHP->shpfile->status, i))
6✔
2465
      i++; /* next "in" shape */
×
2466

2467
    if (i ==
6✔
2468
        tSHP->shpfile->numshapes) {    /* done with this tile, need a new one */
6✔
2469
      msShapefileClose(tSHP->shpfile); /* clean up */
3✔
2470

2471
      /* position the source to the NEXT shapefile based on the tileindex */
2472
      if (tSHP->tilelayerindex !=
3✔
2473
          -1) { /* does the tileindex reference another layer */
2474
        layerObj *tlp;
2475
        shapeObj tshape;
2476
        int try_open;
2477

2478
        tlp = (GET_LAYER(layer->map, tSHP->tilelayerindex));
×
2479

2480
        msInitShape(&tshape);
×
2481
        while ((status = msLayerNextShape(tlp, &tshape)) == MS_SUCCESS) {
×
2482
          rectObj rectTile = tSHP->searchrect;
×
2483

2484
          filename = msTiledSHPLoadEntry(layer, tshape.index, tilename,
×
2485
                                         sizeof(tilename));
2486
          if (strlen(filename) == 0)
×
2487
            continue; /* check again */
×
2488

2489
          try_open =
2490
              msTiledSHPTryOpen(tSHP->shpfile, layer, tiFileAbsDir, filename);
×
2491
          if (try_open == MS_DONE)
×
2492
            continue;
×
2493
          else if (try_open == MS_FAILURE)
×
2494
            return (MS_FAILURE);
×
2495

2496
          if (tSHP->sTileProj.numargs > 0) {
×
2497
            msProjectRect(&(layer->projection), &(tSHP->sTileProj), &rectTile);
×
2498
          }
2499

2500
          status =
2501
              msShapefileWhichShapes(tSHP->shpfile, rectTile, layer->debug);
×
2502
          if (status == MS_DONE) {
×
2503
            /* Close and continue to next tile */
2504
            msShapefileClose(tSHP->shpfile);
×
2505
            continue;
×
2506
          } else if (status != MS_SUCCESS) {
×
2507
            msShapefileClose(tSHP->shpfile);
×
2508
            tSHP->tileshpfile->lastshape = -1;
×
2509
            return (MS_FAILURE);
×
2510
          }
2511

2512
          /* the layer functions keeps track of this */
2513
          /* tSHP->tileshpfile->lastshape = tshape.index; */
2514
          break;
×
2515
        }
2516

2517
        if (status == MS_DONE) {
×
2518
          tSHP->tileshpfile->lastshape = -1;
×
2519
          return (MS_DONE); /* no more tiles */
×
2520
        } else {
2521
          msFreeShape(&tshape);
×
2522
          continue; /* we've got shapes */
×
2523
        }
2524

2525
      } else { /* or reference a shapefile directly   */
2526

2527
        for (i = (tSHP->tileshpfile->lastshape + 1);
3✔
2528
             i < tSHP->tileshpfile->numshapes; i++) {
4✔
2529
          if (msGetBit(tSHP->tileshpfile->status, i)) {
2✔
2530
            rectObj rectTile = tSHP->searchrect;
1✔
2531
            int try_open;
2532

2533
            filename =
2534
                msTiledSHPLoadEntry(layer, i, tilename, sizeof(tilename));
1✔
2535
            if (strlen(filename) == 0)
1✔
2536
              continue; /* check again */
×
2537

2538
            try_open =
2539
                msTiledSHPTryOpen(tSHP->shpfile, layer, tiFileAbsDir, filename);
1✔
2540
            if (try_open == MS_DONE)
1✔
2541
              continue;
×
2542
            else if (try_open == MS_FAILURE)
1✔
2543
              return (MS_FAILURE);
×
2544

2545
            if (tSHP->sTileProj.numargs > 0) {
1✔
2546
              msProjectRect(&(layer->projection), &(tSHP->sTileProj),
1✔
2547
                            &rectTile);
2548
            }
2549

2550
            status =
2551
                msShapefileWhichShapes(tSHP->shpfile, rectTile, layer->debug);
1✔
2552
            if (status == MS_DONE) {
1✔
2553
              /* Close and continue to next tile */
2554
              msShapefileClose(tSHP->shpfile);
×
2555
              continue;
×
2556
            } else if (status != MS_SUCCESS) {
1✔
2557
              msShapefileClose(tSHP->shpfile);
×
2558
              tSHP->tileshpfile->lastshape = -1;
×
2559
              return (MS_FAILURE);
×
2560
            }
2561

2562
            tSHP->tileshpfile->lastshape = i;
1✔
2563
            break;
1✔
2564
          }
2565
        } /* end for loop */
2566

2567
        if (i == tSHP->tileshpfile->numshapes) {
3✔
2568
          tSHP->tileshpfile->lastshape = -1;
2✔
2569
          return (MS_DONE); /* no more tiles */
2✔
2570
        } else
2571
          continue; /* we've got shapes */
1✔
2572
      }
2573
    }
2574

2575
    tSHP->shpfile->lastshape = i;
3✔
2576

2577
    msSHPReadShape(tSHP->shpfile->hSHP, i, shape);
3✔
2578
    if (shape->type == MS_SHAPE_NULL) {
3✔
2579
      msFreeShape(shape);
×
2580
      continue; /* skip NULL shapes */
×
2581
    }
2582

2583
    if (tSHP->sTileProj.numargs > 0) {
3✔
2584
      if (tSHP->reprojectorFromTileProjToLayerProj == NULL) {
2✔
2585
        tSHP->reprojectorFromTileProjToLayerProj = msProjectCreateReprojector(
2✔
2586
            &(tSHP->sTileProj), &(layer->projection));
2587
      }
2588
      if (tSHP->reprojectorFromTileProjToLayerProj) {
2✔
2589
        msProjectShapeEx(tSHP->reprojectorFromTileProjToLayerProj, shape);
2✔
2590
      }
2591
    }
2592

2593
    shape->tileindex = tSHP->tileshpfile->lastshape;
3✔
2594
    shape->numvalues = layer->numitems;
3✔
2595
    shape->values = msDBFGetValueList(tSHP->shpfile->hDBF, i, layer->iteminfo,
3✔
2596
                                      layer->numitems);
2597
    if (!shape->values)
3✔
2598
      shape->numvalues = 0;
×
2599

2600
    filter_passed = MS_TRUE; /* By default accept ANY shape */
2601
    if (layer->numitems > 0 && layer->iteminfo) {
3✔
2602
      filter_passed = msEvalExpression(layer, shape, &(layer->filter),
3✔
2603
                                       layer->filteritemindex);
2604
    }
2605

2606
    if (!filter_passed)
3✔
2607
      msFreeShape(shape); /* free's values as well */
×
2608

2609
  } while (
2610
      !filter_passed); /* Loop until both spatial and attribute filters match */
4✔
2611

2612
  return (MS_SUCCESS);
2613
}
2614

2615
static int msTiledSHPGetShape(layerObj *layer, shapeObj *shape,
3✔
2616
                              resultObj *record) {
2617
  const char *filename;
2618
  char tilename[MS_MAXPATHLEN], szPath[MS_MAXPATHLEN];
2619

2620
  msTiledSHPLayerInfo *tSHP = NULL;
2621
  char tiFileAbsDir[MS_MAXPATHLEN];
2622

2623
  long shapeindex = record->shapeindex;
3✔
2624
  int tileindex = record->tileindex;
3✔
2625

2626
  if (msCheckParentPointer(layer->map, "map") == MS_FAILURE)
3✔
2627
    return MS_FAILURE;
2628

2629
  tSHP = layer->layerinfo;
3✔
2630
  if (!tSHP) {
3✔
2631
    msSetError(MS_SHPERR, "Tiled shapefile layer has not been opened.",
×
2632
               "msTiledSHPGetShape()");
2633
    return (MS_FAILURE);
×
2634
  }
2635

2636
  msTileIndexAbsoluteDir(tiFileAbsDir, layer);
3✔
2637

2638
  if ((tileindex < 0) || (tileindex >= tSHP->tileshpfile->numshapes))
3✔
2639
    return (MS_FAILURE); /* invalid tile id */
2640

2641
  if (tileindex !=
3✔
2642
      tSHP->tileshpfile->lastshape) { /* correct tile is not currently open so
3✔
2643
                                         open the correct tile */
2644
    msShapefileClose(tSHP->shpfile);  /* close current tile */
3✔
2645

2646
    filename =
2647
        msTiledSHPLoadEntry(layer, tileindex, tilename, sizeof(tilename));
3✔
2648

2649
    /* open the shapefile, since a specific tile was request an error should be
2650
     * generated if that tile does not exist */
2651
    if (strlen(filename) == 0)
3✔
2652
      return (MS_FAILURE);
2653
    if (msShapefileOpen(
3✔
2654
            tSHP->shpfile, "rb",
2655
            msBuildPath3(szPath, tiFileAbsDir, layer->map->shapepath, filename),
3✔
2656
            MS_TRUE) == -1) {
2657
      if (msShapefileOpen(tSHP->shpfile, "rb",
×
2658
                          msBuildPath3(szPath, layer->map->mappath,
×
2659
                                       layer->map->shapepath, filename),
×
2660
                          MS_TRUE) == -1) {
2661
        if (msShapefileOpen(tSHP->shpfile, "rb",
×
2662
                            msBuildPath(szPath, layer->map->mappath, filename),
×
2663
                            MS_TRUE) == -1) {
2664
          return (MS_FAILURE);
2665
        }
2666
      }
2667
    }
2668
  }
2669

2670
  if ((shapeindex < 0) || (shapeindex >= tSHP->shpfile->numshapes))
3✔
2671
    return (MS_FAILURE);
2672

2673
  msSHPReadShape(tSHP->shpfile->hSHP, shapeindex, shape);
3✔
2674
  tSHP->shpfile->lastshape = shapeindex;
3✔
2675
  tSHP->tileshpfile->lastshape = tileindex;
3✔
2676

2677
  if (tSHP->sTileProj.numargs > 0) {
3✔
2678
    if (tSHP->reprojectorFromTileProjToLayerProj == NULL) {
2✔
2679
      tSHP->reprojectorFromTileProjToLayerProj =
2✔
2680
          msProjectCreateReprojector(&(tSHP->sTileProj), &(layer->projection));
2✔
2681
    }
2682
    if (tSHP->reprojectorFromTileProjToLayerProj) {
2✔
2683
      msProjectShapeEx(tSHP->reprojectorFromTileProjToLayerProj, shape);
2✔
2684
    }
2685
  }
2686

2687
  if (layer->numitems > 0 && layer->iteminfo) {
3✔
2688
    shape->numvalues = layer->numitems;
3✔
2689
    shape->values = msDBFGetValueList(tSHP->shpfile->hDBF, shapeindex,
3✔
2690
                                      layer->iteminfo, layer->numitems);
2691
    if (!shape->values)
3✔
2692
      return (MS_FAILURE);
2693
  }
2694

2695
  shape->tileindex = tileindex;
3✔
2696

2697
  return (MS_SUCCESS);
3✔
2698
}
2699

2700
static void msTiledSHPClose(layerObj *layer) {
6✔
2701
  msTiledSHPLayerInfo *tSHP = NULL;
2702

2703
  tSHP = layer->layerinfo;
6✔
2704
  if (tSHP) {
6✔
2705
    msShapefileClose(tSHP->shpfile);
5✔
2706
    free(tSHP->shpfile);
5✔
2707

2708
    if (tSHP->tilelayerindex != -1) {
5✔
2709
      layerObj *tlp;
2710
      if (msCheckParentPointer(layer->map, "map") == MS_FAILURE)
×
2711
        return;
2712
      tlp = (GET_LAYER(layer->map, tSHP->tilelayerindex));
×
2713
      msLayerClose(tlp);
×
2714
    } else {
2715
      msShapefileClose(tSHP->tileshpfile);
5✔
2716
      free(tSHP->tileshpfile);
5✔
2717
    }
2718

2719
    msProjectDestroyReprojector(tSHP->reprojectorFromTileProjToLayerProj);
5✔
2720

2721
    msFreeProjection(&(tSHP->sTileProj));
5✔
2722

2723
    free(tSHP);
5✔
2724
  }
2725
  layer->layerinfo = NULL;
6✔
2726
}
2727
/************************************************************************/
2728
/*                              msTiledSHPClose()                       */
2729
/* Overloaded version of msTiledSHPClose for virtual table architecture */
2730
/************************************************************************/
2731
int msTiledSHPCloseVT(layerObj *layer) {
6✔
2732
  msTiledSHPClose(layer);
6✔
2733
  return MS_SUCCESS;
6✔
2734
}
2735

2736
void msTiledSHPLayerFreeItemInfo(layerObj *layer) {
20✔
2737
  if (layer->iteminfo) {
20✔
2738
    free(layer->iteminfo);
7✔
2739
    layer->iteminfo = NULL;
7✔
2740
  }
2741
}
20✔
2742

2743
int msTiledSHPLayerInitItemInfo(layerObj *layer) {
7✔
2744
  msTiledSHPLayerInfo *tSHP = NULL;
2745

2746
  tSHP = layer->layerinfo;
7✔
2747
  if (!tSHP) {
7✔
2748
    msSetError(MS_SHPERR, "Tiled shapefile layer has not been opened.",
×
2749
               "msTiledSHPLayerInitItemInfo()");
2750
    return MS_FAILURE;
×
2751
  }
2752

2753
  msTiledSHPLayerFreeItemInfo(layer);
7✔
2754
  layer->iteminfo = (int *)msDBFGetItemIndexes(tSHP->shpfile->hDBF,
7✔
2755
                                               layer->items, layer->numitems);
2756
  if (!layer->iteminfo)
7✔
2757
    return (MS_FAILURE);
2758

2759
  return MS_SUCCESS;
2760
}
2761

2762
static void msSHPPassThroughFieldDefinitions(layerObj *layer, DBFHandle hDBF) {
59✔
2763
  int numitems, i;
2764

2765
  numitems = msDBFGetFieldCount(hDBF);
59✔
2766

2767
  for (i = 0; i < numitems; i++) {
497✔
2768
    char item[16];
2769
    int nWidth = 0, nPrecision = 0;
438✔
2770
    char gml_width[32], gml_precision[32];
2771
    DBFFieldType eType;
2772
    const char *gml_type = NULL;
2773

2774
    eType = msDBFGetFieldInfo(hDBF, i, item, &nWidth, &nPrecision);
438✔
2775

2776
    gml_width[0] = '\0';
438✔
2777
    gml_precision[0] = '\0';
438✔
2778

2779
    switch (eType) {
438✔
2780
    case FTInteger:
299✔
2781
      gml_type = "Integer";
2782
      sprintf(gml_width, "%d", nWidth);
299✔
2783
      break;
2784

2785
    case FTDouble:
40✔
2786
      gml_type = "Real";
2787
      sprintf(gml_width, "%d", nWidth);
40✔
2788
      sprintf(gml_precision, "%d", nPrecision);
40✔
2789
      break;
2790

2791
    case FTString:
99✔
2792
    default:
2793
      gml_type = "Character";
2794
      sprintf(gml_width, "%d", nWidth);
99✔
2795
      break;
2796
    }
2797

2798
    msUpdateGMLFieldMetadata(layer, item, gml_type, gml_width, gml_precision,
438✔
2799
                             0);
2800
  }
2801
}
59✔
2802

2803
int msTiledSHPLayerGetItems(layerObj *layer) {
5✔
2804
  msTiledSHPLayerInfo *tSHP = NULL;
2805
  const char *value;
2806

2807
  tSHP = layer->layerinfo;
5✔
2808
  if (!tSHP) {
5✔
2809
    msSetError(MS_SHPERR, "Tiled shapefile layer has not been opened.",
×
2810
               "msTiledSHPLayerGetItems()");
2811
    return MS_FAILURE;
×
2812
  }
2813

2814
  layer->numitems = msDBFGetFieldCount(tSHP->shpfile->hDBF);
5✔
2815
  layer->items = msDBFGetItems(tSHP->shpfile->hDBF);
5✔
2816
  if (!layer->items)
5✔
2817
    return MS_FAILURE;
2818

2819
  /* -------------------------------------------------------------------- */
2820
  /*      consider populating the field definitions in metadata.          */
2821
  /* -------------------------------------------------------------------- */
2822
  if ((value = msOWSLookupMetadata(&(layer->metadata), "G", "types")) != NULL &&
5✔
2823
      strcasecmp(value, "auto") == 0)
×
2824
    msSHPPassThroughFieldDefinitions(layer, tSHP->shpfile->hDBF);
×
2825

2826
  return msTiledSHPLayerInitItemInfo(layer);
5✔
2827
}
2828

2829
int msTiledSHPLayerGetExtent(layerObj *layer, rectObj *extent) {
×
2830
  msTiledSHPLayerInfo *tSHP = NULL;
2831

2832
  tSHP = layer->layerinfo;
×
2833
  if (!tSHP) {
×
2834
    msSetError(MS_SHPERR, "Tiled shapefile layer has not been opened.",
×
2835
               "msTiledSHPLayerGetExtent()");
2836
    return MS_FAILURE;
×
2837
  }
2838

2839
  *extent = tSHP->tileshpfile->bounds;
×
2840
  return MS_SUCCESS;
×
2841
}
2842

2843
int msTiledSHPLayerIsOpen(layerObj *layer) {
4✔
2844
  if (layer->layerinfo)
4✔
2845
    return MS_TRUE;
2846
  else
2847
    return MS_FALSE;
1✔
2848
}
2849

2850
int msTiledSHPLayerSupportsCommonFilters(layerObj *layer) {
2✔
2851
  (void)layer;
2852
  return MS_TRUE;
2✔
2853
}
2854

2855
int msTiledSHPLayerInitializeVirtualTable(layerObj *layer) {
2✔
2856
  assert(layer != NULL);
2857
  assert(layer->vtable != NULL);
2858

2859
  layer->vtable->LayerSupportsCommonFilters =
2✔
2860
      msTiledSHPLayerSupportsCommonFilters;
2861
  layer->vtable->LayerInitItemInfo = msTiledSHPLayerInitItemInfo;
2✔
2862
  layer->vtable->LayerFreeItemInfo = msTiledSHPLayerFreeItemInfo;
2✔
2863
  layer->vtable->LayerOpen = msTiledSHPOpenFile;
2✔
2864
  layer->vtable->LayerIsOpen = msTiledSHPLayerIsOpen;
2✔
2865
  layer->vtable->LayerWhichShapes = msTiledSHPWhichShapes;
2✔
2866
  layer->vtable->LayerNextShape = msTiledSHPNextShape;
2✔
2867
  /* no special version, use ...GetShape() */
2868
  /* layer->vtable->LayerResultsGetShape = msTiledSHPGetShape; */
2869
  layer->vtable->LayerGetShape = msTiledSHPGetShape;
2✔
2870
  layer->vtable->LayerClose = msTiledSHPCloseVT;
2✔
2871
  layer->vtable->LayerGetItems = msTiledSHPLayerGetItems;
2✔
2872
  layer->vtable->LayerGetExtent = msTiledSHPLayerGetExtent;
2✔
2873
  /* layer->vtable->LayerApplyFilterToLayer, use default */
2874
  /* layer->vtable->LayerGetAutoStyle, use default */
2875
  /* layer->vtable->LayerCloseConnection, use default */;
2876
  layer->vtable->LayerSetTimeFilter = msLayerMakeBackticsTimeFilter;
2✔
2877
  /* layer->vtable->LayerCreateItems, use default */
2878
  /* layer->vtable->LayerGetNumFeatures, use default */
2879
  /* layer->vtable->LayerGetAutoProjection, use default*/
2880

2881
  return MS_SUCCESS;
2✔
2882
}
2883

2884
/* SHAPEFILE Layer virtual table functions */
2885

2886
void msSHPLayerFreeItemInfo(layerObj *layer) {
9,725✔
2887
  if (layer->iteminfo) {
9,725✔
2888
    free(layer->iteminfo);
3,027✔
2889
    layer->iteminfo = NULL;
3,027✔
2890
  }
2891
}
9,725✔
2892

2893
int msSHPLayerInitItemInfo(layerObj *layer) {
3,029✔
2894
  shapefileObj *shpfile = layer->layerinfo;
3,029✔
2895
  if (!shpfile) {
3,029✔
2896
    msSetError(MS_SHPERR, "Shapefile layer has not been opened.",
×
2897
               "msSHPLayerInitItemInfo()");
2898
    return MS_FAILURE;
×
2899
  }
2900

2901
  /* iteminfo needs to be a bit more complex, a list of indexes plus the length
2902
   * of the list */
2903
  msSHPLayerFreeItemInfo(layer);
3,029✔
2904
  layer->iteminfo =
3,029✔
2905
      (int *)msDBFGetItemIndexes(shpfile->hDBF, layer->items, layer->numitems);
3,029✔
2906
  if (!layer->iteminfo) {
3,029✔
2907
    return MS_FAILURE;
2908
  }
2909

2910
  return MS_SUCCESS;
2911
}
2912

2913
int msSHPLayerOpen(layerObj *layer) {
3,104✔
2914
  char szPath[MS_MAXPATHLEN];
2915
  shapefileObj *shpfile;
2916

2917
  if (layer->layerinfo)
3,104✔
2918
    return MS_SUCCESS; /* layer already open */
2919

2920
  if (msCheckParentPointer(layer->map, "map") == MS_FAILURE)
2,913✔
2921
    return MS_FAILURE;
2922

2923
  /* allocate space for a shapefileObj using layer->layerinfo  */
2924
  shpfile = (shapefileObj *)malloc(sizeof(shapefileObj));
2,913✔
2925
  MS_CHECK_ALLOC(shpfile, sizeof(shapefileObj), MS_FAILURE);
2,913✔
2926

2927
  layer->layerinfo = shpfile;
2,913✔
2928

2929
  if (msShapefileOpen(shpfile, "rb",
2,913✔
2930
                      msBuildPath3(szPath, layer->map->mappath,
2,913✔
2931
                                   layer->map->shapepath, layer->data),
2,913✔
2932
                      MS_TRUE) == -1) {
2933
    if (msShapefileOpen(shpfile, "rb",
12✔
2934
                        msBuildPath(szPath, layer->map->mappath, layer->data),
12✔
2935
                        MS_TRUE) == -1) {
2936
      layer->layerinfo = NULL;
8✔
2937
      free(shpfile);
8✔
2938
      return MS_FAILURE;
8✔
2939
    }
2940
  }
2941

2942
  /* Update layer encoding if encoding is defined in CPG file */
2943
  if (!layer->encoding && shpfile->hDBF->pszEncoding) {
2,905✔
2944
    layer->encoding = msStrdup(shpfile->hDBF->pszEncoding);
47✔
2945
  }
2946

2947
  if (layer->projection.numargs > 0 &&
2,905✔
2948
      EQUAL(layer->projection.args[0], "auto")) {
2,265✔
2949
    const char *pszPRJFilename = CPLResetExtension(szPath, "prj");
3✔
2950
    int bOK = MS_FALSE;
2951
    VSILFILE *fp = VSIFOpenL(pszPRJFilename, "rb");
3✔
2952
    if (fp != NULL) {
3✔
2953
      char szPRJ[2048];
2954
      OGRSpatialReferenceH hSRS;
2955
      int nRead;
2956

2957
      nRead = (int)VSIFReadL(szPRJ, 1, sizeof(szPRJ) - 1, fp);
3✔
2958
      szPRJ[nRead] = '\0';
3✔
2959
      hSRS = OSRNewSpatialReference(szPRJ);
3✔
2960
      if (hSRS != NULL) {
3✔
2961
        if (OSRMorphFromESRI(hSRS) == OGRERR_NONE) {
3✔
2962
          char *pszWKT = NULL;
3✔
2963
          if (OSRExportToWkt(hSRS, &pszWKT) == OGRERR_NONE) {
3✔
2964
            if (msOGCWKT2ProjectionObj(pszWKT, &(layer->projection),
3✔
2965
                                       layer->debug) == MS_SUCCESS) {
2966
              bOK = MS_TRUE;
2967
            }
2968
          }
2969
          CPLFree(pszWKT);
3✔
2970
        }
2971
        OSRDestroySpatialReference(hSRS);
3✔
2972
      }
2973
      VSIFCloseL(fp);
3✔
2974
    }
2975

2976
    if (bOK != MS_TRUE) {
3✔
2977
      if (layer->debug || layer->map->debug) {
×
2978
        msDebug("Unable to get SRS from shapefile '%s' for layer '%s'.\n",
×
2979
                szPath, layer->name);
2980
      }
2981
    }
2982
  }
2983

2984
  return MS_SUCCESS;
2985
}
2986

2987
int msSHPLayerIsOpen(layerObj *layer) {
8,755✔
2988
  if (layer->layerinfo)
8,755✔
2989
    return MS_TRUE;
2990
  else
2991
    return MS_FALSE;
8,100✔
2992
}
2993

2994
int msSHPLayerWhichShapes(layerObj *layer, rectObj rect, int isQuery) {
1,788✔
2995
  (void)isQuery;
2996
  int status;
2997
  shapefileObj *shpfile;
2998

2999
  shpfile = layer->layerinfo;
1,788✔
3000

3001
  if (!shpfile) {
1,788✔
3002
    msSetError(MS_SHPERR, "Shapefile layer has not been opened.",
×
3003
               "msSHPLayerWhichShapes()");
3004
    return MS_FAILURE;
×
3005
  }
3006

3007
  status = msShapefileWhichShapes(shpfile, rect, layer->debug);
1,788✔
3008
  if (status != MS_SUCCESS) {
3009
    return status;
3010
  }
3011

3012
  return MS_SUCCESS;
3013
}
3014

3015
int msSHPLayerNextShape(layerObj *layer, shapeObj *shape) {
31,431✔
3016
  int i;
3017
  shapefileObj *shpfile;
3018

3019
  shpfile = layer->layerinfo;
31,431✔
3020

3021
  if (!shpfile) {
31,431✔
3022
    msSetError(MS_SHPERR, "Shapefile layer has not been opened.",
×
3023
               "msSHPLayerNextShape()");
3024
    return MS_FAILURE;
×
3025
  }
3026

3027
  if (!shpfile->status) {
31,431✔
3028
    /* probably whichShapes didn't overlap */
3029
    return MS_DONE;
3030
  }
3031

3032
  i = msGetNextBit(shpfile->status, shpfile->lastshape + 1, shpfile->numshapes);
31,431✔
3033
  shpfile->lastshape = i;
31,431✔
3034
  if (i == -1)
31,431✔
3035
    return (MS_DONE); /* nothing else to read */
3036

3037
  msSHPReadShape(shpfile->hSHP, i, shape);
29,742✔
3038
  if (shape->type == MS_SHAPE_NULL) {
29,742✔
3039
    msFreeShape(shape);
×
3040
    return msSHPLayerNextShape(layer, shape); /* skip NULL shapes */
×
3041
  }
3042
  shape->numvalues = layer->numitems;
29,742✔
3043
  shape->values =
29,742✔
3044
      msDBFGetValueList(shpfile->hDBF, i, layer->iteminfo, layer->numitems);
29,742✔
3045
  if (!shape->values)
29,742✔
3046
    shape->numvalues = 0;
5,652✔
3047

3048
  return MS_SUCCESS;
3049
}
3050

3051
int msSHPLayerGetShape(layerObj *layer, shapeObj *shape, resultObj *record) {
2,168✔
3052
  shapefileObj *shpfile;
3053
  long shapeindex;
3054

3055
  shpfile = layer->layerinfo;
2,168✔
3056

3057
  shapeindex = record->shapeindex;
2,168✔
3058

3059
  if (!shpfile) {
2,168✔
3060
    msSetError(MS_SHPERR, "Shapefile layer has not been opened.",
×
3061
               "msSHPLayerGetShape()");
3062
    return MS_FAILURE;
×
3063
  }
3064

3065
  /* msSHPReadShape *should* return success or failure so we don't have to test
3066
   * here */
3067
  if (shapeindex < 0 || shapeindex >= shpfile->numshapes) {
2,168✔
3068
    msSetError(MS_MISCERR, "Invalid feature id.", "msSHPLayerGetShape()");
×
3069
    return MS_FAILURE;
×
3070
  }
3071

3072
  msSHPReadShape(shpfile->hSHP, shapeindex, shape);
2,168✔
3073
  if (layer->numitems > 0 && layer->iteminfo) {
2,168✔
3074
    shape->numvalues = layer->numitems;
2,168✔
3075
    shape->values = msDBFGetValueList(shpfile->hDBF, shapeindex,
2,168✔
3076
                                      layer->iteminfo, layer->numitems);
3077
    if (!shape->values)
2,168✔
3078
      return MS_FAILURE;
3079
  }
3080

3081
  shpfile->lastshape = shapeindex;
2,168✔
3082

3083
  return MS_SUCCESS;
2,168✔
3084
}
3085

3086
int msSHPLayerClose(layerObj *layer) {
3,290✔
3087
  shapefileObj *shpfile;
3088
  shpfile = layer->layerinfo;
3,290✔
3089
  if (!shpfile)
3,290✔
3090
    return MS_SUCCESS; /* nothing to do */
3091

3092
  msShapefileClose(shpfile);
2,905✔
3093
  free(layer->layerinfo);
2,905✔
3094
  layer->layerinfo = NULL;
2,905✔
3095

3096
  return MS_SUCCESS;
2,905✔
3097
}
3098

3099
int msSHPLayerGetItems(layerObj *layer) {
1,599✔
3100
  shapefileObj *shpfile;
3101
  const char *value;
3102

3103
  shpfile = layer->layerinfo;
1,599✔
3104

3105
  if (!shpfile) {
1,599✔
3106
    msSetError(MS_SHPERR, "Shapefile layer has not been opened.",
×
3107
               "msSHPLayerGetItems()");
3108
    return MS_FAILURE;
×
3109
  }
3110

3111
  layer->numitems = msDBFGetFieldCount(shpfile->hDBF);
1,599✔
3112
  layer->items = msDBFGetItems(shpfile->hDBF);
1,599✔
3113
  if (layer->numitems == 0)
1,599✔
3114
    return MS_SUCCESS; /* No items is a valid case (#3147) */
3115
  if (!layer->items)
1,599✔
3116
    return MS_FAILURE;
3117

3118
  /* -------------------------------------------------------------------- */
3119
  /*      consider populating the field definitions in metadata.          */
3120
  /* -------------------------------------------------------------------- */
3121
  if ((value = msOWSLookupMetadata(&(layer->metadata), "G", "types")) != NULL &&
1,599✔
3122
      strcasecmp(value, "auto") == 0)
59✔
3123
    msSHPPassThroughFieldDefinitions(layer, shpfile->hDBF);
59✔
3124

3125
  return msLayerInitItemInfo(layer);
1,599✔
3126
}
3127

3128
int msSHPLayerGetExtent(layerObj *layer, rectObj *extent) {
380✔
3129
  *extent = ((shapefileObj *)layer->layerinfo)->bounds;
380✔
3130
  return MS_SUCCESS;
380✔
3131
}
3132

3133
int msSHPLayerSupportsCommonFilters(layerObj *layer) {
1,788✔
3134
  (void)layer;
3135
  return MS_TRUE;
1,788✔
3136
}
3137

3138
int msSHPLayerInitializeVirtualTable(layerObj *layer) {
7,823✔
3139
  assert(layer != NULL);
3140
  assert(layer->vtable != NULL);
3141

3142
  layer->vtable->LayerSupportsCommonFilters = msSHPLayerSupportsCommonFilters;
7,823✔
3143
  layer->vtable->LayerInitItemInfo = msSHPLayerInitItemInfo;
7,823✔
3144
  layer->vtable->LayerFreeItemInfo = msSHPLayerFreeItemInfo;
7,823✔
3145
  layer->vtable->LayerOpen = msSHPLayerOpen;
7,823✔
3146
  layer->vtable->LayerIsOpen = msSHPLayerIsOpen;
7,823✔
3147
  layer->vtable->LayerWhichShapes = msSHPLayerWhichShapes;
7,823✔
3148
  layer->vtable->LayerNextShape = msSHPLayerNextShape;
7,823✔
3149
  layer->vtable->LayerGetShape = msSHPLayerGetShape;
7,823✔
3150
  /* layer->vtable->LayerGetShapeCount, use default */
3151
  layer->vtable->LayerClose = msSHPLayerClose;
7,823✔
3152
  layer->vtable->LayerGetItems = msSHPLayerGetItems;
7,823✔
3153
  layer->vtable->LayerGetExtent = msSHPLayerGetExtent;
7,823✔
3154
  /* layer->vtable->LayerGetAutoStyle, use default */
3155
  /* layer->vtable->LayerCloseConnection, use default */
3156
  layer->vtable->LayerSetTimeFilter = msLayerMakeBackticsTimeFilter;
7,823✔
3157
  /* layer->vtable->LayerTranslateFilter, use default */
3158
  /* layer->vtable->LayerApplyFilterToLayer, use default */
3159
  /* layer->vtable->LayerCreateItems, use default */
3160
  /* layer->vtable->LayerGetNumFeatures, use default */
3161

3162
  return MS_SUCCESS;
7,823✔
3163
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc