| /* |
| * 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); |
| } |