blob: a35d2135e9998922b5e7123e6efb4c4993fada2b [file] [log] [blame]
/*
* Routines specific to AIF aggregate (struct/class) objects.
*
* Copyright (c) 1996-2002 by Guardsoft Pty Ltd.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_H */
#include <stdio.h>
#include <string.h>
#ifndef WIN32
#include <unistd.h>
#endif /* !WIN32 */
#include "aif.h"
#include "aifint.h"
#include "aiferr.h"
/*
* Create an empty AIF aggregate.
*/
AIF *
EmptyAggregateToAIF(char *id)
{
AIF * a;
a = NewAIF(0, 0);
AIF_FORMAT(a) = FDSAggregateInit(id);
ResetAIFError();
return a;
}
/*
* Add a field to an aggregate. The field will be added to
* the end of the section specified by the access qualifier.
*/
int
AIFAddFieldToAggregate(AIF *a, AIFAccess acc, char* field, AIF *content)
{
int data_len;
int old_len;
int new_len;
char * new_fmt;
char * new_data;
char * dummy;
char * data;
char * fds;
if ( !FDSAggregateFieldByName(AIF_FORMAT(a), field, &dummy) )
{
_aif_free(dummy);
SetAIFError(AIFERR_BADARG, NULL);
return -1;
}
old_len = AIF_LEN(a);
new_len = old_len + AIF_LEN(content);
new_data = _aif_alloc(new_len);
fds = AIF_FORMAT(a);
data = AIF_DATA(a);
_fds_skip_typename(&fds);
_aggregate_skip_to_section_end(&fds, &data, acc);
data_len = data - AIF_DATA(a);
if (data_len > 0) {
memcpy(new_data, AIF_DATA(a), data_len);
memcpy(new_data + data_len, AIF_DATA(content), AIF_LEN(content));
memcpy(new_data + data_len + AIF_LEN(content), AIF_DATA(a) + data_len, AIF_LEN(a) - data_len);
} else {
memcpy(new_data, AIF_DATA(content), AIF_LEN(content));
}
if (AIF_DATA(a) != NULL) {
_aif_free(AIF_DATA(a));
}
AIF_DATA(a) = new_data;
AIF_LEN(a) = new_len;
new_fmt = FDSAddFieldToAggregate(AIF_FORMAT(a), acc, field, AIF_FORMAT(content));
_aif_free(AIF_FORMAT(a));
AIF_FORMAT(a) = new_fmt;
ResetAIFError();
return 0;
}
/*
* Set the value of a field in an aggregate
*/
int
AIFSetAggregate(AIF *a, char* field, AIF *content)
{
int preLength;
char * dummyString;
int index;
if ( FDSAggregateFieldByName(AIF_FORMAT(a), field, &dummyString) )
{
SetAIFError(AIFERR_BADARG, NULL);
return -1;
}
index = FDSAggregateFieldIndex(AIF_FORMAT(a), field);
preLength = _data_len_index(AIF_FORMAT(a), index);
preLength -= FDSTypeSize(dummyString);
_aif_free(dummyString);
memcpy(AIF_DATA(a)+preLength, AIF_DATA(content), AIF_LEN(content));
ResetAIFError();
return(0);
}
/*
* Get the value of a field in an aggregate
*/
AIF *
AIFGetAggregate(AIF *a, char *field)
{
AIF * new;
char * type;
int len;
int pre;
int index;
if ( FDSAggregateFieldByName(AIF_FORMAT(a), field, &type) < 0 )
{
SetAIFError(AIFERR_FIELD, NULL);
return NULL;
}
if ( (len = FDSTypeSize(type)) < 0 )
{
_aif_free(type);
return NULL;
}
new = NewAIF(0, len);
index = FDSAggregateFieldIndex(AIF_FORMAT(a), field);
pre = _data_len_index(AIF_FORMAT(a), index);
pre -= len;
AIF_FORMAT(new) = type;
AIF_LEN(new) = len;
memcpy(AIF_DATA(new), AIF_DATA(a)+pre, len);
return new;
}
int
AIFNumFields(AIF *a)
{
if ( a == (AIF *)NULL )
{
SetAIFError(AIFERR_BADARG, NULL);
return -1;
}
if ( AIFType(a) != AIF_AGGREGATE )
{
SetAIFError(AIFERR_TYPE, NULL);
return -1;
}
return FDSNumFields(AIF_FORMAT(a));
}
int
AIFFieldType(AIF *a, char *name)
{
int ret;
char * type;
if ( a == (AIF *)NULL )
{
SetAIFError(AIFERR_BADARG, NULL);
return AIF_INVALID;
}
if ( AIFType(a) != AIF_AGGREGATE )
{
SetAIFError(AIFERR_TYPE, NULL);
return AIF_INVALID;
}
if ( FDSAggregateFieldByName(AIF_FORMAT(a), name, &type) < 0 )
{
SetAIFError(AIFERR_FDS, NULL);
return AIF_INVALID;
}
ret = FDSType(type);
_aif_free(type);
return ret;
}
int
AIFFieldToInt(AIF *a, char *name, int *val)
{
AIFLONGEST l;
if ( AIFFieldToLongest(a, name, &l) < 0 )
return -1;
*val = (int)l; /* potential loss of precision */
return 0;
}
/*XXX
* AIFFieldToLongest() and AIFFieldToDoublest() are broken because of the
* new structure format. We need to add AIFField().
*/
int
AIFFieldToLongest(AIF *a, char *name, AIFLONGEST *val)
{
char * type;
if ( a == (AIF *)NULL || name == NULL )
{
SetAIFError(AIFERR_BADARG, NULL);
return -1;
}
if ( AIFType(a) != AIF_AGGREGATE )
{
SetAIFError(AIFERR_TYPE, NULL);
return -1;
}
if ( name != NULL )
{
if ( FDSAggregateFieldByName(AIF_FORMAT(a), name, &type) < 0 )
{
SetAIFError(AIFERR_FDS, NULL);
return -1;
}
if ( FDSType(type) != AIF_INTEGER )
{
SetAIFError(AIFERR_TYPE, NULL);
return -1;
}
}
/* return _aif_to_longest(AIF_DATA(a) + off, size, val);*/
return 0;
}
int
AIFFieldToDouble(AIF *a, char *name, double *val)
{
AIFDOUBLEST d;
if ( AIFFieldToDoublest(a, name, &d) < 0 )
return -1;
*val = (double)d; /* possible loss of precision */
return 0;
}
/*XXX*/
int
AIFFieldToDoublest(AIF *a, char *name, AIFDOUBLEST *val)
{
char * type;
if ( a == (AIF *)NULL || name == NULL )
{
SetAIFError(AIFERR_BADARG, NULL);
return -1;
}
if ( AIFType(a) != AIF_AGGREGATE )
{
SetAIFError(AIFERR_TYPE, NULL);
return -1;
}
if ( name != NULL )
{
if ( FDSAggregateFieldByName(AIF_FORMAT(a), name, &type) < 0 )
{
SetAIFError(AIFERR_FDS, NULL);
return -1;
}
if ( FDSType(type) != AIF_FLOATING )
{
SetAIFError(AIFERR_TYPE, NULL);
return -1;
}
}
/* return _aif_to_doublest(AIF_DATA(a) + off, size, val);*/
return 0;
}
/*
* Skip to the end of the access qualifier section specified by 'acc'
* for the aggregate type 'fds'. Note that fds must be pointing
* to the beginning of a section on entry.
*
* The data pointer will be advanced so that it points to the first
* data byte of the next section, or one byte past the end of the
* data if the PACKAGE section has been specified.
*/
void
_aggregate_skip_to_section_end(char **fds, char **data, AIFAccess acc)
{
_fds_skip_name(fds);
_aggregate_skip_section(fds, data);
switch ( acc )
{
case AIF_ACCESS_PACKAGE:
_aggregate_skip_section(fds, data);
/* fall through */
case AIF_ACCESS_PRIVATE:
_aggregate_skip_section(fds, data);
/* fall through */
case AIF_ACCESS_PROTECTED:
_aggregate_skip_section(fds, data);
/* fall through */
case AIF_ACCESS_PUBLIC:
case AIF_ACCESS_UNKNOWN:
break;
}
}
/*
* Skip fields until the end of a section or the end of
* the aggregate is found. Note that fds must be pointing
* to the beginning of a field on entry.
*
* On completion, the fds and data will point as follows:
*
* 1. If this was the last section, fds will point to the
* end of aggregate and data will point one byte past
* the end of the aggregate data.
*
* 2. Otherwise, fds will point to the section separator
* and data will point to the beginning of the next section.
*/
void
_aggregate_skip_section(char **fds, char **data)
{
while (**fds != FDS_AGGREGATE_END && **fds != FDS_AGGREGATE_ACCESS_SEP) {
_aggregate_skip_field(fds, data);
if (**fds == FDS_AGGREGATE_FIELD_SEP) {
(*fds)++;
}
}
if (**fds == FDS_AGGREGATE_ACCESS_SEP) {
(*fds)++;
}
}
/*
* Skip one field. The fds and data will point as
* follows:
*
* 1. If this was the last field in a section, fds
* will point to the section separator and data
* will point to the first field in the
* following section.
*
* 2. If this was the last field in the last section,
* fds will point to the end of aggregate character
* and data will point one byte past the end of the
* aggregate data.
*
* 3. Otherwise, fds will point to the field separator
* and data will point to the next field.
*/
void
_aggregate_skip_field(char **fds, char **data)
{
*fds = strchr(*fds, FDS_AGGREGATE_FIELD_NAME_END) + 1;
_fds_skip_data(fds, data);
}