You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

806 lines
18 KiB

/*
* $Id: location.c,v 1.1 2009/02/22 08:09:01 nicholas Exp $
*
* location.c: Translate Pilot location data formats
* (c) 2008, Jon Schewe
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Library General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library
* General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "pi-macros.h"
#include "pi-location.h"
/***********************************************************************
*
* Function: new_Timezone
*
* Summary: Create empty timzone
*
* Parameters: Timezone_t*
*
* Returns: void
*
***********************************************************************/
void
new_Timezone(Timezone_t *a)
{
a->offset = 0;
a->t2 = 0;
a->dstStart.dayOfWeek = 0;
a->dstStart.weekOfMonth = 0;
a->dstStart.month = 0;
a->dstStart.unknown = 0;
a->dstEnd.dayOfWeek = 0;
a->dstEnd.weekOfMonth = 0;
a->dstEnd.month = 0;
a->dstEnd.unknown = 0;
a->dstObserved = 0;
a->t4 = 0;
a->unknown = 0;
a->name = NULL;
}
/***********************************************************************
*
* Function: new_Locatio
*
* Summary: Create empty location
*
* Parameters: Location_t*
*
* Returns: void
*
***********************************************************************/
void
new_Location(Location_t *a)
{
new_Timezone(&(a->tz));
a->unknownExists = 0;
a->unknown = 0;
a->latitude.degrees = 0;
a->latitude.minutes = 0;
a->latitude.direction = 0;
a->longitude.degrees = 0;
a->longitude.minutes = 0;
a->longitude.direction = 0;
a->note = NULL;
}
/***********************************************************************
*
* Function: copy_Timezone
*
* Summary: Copy the data from one timezone to another. The destination
* timezone event must already be cleared, either by creating new or by
* calling free_Timezone on it first.
*
* Parameters: Timezone_t*, Timezone_t*
*
* Returns: int -1 on failure (errno will be set), 0 on success
*
***********************************************************************/
int
copy_Timezone(const Timezone_t *source, Timezone_t *dest)
{
dest->offset = source->offset;
dest->t2 = source->t2;
dest->dstStart.dayOfWeek = source->dstStart.dayOfWeek;
dest->dstStart.weekOfMonth = source->dstStart.weekOfMonth;
dest->dstStart.month = source->dstStart.month;
dest->dstStart.unknown = source->dstStart.unknown;
dest->dstEnd.dayOfWeek = source->dstEnd.dayOfWeek;
dest->dstEnd.weekOfMonth = source->dstEnd.weekOfMonth;
dest->dstEnd.month = source->dstEnd.month;
dest->dstEnd.unknown = source->dstEnd.unknown;
dest->dstObserved = source->dstObserved;
dest->t4 = source->t4;
dest->unknown = source->unknown;
if(NULL != source->name) {
dest->name = strdup(source->name);
} else {
dest->name = NULL;
}
return 0;
}
/***********************************************************************
*
* Function: copy_Location
*
* Summary: Copy the data from one location to another. The destination
* location event must already be cleared, either by creating new or by
* calling free_Location on it first.
*
* Parameters: Location_t*, Location_t*
*
* Returns: int -1 on failure (errno will be set), 0 on success
*
***********************************************************************/
int
copy_Location(const Location_t *source, Location_t *dest)
{
int retval;
retval = copy_Timezone(&(source->tz), &(dest->tz));
if(0 != retval) {
return retval;
}
dest->unknownExists = source->unknownExists;
dest->unknown = source->unknown;
dest->latitude.degrees = source->latitude.degrees;
dest->latitude.minutes = source->latitude.minutes;
dest->latitude.direction = source->latitude.direction;
dest->longitude.degrees = source->longitude.degrees;
dest->longitude.minutes = source->longitude.minutes;
dest->longitude.direction = source->longitude.direction;
if(NULL != source->note) {
dest->note = strdup(source->note);
} else {
dest->note = NULL;
}
return 0;
}
/***********************************************************************
*
* Function: free_Location
*
* Summary: Free the members of a location structure
*
* Parameters: Location_t*
*
* Returns: void
*
***********************************************************************/
void
free_Location(Location_t *loc)
{
free_Timezone(&(loc->tz));
if(loc->note != NULL) {
free(loc->note);
loc->note = NULL;
}
}
/***********************************************************************
*
* Function: dup_Timezone
*
* Summary: Allocate memory for a new timezone that is a duplicate of this one and copy the data into it
*
* Parameters: Timezone_t*
*
* Returns: Timezone_t* or NULL if there isn't enough memory and errno is set to ENOMEM
*
***********************************************************************/
Timezone_t*
dup_Timezone(const Timezone_t *tz)
{
Timezone_t *retval = (Timezone_t*)malloc(sizeof(Timezone_t));
if(NULL == retval) {
errno = ENOMEM;
return NULL;
}
retval->offset = tz->offset;
retval->t2 = tz->t2;
memcpy(&(retval->dstStart), &(tz->dstStart), sizeof(DST_t));
memcpy(&(retval->dstEnd), &(tz->dstEnd), sizeof(DST_t));
retval->dstObserved = tz->dstObserved;
retval->t4 = tz->t4;
retval->unknown = tz->unknown;
if(NULL != tz->name) {
retval->name = strdup(tz->name);
} else {
retval->name = NULL;
}
return retval;
}
/***********************************************************************
*
* Function: free_Timezone
*
* Summary: Free the members of a timezone structure
*
* Parameters: Timezone_t*
*
* Returns: void
*
***********************************************************************/
void
free_Timezone(Timezone_t *tz) {
if(tz->name != NULL) {
free(tz->name);
tz->name = NULL;
}
}
/***********************************************************************
*
* Function: unpack_DST
*
* Summary: Fill in the daylight savings time structure based on the raw record
* data
*
* Parameters: DST_t*, pi_buffer_t *buf
*
* Returns: -1 on error, 0 on success
*
***********************************************************************/
int
unpack_DST(DST_t *dst, const pi_buffer_t *buf) {
return unpack_DST_p(dst, buf->data, 0);
}
/**
Does the work for unpack_DST given a position in buf
*/
int
unpack_DST_p(DST_t *dst, const unsigned char *data, const size_t position) {
uint8_t byte;
byte = get_byte(data+position);
switch(byte) {
case 0x00:
dst->dayOfWeek = sunday;
break;
case 0x01:
dst->dayOfWeek = monday;
break;
case 0x02:
dst->dayOfWeek = tuesday;
break;
case 0x03:
dst->dayOfWeek = wednesday;
break;
case 0x04:
dst->dayOfWeek = thursday;
break;
case 0x05:
dst->dayOfWeek = friday;
break;
case 0x06:
dst->dayOfWeek = saturday;
break;
default:
printf("Illegal value found in day of week: 0x%02X\n", byte);
return -1;
}
byte = get_byte(data+position+1);
switch(byte) {
case 0x00:
dst->weekOfMonth = first;
break;
case 0x01:
dst->weekOfMonth = second;
break;
case 0x02:
dst->weekOfMonth = third;
break;
case 0x03:
dst->weekOfMonth = fourth;
break;
case 0x04:
dst->weekOfMonth = last;
break;
default:
printf("Illegal value found in week: 0x%02Xd\n", byte);
return -1;
}
byte = get_byte(data+position+2);
switch(byte) {
case 0x00:
dst->month = none;
break;
case 0x01:
dst->month = january;
break;
case 0x02:
dst->month = february;
break;
case 0x03:
dst->month = march;
break;
case 0x04:
dst->month = april;
break;
case 0x05:
dst->month = may;
break;
case 0x06:
dst->month = june;
break;
case 0x07:
dst->month = july;
break;
case 0x08:
dst->month = august;
break;
case 0x09:
dst->month = september;
break;
case 0x0a:
dst->month = october;
break;
case 0x0b:
dst->month = november;
break;
case 0x0c:
dst->month = december;
break;
default:
printf("Illegal value found in month: 0x%02Xd\n", byte);
return -1;
}
dst->unknown = get_byte(data+position+3);
switch(dst->unknown) {
case 0x00:
case 0x01:
case 0x02:
case 0x03:
/*case 0x04:*/
break;
default:
printf("Bad value for DST.unknown: 0x%02x\n", dst->unknown);
return -1;
}
return 0;
}
/***********************************************************************
*
* Function: unpack_timezone
*
* Summary: Fill in the timezone structure based on the raw record
* data
*
* Parameters: Timezone_t*, pi_buffer_t *buf, optional position in buf
*
* Returns: -1 on error, number of bytes read on success
*
***********************************************************************/
int
unpack_Timezone(Timezone_t *tz, const pi_buffer_t *buf) {
return unpack_Timezone_p(tz, buf->data, 0);
}
/**
* Does the work of unpack_Timezone given a position in buf.
*
* Returns: -1 on error, number of bytes read on success
*/
int
unpack_Timezone_p(Timezone_t *tz, const unsigned char *data, const size_t position) {
uint8_t byte;
size_t localPosition = position;
tz->offset = get_short(data+localPosition);
localPosition += 2;
/*printf("Offset is %d\n", tz->offset);*/
tz->t2 = get_byte(data + localPosition);
++localPosition;
switch(tz->t2) {
case 0x00:
break;
case 0x01:
break;
case 0x02:
break;
case 0x03:
break;
default:
/*printf("Bad value for t2 0x%02X\n", tz->t2);*/
return -1;
}
if(unpack_DST_p(&(tz->dstStart), data, localPosition) != 0) {
return -1;
}
localPosition += 4;
if(unpack_DST_p(&(tz->dstEnd), data, localPosition) != 0) {
return -1;
}
localPosition += 4;
byte = get_byte(data+localPosition);
++localPosition;
switch(byte) {
case 0x3c:
/* dst observed */
tz->dstObserved = 1;
break;
case 0x00:
/* dst not observed */
tz->dstObserved = 0;
break;
default:
printf("Illegal value in dst_observed 0x%02X\n", byte);
return -1;
}
tz->t4 = get_byte(data+localPosition);
++localPosition;
tz->unknown = get_byte(data+localPosition);
++localPosition;
switch(tz->unknown) {
case 0x80:
case 0x00:
break;
default:
printf("Bad value for unknown 0x%02X\n", tz->unknown);
return -1;
}
if(0x00 == data+localPosition) {
tz->name = NULL;
++localPosition;
} else {
tz->name = strdup((char *)(data+localPosition));
localPosition += strlen(tz->name) + 1;
}
return localPosition;
}
/***********************************************************************
*
* Function: unpack_Location
*
* Summary: Fill in the location structure based on the raw record
* data
*
* Parameters: Location_t*, pi_buffer_t *buf
*
* Returns: -1 on error, 0 on success
*
***********************************************************************/
int
unpack_Location(Location_t *loc, const pi_buffer_t *buf)
{
size_t localPosition = 0;
localPosition = unpack_Timezone_p(&(loc->tz), buf->data, localPosition);
if(localPosition < 0) {
return -1;
}
loc->unknownExists = 0;
/* unpack latitude */
loc->latitude.degrees = get_short(buf->data+localPosition);
loc->latitude.minutes = get_short(buf->data+localPosition+2);
if(loc->latitude.degrees > 90 || loc->latitude.degrees < -90
|| loc->latitude.minutes > 60 || loc->latitude.minutes < -60) {
/*
printf("latitude degrees out of range: %d or\n", loc->latitude.degrees);
printf("latitude minutes out of range: %d\n", loc->latitude.minutes);
*/
loc->unknownExists = 1;
loc->unknown = get_byte(buf->data+localPosition);
++localPosition;
/*printf("Found unknown: 0x%02X\n", loc->unknown); */
loc->latitude.degrees = get_short(buf->data+localPosition);
localPosition += 2;
loc->latitude.minutes = get_short(buf->data+localPosition);
localPosition += 2;
} else {
localPosition += 4;
}
loc->longitude.degrees = get_short(buf->data+localPosition);
localPosition += 2;
loc->longitude.minutes = get_short(buf->data+localPosition);
localPosition += 2;
/* now make latitude and longitude easy to read */
loc->latitude.direction = south;
loc->longitude.direction = west;
if(loc->latitude.minutes < 0) {
loc->latitude.direction = north;
loc->latitude.minutes = -1 * loc->latitude.minutes;
}
if(loc->latitude.degrees < 0) {
loc->latitude.direction = north;
loc->latitude.degrees = -1 * loc->latitude.degrees;
}
if(loc->longitude.minutes < 0) {
loc->longitude.direction = east;
loc->longitude.minutes = -1 * loc->longitude.minutes;
}
if(loc->longitude.degrees < 0) {
loc->longitude.direction = east;
loc->longitude.degrees = -1 * loc->longitude.degrees;
}
if(0x00 == buf->data[localPosition]) {
loc->note = NULL;
++localPosition;
} else {
loc->note = strdup((char *)(buf->data+localPosition));
localPosition += strlen(loc->note) + 1;
}
return 0;
}
/***********************************************************************
*
* Function: pack_DST
*
* Summary: append raw DST record data to buf based on the
* DST structure
*
* Parameters: DST_t*, pi_buffer_t *buf of record, record type
*
* Returns: -1 on error, 0 on success.
*
***********************************************************************/
int
pack_DST(const DST_t *dst, pi_buffer_t *buf)
{
size_t offset;
if (dst == NULL || buf == NULL)
return -1;
offset = buf->used;
pi_buffer_expect(buf, buf->used + 4);
buf->used = buf->used + 4;
switch(dst->dayOfWeek) {
case sunday:
set_byte(buf->data+offset, 0x00);
break;
case monday:
set_byte(buf->data+offset, 0x01);
break;
case tuesday:
set_byte(buf->data+offset, 0x02);
break;
case wednesday:
set_byte(buf->data+offset, 0x03);
break;
case thursday:
set_byte(buf->data+offset, 0x04);
break;
case friday:
set_byte(buf->data+offset, 0x05);
break;
case saturday:
set_byte(buf->data+offset, 0x06);
break;
default:
return -1;
}
switch(dst->weekOfMonth) {
case first:
set_byte(buf->data+offset+1, 0x00);
break;
case second:
set_byte(buf->data+offset+1, 0x01);
break;
case third:
set_byte(buf->data+offset+1, 0x02);
break;
case fourth:
set_byte(buf->data+offset+1, 0x03);
break;
case last:
set_byte(buf->data+offset+1, 0x04);
break;
default:
return -1;
}
switch(dst->month) {
case none:
set_byte(buf->data+offset+2, 0x00);
break;
case january:
set_byte(buf->data+offset+2, 0x01);
break;
case february:
set_byte(buf->data+offset+2, 0x02);
break;
case march:
set_byte(buf->data+offset+2, 0x03);
break;
case april:
set_byte(buf->data+offset+2, 0x04);
break;
case may:
set_byte(buf->data+offset+2, 0x05);
break;
case june:
set_byte(buf->data+offset+2, 0x06);
break;
case july:
set_byte(buf->data+offset+2, 0x07);
break;
case august:
set_byte(buf->data+offset+2, 0x08);
break;
case september:
set_byte(buf->data+offset+2, 0x09);
break;
case october:
set_byte(buf->data+offset+2, 0x0a);
break;
case november:
set_byte(buf->data+offset+2, 0x0b);
break;
case december:
set_byte(buf->data+offset+2, 0x0c);
break;
default:
return -1;
}
set_byte(buf->data+offset+3, dst->unknown);
return 0;
}
/***********************************************************************
*
* Function: pack_Timezone
*
* Summary: Append the raw Timezone record to buf based on the
* Timezone structure
*
* Parameters: Timezone_t*, pi_buffer_t *buf of record, record type
*
* Returns: -1 on error, 0 on success.
*
***********************************************************************/
int
pack_Timezone(const Timezone_t *tz, pi_buffer_t *buf)
{
size_t offset;
if (tz == NULL || buf == NULL)
return -1;
offset = buf->used;
pi_buffer_expect(buf, buf->used + 3);
buf->used = buf->used + 3;
set_short(buf->data+offset, tz->offset);
set_byte(buf->data+offset+2, tz->t2);
pack_DST(&(tz->dstStart), buf);
pack_DST(&(tz->dstEnd), buf);
offset = buf->used;
pi_buffer_expect(buf, buf->used + 3);
buf->used = buf->used + 3;
if(tz->dstObserved) {
set_byte(buf->data+offset, 0x3c);
} else {
set_byte(buf->data+offset, 0x00);
}
set_byte(buf->data+offset, tz->t4);
if(NULL != tz->name) {
offset = buf->used;
pi_buffer_expect(buf, buf->used + strlen(tz->name)+1);
buf->used = buf->used + strlen(tz->name)+1;
strcpy((char *)(buf->data+offset), tz->name);
}
return 0;
}
/***********************************************************************
*
* Function: pack_Location
*
* Summary: Append the raw Location record to buf based on the
* Location structure
*
* Parameters: Location_t*, pi_buffer_t *buf of record, record type
*
* Returns: -1 on error, 0 on success.
*
***********************************************************************/
int
pack_Location(const Location_t *loc, pi_buffer_t *buf)
{
size_t offset;
if (loc == NULL || buf == NULL)
return -1;
pack_Timezone(&(loc->tz), buf);
if(loc->unknownExists) {
offset = buf->used;
pi_buffer_expect(buf, buf->used + 1);
buf->used = buf->used+1;
set_byte(buf->data+offset, loc->unknown);
}
offset = buf->used;
pi_buffer_expect(buf, buf->used+8);
buf->used = buf->used+8;
if(loc->latitude.direction == north) {
set_short(buf->data+offset, -1 * loc->latitude.degrees);
set_short(buf->data+offset+2, -1 * loc->latitude.minutes);
} else {
set_short(buf->data+offset, loc->latitude.degrees);
set_short(buf->data+offset+2, loc->latitude.minutes);
}
if(loc->longitude.direction == east) {
set_short(buf->data+offset+4, -1 * loc->longitude.degrees);
set_short(buf->data+offset+6, -1 * loc->longitude.minutes);
} else {
set_short(buf->data+offset+4, loc->longitude.degrees);
set_short(buf->data+offset+6, loc->longitude.minutes);
}
if(NULL != loc->note) {
offset = buf->used;
pi_buffer_expect(buf, buf->used + strlen(loc->note)+1);
buf->used = buf->used + strlen(loc->note)+1;
strcpy((char *)(buf->data+offset), loc->note);
} else {
offset = buf->used;
pi_buffer_expect(buf, buf->used + 1);
set_byte(buf->data+offset, 0);
buf->used = buf->used + 1;
}
return 0;
}
/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */
/* ex: set tabstop=4 expandtab: */
/* Local Variables: */
/* indent-tabs-mode: t */
/* c-basic-offset: 8 */
/* End: */