예제 #1
0
/*
 * 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, &deg, "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;
}
예제 #2
0
/*
 * 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 */
}