Subversion Repositories public

Compare Revisions

Ignore whitespace Rev 92 → Rev 93

/sportwatcher/trunk/libgarmin/datatype.c
0,0 → 1,425
#include "config.h"
#include <string.h>
#include <stdlib.h>
#include "garmin.h"
 
 
static uint32 gListId = 0;
 
 
garmin_data *
garmin_alloc_data ( garmin_datatype type )
{
garmin_data * d = malloc(sizeof(garmin_data));
 
d->type = type;
 
#define CASE_DATA(x) \
case data_D##x: d->data = calloc(1,sizeof(D##x)); break
 
switch ( type ) {
case data_Dlist: d->data = garmin_alloc_list(); break;
CASE_DATA(100);
CASE_DATA(101);
CASE_DATA(102);
CASE_DATA(103);
CASE_DATA(104);
CASE_DATA(105);
CASE_DATA(106);
CASE_DATA(107);
CASE_DATA(108);
CASE_DATA(109);
CASE_DATA(110);
CASE_DATA(120);
CASE_DATA(150);
CASE_DATA(151);
CASE_DATA(152);
CASE_DATA(154);
CASE_DATA(155);
CASE_DATA(200);
CASE_DATA(201);
CASE_DATA(202);
CASE_DATA(210);
CASE_DATA(300);
CASE_DATA(301);
CASE_DATA(302);
CASE_DATA(303);
CASE_DATA(304);
CASE_DATA(310);
CASE_DATA(311);
CASE_DATA(312);
CASE_DATA(400);
CASE_DATA(403);
CASE_DATA(450);
CASE_DATA(500);
CASE_DATA(501);
CASE_DATA(550);
CASE_DATA(551);
CASE_DATA(600);
CASE_DATA(650);
CASE_DATA(700);
CASE_DATA(800);
CASE_DATA(906);
CASE_DATA(1000);
CASE_DATA(1001);
CASE_DATA(1002);
CASE_DATA(1003);
CASE_DATA(1004);
CASE_DATA(1005);
CASE_DATA(1006);
CASE_DATA(1007);
CASE_DATA(1008);
CASE_DATA(1009);
CASE_DATA(1010);
CASE_DATA(1011);
CASE_DATA(1012);
CASE_DATA(1013);
CASE_DATA(1015);
default: d->data = NULL; break;
}
 
return d;
}
 
 
garmin_list *
garmin_alloc_list ( void )
{
garmin_list * l;
 
l = calloc(1,sizeof(garmin_list));
l->id = ++gListId;
 
return l;
}
 
 
garmin_list *
garmin_list_append ( garmin_list * list, garmin_data * data )
{
garmin_list * l = list;
garmin_list_node * n;
 
if ( data != NULL ) {
if ( l == NULL ) l = garmin_alloc_list();
n = malloc(sizeof(garmin_list_node));
 
n->data = data;
n->next = NULL;
if ( l->head == NULL ) l->head = n;
if ( l->tail != NULL ) l->tail->next = n;
l->tail = n;
l->elements++;
}
 
return l;
}
 
 
garmin_data *
garmin_list_data ( garmin_data * data, uint32 which )
{
garmin_data * ret = NULL;
garmin_list * list;
garmin_list_node * n;
unsigned int i;
 
if ( data != NULL &&
data->type == data_Dlist &&
(list = data->data) != NULL ) {
for ( i = 0, n = list->head; i < which && n != NULL; i++, n = n->next );
if ( n != NULL ) ret = n->data;
}
 
return ret;
}
 
 
void
garmin_free_list ( garmin_list * l )
{
garmin_list_node * n;
garmin_list_node * x;
 
if ( l != NULL ) {
for ( n = l->head; n != NULL; n = x ) {
x = n->next;
garmin_free_data(n->data);
free(n);
}
free(l);
}
}
 
 
void
garmin_free_list_only ( garmin_list * l )
{
garmin_list_node * n;
garmin_list_node * x;
 
if ( l != NULL ) {
for ( n = l->head; n != NULL; n = x ) {
x = n->next;
free(n);
}
free(l);
}
}
 
 
#define TRYFREE(x) if ( x != NULL ) free(x)
 
 
void
garmin_free_data ( garmin_data * d )
{
D105 * d105;
D106 * d106;
D108 * d108;
D109 * d109;
D110 * d110;
D202 * d202;
D210 * d210;
D310 * d310;
D312 * d312;
D650 * d650;
 
if ( d != NULL ) {
if ( d->data != NULL ) {
if ( d->type == data_Dlist ) {
garmin_free_list((garmin_list *)d->data);
} else {
switch ( d->type ) {
case data_D105:
d105 = d->data;
TRYFREE(d105->wpt_ident);
break;
case data_D106:
d106 = d->data;
TRYFREE(d106->wpt_ident);
TRYFREE(d106->lnk_ident);
break;
case data_D108:
d108 = d->data;
TRYFREE(d108->ident);
TRYFREE(d108->comment);
TRYFREE(d108->facility);
TRYFREE(d108->city);
TRYFREE(d108->addr);
TRYFREE(d108->cross_road);
break;
case data_D109:
d109 = d->data;
TRYFREE(d109->ident);
TRYFREE(d109->comment);
TRYFREE(d109->facility);
TRYFREE(d109->city);
TRYFREE(d109->addr);
TRYFREE(d109->cross_road);
break;
case data_D110:
d110 = d->data;
TRYFREE(d110->ident);
TRYFREE(d110->comment);
TRYFREE(d110->facility);
TRYFREE(d110->city);
TRYFREE(d110->addr);
TRYFREE(d110->cross_road);
break;
case data_D202:
d202 = d->data;
TRYFREE(d202->rte_ident);
break;
case data_D210:
d210 = d->data;
TRYFREE(d210->ident);
break;
case data_D310:
d310 = d->data;
TRYFREE(d310->trk_ident);
break;
case data_D312:
d312 = d->data;
TRYFREE(d312->trk_ident);
break;
case data_D650:
d650 = d->data;
TRYFREE(d650->departure_name);
TRYFREE(d650->departure_ident);
TRYFREE(d650->arrival_name);
TRYFREE(d650->arrival_ident);
TRYFREE(d650->ac_id);
break;
default:
break;
}
free(d->data);
}
}
free(d);
}
}
 
 
/*
Returns the number of bytes needed in order to serialize the data. Note
that this is an upper bound! Some of the Garmin data structures do not
align to word boundaries. Their memory representation will take up more
bytes than the serialized representation will.
*/
 
