/*!\file res_loc.c * Resolver library. */ /* ++Copyright++ 1985, 1989, 1993 * - * Copyright (c) 1985, 1989, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * Portions Copyright (c) 1993 by Digital Equipment Corporation. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies, and that * the name of Digital Equipment Corporation not be used in advertising or * publicity pertaining to distribution of the document or software without * specific, written prior permission. * * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. * - * --Copyright-- * * Code taken from RFC-1876 * * Routines to convert between on-the-wire RR format and zone file * format. Does not contain conversion to/from decimal degrees; * divide or multiply by 60*60*1000 for that. * * Adapted for Watt-32 by Gisle Vanem 1997 */ #include "resolver.h" #if defined(USE_BIND) static unsigned long power_of_ten[10] = { 1, 10, 100, 1000, 10000, 100000, 1000000,10000000,100000000,1000000000 }; /* * takes an XeY precision/size value, returns a string representation. */ static const char *precsize_ntoa (BYTE prec) { static char retbuf[sizeof("90000000.00")]; int mantissa = (int)((prec >> 4) & 0x0f) % 10; int exponent = (int)((prec >> 0) & 0x0f) % 10; u_long value = mantissa * power_of_ten[exponent]; sprintf (retbuf, "%lu.%.2lu", value / 100, value % 100); return (retbuf); } /* * converts ASCII size/precision X * 10**Y(cm) to 0xXY. moves pointer. */ static BYTE precsize_aton (char **strptr) { UINT mval = 0; UINT cmval = 0; BYTE retval = 0; char *cp = *strptr; int exponent; int mantissa; while (isdigit((int)*cp)) mval = mval * 10 + (*cp++ - '0'); if (*cp == '.') /* centimeters */ { cp++; if (isdigit((int)*cp)) { cmval = (*cp++ - '0') * 10; if (isdigit((int)*cp)) cmval += (*cp++ - '0'); } } cmval = (mval * 100) + cmval; for (exponent = 0; exponent < 9; exponent++) if (cmval < power_of_ten[exponent+1]) break; mantissa = cmval / power_of_ten[exponent]; if (mantissa > 9) mantissa = 9; retval = (mantissa << 4) | exponent; *strptr = cp; return (retval); } /* * Converts ASCII lat/long to unsigned encoded 32-bit number */ static DWORD latlon2ul (char **latlonstrptr, int *which) { DWORD retval; char *cp = *latlonstrptr; int deg = 0; int min = 0; int secs = 0; int secsfrac = 0; while (isdigit((int)*cp)) deg = deg * 10 + (*cp++ - '0'); while (isspace((int)*cp)) cp++; if (!(isdigit((int)*cp))) goto fndhemi; while (isdigit((int)*cp)) min = min * 10 + (*cp++ - '0'); while (isspace((int)*cp)) cp++; if (!(isdigit((int)*cp))) goto fndhemi; while (isdigit((int)*cp)) secs = secs * 10 + (*cp++ - '0'); if (*cp == '.') /* decimal seconds */ { cp++; if (isdigit((int)*cp)) { secsfrac = (*cp++ - '0') * 100; if (isdigit((int)*cp)) { secsfrac += (*cp++ - '0') * 10; if (isdigit((int)*cp)) secsfrac += (*cp++ - '0'); } } } while (!isspace((int)*cp)) /* if any trailing garbage */ cp++; while (isspace((int)*cp)) cp++; fndhemi: switch (toupper((int)*cp)) { case 'N': case 'E': retval = (1UL << 31UL) + (((((deg * 60UL) + min) * 60UL) + secs) * 1000UL) + secsfrac; break; case 'S': case 'W': retval = (1UL << 31UL) - (((((deg * 60UL) + min) * 60UL) + secs) * 1000UL) - secsfrac; break; default: retval = 0; /* invalid value -- indicates error */ break; } switch (toupper((int)*cp)) { case 'N': case 'S': *which = 1; /* latitude */ break; case 'E': case 'W': *which = 2; /* longitude */ break; default: *which = 0; /* error */ break; } cp++; /* skip the hemisphere */ while (!isspace((int)*cp)) /* if any trailing garbage */ cp++; while (isspace((int)*cp)) /* move to next field */ cp++; *latlonstrptr = cp; return (retval); } /* * Converts a zone file representation in a string to an RDATA * on-the-wire representation. */ int W32_CALL 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((int)*cp)) altmeters = altmeters * 10 + (*cp++ - '0'); if (*cp == '.') /* decimal meters */ { cp++; if (isdigit((int)*cp)) { altfrac = (*cp++ - '0') * 10; if (isdigit((int)*cp)) altfrac += (*cp++ - '0'); } } alt = (10000000 + (altsign * (altmeters * 100 + altfrac))); while (!isspace((int)*cp) && (cp < maxcp)) cp++; /* if trailing garbage or m */ while (isspace((int)*cp) && (cp < maxcp)) cp++; if (cp >= maxcp) goto defaults; siz = precsize_aton (&cp); while (!isspace((int)*cp) && (cp < maxcp)) /* if trailing garbage or m */ cp++; while (isspace((int)*cp) && (cp < maxcp)) cp++; if (cp >= maxcp) goto defaults; hp = precsize_aton (&cp); while (!isspace((int)*cp) && (cp < maxcp)) /* if trailing garbage or m */ cp++; while (isspace((int)*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 */ } /* * Takes an on-the-wire LOC RR and prints it in zone file * (human readable) format. */ char * W32_CALL loc_ntoa (const u_char *binary, char *ascii) { static char tmpbuf[255*3]; const DWORD referencealt = 100000UL * 100UL; const BYTE *rcp; char *cp0, *cp; int latdeg, latmin, latsec, latsecfrac; int longdeg, longmin, longsec, longsecfrac; char northsouth, eastwest; int altmeters, altfrac, altsign; long latval, longval, altval; DWORD templ; BYTE sizeval, hpval, vpval, versionval; rcp = binary; if (ascii) cp0 = cp = ascii; else cp0 = cp = tmpbuf; versionval = *rcp++; if (versionval) { sprintf (cp, "; error: unknown LOC RR version"); return (cp); } sizeval = *rcp++; hpval = *rcp++; vpval = *rcp++; GETLONG (templ, rcp); latval = (templ - (1UL << 31)); GETLONG (templ, rcp); longval = (templ - (1UL << 31)); GETLONG (templ, rcp); if (templ < referencealt) /* below WGS 84 spheroid */ { altval = referencealt - templ; altsign = -1; } else { altval = templ - referencealt; altsign = 1; } if (latval < 0) { northsouth = 'S'; latval = -latval; } else northsouth = 'N'; latsecfrac = latval % 1000; latval = latval / 1000; latsec = latval % 60; latval = latval / 60; latmin = latval % 60; latval = latval / 60; latdeg = latval; if (longval < 0) { eastwest = 'W'; longval = -longval; } else eastwest = 'E'; longsecfrac = longval % 1000; longval = longval / 1000; longsec = longval % 60; longval = longval / 60; longmin = longval % 60; longval = longval / 60; longdeg = longval; altfrac = altval % 100; altmeters = (altval / 100) * altsign; cp += sprintf (cp, "%d %.2d %.2d.%.3d %c %d %.2d %.2d.%.3d %c %d.%.2dm", latdeg, latmin, latsec, latsecfrac, northsouth, longdeg, longmin, longsec, longsecfrac, eastwest, altmeters, altfrac); cp += sprintf (cp, " %sm", precsize_ntoa(sizeval)); cp += sprintf (cp, " %sm", precsize_ntoa(hpval)); cp += sprintf (cp, " %sm", precsize_ntoa(vpval)); return (cp0); } #endif /* USE_BIND */