diff options
| -rw-r--r-- | docs/source/apps/cs2cs.rst | 2 | ||||
| -rw-r--r-- | src/dmstor.cpp | 63 | ||||
| -rw-r--r-- | test/unit/gie_self_tests.cpp | 6 |
3 files changed, 51 insertions, 20 deletions
diff --git a/docs/source/apps/cs2cs.rst b/docs/source/apps/cs2cs.rst index 909912df..abddae9e 100644 --- a/docs/source/apps/cs2cs.rst +++ b/docs/source/apps/cs2cs.rst @@ -261,7 +261,7 @@ The following script :: cs2cs +proj=latlong +datum=NAD83 +to +proj=utm +zone=10 +datum=NAD27 -r <<EOF - 45d15'33.1" 111.5W + 45°15'33.1" 111.5W 45d15.551666667N -111d30 +45.25919444444 111d30'000w EOF diff --git a/src/dmstor.cpp b/src/dmstor.cpp index e65d4884..eeff1841 100644 --- a/src/dmstor.cpp +++ b/src/dmstor.cpp @@ -20,6 +20,12 @@ vm[] = { .0002908882086657216, .0000048481368110953599 }; +/* byte sequence for Degree Sign U+00B0 in UTF-8. */ + static constexpr char +DEG_SIGN1 = '\xc2'; + static constexpr char +DEG_SIGN2 = '\xb0'; + double dmstor(const char *is, char **rs) { return dmstor_ctx( pj_get_default_ctx(), is, rs ); @@ -29,57 +35,76 @@ dmstor(const char *is, char **rs) { dmstor_ctx(PJ_CONTEXT *ctx, const char *is, char **rs) { int n, nl; char *s, work[MAX_WORK]; - const char* p; + const char* p; double v, tv; if (rs) *rs = (char *)is; - /* copy sting into work space */ + /* copy string into work space */ while (isspace(*is)) ++is; n = MAX_WORK; s = work; p = (char *)is; - while (isgraph(*p) && --n) + + /* + * Copy characters into work until we hit a non-printable character or run + * out of space in the buffer. Make a special exception for the bytes of + * the Degree Sign in UTF-8. + * + * It is possible that a really odd input (like lots of leading zeros) + * could be truncated in copying into work. But ... + */ + while ((isgraph(*p) || *p == DEG_SIGN1 || *p == DEG_SIGN2) && --n) *s++ = *p++; *s = '\0'; - /* it is possible that a really odd input (like lots of leading - zeros) could be truncated in copying into work. But ... */ int sign = *(s = work); if (sign == '+' || sign == '-') s++; else sign = '+'; v = 0.; - for (nl = 0 ; nl < 3 ; nl = n + 1 ) { + for (nl = 0 ; nl < 3 ; nl = n + 1) { if (!(isdigit(*s) || *s == '.')) break; if ((tv = proj_strtod(s, &s)) == HUGE_VAL) return tv; - switch (*s) { - case 'D': case 'd': - n = 0; break; - case '\'': - n = 1; break; - case '"': - n = 2; break; - case 'r': case 'R': + int adv = 1; + + if (*s == 'D' || *s == 'd' || *s == DEG_SIGN2) { + /* + * Accept \xb0 as a single-byte degree symbol. This byte is the + * degree symbol in various single-byte encodings: multiple ISO + * 8859 parts, several Windows code pages and others. + */ + n = 0; + } else if (*s == '\'') { + n = 1; + } else if (*s == '"') { + n = 2; + } else if (s[0] == DEG_SIGN1 && s[1] == DEG_SIGN2) { + /* degree symbol in UTF-8 */ + n = 0; + adv = 2; + } else if (*s == 'r' || *s == 'R') { if (nl) { proj_context_errno_set( ctx, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE ); return HUGE_VAL; } ++s; v = tv; - goto skip; - default: + n = 4; + continue; + } else { v += tv * vm[nl]; - skip: n = 4; + n = 4; continue; } + if (n < nl) { proj_context_errno_set( ctx, PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE ); return HUGE_VAL; } v += tv * vm[n]; - ++s; + s += adv; } - /* postfix sign */ + /* postfix sign */ if (*s && (p = strchr(sym, *s))) { sign = (p - sym) >= 4 ? '-' : '+'; ++s; diff --git a/test/unit/gie_self_tests.cpp b/test/unit/gie_self_tests.cpp index c7c1ddf5..f0d4ea86 100644 --- a/test/unit/gie_self_tests.cpp +++ b/test/unit/gie_self_tests.cpp @@ -442,6 +442,12 @@ TEST(gie, info_functions) { /* we can't expect perfect numerical accuracy so testing with a tolerance */ ASSERT_NEAR(-2.0, proj_dmstor(&buf[0], NULL), 1e-7); + /* test UTF-8 degree sign on DMS input */ + ASSERT_NEAR(0.34512432, proj_dmstor("19°46'27\"E", NULL), 1e-7); + + /* test ISO 8859-1, cp1252, et al. degree sign on DMS input */ + ASSERT_NEAR(0.34512432, proj_dmstor("19" "\260" "46'27\"E", NULL), 1e-7); + /* test proj_derivatives_retrieve() and proj_factors_retrieve() */ P = proj_create(PJ_DEFAULT_CTX, "+proj=merc +ellps=WGS84"); a = proj_coord(0, 0, 0, 0); |