uint32
garmin_data_size ( garmin_data * d )
{
garmin_list * list;
garmin_list_node * node;
uint32 bytes = 0;
 
/*
The number of bytes needed in order to serialize a Garmin data structure
is almost equal to the size of its data structure - but not quite. If
we have variable length strings, we need to add their string lengths
(including space for the terminating '\0') and subtract the size of the
char * placeholders. We also need 4 bytes for the data type, and 4
additional bytes in which we store the number of bytes that we should
seek forward in order to skip this record. This allows us to handle
files that include new, unrecognized data types but still conform to
the file format rules (i.e. we can skip data records that we don't
yet know about).
*/
 
#define ADDBYTES(x,y) \
bytes = sizeof(D##x) + 8 - 3 * y
 
#define ADDSTRING(x,y) \
if (d##x->y != NULL) bytes += strlen(d##x->y)
 
#define ADDBYTES1(x,a) \
ADDBYTES(x,1); \
ADDSTRING(x,a)
 
#define ADDBYTES2(x,a,b) \
ADDBYTES(x,2); \
ADDSTRING(x,a); \
ADDSTRING(x,b)
 
#define ADDBYTES5(x,a,b,c,d,e) \
ADDBYTES(x,5); \
ADDSTRING(x,a); \
ADDSTRING(x,b); \
ADDSTRING(x,c); \
ADDSTRING(x,d); \
ADDSTRING(x,e)
 
#define ADDBYTES6(x,a,b,c,d,e,f) \
ADDBYTES(x,6); \
ADDSTRING(x,a); \
ADDSTRING(x,b); \
ADDSTRING(x,c); \
ADDSTRING(x,d); \
ADDSTRING(x,e); \
ADDSTRING(x,f)
 
#define DATASIZE0(x) \
case data_D##x: \
{ \
ADDBYTES(x,0); \
} \
break
 
#define DATASIZE(x,y) \
case data_D##x: \
{ \
D##x * d##x = d->data; \
\
y; \
} \
break
 
#define DATASIZE1(x,a) DATASIZE(x,ADDBYTES1(x,a))
#define DATASIZE2(x,a,b) DATASIZE(x,ADDBYTES2(x,a,b))
#define DATASIZE5(x,a,b,c,d,e) DATASIZE(x,ADDBYTES5(x,a,b,c,d,e))
#define DATASIZE6(x,a,b,c,d,e,f) DATASIZE(x,ADDBYTES6(x,a,b,c,d,e,f))
 
 
if ( d != NULL ) {
if ( d->data != NULL ) {
if ( d->type == data_Dlist ) {
list = d->data;
bytes += 16; /* { datatype, bytes, list ID, element count } */
for ( node = list->head; node != NULL; node = node->next ) {
bytes += 4; /* list ID */
bytes += garmin_data_size(node->data);
}
} else {
switch ( d->type ) {
DATASIZE0(100);
DATASIZE0(101);
DATASIZE0(102);
DATASIZE0(103);
DATASIZE0(104);
DATASIZE1(105,wpt_ident);
DATASIZE2(106,wpt_ident,lnk_ident);
DATASIZE0(107);
DATASIZE6(108,ident,comment,facility,city,addr,cross_road);
DATASIZE6(109,ident,comment,facility,city,addr,cross_road);
DATASIZE6(110,ident,comment,facility,city,addr,cross_road);
DATASIZE0(120);
DATASIZE0(150);
DATASIZE0(151);
DATASIZE0(152);
DATASIZE0(154);
DATASIZE0(155);
DATASIZE0(200);
DATASIZE0(201);
DATASIZE1(202,rte_ident);
DATASIZE1(210,ident);
DATASIZE0(300);
DATASIZE0(301);
DATASIZE0(302);
DATASIZE0(303);
DATASIZE0(304);
DATASIZE1(310,trk_ident);
DATASIZE0(311);
DATASIZE1(312,trk_ident);
DATASIZE0(400);
DATASIZE0(403);
DATASIZE0(450);
DATASIZE0(500);
DATASIZE0(501);
DATASIZE0(550);
DATASIZE0(551);
DATASIZE0(600);
DATASIZE5(650,departure_name,departure_ident,
arrival_name,arrival_ident,ac_id);
DATASIZE0(700);
DATASIZE0(800);
DATASIZE0(906);
DATASIZE0(1000);
DATASIZE0(1001);
DATASIZE0(1002);
DATASIZE0(1003);
DATASIZE0(1004);
DATASIZE0(1005);
DATASIZE0(1006);
DATASIZE0(1007);
DATASIZE0(1008);
DATASIZE0(1009);
DATASIZE0(1010);
DATASIZE0(1011);
DATASIZE0(1012);
DATASIZE0(1013);
DATASIZE0(1015);
default:
printf("garmin_data_size: data type %d not supported\n",d->type);
break;
}
}
}
}
 
return bytes;
}