]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Refactor totext_loc
authorMark Andrews <marka@isc.org>
Tue, 25 Aug 2020 01:03:30 +0000 (11:03 +1000)
committerOndřej Surý <ondrej@isc.org>
Wed, 26 Aug 2020 14:44:01 +0000 (16:44 +0200)
(cherry picked from commit 2ca4d3503779106c4608b3ca3f4832582e8732e3)

lib/dns/rdata/generic/loc_29.c
lib/dns/tests/rdata_test.c

index ce9235f01af6206fb9841cd17a9a2dd774fb40ab..5bd6e800a58059801f9314784b2cdc2a17b913a2 100644 (file)
 
 #define RRTYPE_LOC_ATTRIBUTES (0)
 
-static inline isc_result_t
-fromtext_loc(ARGS_FROMTEXT) {
-       isc_token_t token;
-       int d1, m1, s1;
-       int d2, m2, s2;
-       unsigned char size;
-       unsigned char hp;
-       unsigned char vp;
-       unsigned char version;
-       bool east = false;
-       bool north = false;
-       bool negative = false;
-       long tmp;
-       long m;
-       long cm;
-       long poweroften[8] = { 1,     10,     100,     1000,
-                              10000, 100000, 1000000, 10000000 };
-       int man;
-       int exp;
-       char *e;
-       int i;
-       unsigned long latitude;
-       unsigned long longitude;
-       unsigned long altitude;
+static isc_result_t
+loc_getdecimal(const char *str, unsigned long max, size_t precision, char units,
+              unsigned long *valuep) {
        bool ok;
+       char *e;
+       size_t i;
+       long tmp;
+       unsigned long value;
 
-       REQUIRE(type == dns_rdatatype_loc);
-
-       UNUSED(type);
-       UNUSED(rdclass);
-       UNUSED(origin);
-       UNUSED(options);
-
-       /*
-        * Defaults.
-        */
-       m1 = s1 = 0;
-       m2 = s2 = 0;
-       size = 0x12; /* 1.00m */
-       hp = 0x16;   /* 10000.00 m */
-       vp = 0x13;   /* 10.00 m */
-       version = 0;
-
-       /*
-        * Degrees.
-        */
-       RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
-                                     false));
-       if (token.value.as_ulong > 90U) {
-               RETTOK(ISC_R_RANGE);
-       }
-       d1 = (int)token.value.as_ulong;
-       /*
-        * Minutes.
-        */
-       RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
-                                     false));
-       if (strcasecmp(DNS_AS_STR(token), "N") == 0) {
-               north = true;
-       }
-       if (north || strcasecmp(DNS_AS_STR(token), "S") == 0) {
-               goto getlong;
-       }
-       m1 = strtol(DNS_AS_STR(token), &e, 10);
-       if (*e != 0) {
-               RETTOK(DNS_R_SYNTAX);
-       }
-       if (m1 < 0 || m1 > 59) {
-               RETTOK(ISC_R_RANGE);
-       }
-       if (d1 == 90 && m1 != 0) {
-               RETTOK(ISC_R_RANGE);
-       }
-
-       /*
-        * Seconds.
-        */
-       RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
-                                     false));
-       if (strcasecmp(DNS_AS_STR(token), "N") == 0) {
-               north = true;
-       }
-       if (north || strcasecmp(DNS_AS_STR(token), "S") == 0) {
-               goto getlong;
-       }
-       s1 = strtol(DNS_AS_STR(token), &e, 10);
-       if (*e != 0 && *e != '.') {
-               RETTOK(DNS_R_SYNTAX);
-       }
-       if (s1 < 0 || s1 > 59) {
-               RETTOK(ISC_R_RANGE);
-       }
-       ok = e != DNS_AS_STR(token);
-       if (*e == '.') {
-               const char *l;
-               e++;
-               for (i = 0; i < 3; i++) {
-                       if (*e == 0) {
-                               break;
-                       }
-                       if ((tmp = decvalue(*e++)) < 0) {
-                               RETTOK(DNS_R_SYNTAX);
-                       }
-                       ok = true;
-                       s1 *= 10;
-                       s1 += tmp;
-               }
-               for (; i < 3; i++)
-                       s1 *= 10;
-               l = e;
-               while (*e != 0) {
-                       if (decvalue(*e++) < 0) {
-                               RETTOK(DNS_R_SYNTAX);
-                       }
-               }
-               if (*l != '\0' && callbacks != NULL) {
-                       const char *file = isc_lex_getsourcename(lexer);
-                       unsigned long line = isc_lex_getsourceline(lexer);
-
-                       if (file == NULL) {
-                               file = "UNKNOWN";
-                       }
-                       (*callbacks->warn)(callbacks,
-                                          "%s: %s:%u: '%s' extra "
-                                          "precision digits ignored",
-                                          "dns_rdata_fromtext", file, line,
-                                          DNS_AS_STR(token));
-               }
-       } else {
-               s1 *= 1000;
-       }
-       if (!ok) {
-               RETTOK(DNS_R_SYNTAX);
-       }
-       if (d1 == 90 && s1 != 0) {
-               RETTOK(ISC_R_RANGE);
-       }
-
-       /*
-        * Direction.
-        */
-       RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
-                                     false));
-       if (strcasecmp(DNS_AS_STR(token), "N") == 0) {
-               north = true;
-       }
-       if (!north && strcasecmp(DNS_AS_STR(token), "S") != 0) {
-               RETTOK(DNS_R_SYNTAX);
-       }
-
-getlong:
-       /*
-        * Degrees.
-        */
-       RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
-                                     false));
-       if (token.value.as_ulong > 180U) {
-               RETTOK(ISC_R_RANGE);
-       }
-       d2 = (int)token.value.as_ulong;
-
-       /*
-        * Minutes.
-        */
-       RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
-                                     false));
-       if (strcasecmp(DNS_AS_STR(token), "E") == 0) {
-               east = true;
-       }
-       if (east || strcasecmp(DNS_AS_STR(token), "W") == 0) {
-               goto getalt;
-       }
-       m2 = strtol(DNS_AS_STR(token), &e, 10);
-       if (*e != 0) {
-               RETTOK(DNS_R_SYNTAX);
+       value = strtoul(str, &e, 10);
+       if (*e != 0 && *e != '.' && *e != units) {
+               return (DNS_R_SYNTAX);
        }
-       if (m2 < 0 || m2 > 59) {
-               RETTOK(ISC_R_RANGE);
-       }
-       if (d2 == 180 && m2 != 0) {
-               RETTOK(ISC_R_RANGE);
-       }
-
-       /*
-        * Seconds.
-        */
-       RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
-                                     false));
-       if (strcasecmp(DNS_AS_STR(token), "E") == 0) {
-               east = true;
-       }
-       if (east || strcasecmp(DNS_AS_STR(token), "W") == 0) {
-               goto getalt;
-       }
-       s2 = strtol(DNS_AS_STR(token), &e, 10);
-       if (*e != 0 && *e != '.') {
-               RETTOK(DNS_R_SYNTAX);
-       }
-       if (s2 < 0 || s2 > 59) {
-               RETTOK(ISC_R_RANGE);
+       if (value > max) {
+               return (ISC_R_RANGE);
        }
-       ok = e != DNS_AS_STR(token);
+       ok = e != str;
        if (*e == '.') {
-               const char *l;
                e++;
-               for (i = 0; i < 3; i++) {
-                       if (*e == 0) {
+               for (i = 0; i < precision; i++) {
+                       if (*e == 0 || *e == units) {
                                break;
                        }
                        if ((tmp = decvalue(*e++)) < 0) {
-                               RETTOK(DNS_R_SYNTAX);
+                               return (DNS_R_SYNTAX);
                        }
                        ok = true;
-                       s2 *= 10;
-                       s2 += tmp;
-               }
-               for (; i < 3; i++)
-                       s2 *= 10;
-               l = e;
-               while (*e != 0) {
-                       if (decvalue(*e++) < 0) {
-                               RETTOK(DNS_R_SYNTAX);
-                       }
+                       value *= 10;
+                       value += tmp;
                }
-               if (*l != '\0' && callbacks != NULL) {
-                       const char *file = isc_lex_getsourcename(lexer);
-                       unsigned long line = isc_lex_getsourceline(lexer);
-
-                       if (file == NULL) {
-                               file = "UNKNOWN";
-                       }
-                       (*callbacks->warn)(callbacks,
-                                          "%s: %s:%u: '%s' extra "
-                                          "precision digits ignored",
-                                          "dns_rdata_fromtext", file, line,
-                                          DNS_AS_STR(token));
+               for (; i < precision; i++) {
+                       value *= 10;
                }
        } else {
-               s2 *= 1000;
-       }
-       if (!ok) {
-               RETTOK(DNS_R_SYNTAX);
-       }
-       if (d2 == 180 && s2 != 0) {
-               RETTOK(ISC_R_RANGE);
-       }
-
-       /*
-        * Direction.
-        */
-       RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
-                                     false));
-       if (strcasecmp(DNS_AS_STR(token), "E") == 0) {
-               east = true;
-       }
-       if (!east && strcasecmp(DNS_AS_STR(token), "W") != 0) {
-               RETTOK(DNS_R_SYNTAX);
-       }
-
-getalt:
-       /*
-        * Altitude.
-        */
-       RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
-                                     false));
-       if (DNS_AS_STR(token)[0] == '-') {
-               negative = true;
-       }
-       m = strtol(DNS_AS_STR(token), &e, 10);
-       if (*e != 0 && *e != '.' && *e != 'm') {
-               RETTOK(DNS_R_SYNTAX);
-       }
-       if (m < -100000 || m > 42849672) {
-               RETTOK(ISC_R_RANGE);
-       }
-       cm = 0;
-       ok = e != DNS_AS_STR(token);
-       if (*e == '.') {
-               e++;
-               for (i = 0; i < 2; i++) {
-                       if (*e == 0 || *e == 'm') {
-                               break;
-                       }
-                       if ((tmp = decvalue(*e++)) < 0) {
-                               return (DNS_R_SYNTAX);
-                       }
-                       ok = true;
-                       cm *= 10;
-                       if (m < 0) {
-                               cm -= tmp;
-                       } else {
-                               cm += tmp;
-                       }
+               for (i = 0; i < precision; i++) {
+                       value *= 10;
                }
-               for (; i < 2; i++)
-                       cm *= 10;
        }
-       if (*e == 'm') {
+       if (*e != 0 && *e == units) {
                e++;
        }
        if (!ok || *e != 0) {
-               RETTOK(DNS_R_SYNTAX);
-       }
-       if (m == -100000 && cm != 0) {
-               RETTOK(ISC_R_RANGE);
-       }
-       if (m == 42849672 && cm > 95) {
-               RETTOK(ISC_R_RANGE);
-       }
-       /*
-        * Adjust base.
-        */
-       if (m < 0 || negative) {
-               cm = -cm;
+               return (DNS_R_SYNTAX);
        }
-       altitude = m + 100000;
-       altitude *= 100;
-       altitude += cm;
+       *valuep = value;
+       return (ISC_R_SUCCESS);
+}
 
-       /*
-        * Size: optional.
-        */
-       RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
-                                     true));
-       if (token.type == isc_tokentype_eol || token.type == isc_tokentype_eof)
-       {
-               isc_lex_ungettoken(lexer, &token);
-               goto encode;
-       }
-       m = strtol(DNS_AS_STR(token), &e, 10);
+static isc_result_t
+loc_getprecision(const char *str, unsigned char *valuep) {
+       unsigned long poweroften[8] = { 1,     10,     100,     1000,
+                                       10000, 100000, 1000000, 10000000 };
+       unsigned long m, cm;
+       bool ok;
+       char *e;
+       size_t i;
+       long tmp;
+       int man;
+       int exp;
+
+       m = strtoul(str, &e, 10);
        if (*e != 0 && *e != '.' && *e != 'm') {
-               RETTOK(DNS_R_SYNTAX);
+               return (DNS_R_SYNTAX);
        }
-       if (m < 0 || m > 90000000) {
-               RETTOK(ISC_R_RANGE);
+       if (m > 90000000) {
+               return (ISC_R_RANGE);
        }
        cm = 0;
-       ok = e != DNS_AS_STR(token);
+       ok = e != str;
        if (*e == '.') {
                e++;
                for (i = 0; i < 2; i++) {
@@ -361,21 +92,23 @@ getalt:
                                break;
                        }
                        if ((tmp = decvalue(*e++)) < 0) {
-                               RETTOK(DNS_R_SYNTAX);
+                               return (DNS_R_SYNTAX);
                        }
                        ok = true;
                        cm *= 10;
                        cm += tmp;
                }
-               for (; i < 2; i++)
+               for (; i < 2; i++) {
                        cm *= 10;
+               }
        }
        if (*e == 'm') {
                e++;
        }
        if (!ok || *e != 0) {
-               RETTOK(DNS_R_SYNTAX);
+               return (DNS_R_SYNTAX);
        }
+
        /*
         * We don't just multiply out as we will overflow.
         */
@@ -387,159 +120,317 @@ getalt:
                }
                man = m / poweroften[exp];
                exp += 2;
