Skip to content

Commit 4de5545

Browse files
Merge pull request #18 from mapcode-foundation/dev
2.1.1. Added unit test
2 parents d9039bf + 5d3df01 commit 4de5545

File tree

5 files changed

+17845
-41
lines changed

5 files changed

+17845
-41
lines changed

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ Documentation, including example snippets of C source code, can be found in
2727

2828
mapcode_library.doc (Microsoft Word format).
2929

30+
A unit test can be found in the unittest\ subdirectory.
31+
Compile and run unittest\unittest/c to see if the library performs as expected.
32+
3033
Also see www.mapcode.com for background and reference materials.
3134

3235
Note: this version may be restricted to a particular area of the Earth!
@@ -56,6 +59,11 @@ decode Mapcodes.
5659

5760
# Release Notes
5861

62+
* 2.1.1
63+
64+
Added unittest\*.* which can be compiled and executed to check
65+
if the mapcode library performs as expected.
66+
5967
* 2.1.0
6068

6169
Fixes floating point inaccuracy (prevent encode(decode(M)) != M

mapcodelib/mapcoder.c

Lines changed: 68 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ static int disambiguate_str(const char *s, int len) // returns disambiguation 1-
185185
}
186186

187187

188+
#ifndef FAST_ALPHA
188189
// returns coode, or negative if invalid
189190
static int ccode_of_iso3(const char *in_iso, int parentcode) {
190191
const char *aliases = ALIASES;
@@ -196,12 +197,14 @@ static int ccode_of_iso3(const char *in_iso, int parentcode) {
196197
if (in_iso[2]) {
197198
if (in_iso[2] == '-') {
198199
parentcode = disambiguate_str(in_iso, 2);
199-
hyphenated = (parentcode > 0);
200+
if (parentcode < 0) { return parentcode; }
201+
hyphenated = 1;
200202
in_iso += 3;
201203
}
202204
else if (in_iso[3] == '-') {
203205
parentcode = disambiguate_str(in_iso, 3);
204-
hyphenated = (parentcode > 0);
206+
if (parentcode < 0) { return parentcode; }
207+
hyphenated = 1;
205208
in_iso += 4;
206209
}
207210
}
@@ -211,11 +214,12 @@ static int ccode_of_iso3(const char *in_iso, int parentcode) {
211214
iso[0] = (char) toupper(in_iso[0]);
212215
if (iso[0]) { iso[1] = (char) toupper(in_iso[1]); }
213216
if (iso[1]) { iso[2] = (char) toupper(in_iso[2]); }
217+
if (iso[2] && in_iso[3]!=0 && in_iso[3]!='-') { return -41; }
214218
iso[3] = 0;
215219

216220
if (iso[2] == 0 || iso[2] == ' ') // 2-letter iso code?
217221
{
218-
static char disambiguate_iso3[4] = {'1', '?', '?', 0}; // cache for disambiguation
222+
static char disambiguate_iso3[4] = {'0', '?', '?', 0}; // cache for disambiguation
219223
if (parentcode > 0) {
220224
disambiguate_iso3[0] = (char) ('0' + parentcode);
221225
}
@@ -227,7 +231,7 @@ static int ccode_of_iso3(const char *in_iso, int parentcode) {
227231
s = strstr(aliases, disambiguate_iso3); // search in aliases
228232
if (s == NULL || s[3] != '=') {
229233
s = NULL;
230-
if (disambiguate_iso3[0] <= '9') {
234+
if (disambiguate_iso3[0] <= '9' && !hyphenated) {
231235
disambiguate_iso3[0] = '0';
232236
s = strstr(aliases, disambiguate_iso3); // search in aliases
233237
}
@@ -237,7 +241,7 @@ static int ccode_of_iso3(const char *in_iso, int parentcode) {
237241
s = strstr(entity_iso, iso); // search disambiguated 2-letter iso
238242
}
239243
}
240-
if (s == NULL) {
244+
if (s == NULL && !hyphenated) {
241245
// find the FIRST disambiguation option, if any
242246
for (s = entity_iso - 1; ;) {
243247
s = strstr(s + 1, disambiguate_iso3 + 1);
@@ -293,7 +297,7 @@ static int ccode_of_iso3(const char *in_iso, int parentcode) {
293297
// return result
294298
return (int) ((s - entity_iso) / 4);
295299
}
296-
300+
#endif
297301

298302
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
299303
//
@@ -357,6 +361,9 @@ static int decodeExtension(decodeRec *dec, int dividerx4, int dividery0, int lon
357361
int lat32 = 0;
358362
int processor = 1;
359363
int odd = 0;
364+
if (strlen(extrapostfix)>MAX_PRECISION_DIGITS) {
365+
return -79; // too many digits
366+
}
360367
while (*extrapostfix) {
361368
int column1, row1, column2, row2;
362369
int c1 = *extrapostfix++;
@@ -978,8 +985,8 @@ static void repack_if_alldigits(char *input, int aonly) {
978985
}
979986
}
980987

981-
static int unpack_if_alldigits(
982-
char *input) // returns 1 if unpacked, 0 if left unchanged, negative if unchanged and an error was detected
988+
// returns 1 if unpacked, 0 if left unchanged, negative if unchanged and an error was detected
989+
static int unpack_if_alldigits(char *input)
983990
{ // rewrite all-digit codes
984991
char *s = input;
985992
char *dotpos = NULL;
@@ -1029,6 +1036,8 @@ static int unpack_if_alldigits(
10291036
if (v < 100) {
10301037
*s = encode_chars[(unsigned int) v / 10];
10311038
*e = encode_chars[(unsigned int) v % 10];
1039+
} else {
1040+
return -31; // overflow (ending in UE or UU)
10321041
}
10331042
return 1;
10341043
}
@@ -1397,22 +1406,22 @@ static int decoderEngine(decodeRec *dec) {
13971406
if (s) {
13981407
*s++ = 0;
13991408
while (*s > 0 && *s <= 32) { s++; }
1400-
ccode = ccode_of_iso3(w, dec->context);
1409+
ccode = convertTerritoryIsoNameToCode(w, dec->context-1) - 1;
14011410
}
14021411
else {
14031412
ccode = dec->context - 1;
14041413
s = w;
14051414
}
14061415
if (ccode == ccode_mex && len < 8) {
1407-
ccode = ccode_of_iso3("5MX", -1);
1416+
ccode = convertTerritoryIsoNameToCode("5MX", -1) - 1;
14081417
} // special case for mexico country vs state
14091418
if (*s=='u' || *s=='U') {
14101419
strcpy(s,s+1);
14111420
repack_if_alldigits(s, 1);
14121421
}
14131422
dec->context = ccode;
14141423
dec->mapcode = s;
1415-
dec->extension = "";
1424+
dec->extension = NULL;
14161425
// make upper, handle i and o, split off high precision characters if any
14171426
for (w = s; *w != 0; w++) {
14181427
// uppercase
@@ -1427,7 +1436,7 @@ static int decoderEngine(decodeRec *dec) {
14271436
*w = '1';
14281437
} else if (*w == 'A' || *w == 'E' || *w == 'U') {
14291438
hasvowels = 1;
1430-
} else {
1439+
} else if (dec->extension == NULL) {
14311440
hasletters = 1;
14321441
}
14331442
}
@@ -1438,9 +1447,9 @@ static int decoderEngine(decodeRec *dec) {
14381447
prelen = (int) ((dot = w) - s);
14391448
}
14401449
else if (*w == '-') {
1441-
if (*dec->extension) {
1442-
return -17;
1443-
} // already had a hyphen
1450+
if (dec->extension != NULL) {
1451+
return -17; // already had a hyphen
1452+
}
14441453
dec->extension = w + 1;
14451454
*w = 0;
14461455
}
@@ -1451,6 +1460,9 @@ static int decoderEngine(decodeRec *dec) {
14511460
if (!dot) {
14521461
return -27;
14531462
}
1463+
if (dec->extension == NULL) {
1464+
dec->extension = "";
1465+
}
14541466

14551467
codex = prelen * 10 + strlen(dot) - 1;
14561468

@@ -1642,7 +1654,7 @@ static int decoderEngine(decodeRec *dec) {
16421654
#ifdef SUPPORT_FOREIGN_ALPHABETS
16431655

16441656
// WARNING - these alphabets have NOT yet been released as standard! use at your own risk! check www.mapcode.com for details.
1645-
static UWORD asc2lan[MAX_LANGUAGES][36] = // A-Z equivalents for ascii characters A to Z, 0-9
1657+
static UWORD asc2lan[MAPCODE_ALPHABETS_TOTAL][36] = // A-Z equivalents for ascii characters A to Z, 0-9
16461658
{
16471659
{0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039}, // roman
16481660
{0x0391, 0x0392, 0x039e, 0x0394, 0x003f, 0x0395, 0x0393, 0x0397, 0x0399, 0x03a0, 0x039a, 0x039b, 0x039c, 0x039d, 0x039f, 0x03a1, 0x0398, 0x03a8, 0x03a3, 0x03a4, 0x003f, 0x03a6, 0x03a9, 0x03a7, 0x03a5, 0x0396, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039}, // greek
@@ -2118,38 +2130,53 @@ int decodeMapcodeToLatLon(double *lat, double *lon, const char *input,
21182130

21192131
#ifdef SUPPORT_FOREIGN_ALPHABETS
21202132

2133+
// convert as much as will fit of mapcode into unibuf
21212134
UWORD *convertToAlphabet(UWORD *unibuf, int maxlength, const char *mapcode, int alphabet) // 0=roman, 2=cyrillic
21222135
{
21232136
UWORD *startbuf = unibuf;
2137+
UWORD *lastspot = &unibuf[maxlength - 1];
2138+
if (maxlength>0) {
2139+
char u[MAX_MAPCODE_RESULT_LEN];
2140+
2141+
// skip leading spaces
2142+
while (*mapcode > 0 && *mapcode <= 32) { mapcode++; }
2143+
2144+
// straight-copy everything up to and including first space
2145+
{
2146+
char *e = strchr(mapcode, ' ');
2147+
if (e) {
2148+
while (mapcode <= e) {
2149+
if (unibuf == lastspot) { // buffer fully filled?
2150+
// zero-terminate and return
2151+
*unibuf = 0;
2152+
return startbuf;
2153+
}
2154+
*unibuf++ = *mapcode++;
2155+
}
2156+
}
2157+
}
21242158

2125-
while (*mapcode > 0 && *mapcode < 32) { mapcode++; }
2126-
{ // skip lead
2127-
char *e = strrchr(mapcode, ' ');
2128-
if (e) {
2129-
while (mapcode <= e) {
2130-
*unibuf++ = *mapcode++;
2131-
}
2132-
}
2133-
}
2134-
2135-
if (asc2lan[alphabet][4] == 0x003f) { // alphabet has no letter E
2136-
if (strchr(mapcode, 'E') || strchr(mapcode, 'U') || strchr(mapcode, 'e') ||
2137-
strchr(mapcode, 'u')) // v1.50 get rid of E and U
2138-
{
2139-
// safely copy mapcode into temporary buffer u
2140-
char u[MAX_MAPCODE_RESULT_LEN];
2141-
int len = (int) strlen(mapcode);
2142-
if (len >= MAX_MAPCODE_RESULT_LEN) {
2143-
len = MAX_MAPCODE_RESULT_LEN - 1;
2159+
// re-pack E/U-voweled mapcodes when necessary:
2160+
if (asc2lan[alphabet][4] == 0x003f) { // alphabet has no letter E
2161+
if (strchr(mapcode, 'E') || strchr(mapcode, 'U') ||
2162+
strchr(mapcode, 'e') || strchr(mapcode, 'u'))
2163+
{
2164+
// copy trimmed mapcode into temporary buffer u
2165+
int len = (int) strlen(mapcode);
2166+
if (len > MAX_MAPCODE_RESULT_LEN - 1) {
2167+
len = MAX_MAPCODE_RESULT_LEN - 1;
2168+
}
2169+
while (len>0 && mapcode[len-1]>0 && mapcode[len-1]<=32) { len--; }
2170+
memcpy(u, mapcode, len);
2171+
u[len] = 0;
2172+
// re-pack into A-voweled mapcode
2173+
unpack_if_alldigits(u);
2174+
repack_if_alldigits(u, 1);
2175+
mapcode = u;
21442176
}
2145-
memcpy(u, mapcode, len);
2146-
u[len] = 0;
2147-
unpack_if_alldigits(u);
2148-
repack_if_alldigits(u, 1);
2149-
mapcode = u;
21502177
}
2178+
encode_utf16(unibuf, 1 + (int)(lastspot - unibuf), mapcode, alphabet);
21512179
}
2152-
encode_utf16(unibuf, maxlength, mapcode, alphabet);
21532180
return startbuf;
21542181
}
21552182

0 commit comments

Comments
 (0)