#include <windows.h>
#elif defined(__APPLE__) || defined(__linux__) || defined(__unix__) || defined(_POSIX_VERSION)
#include <cerrno>
+#include <memory>
+#include <vector>
+
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
unsigned int shift = 0;
while(true) {
value |= (((static_cast<uint64_t>(buffer[i])) & UINT8_C(0x7F)) << shift);
- shift += 7u;
+ shift += 7U;
if(!(buffer[i] & UINT8_C(0x80))) {
break;
#if defined(_MSC_VER)
__try {
#endif
- if(memcmp(library->mapping, "PLB", 3)) {
+ if(memcmp(library->mapping, "PLB", 3) != 0) {
return -1;
}
static uint32_t ZDUnshuffle(uint64_t w)
{
- w &= 0x5555555555555555llu;
- w = (w | (w >> 1)) & 0x3333333333333333llu;
- w = (w | (w >> 2)) & 0x0F0F0F0F0F0F0F0Fllu;
- w = (w | (w >> 4)) & 0x00FF00FF00FF00FFllu;
- w = (w | (w >> 8)) & 0x0000FFFF0000FFFFllu;
- w = (w | (w >> 16)) & 0x00000000FFFFFFFFllu;
+ w &= 0x5555555555555555LLU;
+ w = (w | (w >> 1)) & 0x3333333333333333LLU;
+ w = (w | (w >> 2)) & 0x0F0F0F0F0F0F0F0FLLU;
+ w = (w | (w >> 4)) & 0x00FF00FF00FF00FFLLU;
+ w = (w | (w >> 8)) & 0x0000FFFF0000FFFFLLU;
+ w = (w | (w >> 16)) & 0x00000000FFFFFFFFLLU;
return static_cast<uint32_t>(w);
}
static int ZDReaderGetPoint(struct Reader *reader, int32_t *pointLat, int32_t *pointLon)
{
- int32_t diffLat = 0, diffLon = 0;
+ int32_t diffLat = 0;
+ int32_t diffLon = 0;
-readNewPoint:
- if(reader->done > 1) {
- return 0;
- }
+ while(true) {
+ if(reader->done > 1) {
+ return 0;
+ }
- if(reader->first && reader->library->version == 0) {
- if(!ZDDecodeVariableLengthUnsigned(reader->library, &reader->polygonIndex, &reader->numVertices)) return -1;
- if(!reader->numVertices) return -1;
- }
+ if(reader->first && reader->library->version == 0) {
+ if(!ZDDecodeVariableLengthUnsigned(reader->library, &reader->polygonIndex, &reader->numVertices)) return -1;
+ if(!reader->numVertices) return -1;
+ }
- uint8_t referenceDone = 0;
+ uint8_t referenceDone = 0;
- if(reader->library->version == 1) {
- uint64_t point = 0;
+ if(reader->library->version == 1) {
+ uint64_t point = 0;
- if(!reader->referenceDirection) {
- if(!ZDDecodeVariableLengthUnsigned(reader->library, &reader->polygonIndex, &point)) return -1;
- } else {
- if(reader->referenceDirection > 0) {
- /* Read reference forward */
- if(!ZDDecodeVariableLengthUnsigned(reader->library, &reader->referenceStart, &point)) return -1;
- if(reader->referenceStart >= reader->referenceEnd) {
- referenceDone = 1;
- }
- } else if(reader->referenceDirection < 0) {
- /* Read reference backwards */
- if(!ZDDecodeVariableLengthUnsignedReverse(reader->library, &reader->referenceStart, &point)) return -1;
- if(reader->referenceStart <= reader->referenceEnd) {
- referenceDone = 1;
+ if(!reader->referenceDirection) {
+ if(!ZDDecodeVariableLengthUnsigned(reader->library, &reader->polygonIndex, &point)) return -1;
+ } else {
+ if(reader->referenceDirection > 0) {
+ /* Read reference forward */
+ if(!ZDDecodeVariableLengthUnsigned(reader->library, &reader->referenceStart, &point)) return -1;
+ if(reader->referenceStart >= reader->referenceEnd) {
+ referenceDone = 1;
+ }
+ } else if(reader->referenceDirection < 0) {
+ /* Read reference backwards */
+ if(!ZDDecodeVariableLengthUnsignedReverse(reader->library, &reader->referenceStart, &point)) return -1;
+ if(reader->referenceStart <= reader->referenceEnd) {
+ referenceDone = 1;
+ }
}
}
- }
- if(!point) {
- /* This is a special marker, it is not allowed in reference mode */
- if(reader->referenceDirection) {
- return -1;
- }
+ if(!point) {
+ /* This is a special marker, it is not allowed in reference mode */
+ if(reader->referenceDirection) {
+ return -1;
+ }
- uint64_t value;
- if(!ZDDecodeVariableLengthUnsigned(reader->library, &reader->polygonIndex, &value)) return -1;
-
- if(value == 0) {
- reader->done = 2;
- } else if(value == 1) {
- int32_t diff;
- int64_t start;
- if(!ZDDecodeVariableLengthUnsigned(reader->library, &reader->polygonIndex, reinterpret_cast<uint64_t*>(&start))) return -1;
- if(!ZDDecodeVariableLengthSigned(reader->library, &reader->polygonIndex, &diff)) return -1;
-
- reader->referenceStart = reader->library->dataOffset+static_cast<uint32_t>(start);
- reader->referenceEnd = reader->library->dataOffset+static_cast<uint32_t>(start + diff);
- reader->referenceDirection = diff;
- if(diff < 0) {
- reader->referenceStart--;
- reader->referenceEnd--;
+ uint64_t value;
+ if(!ZDDecodeVariableLengthUnsigned(reader->library, &reader->polygonIndex, &value)) return -1;
+
+ if(value == 0) {
+ reader->done = 2;
+ } else if(value == 1) {
+ int32_t diff;
+ int64_t start;
+ if(!ZDDecodeVariableLengthUnsigned(reader->library, &reader->polygonIndex, reinterpret_cast<uint64_t*>(&start))) return -1;
+ if(!ZDDecodeVariableLengthSigned(reader->library, &reader->polygonIndex, &diff)) return -1;
+
+ reader->referenceStart = reader->library->dataOffset+static_cast<uint32_t>(start);
+ reader->referenceEnd = reader->library->dataOffset+static_cast<uint32_t>(start + diff);
+ reader->referenceDirection = diff;
+ if(diff < 0) {
+ reader->referenceStart--;
+ reader->referenceEnd--;
+ }
+ continue;
+ }
+ } else {
+ ZDDecodePoint(point, &diffLat, &diffLon);
+ if(reader->referenceDirection < 0) {
+ diffLat = -diffLat;
+ diffLon = -diffLon;
}
- goto readNewPoint;
- }
- } else {
- ZDDecodePoint(point, &diffLat, &diffLon);
- if(reader->referenceDirection < 0) {
- diffLat = -diffLat;
- diffLon = -diffLon;
}
}
- }
- if(reader->library->version == 0) {
- if(!ZDDecodeVariableLengthSigned(reader->library, &reader->polygonIndex, &diffLat)) return -1;
- if(!ZDDecodeVariableLengthSigned(reader->library, &reader->polygonIndex, &diffLon)) return -1;
- }
+ if(reader->library->version == 0) {
+ if(!ZDDecodeVariableLengthSigned(reader->library, &reader->polygonIndex, &diffLat)) return -1;
+ if(!ZDDecodeVariableLengthSigned(reader->library, &reader->polygonIndex, &diffLon)) return -1;
+ }
- if(!reader->done) {
- reader->pointLat += diffLat;
- reader->pointLon += diffLon;
- if(reader->first) {
- reader->firstLat = reader->pointLat;
- reader->firstLon = reader->pointLon;
+ if(!reader->done) {
+ reader->pointLat += diffLat;
+ reader->pointLon += diffLon;
+ if(reader->first) {
+ reader->firstLat = reader->pointLat;
+ reader->firstLon = reader->pointLon;
+ }
+ } else {
+ /* Close the polygon (the closing point is not encoded) */
+ reader->pointLat = reader->firstLat;
+ reader->pointLon = reader->firstLon;
+ reader->done = 2;
}
- } else {
- /* Close the polygon (the closing point is not encoded) */
- reader->pointLat = reader->firstLat;
- reader->pointLon = reader->firstLon;
- reader->done = 2;
- }
- reader->first = 0;
+ reader->first = 0;
- if(reader->library->version == 0) {
- reader->numVertices--;
- if(!reader->numVertices) {
- reader->done = 1;
+ if(reader->library->version == 0) {
+ reader->numVertices--;
+ if(!reader->numVertices) {
+ reader->done = 1;
+ }
+ if(!diffLat && !diffLon) {
+ continue;
+ }
}
- if(!diffLat && !diffLon) {
- goto readNewPoint;
+
+ if(referenceDone) {
+ reader->referenceDirection = 0;
}
- }
- if(referenceDone) {
- reader->referenceDirection = 0;
+ break;
}
if(pointLat) {
uint32_t polygonId = 0;
uint32_t bboxIndex = library->bboxOffset;
- uint32_t metadataIndex = 0, polygonIndex = 0;
+ uint32_t metadataIndex = 0;
+ uint32_t polygonIndex = 0;
while(bboxIndex < library->metadataOffset) {
uint64_t polygonIndexDelta;
return 0;
}
-static int32_t* ZDPolygonToListInternal(const ZoneDetect *library, uint32_t polygonIndex, size_t* length)
+static std::vector<int32_t> ZDPolygonToListInternal(const ZoneDetect *library, uint32_t polygonIndex)
{
struct Reader reader;
ZDReaderInit(&reader, library, polygonIndex);
- size_t listLength = 2 * 100;
- size_t listIndex = 0;
-
- auto list = static_cast<int32_t *>(malloc(sizeof(int32_t) * listLength));
- if(!list) {
- goto fail;
- }
+ constexpr size_t listLength = 2 * 100;
+ std::vector<int32_t> list;
+ list.reserve(listLength);
while(true) {
- int32_t pointLat, pointLon;
+ int32_t pointLat;
+ int32_t pointLon;
int result = ZDReaderGetPoint(&reader, &pointLat, &pointLon);
if(result < 0) {
- goto fail;
- } else if(result == 0) {
+ return {};
+ }
+ if(result == 0) {
break;
}
- if(listIndex >= listLength) {
- listLength *= 2;
- if(listLength >= 1048576) {
- goto fail;
- }
+ list.push_back(pointLat);
+ list.push_back(pointLon);
- list = static_cast<int32_t *>(realloc(list, sizeof(int32_t) * listLength));
- if(!list) {
- goto fail;
- }
+ if(list.size() >= 1048576) {
+ return {};
}
-
- list[listIndex++] = pointLat;
- list[listIndex++] = pointLon;
- }
-
- if(length) {
- *length = listIndex;
}
return list;
-
-fail:
- if(list) {
- free(list);
- }
- return nullptr;
}
float* ZDPolygonToList(const ZoneDetect *library, uint32_t polygonId, size_t* lengthPtr)
{
uint32_t polygonIndex;
- int32_t* data = nullptr;
float* flData = nullptr;
- size_t length = 0;
if (!ZDFindPolygon(library, polygonId, nullptr, &polygonIndex))
- return nullptr;
+ return nullptr;
+
+ const auto data = ZDPolygonToListInternal(library, polygonIndex);
+ if (data.empty())
+ return nullptr;
- data = ZDPolygonToListInternal(library, polygonIndex, &length);
- if (!data)
- return nullptr;
+ size_t length = data.size();
flData = static_cast<float *>(malloc(sizeof(float) * length));
if(!flData) {
- free(data);
- return nullptr;
- }
+ return nullptr;
+ }
for(size_t i = 0; i<length; i+= 2) {
int32_t lat = data[i];
flData[i+1] = ZDFixedPointToFloat(lon, 180, library->precision);
}
- free(data);
-
if(lengthPtr) {
*lengthPtr = length;
}
static ZDLookupResult ZDPointInPolygon(const ZoneDetect *library, uint32_t polygonIndex, int32_t latFixedPoint, int32_t lonFixedPoint, uint64_t *distanceSqrMin)
{
- int32_t pointLat, pointLon, prevLat = 0, prevLon = 0;
- int prevQuadrant = 0, winding = 0;
+ int32_t pointLat;
+ int32_t pointLon;
+ int32_t prevLat = 0;
+ int32_t prevLon = 0;
+ int prevQuadrant = 0;
+ int winding = 0;
uint8_t first = 1;
int result = ZDReaderGetPoint(&reader, &pointLat, &pointLon);
if(result < 0) {
return ZD_LOOKUP_PARSE_ERROR;
- } else if(result == 0) {
+ } if(result == 0) {
break;
}
}
if(!first) {
- int windingNeedCompare = 0, lineIsStraight = 0;
- float a = 0, b = 0;
+ int windingNeedCompare = 0;
+ int lineIsStraight = 0;
+ float a = 0;
+ float b = 0;
/* Calculate winding number */
if(quadrant == prevQuadrant) {
/* Calculate closest point on line (if needed) */
if(distanceSqrMin) {
- float closestLon, closestLat;
+ float closestLon;
+ float closestLat;
if(!lineIsStraight) {
closestLon = (static_cast<float>(lonFixedPoint) + a * static_cast<float>(latFixedPoint) - a * b) / (a * a + 1);
closestLat = (a * (static_cast<float>(lonFixedPoint) + a * static_cast<float>(latFixedPoint)) + b) / (a * a + 1);
const int closestInBox = ZDPointInBox(pointLon, static_cast<int32_t>(closestLon), prevLon, pointLat, static_cast<int32_t>(closestLat), prevLat);
- int64_t diffLat, diffLon;
+ int64_t diffLat;
+ int64_t diffLon;
if(closestInBox) {
/* Calculate squared distance to segment. */
diffLat = static_cast<int64_t>(closestLat - static_cast<float>(latFixedPoint));
if(winding == -4) {
return ZD_LOOKUP_IN_ZONE;
- } else if(winding == 4) {
+ } if(winding == 4) {
return ZD_LOOKUP_IN_EXCLUDED_ZONE;
- } else if(winding == 0) {
+ } if(winding == 0) {
return ZD_LOOKUP_NOT_IN_ZONE;
}
}
}
+struct ZoneDetectDeleter {
+ void operator()(ZoneDetect *library)
+ {
+ ZDCloseDatabase(library);
+ }
+};
+
+using ZoneDetectPtr = std::unique_ptr<ZoneDetect, ZoneDetectDeleter>;
+
ZoneDetect *ZDOpenDatabaseFromMemory(void* buffer, size_t length)
{
- auto library = static_cast<ZoneDetect *>(malloc(sizeof(ZoneDetect)));
+ ZoneDetectPtr library{static_cast<ZoneDetect *>(calloc(1, sizeof(ZoneDetect)))};
if(library) {
- memset(library, 0, sizeof(*library));
library->closeType = 1;
library->length = static_cast<long int>(length);
#else
zdError(ZD_E_DB_SEEK, 0);
#endif
- goto fail;
+ return nullptr;
}
library->mapping = static_cast<uint8_t *>(buffer);
/* Parse the header */
- if(ZDParseHeader(library)) {
+ if(ZDParseHeader(library.get())) {
zdError(ZD_E_PARSE_HEADER, 0);
- goto fail;
+ return nullptr;
}
}
- return library;
-
-fail:
- ZDCloseDatabase(library);
- return nullptr;
+ return library.release();
}
ZoneDetect *ZDOpenDatabase(const char *path)
{
- auto library = static_cast<ZoneDetect *>(malloc(sizeof(ZoneDetect)));
+ ZoneDetectPtr library{static_cast<ZoneDetect *>(calloc(1, sizeof(ZoneDetect)))};
if(library) {
- memset(library, 0, sizeof(*library));
-
#if defined(_MSC_VER) || defined(__MINGW32__)
library->fd = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (library->fd == INVALID_HANDLE_VALUE) {
zdError(ZD_E_DB_OPEN, (int)GetLastError());
- goto fail;
+ return nullptr;
}
const DWORD fsize = GetFileSize(library->fd, NULL);
if (fsize == INVALID_FILE_SIZE) {
zdError(ZD_E_DB_SEEK, (int)GetLastError());
- goto fail;
+ return nullptr;
}
library->length = (int32_t)fsize;
library->fdMap = CreateFileMappingA(library->fd, NULL, PAGE_READONLY, 0, 0, NULL);
if (!library->fdMap) {
zdError(ZD_E_DB_MMAP, (int)GetLastError());
- goto fail;
+ return nullptr;
}
library->mapping = MapViewOfFile(library->fdMap, FILE_MAP_READ, 0, 0, 0);
if (!library->mapping) {
zdError(ZD_E_DB_MMAP_MSVIEW, (int)GetLastError());
- goto fail;
+ return nullptr;
}
#elif defined(__APPLE__) || defined(__linux__) || defined(__unix__) || defined(_POSIX_VERSION)
library->fd = open(path, O_RDONLY | O_CLOEXEC);
if(library->fd < 0) {
zdError(ZD_E_DB_OPEN, errno);
- goto fail;
+ return nullptr;
}
library->length = lseek(library->fd, 0, SEEK_END);
if(library->length <= 0 || library->length > 50331648) {
zdError(ZD_E_DB_SEEK, errno);
- goto fail;
+ return nullptr;
}
lseek(library->fd, 0, SEEK_SET);
library->mapping = static_cast<uint8_t *>(mmap(nullptr, static_cast<size_t>(library->length), PROT_READ, MAP_PRIVATE | MAP_FILE, library->fd, 0));
if(library->mapping == MAP_FAILED) {
zdError(ZD_E_DB_MMAP, errno);
- goto fail;
+ return nullptr;
}
#endif
/* Parse the header */
- if(ZDParseHeader(library)) {
+ if(ZDParseHeader(library.get())) {
zdError(ZD_E_PARSE_HEADER, 0);
- goto fail;
+ return nullptr;
}
}
- return library;
-
-fail:
- ZDCloseDatabase(library);
- return nullptr;
+ return library.release();
}
ZoneDetectResult *ZDLookup(const ZoneDetect *library, float lat, float lon, float *safezone)
uint32_t polygonId = 0;
while(bboxIndex < library->metadataOffset) {
- int32_t minLat, minLon, maxLat, maxLon, metadataIndexDelta;
+ int32_t minLat;
+ int32_t minLon;
+ int32_t maxLat;
+ int32_t maxLon;
+ int32_t metadataIndexDelta;
uint64_t polygonIndexDelta;
if(!ZDDecodeVariableLengthSigned(library, &bboxIndex, &minLat)) break;
if(!ZDDecodeVariableLengthSigned(library, &bboxIndex, &minLon)) break;
const ZDLookupResult lookupResult = ZDPointInPolygon(library, library->dataOffset + polygonIndex, latFixedPoint, lonFixedPoint, (safezone) ? &distanceSqrMin : nullptr);
if(lookupResult == ZD_LOOKUP_PARSE_ERROR) {
break;
- } else if(lookupResult != ZD_LOOKUP_NOT_IN_ZONE) {
+ } if(lookupResult != ZD_LOOKUP_NOT_IN_ZONE) {
auto newResults = static_cast<ZoneDetectResult *>(realloc(results, sizeof(ZoneDetectResult) * (numResults + 2)));
if(newResults) {
char* ZDHelperSimpleLookupString(const ZoneDetect* library, float lat, float lon)
{
- ZoneDetectResult *result = ZDLookup(library, lat, lon, nullptr);
+ std::unique_ptr<ZoneDetectResult, decltype(&ZDFreeResults)> result{ZDLookup(library, lat, lon, nullptr), ZDFreeResults};
if(!result) {
return nullptr;
}
size_t length = 0;
char* strings[2] = {nullptr};
- if(result[0].lookupResult == ZD_LOOKUP_END) {
- goto done;
+ if(result->lookupResult == ZD_LOOKUP_END) {
+ return nullptr;
}
- for(int i = 0; i < result[0].numFields; i++) {
- if(result[0].fieldNames[i] && result[0].data[i]) {
+ for(int i = 0; i < result->numFields; i++) {
+ if(result->fieldNames[i] && result->data[i]) {
if(library->tableType == 'T') {
- if(!strcmp(result[0].fieldNames[i], "TimezoneIdPrefix")) {
- strings[0] = result[0].data[i];
+ if(!strcmp(result->fieldNames[i], "TimezoneIdPrefix")) {
+ strings[0] = result->data[i];
}
- if(!strcmp(result[0].fieldNames[i], "TimezoneId")) {
- strings[1] = result[0].data[i];
+ if(!strcmp(result->fieldNames[i], "TimezoneId")) {
+ strings[1] = result->data[i];
}
}
if(library->tableType == 'C') {
- if(!strcmp(result[0].fieldNames[i], "Name")) {
- strings[0] = result[0].data[i];
+ if(!strcmp(result->fieldNames[i], "Name")) {
+ strings[0] = result->data[i];
}
}
}
if(string) {
size_t partLength = strlen(string);
if(partLength > 512) {
- goto done;
+ return nullptr;
}
length += partLength;
}
}
if(length == 0) {
- goto done;
+ return nullptr;
}
length += 1;
}
}
-done:
- ZDFreeResults(result);
return output;
}