aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/source/apps/cs2cs.rst2
-rw-r--r--src/dmstor.cpp63
-rw-r--r--test/unit/gie_self_tests.cpp6
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);