Subversion Repositories public

Rev

Rev 136 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include "config.h"
#include <stdlib.h>
#include <string.h>
#include "garmin.h"


#ifdef WORDS_BIGENDIAN
#define ENDIAN_FOR(i,x)     for ( i = sizeof(x)-1; i >= 0; i-- )
#define ENDIAN_GET(i,x,y,z) ENDIAN_FOR(i,x) *z++ = y[i]
#define ENDIAN_PUT(i,x,y,z) ENDIAN_FOR(i,x) z[i] = *y++
#else /* WORDS_BIGENDIAN */
#define ENDIAN_FOR(i,x)     for ( i = 0; i < (int)sizeof(x); i++ )
#define ENDIAN_GET(i,x,y,z) ENDIAN_FOR(i,x) *z++ = y[i]
#define ENDIAN_PUT(i,x,y,z) ENDIAN_FOR(i,x) z[i] = *y++
#endif /* WORDS_BIGENDIAN */

#define DEF_ENDIAN_GET(x)          \
  x                                \
  get_##x ( const uint8 * d )      \
  {                                \
    x       v;                     \
    uint8 * b;                     \
    int     i;                     \
                                   \
    b = (uint8 *)&v;               \
    ENDIAN_GET(i,x,d,b);           \
                                   \
    return v;                      \
  }


#define DEF_ENDIAN_PUT(x)          \
  void                             \
  put_##x ( uint8 * d, const x v ) \
  {                                \
    uint8 * b;                     \
    int     i;                     \
                                   \
    b = (uint8 *)&v;               \
    ENDIAN_PUT(i,x,b,d);           \
  }


/* Here are the definitions for the get/put functions. */

DEF_ENDIAN_GET(uint16)
DEF_ENDIAN_GET(sint16)
DEF_ENDIAN_GET(uint32)
DEF_ENDIAN_GET(sint32)
DEF_ENDIAN_GET(float32)
DEF_ENDIAN_GET(float64)

DEF_ENDIAN_PUT(uint16)
DEF_ENDIAN_PUT(sint16)
DEF_ENDIAN_PUT(uint32)
DEF_ENDIAN_PUT(sint32)
DEF_ENDIAN_PUT(float32)
DEF_ENDIAN_PUT(float64)


/* 
   Return a memory-allocated, NULL-terminated string and set the 'pos'
   argument to point to the next position. 
*/

char *
get_string ( garmin_packet * p, int * offset )
{
  char * start;
  char * cursor;
  int    allow;
  char * ret    = NULL;
  int    bytes  = 0;

  /* early exit */
  if (!p || !offset) return NULL;

  start  = (char *)(p->packet.data + *offset);
  cursor = start;
  allow  = garmin_packet_size(p) - *offset;

  if ( allow <= 0 ) return NULL;

  /* OK, we have space to work with. */

  do { bytes++; } while ( --allow && *cursor++ );
  
  ret = malloc(bytes);
  strncpy(ret,start,bytes-1);
  
  *offset += bytes;

  return ret;
}


/* 
   Same as above, but straight from the buffer until we hit a NULL, and
   update the buffer to point to the start of the next string.
*/

char *
get_vstring ( uint8 ** buf )
{
  char * start  = (char *)*buf;
  char * cursor = start;
  char * ret    = NULL;
  int    bytes  = 0;

  if (!buf) return NULL;

  do { bytes++; } while ( *cursor++ );

  ret = malloc(bytes);
  strncpy(ret,start,bytes-1);

  *buf += bytes;

  return ret;
}


void
put_vstring ( uint8 ** buf, const char * x )
{
  if ( x != NULL ) {
    strcpy((char *)*buf,x);
    *buf += strlen(x)+1;
  }
}


/* 
   Return a NULL-terminated list of strings, and set the 'pos' argument
   to point to the next position.
*/

char **
get_strings ( garmin_packet * p, int * offset )
{
  char *  start  = (char *)(p->packet.data + *offset);
  char *  cursor = start;
  int     allow  = garmin_packet_size(p) - *offset;
  char ** ret    = NULL;
  char *  elem   = NULL;
  int     nstr   = 0;
  int     bytes  = 0;

  /* early exit */

  if ( allow <= 0 ) return NULL;

  /* OK, we have space to work with. */

  while ( allow ) {

    /* extract the next string from the buffer */

    do { bytes++; } while ( --allow && *cursor++ );

    elem = malloc(bytes);
    strncpy(elem,start,bytes-1);

    /* append it to the list of strings */

    if ( ret != NULL ) ret = realloc(ret,(nstr+2) * sizeof(char *));
    else               ret = malloc(2 * sizeof(char *));

    ret[nstr++] = elem;
    ret[nstr]   = NULL;

    /* update the offset */

    *offset += bytes;
  }

  return ret;
}