Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
unittest/gmon.out
unittest/_*.txt
unittest/*.gcov
unittest/*.gcda
unittest/*.gcno
mapcodelib/*.gcov
mapcodelib/*.gcda
mapcodelib/*.gcno

# -----------------------------------------------------------------------------
# Compiled sources
Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ decode Mapcodes.

This produces the following help text:

MAPCODE (version 2.4.1)
MAPCODE (version 2.5.1)
Copyright (C) 2014-2016 Stichting Mapcode Foundation

Usage:
Expand Down Expand Up @@ -137,6 +137,10 @@ footprint, for example for embedded applications.

## Release Notes

### 2.5.1

* Updated unit test to compile with plain C and added some test cases.

### 2.5.0

* Added support for getting territory names in English and local alphabets.
Expand Down
2 changes: 1 addition & 1 deletion mapcodelib/internal_alphabet_recognizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ static const signed char ALPHABET_OF[] = {
#define ROMAN_VERSION_MAX_CHAR 0x3129
static const char *ROMAN_VERSION_OF[] = {
/* 0000 */ "\0 !?#$%&'()*+,-./0123456789:;<=>?",
/* 0040 */ "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[?]^_`abcdefghijklmnopqrstuvwxyz{|}~?",
/* 0040 */ "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[?]^_`ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~?",
/* 0080 */ NULL,
/* 00c0 */ NULL,
/* 0100 */ NULL,
Expand Down
57 changes: 30 additions & 27 deletions mapcodelib/mapcoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ void _TestAssert(int iCondition, const char *cstrFile, int iLine) {
#define REC_TYPE(m) ((TERRITORY_BOUNDARIES[m].flags >> 7) & 3)
#define SMART_DIV(m) (TERRITORY_BOUNDARIES[m].flags >> 16)
#define HEADER_LETTER(m) (ENCODE_CHARS[(TERRITORY_BOUNDARIES[m].flags >> 11) & 31])
#define BOUNDARY_PTR(m) (&TERRITORY_BOUNDARIES[m])

#define TOKENSEP 0
#define TOKENDOT 1
Expand All @@ -90,6 +89,12 @@ void _TestAssert(int iCondition, const char *cstrFile, int iLine) {
#define EARTH_CIRCUMFERENCE_X (EARTH_RADIUS_X_METERS * 2 * MATH_PI)
#define EARTH_CIRCUMFERENCE_Y (EARTH_RADIUS_Y_METERS * 2 * MATH_PI)

#define MICROLAT_TO_FRACTIONS_FACTOR ((double) MAX_PRECISION_FACTOR)
#define MICROLON_TO_FRACTIONS_FACTOR (4.0 * MAX_PRECISION_FACTOR)

#define FLAG_UTF8_STRING 0 // interpret pointer a utf8 characters
#define FLAG_UTF16_STRING 1 // interpret pointer a UWORD* to utf16 characters

// Meters per degree latitude is fixed. For longitude: use factor * cos(midpoint of two degree latitudes).
static const double METERS_PER_DEGREE_LAT = EARTH_CIRCUMFERENCE_Y / 360.0;
static const double METERS_PER_DEGREE_LON = EARTH_CIRCUMFERENCE_X / 360.0;
Expand Down Expand Up @@ -330,8 +335,7 @@ static TerritoryBoundary *getExtendedBoundaries(TerritoryBoundary *target, const
//
///////////////////////////////////////////////////////////////////////////////////////////////

#define MICROLAT_TO_FRACTIONS_FACTOR ((double)MAX_PRECISION_FACTOR)
#define MICROLON_TO_FRACTIONS_FACTOR (4.0 * MAX_PRECISION_FACTOR)

typedef struct {
// latitudes in "810 billionths", range [-729 E11 .. +720 E11), is well within (-2^47 ... +2^47)
double fminy;
Expand Down Expand Up @@ -822,7 +826,7 @@ static const int NC[6] = {1, 31, 961, 29791, 923521, 28629151};
// returns *result==0 in case of error
static void encodeGrid(char *result, const EncodeRec *enc, const int m, const int extraDigits,
const char headerLetter) {
const TerritoryBoundary *b = BOUNDARY_PTR(m);
const TerritoryBoundary *b = TERRITORY_BOUNDARY(m);
const int orgcodex = coDex(m);
int codexm;
ASSERT(result);
Expand Down Expand Up @@ -999,7 +1003,7 @@ static void encodeNameless(char *result, const EncodeRec *enc, const enum Territ

SIDE = SMART_DIV(m);

b = BOUNDARY_PTR(m);
b = TERRITORY_BOUNDARY(m);
orgSIDE = SIDE;

{
Expand Down Expand Up @@ -1075,7 +1079,7 @@ static void encodeAutoHeader(char *result, const EncodeRec *enc, const int m, co

i = firstindex;
for (;;) {
b = BOUNDARY_PTR(i);
b = TERRITORY_BOUNDARY(i);
// determine how many cells
H = (b->maxy - b->miny + 89) / 90; // multiple of 10m
xdiv = xDivider4(b->miny, b->maxy);
Expand Down Expand Up @@ -1137,7 +1141,7 @@ static void encoderEngine(const enum Territory ccode, const EncodeRec *enc, cons
from = firstRec(ccode);
upto = lastRec(ccode);

if (!fitsInsideBoundaries(&enc->coord32, BOUNDARY_PTR(upto))) {
if (!fitsInsideBoundaries(&enc->coord32, TERRITORY_BOUNDARY(upto))) {
return;
}

Expand All @@ -1151,7 +1155,7 @@ static void encoderEngine(const enum Territory ccode, const EncodeRec *enc, cons

*result = 0;
for (i = from; i <= upto; i++) {
if (fitsInsideBoundaries(&enc->coord32, BOUNDARY_PTR(i))) {
if (fitsInsideBoundaries(&enc->coord32, TERRITORY_BOUNDARY(i))) {
if (IS_NAMELESS(i)) {
encodeNameless(result, enc, ccode, extraDigits, i);
} else if (REC_TYPE(i) > 1) {
Expand Down Expand Up @@ -1478,7 +1482,7 @@ static enum MapcodeError decodeGrid(DecodeRec *dec, const int m, const int hasHe


{
const TerritoryBoundary *b = BOUNDARY_PTR(m);
const TerritoryBoundary *b = TERRITORY_BOUNDARY(m);
const int ygridsize = (b->maxy - b->miny + divy - 1) / divy; // microdegrees per cell
const int xgridsize = (b->maxx - b->minx + divx - 1) / divx; // microdegrees per cell

Expand Down Expand Up @@ -1521,7 +1525,7 @@ static enum MapcodeError decodeGrid(DecodeRec *dec, const int m, const int hasHe

dec->coord32.lonMicroDeg = relx + (difx * dividerx);
dec->coord32.latMicroDeg = rely + (dify * dividery);
if (!fitsInsideBoundaries(&dec->coord32, BOUNDARY_PTR(m))) {
if (!fitsInsideBoundaries(&dec->coord32, TERRITORY_BOUNDARY(m))) {
return ERR_MAPCODE_UNDECODABLE; // type 2 "NLD Q000.000"
}

Expand Down Expand Up @@ -1637,7 +1641,7 @@ static enum MapcodeError decodeNameless(DecodeRec *dec, int m) {

xSIDE = SIDE = SMART_DIV(m);

b = BOUNDARY_PTR(m);
b = TERRITORY_BOUNDARY(m);

// decode
{
Expand Down Expand Up @@ -1692,7 +1696,7 @@ static enum MapcodeError decodeAutoHeader(DecodeRec *dec, int m) {
value *= (961 * 31);

for (; coDex(m) == codexm && REC_TYPE(m) > 1; m++) {
const TerritoryBoundary *b = BOUNDARY_PTR(m);
const TerritoryBoundary *b = TERRITORY_BOUNDARY(m);
// determine how many cells
int H = (b->maxy - b->miny + 89) / 90; // multiple of 10m
const int xdiv = xDivider4(b->miny, b->maxy);
Expand Down Expand Up @@ -2020,12 +2024,8 @@ static const int STATE_MACHINE[27][6] = {


// Returns 0 if ok, negative in case of error (where -999 represents "may BECOME a valid mapcode if more characters are added)
#define FLAG_UTF8_STRING 0 // interpret pointer a utf8 characters
#define FLAG_UTF16_STRING 1 // interpret pointer a UWORD* to utf16 characters


static enum MapcodeError parseMapcodeString(MapcodeElements *mapcodeElements, const char *string, int interpretAsUtf16,
enum Territory territory) {
enum Territory territory) {
const UWORD *utf16 = (const UWORD *) string;
int isAbjad = 0;
const unsigned char *utf8 = (unsigned char *) string;
Expand Down Expand Up @@ -2168,7 +2168,8 @@ static enum MapcodeError parseMapcodeString(MapcodeElements *mapcodeElements, co
}
if (isAbjad) {
convertFromAbjad(mapcodeElements->properMapcode);
mapcodeElements->indexOfDot = (int) (strchr(mapcodeElements->properMapcode, '.') - mapcodeElements->properMapcode);
mapcodeElements->indexOfDot = (int) (strchr(mapcodeElements->properMapcode, '.') -
mapcodeElements->properMapcode);
}
if (*mapcodeElements->territoryISO) {
mapcodeElements->territoryCode = getTerritoryCode(mapcodeElements->territoryISO, territory);
Expand Down Expand Up @@ -2270,7 +2271,7 @@ static enum MapcodeError decoderEngine(DecodeRec *dec, int parseFlags) {
err = decodeGrid(dec, i, 0);

// first of all, make sure the zone fits the country
restrictZoneTo(&dec->zone, &dec->zone, BOUNDARY_PTR(upto));
restrictZoneTo(&dec->zone, &dec->zone, TERRITORY_BOUNDARY(upto));

if ((err == ERR_OK) && IS_RESTRICTED(i)) {
int nrZoneOverlaps = 0;
Expand All @@ -2281,7 +2282,7 @@ static enum MapcodeError decoderEngine(DecodeRec *dec, int parseFlags) {
dec->coord32 = convertFractionsToCoord32(&dec->result);
for (j = i - 1; j >= from; j--) { // look in previous rects
if (!IS_RESTRICTED(j)) {
if (fitsInsideBoundaries(&dec->coord32, BOUNDARY_PTR(j))) {
if (fitsInsideBoundaries(&dec->coord32, TERRITORY_BOUNDARY(j))) {
nrZoneOverlaps = 1;
break;
}
Expand All @@ -2294,13 +2295,13 @@ static enum MapcodeError decoderEngine(DecodeRec *dec, int parseFlags) {
for (j = from; j < i; j++) { // try all smaller rectangles j
if (!IS_RESTRICTED(j)) {
MapcodeZone z;
if (restrictZoneTo(&z, &dec->zone, BOUNDARY_PTR(j))) {
if (restrictZoneTo(&z, &dec->zone, TERRITORY_BOUNDARY(j))) {
nrZoneOverlaps++;
if (nrZoneOverlaps == 1) {
// first fit! remember...
zoneCopyFrom(&zfound, &z);
ASSERT(j <= MAPCODE_BOUNDARY_MAX);
memcpy(&prevu, BOUNDARY_PTR(j), sizeof(TerritoryBoundary));
memcpy(&prevu, TERRITORY_BOUNDARY(j), sizeof(TerritoryBoundary));
} else { // nrZoneOverlaps >= 2
// more than one hit
break; // give up
Expand Down Expand Up @@ -2338,7 +2339,7 @@ static enum MapcodeError decoderEngine(DecodeRec *dec, int parseFlags) {
} // for

if (!err) {
restrictZoneTo(&dec->zone, &dec->zone, BOUNDARY_PTR(lastRec(ccode)));
restrictZoneTo(&dec->zone, &dec->zone, TERRITORY_BOUNDARY(lastRec(ccode)));

if (isEmpty(&dec->zone)) {
err = ERR_MAPCODE_UNDECODABLE; // type 0 "BRA xx.xx"
Expand Down Expand Up @@ -2794,7 +2795,7 @@ int multipleBordersNearby(double latDeg, double lonDeg, enum Territory territory
convertCoordsToMicrosAndFractions(&coord32, NULL, NULL, latDeg, lonDeg);
for (m = upto; m >= from; m--) {
if (!IS_RESTRICTED(m)) {
if (isNearBorderOf(&coord32, BOUNDARY_PTR(m))) {
if (isNearBorderOf(&coord32, TERRITORY_BOUNDARY(m))) {
nrFound++;
if (nrFound > 1) {
return 1;
Expand Down Expand Up @@ -2924,8 +2925,9 @@ decodeMapcodeToLatLonUtf8(double *latDeg, double *lonDeg, const char *mapcode, e


// PUBLIC - decode string into lat,lon; returns negative in case of error
enum MapcodeError decodeMapcodeToLatLonUtf16(double *latDeg, double *lonDeg, const UWORD *mapcode, enum Territory territory,
MapcodeElements *mapcodeElements) {
enum MapcodeError
decodeMapcodeToLatLonUtf16(double *latDeg, double *lonDeg, const UWORD *mapcode, enum Territory territory,
MapcodeElements *mapcodeElements) {
if ((latDeg == NULL) || (lonDeg == NULL) || (mapcode == NULL)) {
return ERR_BAD_ARGUMENTS;
} else {
Expand Down Expand Up @@ -3093,7 +3095,8 @@ int getFullTerritoryNameLocalInAlphabet(char *territoryName, enum Territory terr
*territoryName = 0;
return 0;
}
return getFullTerritoryName_internal(territoryName, territory, alternative, (int) alphabet, TERRITORY_LOCAL_NAME_UTF8);
return getFullTerritoryName_internal(territoryName, territory, alternative, (int) alphabet,
TERRITORY_LOCAL_NAME_UTF8);
}


Expand Down
2 changes: 1 addition & 1 deletion mapcodelib/mapcoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ extern "C" {
#include "mapcode_alphabets.h"


#define MAPCODE_C_VERSION "2.5.0"
#define MAPCODE_C_VERSION "2.5.1"
#define UWORD unsigned short int // 2-byte unsigned integer.
#define MAX_NR_OF_MAPCODE_RESULTS 22 // Max. number of results ever returned by encoder (e.g. for 26.904899, 95.138515).
#define MAX_PROPER_MAPCODE_LEN 11 // Max. number of characters in a proper mapcode (including the dot, excl. precision extension).
Expand Down
18 changes: 17 additions & 1 deletion unittest/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Or, add `-fsanitize=address` to run the address sanitizer:
cd ../mapcodelib
gcc -O -c mapcoder.c
cd ../unittest
gcc -O unittest.c -lm -lpthread -fsanitize=address -o unittest
gcc -O unittest.c -lm -lpthread -fsanitize=address -o unittest ../mapcodelib/mapcoder.o

And add the environment variable `ASAN_OPTIONS` to your shell:

Expand All @@ -45,6 +45,22 @@ Compile and run as follows to use `gprof` to profile the library:
cd ../unittest
gcc -g -O0 unittest.c -lm -lpthread -o unittest ../mapcodelib/mapcoder.o -pg

## Using `gcov` to Show Test Coverage

Compile and run as follows to use `gcov` to show test coverage for the libray:

cd ../mapcodelib
gcc -fprofile-arcs -ftest-coverage -O0 -c mapcoder.c
cd ../unittest
gcc -fprofile-arcs -ftest-coverage -O0 unittest.c -lm -lpthread -o unittest ../mapcodelib/mapcoder.o -pg
./unittest
cd ../mapcodelib
gcov mapcoder.c
cd ../unittest
gcov unittest.c

The test coverage reports are the `*.gcov` text files.

## Using Microsoft Visual C++

If you use **Microsoft Visual C++**, you may need to add the following defines to your preprocessor
Expand Down
3 changes: 2 additions & 1 deletion unittest/clean.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#!/bin/sh
echo "Clean test files..."
if [ -f unittest.c ]
then
rm -f _*.txt gmon.out
rm -f _*.txt gmon.out *.gcda *.gcno *.gcov ../mapcodelib/*.gcda ../mapcodelib/*.gcno ../mapcodelib/*.gcov
fi
22 changes: 12 additions & 10 deletions unittest/run_all.sh
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
#!/bin/sh
echo "Run all tests..."
date
echo ""
./run_normal.sh
./run_sanitizer.sh
./run_gprof.sh
./run_valgrind.sh
./run_compare.sh
echo ""
echo "Done"
OUT=_report.txt
echo "Run all tests..." | tee $OUT
date | tee -a $OUT
echo "" | tee -a $OUT
./run_normal.sh | tee -a $OUT
./run_sanitizer.sh | tee -a $OUT
./run_gcov.h | tee -a $OUT
./run_gprof.sh | tee -a $OUT
./run_valgrind.sh | tee -a $OUT
./run_compare.sh | tee -a $OUT
echo "" | tee -a $OUT
echo "Done" | tee -a $OUT
Loading