/* * Parses a specific part of rdata. * * Returns: * * number of elements parsed * zero on error * */ uint16_t * zparser_conv_loc(region_type *region, char *str) { uint16_t *r; uint32_t *p; int i; int deg, min, secs; /* Secs is stored times 1000. */ uint32_t lat = 0, lon = 0, alt = 0; /* encoded defaults: version=0 sz=1m hp=10000m vp=10m */ uint8_t vszhpvp[4] = {0, 0x12, 0x16, 0x13}; char *start; double d; for(;;) { deg = min = secs = 0; /* Degrees */ if (*str == '\0') { zc_error_prev_line("unexpected end of LOC data"); return NULL; } if (!parse_int(str, &str, °, "degrees", 0, 180)) return NULL; if (!isspace((unsigned char)*str)) { zc_error_prev_line("space expected after degrees"); return NULL; } ++str; /* Minutes? */ if (isdigit((unsigned char)*str)) { if (!parse_int(str, &str, &min, "minutes", 0, 60)) return NULL; if (!isspace((unsigned char)*str)) { zc_error_prev_line("space expected after minutes"); return NULL; } ++str; } /* Seconds? */ if (isdigit((unsigned char)*str)) { start = str; if (!parse_int(str, &str, &i, "seconds", 0, 60)) { return NULL; } if (*str == '.' && !parse_int(str + 1, &str, &i, "seconds fraction", 0, 999)) { return NULL; } if (!isspace((unsigned char)*str)) { zc_error_prev_line("space expected after seconds"); return NULL; } /* No need for precision specifiers, it's a double */ if (sscanf(start, "%lf", &d) != 1) { zc_error_prev_line("error parsing seconds"); } if (d < 0.0 || d > 60.0) { zc_error_prev_line("seconds not in range 0.0 .. 60.0"); } secs = (int) (d * 1000.0 + 0.5); ++str; } switch(*str) { case 'N': case 'n': lat = ((uint32_t)1<<31) + (deg * 3600000 + min * 60000 + secs); break; case 'E': case 'e': lon = ((uint32_t)1<<31) + (deg * 3600000 + min * 60000 + secs); break; case 'S': case 's': lat = ((uint32_t)1<<31) - (deg * 3600000 + min * 60000 + secs); break; case 'W': case 'w': lon = ((uint32_t)1<<31) - (deg * 3600000 + min * 60000 + secs); break; default: zc_error_prev_line("invalid latitude/longtitude: '%c'", *str); return NULL; } ++str; if (lat != 0 && lon != 0) break; if (!isspace((unsigned char)*str)) { zc_error_prev_line("space expected after latitude/longitude"); return NULL; } ++str; } /* Altitude */ if (*str == '\0') { zc_error_prev_line("unexpected end of LOC data"); return NULL; } if (!isspace((unsigned char)*str)) { zc_error_prev_line("space expected before altitude"); return NULL; } ++str; start = str; /* Sign */ if (*str == '+' || *str == '-') { ++str; } /* Meters of altitude... */ if(strtol(str, &str, 10) == LONG_MAX) { zc_error_prev_line("altitude too large, number overflow"); return NULL; } switch(*str) { case ' ': case '\0': case 'm': break; case '.': if (!parse_int(str + 1, &str, &i, "altitude fraction", 0, 99)) { return NULL; } if (!isspace((unsigned char)*str) && *str != '\0' && *str != 'm') { zc_error_prev_line("altitude fraction must be a number"); return NULL; } break; default: zc_error_prev_line("altitude must be expressed in meters"); return NULL; } if (!isspace((unsigned char)*str) && *str != '\0') ++str; if (sscanf(start, "%lf", &d) != 1) { zc_error_prev_line("error parsing altitude"); } alt = (uint32_t) (10000000.0 + d * 100 + 0.5); if (!isspace((unsigned char)*str) && *str != '\0') { zc_error_prev_line("unexpected character after altitude"); return NULL; } /* Now parse size, horizontal precision and vertical precision if any */ for(i = 1; isspace((unsigned char)*str) && i <= 3; i++) { vszhpvp[i] = precsize_aton(str + 1, &str); if (!isspace((unsigned char)*str) && *str != '\0') { zc_error_prev_line("invalid size or precision"); return NULL; } } /* Allocate required space... */ r = alloc_rdata(region, 16); p = (uint32_t *) (r + 1); memmove(p, vszhpvp, 4); write_uint32(p + 1, lat); write_uint32(p + 2, lon); write_uint32(p + 3, alt); return r; }
/* * Converts a zone file representation in a string to an RDATA * on-the-wire representation. */ int loc_aton (const char *ascii, u_char *binary) { char *cp, *maxcp; BYTE *bcp; DWORD latit = 0, longit = 0, alt = 0; DWORD lltemp1 = 0, lltemp2 = 0; int altmeters = 0; int altfrac = 0; int altsign = 1; BYTE hp = 0x16; /* default = 1e6 cm = 10000.00m = 10km */ BYTE vp = 0x13; /* default = 1e3 cm = 10.00m */ BYTE siz = 0x12; /* default = 1e2 cm = 1.00m */ int which1 = 0; int which2 = 0; cp = (char*)ascii; maxcp = cp + strlen (ascii); lltemp1 = latlon2ul (&cp, &which1); lltemp2 = latlon2ul (&cp, &which2); switch (which1 + which2) { case 3: /* 1 + 2, the only valid combination */ if (which1 == 1 && which2 == 2) /* normal case */ { latit = lltemp1; longit = lltemp2; } else if (which1 == 2 && which2 == 1) /* reversed */ { longit = lltemp1; latit = lltemp2; } else /* some kind of brokenness */ return (0); break; default: /* we didn't get one of each */ return (0); } /* altitude */ if (*cp == '-') { altsign = -1; cp++; } if (*cp == '+') ++cp; while (isdigit(*cp)) altmeters = altmeters * 10 + (*cp++ - '0'); if (*cp == '.') /* decimal meters */ { cp++; if (isdigit(*cp)) { altfrac = (*cp++ - '0') * 10; if (isdigit(*cp)) altfrac += (*cp++ - '0'); } } alt = (10000000 + (altsign * (altmeters * 100 + altfrac))); while (!isspace(*cp) && (cp < maxcp)) cp++; /* if trailing garbage or m */ while (isspace(*cp) && (cp < maxcp)) cp++; if (cp >= maxcp) goto defaults; siz = precsize_aton (&cp); while (!isspace(*cp) && (cp < maxcp)) /* if trailing garbage or m */ cp++; while (isspace(*cp) && (cp < maxcp)) cp++; if (cp >= maxcp) goto defaults; hp = precsize_aton (&cp); while (!isspace(*cp) && (cp < maxcp)) /* if trailing garbage or m */ cp++; while (isspace(*cp) && (cp < maxcp)) cp++; if (cp >= maxcp) goto defaults; vp = precsize_aton(&cp); defaults: bcp = binary; *bcp++ = (BYTE) 0; /* version byte */ *bcp++ = siz; *bcp++ = hp; *bcp++ = vp; PUTLONG (latit,bcp); PUTLONG (longit,bcp); PUTLONG (alt,bcp); return (16); /* size of RR in octets */ }