31 #define ByteCopy(a, b, c) memcpy(b, a, c)
33 #define MIN(a, b) ((a < b) ? a : b)
34 #define MAX(a, b) ((a > b) ? a : b)
40 #define snprintf _snprintf
44 #define snprintf _snprintf
59 psSHP->
sHooks.
Error(
"SHPWriteHeader failed : SHX file is closed");
67 unsigned char abyHeader[100] = {0};
73 #if !defined(SHP_BIG_ENDIAN)
79 #if defined(SHP_BIG_ENDIAN)
85 #if defined(SHP_BIG_ENDIAN)
90 ByteCopy(&dValue, abyHeader + 36, 8);
91 #if defined(SHP_BIG_ENDIAN)
95 ByteCopy(&dValue, abyHeader + 44, 8);
96 #if defined(SHP_BIG_ENDIAN)
100 ByteCopy(&dValue, abyHeader + 52, 8);
101 #if defined(SHP_BIG_ENDIAN)
106 ByteCopy(&dValue, abyHeader + 60, 8);
107 #if defined(SHP_BIG_ENDIAN)
112 ByteCopy(&dValue, abyHeader + 68, 8);
113 #if defined(SHP_BIG_ENDIAN)
118 ByteCopy(&dValue, abyHeader + 76, 8);
119 #if defined(SHP_BIG_ENDIAN)
124 ByteCopy(&dValue, abyHeader + 84, 8);
125 #if defined(SHP_BIG_ENDIAN)
130 ByteCopy(&dValue, abyHeader + 92, 8);
131 #if defined(SHP_BIG_ENDIAN)
140 char szErrorMsg[200];
142 snprintf(szErrorMsg,
sizeof(szErrorMsg),
143 "Failure writing .shp header: %s", strerror(errno));
144 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
152 i32 = (psSHP->
nRecords * 2 *
sizeof(uint32_t) + 100) / 2;
154 #if !defined(SHP_BIG_ENDIAN)
160 char szErrorMsg[200];
162 snprintf(szErrorMsg,
sizeof(szErrorMsg),
163 "Failure writing .shx header: %s", strerror(errno));
164 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
180 for (
int i = 0; i < psSHP->
nRecords; i++) {
183 #if !defined(SHP_BIG_ENDIAN)
192 char szErrorMsg[200];
194 snprintf(szErrorMsg,
sizeof(szErrorMsg),
195 "Failure writing .shx contents: %s", strerror(errno));
196 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
219 return SHPOpenLL(pszLayer, pszAccess, &sHooks);
226 static int SHPGetLenWithoutExtension(
const char *pszBasename)
228 const int nLen =
STATIC_CAST(
int, strlen(pszBasename));
229 for (
int i = nLen - 1;
230 i > 0 && pszBasename[i] !=
'/' && pszBasename[i] !=
'\\'; i--) {
231 if (pszBasename[i] ==
'.') {
253 bool bLazySHXLoading =
false;
254 if (strcmp(pszAccess,
"rb+") == 0 || strcmp(pszAccess,
"r+b") == 0 ||
255 strcmp(pszAccess,
"r+") == 0) {
275 const int nLenWithoutExtension = SHPGetLenWithoutExtension(pszLayer);
277 memcpy(pszFullname, pszLayer, nLenWithoutExtension);
278 memcpy(pszFullname + nLenWithoutExtension,
".shp", 5);
282 memcpy(pszFullname + nLenWithoutExtension,
".SHP", 5);
288 const size_t nMessageLen = strlen(pszFullname) * 2 + 256;
290 pszFullname[nLenWithoutExtension] = 0;
291 snprintf(pszMessage, nMessageLen,
292 "Unable to open %s.shp or %s.SHP in %s mode.", pszFullname,
293 pszFullname, pszAccess);
294 psHooks->
Error(pszMessage);
303 memcpy(pszFullname + nLenWithoutExtension,
".shx", 5);
307 memcpy(pszFullname + nLenWithoutExtension,
".SHX", 5);
313 const size_t nMessageLen = strlen(pszFullname) * 2 + 256;
315 pszFullname[nLenWithoutExtension] = 0;
316 snprintf(pszMessage, nMessageLen,
317 "Unable to open %s.shx or %s.SHX. "
318 "Set SHAPE_RESTORE_SHX config option to YES to restore or "
320 pszFullname, pszFullname);
321 psHooks->
Error(pszMessage);
337 psSHP->
sHooks.
Error(
".shp file is unreadable, or corrupt.");
347 (pabyBuf[25] << 16) | (pabyBuf[26] << 8) | pabyBuf[27];
357 pabyBuf[0] != 0 || pabyBuf[1] != 0 || pabyBuf[2] != 0x27 ||
358 (pabyBuf[3] != 0x0a && pabyBuf[3] != 0x0d)) {
359 psSHP->
sHooks.
Error(
".shx file is unreadable, or corrupt.");
368 psSHP->
nRecords = pabyBuf[27] | (pabyBuf[26] << 8) | (pabyBuf[25] << 16) |
369 ((pabyBuf[24] & 0x7F) << 24);
375 char szErrorMsg[200];
377 snprintf(szErrorMsg,
sizeof(szErrorMsg),
378 "Record count in .shx header is %d, which seems\n"
379 "unreasonable. Assuming header is corrupt.",
381 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
393 if (psSHP->
nRecords >= 1024 * 1024) {
396 if (nFileSize > 100 &&
408 #if defined(SHP_BIG_ENDIAN)
411 memcpy(&dValue, pabyBuf + 36, 8);
414 #if defined(SHP_BIG_ENDIAN)
417 memcpy(&dValue, pabyBuf + 44, 8);
420 #if defined(SHP_BIG_ENDIAN)
423 memcpy(&dValue, pabyBuf + 52, 8);
426 #if defined(SHP_BIG_ENDIAN)
429 memcpy(&dValue, pabyBuf + 60, 8);
432 #if defined(SHP_BIG_ENDIAN)
435 memcpy(&dValue, pabyBuf + 68, 8);
438 #if defined(SHP_BIG_ENDIAN)
441 memcpy(&dValue, pabyBuf + 76, 8);
444 #if defined(SHP_BIG_ENDIAN)
447 memcpy(&dValue, pabyBuf + 84, 8);
450 #if defined(SHP_BIG_ENDIAN)
453 memcpy(&dValue, pabyBuf + 92, 8);
479 char szErrorMsg[200];
482 szErrorMsg,
sizeof(szErrorMsg),
483 "Not enough memory to allocate requested memory (nRecords=%d).\n"
484 "Probably broken SHP file",
486 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
500 if (bLazySHXLoading) {
512 char szErrorMsg[200];
514 snprintf(szErrorMsg,
sizeof(szErrorMsg),
515 "Failed to read all values for %d records in .shx file: %s.",
517 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
532 if (strcmp(pszAccess,
"rb") == 0) {
537 for (
int i = 0; i < psSHP->
nRecords; i++) {
538 unsigned int nOffset;
539 memcpy(&nOffset, pabyBuf + i * 8, 4);
540 #if !defined(SHP_BIG_ENDIAN)
544 unsigned int nLength;
545 memcpy(&nLength, pabyBuf + i * 8 + 4, 4);
546 #if !defined(SHP_BIG_ENDIAN)
550 if (nOffset >
STATIC_CAST(
unsigned int, INT_MAX)) {
552 snprintf(str,
sizeof(str),
"Invalid offset for entity %d", i);
553 str[
sizeof(str) - 1] =
'\0';
560 if (nLength >
STATIC_CAST(
unsigned int, INT_MAX / 2 - 4)) {
562 snprintf(str,
sizeof(str),
"Invalid length for entity %d", i);
563 str[
sizeof(str) - 1] =
'\0';
587 const SAHooks *psHooks,
int bRestoreSHX)
590 return SHPOpenLL(pszLayer, pszAccess, psHooks);
593 return SHPOpenLL(pszLayer, pszAccess, psHooks);
615 if (strcmp(pszAccess,
"rb+") == 0 || strcmp(pszAccess,
"r+b") == 0 ||
616 strcmp(pszAccess,
"r+") == 0) {
627 const int nLenWithoutExtension = SHPGetLenWithoutExtension(pszLayer);
629 memcpy(pszFullname, pszLayer, nLenWithoutExtension);
630 memcpy(pszFullname + nLenWithoutExtension,
".shp", 5);
633 memcpy(pszFullname + nLenWithoutExtension,
".SHP", 5);
638 const size_t nMessageLen = strlen(pszFullname) * 2 + 256;
641 pszFullname[nLenWithoutExtension] = 0;
642 snprintf(pszMessage, nMessageLen,
"Unable to open %s.shp or %s.SHP.",
643 pszFullname, pszFullname);
644 psHooks->
Error(pszMessage);
656 if (psHooks->
FRead(pabyBuf, 100, 1, fpSHP) != 1) {
657 psHooks->
Error(
".shp file is unreadable, or corrupt.");
666 unsigned int nSHPFilesize = (
STATIC_CAST(
unsigned int, pabyBuf[24]) << 24) |
667 (pabyBuf[25] << 16) | (pabyBuf[26] << 8) |
669 if (nSHPFilesize < UINT_MAX / 2)
672 nSHPFilesize = (UINT_MAX / 2) * 2;
674 memcpy(pszFullname + nLenWithoutExtension,
".shx", 5);
675 const char pszSHXAccess[] =
"w+b";
679 size_t nMessageLen = strlen(pszFullname) * 2 + 256;
681 pszFullname[nLenWithoutExtension] = 0;
682 snprintf(pszMessage, nMessageLen,
683 "Error opening file %s.shx for writing", pszFullname);
684 psHooks->
Error(pszMessage);
698 psHooks->
FSeek(fpSHP, 100, 0);
700 memcpy(pabySHXHeader, pabyBuf, 100);
701 psHooks->
FWrite(pabySHXHeader, 100, 1, fpSHX);
705 unsigned int nCurrentSHPOffset = 100;
706 unsigned int nRealSHXContentSize = 100;
708 unsigned int nRecordOffset = 50;
710 while (nCurrentSHPOffset < nSHPFilesize) {
711 unsigned int niRecord = 0;
712 unsigned int nRecordLength = 0;
715 if (psHooks->
FRead(&niRecord, 4, 1, fpSHP) == 1 &&
716 psHooks->
FRead(&nRecordLength, 4, 1, fpSHP) == 1 &&
718 char abyReadRecord[8];
719 unsigned int nRecordOffsetBE = nRecordOffset;
721 #if !defined(SHP_BIG_ENDIAN)
724 memcpy(abyReadRecord, &nRecordOffsetBE, 4);
725 memcpy(abyReadRecord + 4, &nRecordLength, 4);
727 #if !defined(SHP_BIG_ENDIAN)
730 #if defined(SHP_BIG_ENDIAN)
735 if (nRecordLength < 1 ||
736 nRecordLength > (nSHPFilesize - (nCurrentSHPOffset + 8)) / 2) {
737 char szErrorMsg[200];
738 snprintf(szErrorMsg,
sizeof(szErrorMsg),
739 "Error parsing .shp to restore .shx. "
740 "Invalid record length = %u at record starting at "
742 nRecordLength, nCurrentSHPOffset);
743 psHooks->
Error(szErrorMsg);
757 char szErrorMsg[200];
758 snprintf(szErrorMsg,
sizeof(szErrorMsg),
759 "Error parsing .shp to restore .shx. "
760 "Invalid shape type = %d at record starting at "
763 psHooks->
Error(szErrorMsg);
769 psHooks->
FWrite(abyReadRecord, 8, 1, fpSHX);
771 nRecordOffset += nRecordLength + 4;
773 nCurrentSHPOffset += 8 + nRecordLength * 2;
775 psHooks->
FSeek(fpSHP, nCurrentSHPOffset, 0);
776 nRealSHXContentSize += 8;
779 char szErrorMsg[200];
780 snprintf(szErrorMsg,
sizeof(szErrorMsg),
781 "Error parsing .shp to restore .shx. "
782 "Cannot read first bytes of record starting at "
785 psHooks->
Error(szErrorMsg);
791 if (nRetCode && nCurrentSHPOffset != nSHPFilesize) {
792 psHooks->
Error(
"Error parsing .shp to restore .shx. "
793 "Not expected number of bytes");
798 nRealSHXContentSize /= 2;
799 #if !defined(SHP_BIG_ENDIAN)
803 psHooks->
FSeek(fpSHX, 24, 0);
804 psHooks->
FWrite(&nRealSHXContentSize, 4, 1, fpSHX);
887 int *pnShapeType,
double *padfMinBound,
888 double *padfMaxBound)
899 for (
int i = 0; i < 4; i++) {
936 const int nLenWithoutExtension = SHPGetLenWithoutExtension(pszLayer);
938 memcpy(pszFullname, pszLayer, nLenWithoutExtension);
939 memcpy(pszFullname + nLenWithoutExtension,
".shp", 5);
942 char szErrorMsg[200];
943 snprintf(szErrorMsg,
sizeof(szErrorMsg),
"Failed to create file %s: %s",
944 pszFullname, strerror(errno));
945 psHooks->
Error(szErrorMsg);
951 memcpy(pszFullname + nLenWithoutExtension,
".shx", 5);
954 char szErrorMsg[200];
955 snprintf(szErrorMsg,
sizeof(szErrorMsg),
"Failed to create file %s: %s",
956 pszFullname, strerror(errno));
957 psHooks->
Error(szErrorMsg);
970 unsigned char abyHeader[100];
971 memset(abyHeader, 0,
sizeof(abyHeader));
978 #if !defined(SHP_BIG_ENDIAN)
984 #if defined(SHP_BIG_ENDIAN)
990 #if defined(SHP_BIG_ENDIAN)
995 ByteCopy(&dValue, abyHeader + 36, 8);
996 ByteCopy(&dValue, abyHeader + 44, 8);
997 ByteCopy(&dValue, abyHeader + 52, 8);
998 ByteCopy(&dValue, abyHeader + 60, 8);
1003 if (psHooks->
FWrite(abyHeader, 100, 1, fpSHP) != 1) {
1004 char szErrorMsg[200];
1006 snprintf(szErrorMsg,
sizeof(szErrorMsg),
1007 "Failed to write .shp header: %s", strerror(errno));
1008 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
1009 psHooks->
Error(szErrorMsg);
1022 #if !defined(SHP_BIG_ENDIAN)
1026 if (psHooks->
FWrite(abyHeader, 100, 1, fpSHX) != 1) {
1027 char szErrorMsg[200];
1029 snprintf(szErrorMsg,
sizeof(szErrorMsg),
1030 "Failure writing .shx header: %s", strerror(errno));
1031 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
1032 psHooks->
Error(szErrorMsg);
1045 psSHP->
fpSHP = fpSHP;
1046 psSHP->
fpSHX = fpSHX;
1056 psSHP->
sHooks.
Error(
"Not enough memory to allocate requested memory");
1077 static void _SHPSetBounds(
unsigned char *pabyRec,
const SHPObject *
psShape)
1084 #if defined(SHP_BIG_ENDIAN)
1111 for (
int i = 0; i < psObject->
nVertices; i++) {
1133 const
int *panPartStart, const
int *panPartType,
1134 int nVertices, const
double *padfX, const
double *padfY,
1135 const
double *padfZ, const
double *padfM)
1183 for (
int i = 0; i < nParts; i++) {
1200 const size_t nSize =
sizeof(double) *
nVertices;
1214 memcpy(psObject->
padfX, padfX, nSize);
1216 memcpy(psObject->
padfY, padfY, nSize);
1218 memcpy(psObject->
padfZ, padfZ, nSize);
1220 memcpy(psObject->
padfM, padfM, nSize);
1243 const
double *padfY, const
double *padfZ)
1287 unsigned int *panRecOffsetNew;
1288 unsigned int *panRecSizeNew;
1292 sizeof(
unsigned int) * nNewMaxRecords));
1294 psSHP->
sHooks.
Error(
"Failed to write shape object. "
1295 "Memory allocation error.");
1302 realloc(psSHP->
panRecSize,
sizeof(
unsigned int) * nNewMaxRecords));
1304 psSHP->
sHooks.
Error(
"Failed to write shape object. "
1305 "Memory allocation error.");
1319 size_t nRecMaxSize =
1323 const unsigned nExtraSpaceForGeomHeader = 128;
1324 if (nRecMaxSize > UINT_MAX - nExtraSpaceForGeomHeader) {
1325 psSHP->
sHooks.
Error(
"Failed to write shape object. Too big geometry.");
1328 nRecMaxSize += nExtraSpaceForGeomHeader;
1331 psSHP->
sHooks.
Error(
"Failed to write shape object. "
1332 "Memory allocation error.");
1339 unsigned int nRecordSize = 0;
1340 const bool bFirstFeature = psSHP->
nRecords == 0;
1348 uint32_t nParts = psObject->
nParts;
1350 _SHPSetBounds(pabyRec + 12, psObject);
1352 #if defined(SHP_BIG_ENDIAN)
1357 ByteCopy(&nPoints, pabyRec + 40 + 8, 4);
1358 ByteCopy(&nParts, pabyRec + 36 + 8, 4);
1367 for (
int i = 0; i < psObject->
nParts; i++) {
1368 #if defined(SHP_BIG_ENDIAN)
1378 memcpy(pabyRec + nRecordSize, psObject->
panPartType,
1380 for (
int i = 0; i < psObject->
nParts; i++) {
1381 #if defined(SHP_BIG_ENDIAN)
1391 for (
int i = 0; i < psObject->
nVertices; i++) {
1393 ByteCopy(psObject->
padfY + i, pabyRec + nRecordSize + 8, 8);
1395 #if defined(SHP_BIG_ENDIAN)
1400 nRecordSize += 2 * 8;
1410 #if defined(SHP_BIG_ENDIAN)
1416 #if defined(SHP_BIG_ENDIAN)
1421 for (
int i = 0; i < psObject->
nVertices; i++) {
1423 #if defined(SHP_BIG_ENDIAN)
1442 #if defined(SHP_BIG_ENDIAN)
1448 #if defined(SHP_BIG_ENDIAN)
1453 for (
int i = 0; i < psObject->
nVertices; i++) {
1455 #if defined(SHP_BIG_ENDIAN)
1471 _SHPSetBounds(pabyRec + 12, psObject);
1473 #if defined(SHP_BIG_ENDIAN)
1476 ByteCopy(&nPoints, pabyRec + 44, 4);
1478 for (
int i = 0; i < psObject->
nVertices; i++) {
1480 ByteCopy(psObject->
padfY + i, pabyRec + 48 + i * 16 + 8, 8);
1482 #if defined(SHP_BIG_ENDIAN)
1488 nRecordSize = 48 + 16 * psObject->
nVertices;
1492 #if defined(SHP_BIG_ENDIAN)
1498 #if defined(SHP_BIG_ENDIAN)
1503 for (
int i = 0; i < psObject->
nVertices; i++) {
1505 #if defined(SHP_BIG_ENDIAN)
1516 #if defined(SHP_BIG_ENDIAN)
1522 #if defined(SHP_BIG_ENDIAN)
1527 for (
int i = 0; i < psObject->
nVertices; i++) {
1529 #if defined(SHP_BIG_ENDIAN)
1546 #if defined(SHP_BIG_ENDIAN)
1555 #if defined(SHP_BIG_ENDIAN)
1564 #if defined(SHP_BIG_ENDIAN)
1590 bool bAppendToLastRecord =
false;
1591 bool bAppendToFile =
false;
1596 bAppendToLastRecord =
true;
1599 if (psSHP->
nFileSize > UINT_MAX - nRecordSize) {
1601 snprintf(str,
sizeof(str),
1602 "Failed to write shape object. "
1603 "The maximum file size of %u has been reached. "
1604 "The current record of size %u cannot be added.",
1606 str[
sizeof(str) - 1] =
'\0';
1612 bAppendToFile =
true;
1624 #
if !defined(SHP_BIG_ENDIAN)
1629 i32 = (nRecordSize - 8) / 2;
1630 #if !defined(SHP_BIG_ENDIAN)
1636 #if defined(SHP_BIG_ENDIAN)
1651 char szErrorMsg[200];
1653 snprintf(szErrorMsg,
sizeof(szErrorMsg),
1654 "Error in psSHP->sHooks.FSeek() while writing object to "
1657 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
1665 char szErrorMsg[200];
1667 snprintf(szErrorMsg,
sizeof(szErrorMsg),
1668 "Error in psSHP->sHooks.FWrite() while writing object of %u "
1669 "bytes to .shp file: %s",
1670 nRecordSize, strerror(errno));
1671 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
1680 if (bAppendToLastRecord) {
1683 else if (bAppendToFile) {
1695 if (bFirstFeature) {
1712 for (
int i = 0; i < psObject->
nVertices; i++) {
1717 if (psObject->
padfZ) {
1723 if (psObject->
padfM) {
1738 static void *SHPAllocBuffer(
unsigned char **pBuffer,
int nSize)
1741 return calloc(1, nSize);
1743 unsigned char *pRet = *pBuffer;
1747 (*pBuffer) += nSize;
1755 static unsigned char *SHPReallocObjectBufIfNecessary(
SHPHandle psSHP,
1758 if (nObjectBufSize == 0) {
1759 nObjectBufSize = 4 *
sizeof(double);
1762 unsigned char *pBuffer;
1790 if (hEntity < 0 || hEntity >= psSHP->nRecords)
1796 if (psSHP->panRecOffset[hEntity] == 0 && psSHP->fpSHX !=
SHPLIB_NULLPTR) {
1797 unsigned int nOffset;
1798 unsigned int nLength;
1800 if (psSHP->sHooks.FSeek(psSHP->fpSHX, 100 + 8 * hEntity, 0) != 0 ||
1801 psSHP->sHooks.FRead(&nOffset, 1, 4, psSHP->fpSHX) != 4 ||
1802 psSHP->sHooks.FRead(&nLength, 1, 4, psSHP->fpSHX) != 4) {
1804 snprintf(str,
sizeof(str),
1805 "Error in fseek()/fread() reading object from .shx file "
1808 str[
sizeof(str) - 1] =
'\0';
1810 psSHP->sHooks.Error(str);
1813 #if !defined(SHP_BIG_ENDIAN)
1818 if (nOffset >
STATIC_CAST(
unsigned int, INT_MAX)) {
1820 snprintf(str,
sizeof(str),
"Invalid offset for entity %d", hEntity);
1821 str[
sizeof(str) - 1] =
'\0';
1823 psSHP->sHooks.Error(str);
1826 if (nLength >
STATIC_CAST(
unsigned int, INT_MAX / 2 - 4)) {
1828 snprintf(str,
sizeof(str),
"Invalid length for entity %d", hEntity);
1829 str[
sizeof(str) - 1] =
'\0';
1831 psSHP->sHooks.Error(str);
1835 psSHP->panRecOffset[hEntity] = nOffset * 2;
1836 psSHP->panRecSize[hEntity] = nLength * 2;
1845 if (nNewBufSize < INT_MAX - nNewBufSize / 3)
1846 nNewBufSize += nNewBufSize / 3;
1848 nNewBufSize = INT_MAX;
1854 if (nNewBufSize >= 10 * 1024 * 1024) {
1855 if (psSHP->nBufSize < 10 * 1024 * 1024) {
1857 psSHP->sHooks.FSeek(psSHP->fpSHP, 0, 2);
1858 nFileSize = psSHP->sHooks.FTell(psSHP->fpSHP);
1859 if (nFileSize >= UINT_MAX)
1860 psSHP->nFileSize = UINT_MAX;
1862 psSHP->nFileSize =
STATIC_CAST(
unsigned int, nFileSize);
1865 if (psSHP->panRecOffset[hEntity] >= psSHP->nFileSize ||
1872 psSHP->panRecSize[hEntity] >
1873 psSHP->nFileSize - psSHP->panRecOffset[hEntity]) {
1875 snprintf(str,
sizeof(str),
1876 "Error in fread() reading object of size %d at offset "
1877 "%u from .shp file",
1879 str[
sizeof(str) - 1] =
'\0';
1881 psSHP->sHooks.Error(str);
1886 unsigned char *pabyRecNew =
1887 STATIC_CAST(
unsigned char *, realloc(psSHP->pabyRec, nNewBufSize));
1889 char szErrorMsg[160];
1890 snprintf(szErrorMsg,
sizeof(szErrorMsg),
1891 "Not enough memory to allocate requested memory "
1892 "(nNewBufSize=%d). "
1893 "Probably broken SHP file",
1895 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
1896 psSHP->sHooks.Error(szErrorMsg);
1901 psSHP->pabyRec = pabyRecNew;
1902 psSHP->nBufSize = nNewBufSize;
1913 if (psSHP->sHooks.FSeek(psSHP->fpSHP, psSHP->panRecOffset[hEntity], 0) !=
1920 snprintf(str,
sizeof(str),
1921 "Error in fseek() reading object from .shp file at offset %u",
1922 psSHP->panRecOffset[hEntity]);
1923 str[
sizeof(str) - 1] =
'\0';
1925 psSHP->sHooks.Error(str);
1930 int, psSHP->sHooks.FRead(psSHP->pabyRec, 1,
nEntitySize, psSHP->fpSHP));
1944 int nSHPContentLength;
1945 memcpy(&nSHPContentLength, psSHP->pabyRec + 4, 4);
1946 #if !defined(SHP_BIG_ENDIAN)
1949 if (nSHPContentLength < 0 || nSHPContentLength > INT_MAX / 2 - 4 ||
1952 snprintf(str,
sizeof(str),
1953 "Sanity check failed when trying to recover from "
1954 "inconsistent .shx/.shp with shape %d",
1956 str[
sizeof(str) - 1] =
'\0';
1958 psSHP->sHooks.Error(str);
1968 snprintf(str,
sizeof(str),
1969 "Error in fread() reading object of size %d at offset %u from "
1972 str[
sizeof(str) - 1] =
'\0';
1974 psSHP->sHooks.Error(str);
1979 char szErrorMsg[160];
1980 snprintf(szErrorMsg,
sizeof(szErrorMsg),
1981 "Corrupted .shp file : shape %d : nEntitySize = %d", hEntity,
1983 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
1984 psSHP->sHooks.Error(szErrorMsg);
1988 memcpy(&
nSHPType, psSHP->pabyRec + 8, 4);
1990 #if defined(SHP_BIG_ENDIAN)
1998 if (psSHP->bFastModeReadObject) {
1999 if (psSHP->psCachedObject->bFastModeReadObject) {
2000 psSHP->sHooks.Error(
"Invalid read pattern in fast read mode. "
2001 "SHPDestroyObject() should be called.");
2005 psShape = psSHP->psCachedObject;
2025 char szErrorMsg[160];
2026 snprintf(szErrorMsg,
sizeof(szErrorMsg),
2027 "Corrupted .shp file : shape %d : nEntitySize = %d",
2029 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
2030 psSHP->sHooks.Error(szErrorMsg);
2039 #if defined(SHP_BIG_ENDIAN)
2058 memcpy(&nPoints, psSHP->pabyRec + 40 + 8, 4);
2060 memcpy(&nParts, psSHP->pabyRec + 36 + 8, 4);
2062 #if defined(SHP_BIG_ENDIAN)
2069 nPoints > 50 * 1000 * 1000 || nParts > 10 * 1000 * 1000) {
2070 char szErrorMsg[160];
2071 snprintf(szErrorMsg,
sizeof(szErrorMsg),
2072 "Corrupted .shp file : shape %d, nPoints=%u, nParts=%u.",
2073 hEntity, nPoints, nParts);
2074 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
2075 psSHP->sHooks.Error(szErrorMsg);
2083 int nRequiredSize = 44 + 8 + 4 * nParts + 16 * nPoints;
2087 nRequiredSize += 16 + 8 * nPoints;
2090 nRequiredSize += 4 * nParts;
2093 char szErrorMsg[160];
2094 snprintf(szErrorMsg,
sizeof(szErrorMsg),
2095 "Corrupted .shp file : shape %d, nPoints=%u, nParts=%u, "
2098 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
2099 psSHP->sHooks.Error(szErrorMsg);
2108 const int nObjectBufSize =
2109 4 *
sizeof(double) * nPoints + 2 *
sizeof(
int) * nParts;
2110 pBuffer = SHPReallocObjectBufIfNecessary(psSHP, nObjectBufSize);
2111 ppBuffer = &pBuffer;
2116 double *, SHPAllocBuffer(ppBuffer,
sizeof(
double) * nPoints));
2118 double *, SHPAllocBuffer(ppBuffer,
sizeof(
double) * nPoints));
2120 double *, SHPAllocBuffer(ppBuffer,
sizeof(
double) * nPoints));
2122 double *, SHPAllocBuffer(ppBuffer,
sizeof(
double) * nPoints));
2126 STATIC_CAST(
int *, SHPAllocBuffer(ppBuffer, nParts *
sizeof(
int)));
2128 STATIC_CAST(
int *, SHPAllocBuffer(ppBuffer, nParts *
sizeof(
int)));
2136 char szErrorMsg[160];
2137 snprintf(szErrorMsg,
sizeof(szErrorMsg),
2138 "Not enough memory to allocate requested memory "
2139 "(nPoints=%u, nParts=%u) for shape %d. "
2140 "Probably broken SHP file",
2141 nPoints, nParts, hEntity);
2142 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
2143 psSHP->sHooks.Error(szErrorMsg);
2148 for (
int i = 0;
STATIC_CAST(uint32_t, i) < nParts; i++)
2157 for (
int i = 0;
STATIC_CAST(uint32_t, i) < nParts; i++) {
2158 #if defined(SHP_BIG_ENDIAN)
2167 char szErrorMsg[160];
2168 snprintf(szErrorMsg,
sizeof(szErrorMsg),
2169 "Corrupted .shp file : shape %d : panPartStart[%d] = "
2170 "%d, nVertices = %d",
2173 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
2174 psSHP->sHooks.Error(szErrorMsg);
2180 char szErrorMsg[160];
2181 snprintf(szErrorMsg,
sizeof(szErrorMsg),
2182 "Corrupted .shp file : shape %d : panPartStart[%d] = "
2183 "%d, panPartStart[%d] = %d",
2186 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
2187 psSHP->sHooks.Error(szErrorMsg);
2193 int nOffset = 44 + 8 + 4 * nParts;
2202 for (
int i = 0;
STATIC_CAST(uint32_t, i) < nParts; i++) {
2203 #if defined(SHP_BIG_ENDIAN)
2208 nOffset += 4 * nParts;
2216 for (
int i = 0;
STATIC_CAST(uint32_t, i) < nPoints; i++) {
2217 #if defined(SHP_BIG_ENDIAN)
2219 psSHP->pabyRec + nOffset + i * 16);
2221 psSHP->pabyRec + nOffset + i * 16 + 8);
2223 memcpy(
psShape->
padfX + i, psSHP->pabyRec + nOffset + i * 16, 8);
2224 memcpy(
psShape->
padfY + i, psSHP->pabyRec + nOffset + i * 16 + 8,
2229 nOffset += 16 * nPoints;
2239 #if defined(SHP_BIG_ENDIAN)
2248 for (
int i = 0;
STATIC_CAST(uint32_t, i) < nPoints; i++) {
2249 #if defined(SHP_BIG_ENDIAN)
2251 psSHP->pabyRec + nOffset + 16 + i * 8);
2254 psSHP->pabyRec + nOffset + 16 + i * 8, 8);
2258 nOffset += 16 + 8 * nPoints;
2273 #if defined(SHP_BIG_ENDIAN)
2281 for (
int i = 0;
STATIC_CAST(uint32_t, i) < nPoints; i++) {
2282 #if defined(SHP_BIG_ENDIAN)
2284 psSHP->pabyRec + nOffset + 16 + i * 8);
2287 psSHP->pabyRec + nOffset + 16 + i * 8, 8);
2304 char szErrorMsg[160];
2305 snprintf(szErrorMsg,
sizeof(szErrorMsg),
2306 "Corrupted .shp file : shape %d : nEntitySize = %d",
2308 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
2309 psSHP->sHooks.Error(szErrorMsg);
2314 memcpy(&nPoints, psSHP->pabyRec + 44, 4);
2316 #if defined(SHP_BIG_ENDIAN)
2321 if ( nPoints > 50 * 1000 * 1000) {
2322 char szErrorMsg[160];
2323 snprintf(szErrorMsg,
sizeof(szErrorMsg),
2324 "Corrupted .shp file : shape %d : nPoints = %u", hEntity,
2326 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
2327 psSHP->sHooks.Error(szErrorMsg);
2332 int nRequiredSize = 48 + nPoints * 16;
2334 nRequiredSize += 16 + nPoints * 8;
2337 char szErrorMsg[160];
2338 snprintf(szErrorMsg,
sizeof(szErrorMsg),
2339 "Corrupted .shp file : shape %d : nPoints = %u, "
2342 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
2343 psSHP->sHooks.Error(szErrorMsg);
2352 const int nObjectBufSize = 4 *
sizeof(double) * nPoints;
2353 pBuffer = SHPReallocObjectBufIfNecessary(psSHP, nObjectBufSize);
2354 ppBuffer = &pBuffer;
2360 double *, SHPAllocBuffer(ppBuffer,
sizeof(
double) * nPoints));
2362 double *, SHPAllocBuffer(ppBuffer,
sizeof(
double) * nPoints));
2364 double *, SHPAllocBuffer(ppBuffer,
sizeof(
double) * nPoints));
2366 double *, SHPAllocBuffer(ppBuffer,
sizeof(
double) * nPoints));
2372 char szErrorMsg[160];
2373 snprintf(szErrorMsg,
sizeof(szErrorMsg),
2374 "Not enough memory to allocate requested memory "
2375 "(nPoints=%u) for shape %d. "
2376 "Probably broken SHP file",
2378 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
2379 psSHP->sHooks.Error(szErrorMsg);
2384 for (
int i = 0;
STATIC_CAST(uint32_t, i) < nPoints; i++) {
2385 #if defined(SHP_BIG_ENDIAN)
2387 psSHP->pabyRec + 48 + 16 * i);
2389 psSHP->pabyRec + 48 + 16 * i + 8);
2391 memcpy(
psShape->
padfX + i, psSHP->pabyRec + 48 + 16 * i, 8);
2392 memcpy(
psShape->
padfY + i, psSHP->pabyRec + 48 + 16 * i + 8, 8);
2396 int nOffset = 48 + 16 * nPoints;
2403 #if defined(SHP_BIG_ENDIAN)
2421 #if defined(SHP_BIG_ENDIAN)
2429 for (
int i = 0;
STATIC_CAST(uint32_t, i) < nPoints; i++) {
2430 #if defined(SHP_BIG_ENDIAN)
2432 psSHP->pabyRec + nOffset + 16 + i * 8);
2435 psSHP->pabyRec + nOffset + 16 + i * 8, 8);
2439 nOffset += 16 + 8 * nPoints;
2453 #if defined(SHP_BIG_ENDIAN)
2461 for (
int i = 0;
STATIC_CAST(uint32_t, i) < nPoints; i++) {
2462 #if defined(SHP_BIG_ENDIAN)
2464 psSHP->pabyRec + nOffset + 16 + i * 8);
2467 psSHP->pabyRec + nOffset + 16 + i * 8, 8);
2500 char szErrorMsg[160];
2501 snprintf(szErrorMsg,
sizeof(szErrorMsg),
2502 "Corrupted .shp file : shape %d : nEntitySize = %d",
2504 szErrorMsg[
sizeof(szErrorMsg) - 1] =
'\0';
2505 psSHP->sHooks.Error(szErrorMsg);
2509 #if defined(SHP_BIG_ENDIAN)
2517 int nOffset = 20 + 8;
2525 #if defined(SHP_BIG_ENDIAN)
2543 #if defined(SHP_BIG_ENDIAN)
2586 return "MultiPoint";
2598 return "MultiPointZ";
2610 return "MultiPointM";
2613 return "MultiPatch";
2616 return "UnknownShapeType";
2626 switch (nPartType) {
2628 return "TriangleStrip";
2631 return "TriangleFan";
2646 return "UnknownPartType";
2685 static int SHPGetPartVertexCount(
const SHPObject *psObject,
int iPart)
2687 if (iPart == psObject->
nParts - 1)
2699 static int SHPRewindIsInnerRing(
const SHPObject *psObject,
int iOpRing,
2700 double dfTestX,
double dfTestY,
2701 double dfRelativeTolerance,
int bSameZ,
2713 bool bInner =
false;
2714 for (
int iCheckRing = 0; iCheckRing < psObject->
nParts; iCheckRing++) {
2715 if (iCheckRing == iOpRing)
2718 const int nVertStartCheck = psObject->
panPartStart[iCheckRing];
2719 const int nVertCountCheck = SHPGetPartVertexCount(psObject, iCheckRing);
2726 int bZTestOK =
TRUE;
2727 for (
int iVert = nVertStartCheck + 1;
2728 iVert < nVertStartCheck + nVertCountCheck; ++iVert) {
2729 if (psObject->
padfZ[iVert] != dfTestZ) {
2738 for (
int iEdge = 0; iEdge < nVertCountCheck; iEdge++) {
2740 if (iEdge < nVertCountCheck - 1)
2745 const double y0 = psObject->
padfY[iEdge + nVertStartCheck];
2746 const double y1 = psObject->
padfY[iNext + nVertStartCheck];
2752 if ((y0 < dfTestY && dfTestY <= y1) ||
2753 (y1 < dfTestY && dfTestY <= y0)) {
2758 const double x0 = psObject->
padfX[iEdge + nVertStartCheck];
2759 const double x1 = psObject->
padfX[iNext + nVertStartCheck];
2760 const double intersect_minus_testX =
2761 (x0 - dfTestX) + (dfTestY - y0) / (y1 - y0) * (x1 - x0);
2763 if (fabs(intersect_minus_testX) <=
2764 dfRelativeTolerance * fabs(dfTestX)) {
2769 else if (intersect_minus_testX < 0) {
2805 for (
int iVert = 1; iVert < psObject->
nVertices; ++iVert) {
2806 if (psObject->
padfZ[iVert] != psObject->
padfZ[0]) {
2817 for (
int iOpRing = 0; iOpRing < psObject->
nParts; iOpRing++) {
2818 const int nVertStart = psObject->
panPartStart[iOpRing];
2819 const int nVertCount = SHPGetPartVertexCount(psObject, iOpRing);
2830 int bDoIsInnerRingTest =
TRUE;
2832 int bPartSameZ =
TRUE;
2833 for (
int iVert = nVertStart + 1; iVert < nVertStart + nVertCount;
2835 if (psObject->
padfZ[iVert] != psObject->
padfZ[nVertStart]) {
2841 bDoIsInnerRingTest =
FALSE;
2845 if (bDoIsInnerRingTest) {
2846 for (
int iTolerance = 0; iTolerance < 2; iTolerance++) {
2854 const double dfRelativeTolerance = (iTolerance == 0) ? 1e-9 : 0;
2855 for (
int iVert = nVertStart;
2856 iVert + 1 < nVertStart + nVertCount; ++iVert) {
2860 const double dfTestX =
2861 (psObject->
padfX[iVert] + psObject->
padfX[iVert + 1]) /
2863 const double dfTestY =
2864 (psObject->
padfY[iVert] + psObject->
padfY[iVert + 1]) /
2866 const double dfTestZ =
2867 !bSameZ ? psObject->
padfZ[nVertStart] : 0;
2869 bInner = SHPRewindIsInnerRing(psObject, iOpRing, dfTestX,
2870 dfTestY, dfRelativeTolerance,
2891 double dfSum = psObject->
padfX[nVertStart] *
2892 (psObject->
padfY[nVertStart + 1] -
2893 psObject->
padfY[nVertStart + nVertCount - 1]);
2894 int iVert = nVertStart + 1;
2895 for (; iVert < nVertStart + nVertCount - 1; iVert++) {
2896 dfSum += psObject->
padfX[iVert] *
2897 (psObject->
padfY[iVert + 1] - psObject->
padfY[iVert - 1]);
2900 dfSum += psObject->
padfX[iVert] *
2901 (psObject->
padfY[nVertStart] - psObject->
padfY[iVert - 1]);
2908 if ((dfSum < 0.0 && bInner) || (dfSum > 0.0 && !bInner)) {
2910 for (
int i = 0; i < nVertCount / 2; i++) {
2912 double dfSaved = psObject->
padfX[nVertStart + i];
2913 psObject->
padfX[nVertStart + i] =
2914 psObject->
padfX[nVertStart + nVertCount - i - 1];
2915 psObject->
padfX[nVertStart + nVertCount - i - 1] = dfSaved;
2918 dfSaved = psObject->
padfY[nVertStart + i];
2919 psObject->
padfY[nVertStart + i] =
2920 psObject->
padfY[nVertStart + nVertCount - i - 1];
2921 psObject->
padfY[nVertStart + nVertCount - i - 1] = dfSaved;
2924 if (psObject->
padfZ) {
2925 dfSaved = psObject->
padfZ[nVertStart + i];
2926 psObject->
padfZ[nVertStart + i] =
2927 psObject->
padfZ[nVertStart + nVertCount - i - 1];
2928 psObject->
padfZ[nVertStart + nVertCount - i - 1] = dfSaved;
2932 if (psObject->
padfM) {
2933 dfSaved = psObject->
padfM[nVertStart + i];
2934 psObject->
padfM[nVertStart + i] =
2935 psObject->
padfM[nVertStart + nVertCount - i - 1];
2936 psObject->
padfM[nVertStart + nVertCount - i - 1] = dfSaved;
#define assert(condition)
void SASetupDefaultHooks(SAHooks *psHooks)
#define DISABLE_MULTIPATCH_MEASURE
#define SHP_SWAPDOUBLE_CPY(dst, src)
#define STATIC_CAST(type, x)
SHPHandle SHPAPI_CALL SHPOpen(const char *pszLayer, const char *pszAccess)
SHPObject SHPAPI_CALL1 * SHPReadObject(const SHPHandle psSHP, int hEntity){ if(hEntity< 0||hEntity >=psSHP->nRecords) return SHPLIB_NULLPTR;if(psSHP->panRecOffset[hEntity]==0 &&psSHP->fpSHX !=SHPLIB_NULLPTR
SHPHandle SHPAPI_CALL SHPOpenLLEx(const char *pszLayer, const char *pszAccess, const SAHooks *psHooks, int bRestoreSHX)
void SHPAPI_CALL SHPGetInfo(const SHPHandle psSHP, int *pnEntities, int *pnShapeType, double *padfMinBound, double *padfMaxBound)
SHPHandle SHPAPI_CALL SHPCreateLL(const char *pszLayer, int nShapeType, const SAHooks *psHooks)
SHPHandle SHPAPI_CALL SHPCreate(const char *pszLayer, int nShapeType)
void SHPAPI_CALL SHPSetFastModeReadObject(SHPHandle hSHP, int bFastMode)
SHPObject SHPAPI_CALL1 * SHPCreateObject(int nSHPType, int nShapeId, int nParts, const int *panPartStart, const int *panPartType, int nVertices, const double *padfX, const double *padfY, const double *padfZ, const double *padfM){ SHPObject *psObject=STATIC_CAST(SHPObject *, calloc(1, sizeof(SHPObject))
void SHPAPI_CALL SHPComputeExtents(SHPObject *psObject)
SHPObject SHPAPI_CALL1 * SHPCreateSimpleObject(int nSHPType, int nVertices, const double *padfX, const double *padfY, const double *padfZ){ return(SHPCreateObject(nSHPType, -1, 0, SHPLIB_NULLPTR, SHPLIB_NULLPTR, nVertices, padfX, padfY, padfZ, SHPLIB_NULLPTR)
if(nSHPType==SHPT_ARCM||nSHPType==SHPT_POINTM||nSHPType==SHPT_POLYGONM||nSHPType==SHPT_MULTIPOINTM)
void SHPAPI_CALL SHPWriteHeader(SHPHandle psSHP)
void SHPAPI_CALL SHPClose(SHPHandle psSHP)
int SHPAPI_CALL SHPRestoreSHX(const char *pszLayer, const char *pszAccess, const SAHooks *psHooks)
SHPHandle SHPAPI_CALL SHPOpenLL(const char *pszLayer, const char *pszAccess, const SAHooks *psHooks)
int SHPAPI_CALL SHPWriteObject(SHPHandle psSHP, int nShapeId, const SHPObject *psObject)
void SHPAPI_CALL SHPDestroyObject(SHPObject *psShape)
int SHPAPI_CALL SHPRewindObject(const SHPHandle hSHP, SHPObject *psObject)
#define ByteCopy(a, b, c)
const char SHPAPI_CALL1 * SHPPartTypeName(int nPartType){ switch(nPartType
const char SHPAPI_CALL1 * SHPTypeName(int nSHPType){ switch(nSHPType
void(* Error)(const char *message)
SAOffset(* FTell)(SAFile file)
int(* FFlush)(SAFile file)
SAFile(* FOpen)(const char *filename, const char *access, void *pvUserData)
SAOffset(* FWrite)(const void *p, SAOffset size, SAOffset nmemb, SAFile file)
int(* FClose)(SAFile file)
SAOffset(* FRead)(void *p, SAOffset size, SAOffset nmemb, SAFile file)
SAOffset(* FSeek)(SAFile file, SAOffset offset, int whence)
SHPObject * psCachedObject
unsigned int * panRecSize
unsigned char * pabyObjectBuf
unsigned int * panRecOffset