+       } else if (cm >= 10) {
+               man = cm / 10;
+               exp = 1;
        } else {
-               if (cm >= 10) {
-                       man = cm / 10;
-                       exp = 1;
-               } else {
-                       man = cm;
-                       exp = 0;
-               }
+               man = cm;
+               exp = 0;
        }
-       size = (man << 4) + exp;
+       *valuep = (man << 4) + exp;
+       return (ISC_R_SUCCESS);
+}
 
-       /*
-        * Horizontal precision: optional.
-        */
-       RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
-                                     true));
-       if (token.type == isc_tokentype_eol || token.type == isc_tokentype_eof)
-       {
-               isc_lex_ungettoken(lexer, &token);
-               goto encode;
+static isc_result_t
+get_degrees(isc_lex_t *lexer, isc_token_t *token, unsigned long *d) {
+       RETERR(isc_lex_getmastertoken(lexer, token, isc_tokentype_number,
+                                     false));
+       *d = token->value.as_ulong;
+
+       return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+check_coordinate(unsigned long d, unsigned long m, unsigned long s,
+                unsigned long maxd) {
+       if (d > maxd || m > 59U) {
+               return (ISC_R_RANGE);
        }
-       m = strtol(DNS_AS_STR(token), &e, 10);
-       if (*e != 0 && *e != '.' && *e != 'm') {
-               RETTOK(DNS_R_SYNTAX);
+       if (d == maxd && (m != 0 || s != 0)) {
+               return (ISC_R_RANGE);
        }
-       if (m < 0 || m > 90000000) {
-               RETTOK(ISC_R_RANGE);
+
+       return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+get_minutes(isc_lex_t *lexer, isc_token_t *token, unsigned long *m) {
+       RETERR(isc_lex_getmastertoken(lexer, token, isc_tokentype_number,
+                                     false));
+
+       *m = token->value.as_ulong;
+
+       return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+get_seconds(isc_lex_t *lexer, isc_token_t *token, unsigned long *s) {
+       RETERR(isc_lex_getmastertoken(lexer, token, isc_tokentype_string,
+                                     false));
+       RETERR(loc_getdecimal(DNS_AS_STR(*token), 59, 3, '\0', s));
+
+       return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+get_direction(isc_lex_t *lexer, isc_token_t *token, const char *directions,
+             int *direction) {
+       RETERR(isc_lex_getmastertoken(lexer, token, isc_tokentype_string,
+                                     false));
+       if (DNS_AS_STR(*token)[0] == directions[1] &&
+           DNS_AS_STR(*token)[1] == 0) {
+               *direction = DNS_AS_STR(*token)[0];
+               return (ISC_R_SUCCESS);
        }
-       cm = 0;
-       ok = e != DNS_AS_STR(token);
-       if (*e == '.') {
-               e++;
-               for (i = 0; i < 2; i++) {
-                       if (*e == 0 || *e == 'm') {
-                               break;
-                       }
-                       if ((tmp = decvalue(*e++)) < 0) {
-                               RETTOK(DNS_R_SYNTAX);
-                       }
-                       ok = true;
-                       cm *= 10;
-                       cm += tmp;
-               }
-               for (; i < 2; i++)
-                       cm *= 10;
+
+       if (DNS_AS_STR(*token)[0] == directions[0] &&
+           DNS_AS_STR(*token)[1] == 0) {
+               *direction = DNS_AS_STR(*token)[0];
+               return (ISC_R_SUCCESS);
        }
-       if (*e == 'm') {
-               e++;
+
+       *direction = 0;
+       isc_lex_ungettoken(lexer, token);
+       return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+loc_getcoordinate(isc_lex_t *lexer, unsigned long *dp, unsigned long *mp,
+                 unsigned long *sp, const char *directions, int *directionp,
+                 unsigned long maxd) {
+       isc_result_t result = ISC_R_SUCCESS;
+       isc_token_t token;
+       unsigned long d, m, s;
+       int direction = 0;
+
+       m = 0;
+       s = 0;
+
+       /*
+        * Degrees.
+        */
+       RETERR(get_degrees(lexer, &token, &d));
+       RETTOK(check_coordinate(d, m, s, maxd));
+
+       /*
+        * Minutes.
+        */
+       RETERR(get_direction(lexer, &token, directions, &direction));
+       if (direction > 0) {
+               goto done;
        }
-       if (!ok || *e != 0) {
-               RETTOK(DNS_R_SYNTAX);
+
+       RETERR(get_minutes(lexer, &token, &m));
+       RETTOK(check_coordinate(d, m, s, maxd));
+
+       /*
+        * Seconds.
+        */
+       RETERR(get_direction(lexer, &token, directions, &direction));
+       if (direction > 0) {
+               goto done;
        }
+
+       result = get_seconds(lexer, &token, &s);
+       if (result == ISC_R_RANGE || result == DNS_R_SYNTAX) {
+               RETTOK(result);
+       }
+       RETERR(result);
+       RETTOK(check_coordinate(d, m, s, maxd));
+
        /*
-        * We don't just multiply out as we will overflow.
+        * Direction.
         */
-       if (m > 0) {
-               for (exp = 0; exp < 7; exp++) {
-                       if (m < poweroften[exp + 1]) {
-                               break;
-                       }
+       RETERR(get_direction(lexer, &token, directions, &direction));
+       if (direction == -1) {
+               RETERR(DNS_R_SYNTAX);
+       }
+done:
+
+       *directionp = direction;
+       *dp = d;
+       *mp = m;
+       *sp = s;
+
+       return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+loc_getlatitude(isc_lex_t *lexer, unsigned long *latitude) {
+       unsigned long d1 = 0, m1 = 0, s1 = 0;
+       int direction = 0;
+
+       RETERR(loc_getcoordinate(lexer, &d1, &m1, &s1, "SN", &direction, 90U));
+
+       switch (direction) {
+       case 'N':
+               *latitude = 0x80000000 + (d1 * 3600 + m1 * 60) * 1000 + s1;
+               break;
+       case 'S':
+               *latitude = 0x80000000 - (d1 * 3600 + m1 * 60) * 1000 - s1;
+               break;
+       default:
+               INSIST(0);
+               ISC_UNREACHABLE();
+       }
+
+       return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+loc_getlongitude(isc_lex_t *lexer, unsigned long *longitude) {
+       unsigned long d2 = 0, m2 = 0, s2 = 0;
+       int direction = 0;
+
+       RETERR(loc_getcoordinate(lexer, &d2, &m2, &s2, "WE", &direction, 180U));
+
+       switch (direction) {
+       case 'E':
+               *longitude = 0x80000000 + (d2 * 3600 + m2 * 60) * 1000 + s2;
+               break;
+       case 'W':
+               *longitude = 0x80000000 - (d2 * 3600 + m2 * 60) * 1000 - s2;
+               break;
+       default:
+               INSIST(0);
+               ISC_UNREACHABLE();
+       }
+
+       return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+loc_getaltitude(isc_lex_t *lexer, unsigned long *altitude) {
+       isc_token_t token;
+       unsigned long cm;
+       const char *str;
+
+       RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
+                                     false));
+       str = DNS_AS_STR(token);
+       if (DNS_AS_STR(token)[0] == '-') {
+               RETTOK(loc_getdecimal(str + 1, 100000, 2, 'm', &cm));
+               if (cm > 10000000UL) {
+                       RETTOK(ISC_R_RANGE);
                }
-               man = m / poweroften[exp];
-               exp += 2;
-       } else if (cm >= 10) {
-               man = cm / 10;
-               exp = 1;
+               *altitude = 10000000 - cm;
        } else {
-               man = cm;
-               exp = 0;
+               RETTOK(loc_getdecimal(str, 42849672, 2, 'm', &cm));
+               if (cm > 4284967295UL) {
+                       RETTOK(ISC_R_RANGE);
+               }
+               *altitude = 10000000 + cm;
        }
-       hp = (man << 4) + exp;
 
-       /*
-        * Vertical precision: optional.
-        */
+       return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+loc_getoptionalprecision(isc_lex_t *lexer, unsigned char *valuep) {
+       isc_token_t token;
+
        RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
                                      true));
        if (token.type == isc_tokentype_eol || token.type == isc_tokentype_eof)
        {
                isc_lex_ungettoken(lexer, &token);
-               goto encode;
-       }
-       m = strtol(DNS_AS_STR(token), &e, 10);
-       if (*e != 0 && *e != '.' && *e != 'm') {
-               RETTOK(DNS_R_SYNTAX);
-       }
-       if (m < 0 || m > 90000000) {
-               RETTOK(ISC_R_RANGE);
-       }
-       cm = 0;
-       ok = e != DNS_AS_STR(token);
-       if (*e == '.') {
-               e++;
-               for (i = 0; i < 2; i++) {
-                       if (*e == 0 || *e == 'm') {
-                               break;
-                       }
-                       if ((tmp = decvalue(*e++)) < 0) {
-                               RETTOK(DNS_R_SYNTAX);
-                       }
-                       ok = true;
-                       cm *= 10;
-                       cm += tmp;
-               }
-               for (; i < 2; i++)
-                       cm *= 10;
+               return (ISC_R_NOMORE);
        }
-       if (*e == 'm') {
-               e++;
+       RETTOK(loc_getprecision(DNS_AS_STR(token), valuep));
+
+       return (ISC_R_SUCCESS);
+}
+
+static inline isc_result_t
+loc_getsize(isc_lex_t *lexer, unsigned char *sizep) {
+       return (loc_getoptionalprecision(lexer, sizep));
+}
+
+static inline isc_result_t
+loc_gethorizontalprecision(isc_lex_t *lexer, unsigned char *hpp) {
+       return (loc_getoptionalprecision(lexer, hpp));
+}
+
+static inline isc_result_t
+loc_getverticalprecision(isc_lex_t *lexer, unsigned char *vpp) {
+       return (loc_getoptionalprecision(lexer, vpp));
+}
+
+/* The LOC record is expressed in a master file in the following format:
+ *
+ * <owner> <TTL> <class> LOC ( d1 [m1 [s1]] {"N"|"S"} d2 [m2 [s2]]
+ *                             {"E"|"W"} alt["m"] [siz["m"] [hp["m"]
+ *                             [vp["m"]]]] )
+ *
+ * (The parentheses are used for multi-line data as specified in [RFC
+ * 1035] section 5.1.)
+ *
+ * where:
+ *
+ *     d1:     [0 .. 90]            (degrees latitude)
+ *     d2:     [0 .. 180]           (degrees longitude)
+ *     m1, m2: [0 .. 59]            (minutes latitude/longitude)
+ *     s1, s2: [0 .. 59.999]        (seconds latitude/longitude)
+ *     alt:    [-100000.00 .. 42849672.95] BY .01 (altitude in meters)
+ *     siz, hp, vp: [0 .. 90000000.00] (size/precision in meters)
+ *
+ * If omitted, minutes and seconds default to zero, size defaults to 1m,
+ * horizontal precision defaults to 10000m, and vertical precision
+ * defaults to 10m.  These defaults are chosen to represent typical
+ * ZIP/postal code area sizes, since it is often easy to find
+ * approximate geographical location by ZIP/postal code.
+ */
+static inline isc_result_t
+fromtext_loc(ARGS_FROMTEXT) {
+       isc_result_t result = ISC_R_SUCCESS;
+       unsigned long latitude = 0;
+       unsigned long longitude = 0;
+       unsigned long altitude = 0;
+       unsigned char size = 0x12; /* Default: 1.00m */
+       unsigned char hp = 0x16;   /* Default: 10000.00 m */
+       unsigned char vp = 0x13;   /* Default: 10.00 m */
+       unsigned char version = 0;
+
+       REQUIRE(type == dns_rdatatype_loc);
+
+       UNUSED(type);
+       UNUSED(rdclass);
+       UNUSED(origin);
+       UNUSED(options);
+       UNUSED(callbacks);
+
+       RETERR(loc_getlatitude(lexer, &latitude));
+       RETERR(loc_getlongitude(lexer, &longitude));
+       RETERR(loc_getaltitude(lexer, &altitude));
+       result = loc_getsize(lexer, &size);
+       if (result == ISC_R_NOMORE) {
+               result = ISC_R_SUCCESS;
+               goto encode;
        }
-       if (!ok || *e != 0) {
-               RETTOK(DNS_R_SYNTAX);
+       RETERR(result);
+       result = loc_gethorizontalprecision(lexer, &hp);
+       if (result == ISC_R_NOMORE) {
+               result = ISC_R_SUCCESS;
+               goto encode;
        }
-       /*
-        * We don't just multiply out as we will overflow.
-        */
-       if (m > 0) {
-               for (exp = 0; exp < 7; exp++) {
-                       if (m < poweroften[exp + 1]) {
-                               break;
-                       }
-               }
-               man = m / poweroften[exp];
-               exp += 2;
-       } else if (cm >= 10) {
-               man = cm / 10;
-               exp = 1;
-       } else {
-               man = cm;
-               exp = 0;
+       RETERR(result);
+       result = loc_getverticalprecision(lexer, &vp);
+       if (result == ISC_R_NOMORE) {
+               result = ISC_R_SUCCESS;
+               goto encode;
        }
-       vp = (man << 4) + exp;
-
+       RETERR(result);
 encode:
        RETERR(mem_tobuffer(target, &version, 1));
        RETERR(mem_tobuffer(target, &size, 1));
        RETERR(mem_tobuffer(target, &hp, 1));
        RETERR(mem_tobuffer(target, &vp, 1));
-       if (north) {
-               latitude = 0x80000000 + (d1 * 3600 + m1 * 60) * 1000 + s1;
-       } else {
-               latitude = 0x80000000 - (d1 * 3600 + m1 * 60) * 1000 - s1;
-       }
-       RETERR(uint32_tobuffer(latitude, target));
 
-       if (east) {
-               longitude = 0x80000000 + (d2 * 3600 + m2 * 60) * 1000 + s2;
-       } else {
-               longitude = 0x80000000 - (d2 * 3600 + m2 * 60) * 1000 - s2;
-       }
+       RETERR(uint32_tobuffer(latitude, target));
        RETERR(uint32_tobuffer(longitude, target));
+       RETERR(uint32_tobuffer(altitude, target));
 
-       return (uint32_tobuffer(altitude, target));
+       return (result);
 }
 
 static inline isc_result_t
index e48c90f10a4f6d5897e21664af86feed9ec30fa7..f5c69b101cbc79177107d7cd3856b3737e58a4df 100644 (file)
@@ -1993,6 +1993,8 @@ loc(void **state) {
                TEXT_VALID_CHANGED("0 0 .0 N 0 0 .0 E 0",
                                   "0 0 0.000 N 0 0 0.000 E 0.00m 1m 10000m "
                                   "10m"),
+               TEXT_INVALID("0 North 0 East 0"),
+               TEXT_INVALID("0 South 0 West 0"),
                TEXT_INVALID("0 0 . N 0 0 0. E 0"),
                TEXT_INVALID("0 0 0. N 0 0 . E 0"),
                TEXT_INVALID("0 0 0. N 0 0 0. E m"),