689 lines
20 KiB
C
689 lines
20 KiB
C
|
|
||
|
/*
|
||
|
|
||
|
Arbitrary Attribute Interchange Protocol , AAIP version 0.2
|
||
|
Demonstration program for encoding and decoding EA and ACL.
|
||
|
|
||
|
See test/aaip_0_2.h
|
||
|
http://libburnia-project.org/wiki/AAIP
|
||
|
|
||
|
>>> ACLs
|
||
|
|
||
|
*/
|
||
|
|
||
|
#include <ctype.h>
|
||
|
#include <sys/types.h>
|
||
|
#include <unistd.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <stdio.h>
|
||
|
|
||
|
/* <<< */
|
||
|
#define Aaip_encode_debuG 1
|
||
|
|
||
|
#include "aaip_0_2.h"
|
||
|
|
||
|
|
||
|
/* --------------------------------- Encoder ---------------------------- */
|
||
|
|
||
|
|
||
|
static int aaip_encode_pair(char *name, size_t attr_length, char *attr,
|
||
|
unsigned int *num_recs, size_t *comp_size,
|
||
|
unsigned char *result, size_t result_fill,
|
||
|
int flag);
|
||
|
|
||
|
|
||
|
/* Convert an array of Arbitrary Attributes into a series of AAIP fields.
|
||
|
@param aa_name The 2 byte SUSP Signature Word of the fields
|
||
|
@param num_attrs Number of attributes
|
||
|
@param names Array of pointers to 0 terminated name strings
|
||
|
@param attr_lengths Array of byte lengths for each attribute payload
|
||
|
@param attrs Array of pointers to the attribute payload bytes
|
||
|
@param result_len Number of bytes in the resulting SUSP field string
|
||
|
@param result *result will point to the start of the result string.
|
||
|
This is malloc() memory which needs to be freed when
|
||
|
no longer needed
|
||
|
@param flag Bitfield for control purposes
|
||
|
bit0= set CONTINUE bit of last AA field to 1
|
||
|
@return >0 is the number of SUSP fields generated,
|
||
|
0 means error
|
||
|
*/
|
||
|
unsigned int aaip_encode(char aa_name[2],
|
||
|
unsigned int num_attrs, char **names,
|
||
|
size_t *attr_lengths, char **attrs,
|
||
|
size_t *result_len, unsigned char **result, int flag)
|
||
|
{
|
||
|
size_t mem_size= 0, comp_size;
|
||
|
unsigned int number_of_fields, i, num_recs, total_recs= 0, ret;
|
||
|
|
||
|
/* Predict memory needs, number of SUSP fields and component records */
|
||
|
*result_len= 0;
|
||
|
for(i= 0; i < num_attrs; i++) {
|
||
|
ret= aaip_encode_pair(names[i], attr_lengths[i], attrs[i],
|
||
|
&num_recs, &comp_size, NULL, (size_t) 0, 1);
|
||
|
if(ret <= 0)
|
||
|
return(ret);
|
||
|
mem_size+= comp_size;
|
||
|
total_recs= num_recs;
|
||
|
}
|
||
|
number_of_fields= mem_size / 250 + !!(mem_size % 250);
|
||
|
mem_size+= number_of_fields * 5;
|
||
|
|
||
|
#ifdef Aaip_encode_debuG
|
||
|
*result= (unsigned char *) calloc(1, mem_size + 1024000);
|
||
|
/* generous honeypot for overflows */
|
||
|
#else
|
||
|
*result= (unsigned char *) calloc(1, mem_size);
|
||
|
#endif
|
||
|
|
||
|
|
||
|
/* Encode pairs into result */
|
||
|
for(i= 0; i < num_attrs; i++) {
|
||
|
ret= aaip_encode_pair(names[i], attr_lengths[i], attrs[i],
|
||
|
&num_recs, &comp_size, *result, *result_len, 0);
|
||
|
if(ret <= 0)
|
||
|
return(ret);
|
||
|
(*result_len)+= comp_size;
|
||
|
}
|
||
|
|
||
|
/* write the field headers */
|
||
|
for(i= 0; i < number_of_fields; i++) {
|
||
|
(*result)[i * 255 + 0]= aa_name[0];
|
||
|
(*result)[i * 255 + 1]= aa_name[1];
|
||
|
if(i < number_of_fields - 1 || (mem_size % 255) == 0)
|
||
|
(*result)[i * 255 + 2]= 255;
|
||
|
else
|
||
|
(*result)[i * 255 + 2]= mem_size % 255;
|
||
|
(*result)[i * 255 + 3]= 1;
|
||
|
(*result)[i * 255 + 4]= (flag & 1) || (i < number_of_fields - 1);
|
||
|
}
|
||
|
(*result_len)+= number_of_fields * 5;
|
||
|
|
||
|
#ifdef Aaip_encode_debuG
|
||
|
if(*result_len != mem_size) {
|
||
|
fprintf(stderr, "aaip_encode(): MEMORY MISMATCH BY %d BYTES\n",
|
||
|
(int) (mem_size - *result_len));
|
||
|
}
|
||
|
ret= 0;
|
||
|
for(i= 0; i < *result_len; i+= ((unsigned char *) (*result))[i + 2])
|
||
|
ret++;
|
||
|
if(ret != number_of_fields) {
|
||
|
fprintf(stderr, "aaip_encode(): WRONG NUMBER OF FIELDS %d <> %d\n",
|
||
|
number_of_fields, ret);
|
||
|
}
|
||
|
#endif /* Aaip_encode_debuG */
|
||
|
|
||
|
return(number_of_fields);
|
||
|
}
|
||
|
|
||
|
|
||
|
static void aaip_encode_byte(unsigned char *result, size_t *result_fill,
|
||
|
unsigned char value)
|
||
|
{
|
||
|
result[(*result_fill / 250) * 255 + 5 + (*result_fill % 250)]= value;
|
||
|
(*result_fill)++;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int aaip_encode_comp(unsigned char *result, size_t *result_fill,
|
||
|
char *data, size_t l, int flag)
|
||
|
{
|
||
|
size_t todo;
|
||
|
char *rpt, *comp_start;
|
||
|
|
||
|
if(l == 0) {
|
||
|
aaip_encode_byte(result, result_fill, 0);
|
||
|
aaip_encode_byte(result, result_fill, 0);
|
||
|
return(1);
|
||
|
}
|
||
|
for(rpt= data; rpt - data < l;) {
|
||
|
todo= l - (rpt - data);
|
||
|
aaip_encode_byte(result, result_fill, (todo > 255));
|
||
|
if(todo > 255)
|
||
|
todo= 255;
|
||
|
aaip_encode_byte(result, result_fill, todo);
|
||
|
for(comp_start= rpt; rpt - comp_start < todo; rpt++)
|
||
|
aaip_encode_byte(result, result_fill, *((unsigned char *) rpt));
|
||
|
}
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Write the component records for name and attr. Skip the positions of
|
||
|
AA field headers.
|
||
|
@param flag bit0= only count but do not produce result
|
||
|
*/
|
||
|
static int aaip_encode_pair(char *name, size_t attr_length, char *attr,
|
||
|
unsigned int *num_recs, size_t *comp_size,
|
||
|
unsigned char *result, size_t result_fill,
|
||
|
int flag)
|
||
|
{
|
||
|
size_t l;
|
||
|
|
||
|
l= strlen(name);
|
||
|
*num_recs= l / 255 + (!!(l % 255)) + (l == 0) +
|
||
|
attr_length / 255 + (!!(attr_length % 255)) + (attr_length == 0);
|
||
|
*comp_size= l + attr_length + 2 * *num_recs;
|
||
|
|
||
|
if(flag & 1)
|
||
|
return(1);
|
||
|
|
||
|
aaip_encode_comp(result, &result_fill, name, l, 0);
|
||
|
aaip_encode_comp(result, &result_fill, attr, attr_length, 0);
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* >>> Encoder for ACLs */;
|
||
|
|
||
|
|
||
|
/* --------------------------------- Decoder ---------------------------- */
|
||
|
|
||
|
/* --- private --- */
|
||
|
|
||
|
/* Not less than 2 * 2048 */
|
||
|
#define Aaip_buffer_sizE 4096
|
||
|
|
||
|
struct aaip_state {
|
||
|
|
||
|
/* AA field status */
|
||
|
unsigned char aa_name[2];
|
||
|
int aa_head_missing; /* number of bytes needed to complete AA field header */
|
||
|
int aa_missing; /* number of bytes needed to complete current AA field */
|
||
|
int aa_ends; /* 0= still AA fields expected, 1= last AA being processed,
|
||
|
2= all AA fields processed, 3= all is delivered */
|
||
|
|
||
|
/* Buffer for component records */
|
||
|
int recs_invalid; /* number of components to skip */
|
||
|
unsigned char recs[Aaip_buffer_sizE];
|
||
|
size_t recs_fill;
|
||
|
int rec_head_missing; /* number of bytes needed to complete rec header */
|
||
|
int rec_missing; /* number of bytes needed to complete current rec */
|
||
|
int rec_ends;
|
||
|
|
||
|
/* Counter for completed data */
|
||
|
unsigned int num_recs;
|
||
|
size_t ready_bytes;
|
||
|
|
||
|
/* Counter and meaning for completed components */
|
||
|
unsigned int num_components;
|
||
|
int first_is_name;
|
||
|
|
||
|
/* Last return value of aaip_decode_pair() */
|
||
|
int pair_status;
|
||
|
unsigned int pairs_skipped;
|
||
|
|
||
|
};
|
||
|
|
||
|
|
||
|
/* ------- functions ------ */
|
||
|
|
||
|
|
||
|
size_t aaip_sizeof_aaip_state(void)
|
||
|
{
|
||
|
return((size_t) sizeof(struct aaip_state));
|
||
|
}
|
||
|
|
||
|
|
||
|
int aaip_init(struct aaip_state *aaip, char aa_name[2], int flag)
|
||
|
{
|
||
|
aaip->aa_name[0]= aa_name[0];
|
||
|
aaip->aa_name[1]= aa_name[1];
|
||
|
aaip->aa_head_missing= 5;
|
||
|
aaip->aa_missing= 0;
|
||
|
|
||
|
aaip->recs_invalid= 0;
|
||
|
memset(aaip->recs, 0, Aaip_buffer_sizE);
|
||
|
aaip->recs_fill= 0;
|
||
|
aaip->rec_head_missing= 2;
|
||
|
aaip->rec_missing= 0;
|
||
|
aaip->rec_ends= 0;
|
||
|
|
||
|
aaip->num_recs= 0;
|
||
|
aaip->ready_bytes= 0;
|
||
|
|
||
|
aaip->num_components= 0;
|
||
|
aaip->first_is_name= 1;
|
||
|
|
||
|
aaip->pair_status= 1;
|
||
|
aaip->pairs_skipped= 0;
|
||
|
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
|
||
|
static int aaip_consume_rec_head(struct aaip_state *aaip,
|
||
|
unsigned char **data, size_t *num_data, int flag)
|
||
|
{
|
||
|
size_t todo, i;
|
||
|
|
||
|
todo= *num_data;
|
||
|
if(todo > aaip->aa_missing)
|
||
|
todo= aaip->aa_missing;
|
||
|
if(todo >= aaip->rec_head_missing)
|
||
|
todo= aaip->rec_head_missing;
|
||
|
if(!aaip->recs_invalid) {
|
||
|
memcpy(aaip->recs + aaip->recs_fill, *data + i, todo);
|
||
|
aaip->recs_fill+= todo;
|
||
|
}
|
||
|
aaip->rec_head_missing-= todo;
|
||
|
if(aaip->rec_head_missing == 0) {
|
||
|
aaip->rec_missing= aaip->recs[aaip->recs_fill - 1];
|
||
|
aaip->rec_ends= !(aaip->recs[aaip->recs_fill - 2] & 1);
|
||
|
}
|
||
|
aaip->aa_missing-= todo;
|
||
|
(*num_data)-= todo;
|
||
|
(*data)+= todo;
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
|
||
|
static int aaip_consume_rec_data(struct aaip_state *aaip,
|
||
|
unsigned char **data, size_t *num_data, int flag)
|
||
|
{
|
||
|
size_t todo, i;
|
||
|
|
||
|
todo= *num_data;
|
||
|
if(todo > aaip->aa_missing)
|
||
|
todo= aaip->aa_missing;
|
||
|
if(todo > aaip->rec_missing)
|
||
|
todo= aaip->rec_missing;
|
||
|
if(!aaip->recs_invalid) {
|
||
|
memcpy(aaip->recs + aaip->recs_fill, *data + i, todo);
|
||
|
aaip->recs_fill+= todo;
|
||
|
aaip->ready_bytes+= todo;
|
||
|
}
|
||
|
aaip->rec_missing-= todo;
|
||
|
aaip->aa_missing-= todo;
|
||
|
(*num_data)-= todo;
|
||
|
(*data)+= todo;
|
||
|
if(aaip->rec_missing <= 0) {
|
||
|
if(aaip->recs_invalid > 0) {
|
||
|
if(aaip->rec_ends)
|
||
|
aaip->recs_invalid--;
|
||
|
} else {
|
||
|
aaip->num_recs++;
|
||
|
if(aaip->rec_ends)
|
||
|
aaip->num_components++;
|
||
|
}
|
||
|
aaip->rec_head_missing= 2;
|
||
|
}
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
|
||
|
static int aaip_consume_aa_head(struct aaip_state *aaip,
|
||
|
unsigned char **data, size_t *num_data, int flag)
|
||
|
{
|
||
|
size_t todo, i;
|
||
|
|
||
|
todo= *num_data;
|
||
|
if(todo >= aaip->aa_head_missing)
|
||
|
todo= aaip->aa_head_missing;
|
||
|
for(i= 0; i < todo; i++)
|
||
|
aaip->recs[aaip->recs_fill++]= (*data)[i];
|
||
|
aaip->aa_head_missing-= todo;
|
||
|
if(aaip->aa_head_missing == 0) {
|
||
|
if(aaip->recs[aaip->recs_fill - 5] != aaip->aa_name[0] ||
|
||
|
aaip->recs[aaip->recs_fill - 4] != aaip->aa_name[1] ||
|
||
|
aaip->recs[aaip->recs_fill - 2] != 1)
|
||
|
return(-1);
|
||
|
aaip->aa_missing= aaip->recs[aaip->recs_fill - 3];
|
||
|
aaip->aa_ends= !(aaip->recs[aaip->recs_fill - 1] & 1);
|
||
|
aaip->recs_fill-= 5; /* AA heads do not get delivered */
|
||
|
if(aaip->aa_missing >= 5)
|
||
|
aaip->aa_missing-= 5;
|
||
|
else
|
||
|
aaip->aa_missing= 0;
|
||
|
}
|
||
|
(*num_data)-= todo;
|
||
|
(*data)+= todo;
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
|
||
|
static int aaip_consume_aa_data(struct aaip_state *aaip,
|
||
|
unsigned char **data, size_t *num_data, int flag)
|
||
|
{
|
||
|
while(*num_data > 0 && aaip->aa_missing > 0) {
|
||
|
if(aaip->rec_head_missing > 0) {
|
||
|
aaip_consume_rec_head(aaip, data, num_data, 0);
|
||
|
if(*num_data == 0 || aaip->aa_missing <= 0)
|
||
|
return(1);
|
||
|
}
|
||
|
aaip_consume_rec_data(aaip, data, num_data, 0);
|
||
|
}
|
||
|
if(aaip->aa_missing <= 0) {
|
||
|
if(aaip->aa_ends) {
|
||
|
|
||
|
/* >>> Check for incomplete component or pair, discard it */;
|
||
|
|
||
|
aaip->aa_ends= 2;
|
||
|
} else
|
||
|
aaip->aa_head_missing= 5;
|
||
|
}
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Submit small data chunk for decoding.
|
||
|
The return value will tell whether data are pending for being fetched.
|
||
|
@param aaip The AAIP decoder context
|
||
|
@param data Not more than 2048 bytes input for the decoder
|
||
|
@parm num_data Number of bytes in data
|
||
|
0 inquires the buffer status avoiding replies <= 0
|
||
|
@param ready_bytes Number of decoded bytes ready for delivery
|
||
|
@param flag Bitfield for control purposes
|
||
|
@return -1= non-AA field detected
|
||
|
*ready_bytes gives number of consumed bytes in data
|
||
|
0= cannot accept data because buffer full
|
||
|
1= no component record complete, submit more data
|
||
|
2= component record complete, may be delivered
|
||
|
3= component complete, may be delivered
|
||
|
4= no component available, no more data expected, done
|
||
|
*/
|
||
|
int aaip_submit_data(struct aaip_state *aaip,
|
||
|
unsigned char *data, size_t num_data,
|
||
|
size_t *ready_bytes, int flag)
|
||
|
{
|
||
|
int ret;
|
||
|
unsigned char *in_data;
|
||
|
|
||
|
if(aaip->aa_ends == 3)
|
||
|
return(4);
|
||
|
in_data= data;
|
||
|
if(num_data == 0)
|
||
|
goto ex;
|
||
|
if(aaip->recs_fill + num_data > Aaip_buffer_sizE)
|
||
|
return(0);
|
||
|
|
||
|
while(aaip->aa_missing == 0 && num_data > 0) {
|
||
|
if(aaip->aa_head_missing > 0) {
|
||
|
ret= aaip_consume_aa_head(aaip, &data, &num_data, 0);
|
||
|
if(ret < 0) {
|
||
|
*ready_bytes= data - in_data;
|
||
|
return(-1);
|
||
|
}
|
||
|
if(num_data == 0 || aaip->aa_missing <= 0)
|
||
|
goto ex;
|
||
|
}
|
||
|
aaip_consume_aa_data(aaip, &data, &num_data, 0);
|
||
|
}
|
||
|
ex:;
|
||
|
*ready_bytes= aaip->ready_bytes;
|
||
|
if(aaip->num_components > 0)
|
||
|
return(3);
|
||
|
if(aaip->num_recs > 0)
|
||
|
return(2);
|
||
|
if(aaip->aa_ends && aaip->aa_head_missing == 0 && aaip->aa_missing == 0)
|
||
|
aaip->aa_ends= 2;
|
||
|
if(aaip->aa_ends == 2 && aaip->num_recs == 0)
|
||
|
aaip->aa_ends= 3;
|
||
|
if(aaip->aa_ends == 3)
|
||
|
return(4);
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Fetch the available part of current component.
|
||
|
The return value will tell whether it belongs to name or to value and
|
||
|
whether that name or value is completed now.
|
||
|
@param aaip The AAIP decoder context
|
||
|
@param result Has to point to storage for the component data
|
||
|
@param result_size Gives the amount of provided result storage
|
||
|
@param num_result Will tell the number of fetched result bytes
|
||
|
@param flag Bitfield for control purposes
|
||
|
bit0= discard data rather than copying to result
|
||
|
@return -2 = insufficient result_size
|
||
|
-1 = no data ready for delivery
|
||
|
0 = result holds the final part of a name
|
||
|
1 = result holds an intermediate part of a name
|
||
|
2 = result holds the final part of a value
|
||
|
3 = result holds an intermediate part of a value
|
||
|
*/
|
||
|
int aaip_fetch_data(struct aaip_state *aaip,
|
||
|
char *result, size_t result_size, size_t *num_result,
|
||
|
int flag)
|
||
|
{
|
||
|
int ret= -1, complete= 0;
|
||
|
unsigned int i, num_bytes= 0, h;
|
||
|
|
||
|
if(aaip->num_recs == 0)
|
||
|
return(-1);
|
||
|
|
||
|
/* Copy data until end of buffer or end of component */
|
||
|
h= 0;
|
||
|
for(i= 0; i < aaip->num_recs && !complete; i++) {
|
||
|
if(!(flag & 1)) {
|
||
|
if(num_bytes + aaip->recs[h + 1] > result_size)
|
||
|
return(-2);
|
||
|
memcpy(result + num_bytes, aaip->recs + h + 2, aaip->recs[h + 1]);
|
||
|
*num_result= num_bytes + aaip->recs[h + 1];
|
||
|
}
|
||
|
num_bytes+= aaip->recs[h + 1];
|
||
|
if(!(aaip->recs[h] & 1))
|
||
|
complete= 1;
|
||
|
h+= aaip->recs[h + 1] + 2;
|
||
|
}
|
||
|
aaip->num_recs-= i;
|
||
|
aaip->ready_bytes-= num_bytes;
|
||
|
|
||
|
/* Shift buffer */
|
||
|
if(h < aaip->recs_fill)
|
||
|
memmove(aaip->recs, aaip->recs + h, aaip->recs_fill - h);
|
||
|
aaip->recs_fill-= h;
|
||
|
|
||
|
/* Compute reply */
|
||
|
ret= 2 * !aaip->first_is_name;
|
||
|
if(complete) {
|
||
|
aaip->first_is_name= !aaip->first_is_name;
|
||
|
if(aaip->num_components > 0)
|
||
|
aaip->num_components--;
|
||
|
} else
|
||
|
ret|= 1;
|
||
|
|
||
|
return(ret);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Skip the current component and eventually the following value component.
|
||
|
This has to be called if fetching of a component shall be aborted
|
||
|
but the next component resp. pair shall be fetchable again.
|
||
|
aaip_submit_data() will not indicate readiness for fetching until all
|
||
|
bytes of the skipped components are submitted. Those bytes get discarded.
|
||
|
@param aaip The AAIP decoder context
|
||
|
@param flag Bitfield for control purposes
|
||
|
bit0= do not skip value if current component is name
|
||
|
@return <=0 error , 1= now in skip state, 2= not in skip state
|
||
|
*/
|
||
|
int aaip_skip_component(struct aaip_state *aaip, int flag)
|
||
|
{
|
||
|
int to_skip= 1;
|
||
|
|
||
|
if(aaip->recs_invalid) {
|
||
|
aaip->recs_invalid+= 1 + (flag & 1);
|
||
|
return(1);
|
||
|
}
|
||
|
if(aaip->first_is_name && !(flag & 1))
|
||
|
to_skip= 2;
|
||
|
|
||
|
if(aaip->num_components) {
|
||
|
/* null-fetch */
|
||
|
aaip_fetch_data(aaip, NULL, (size_t) 0, NULL, 1);
|
||
|
to_skip--;
|
||
|
}
|
||
|
if(aaip->num_components && to_skip) {
|
||
|
/* null-fetch */
|
||
|
aaip_fetch_data(aaip, NULL, (size_t) 0, NULL, 1);
|
||
|
to_skip--;
|
||
|
}
|
||
|
if(to_skip) {
|
||
|
aaip->recs_fill= 0;
|
||
|
aaip->num_recs= 0;
|
||
|
aaip->ready_bytes= 0;
|
||
|
}
|
||
|
aaip->recs_invalid= to_skip;
|
||
|
if(aaip->aa_ends == 2 && aaip->num_recs == 0)
|
||
|
aaip->aa_ends= 3;
|
||
|
return(1 + (aaip->num_recs > 0));
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
@return see aaip_decode_pair
|
||
|
*/
|
||
|
static int aaip_advance_pair(struct aaip_state *aaip,
|
||
|
char *name, size_t name_size, size_t *name_fill,
|
||
|
char *value, size_t value_size, size_t *value_fill,
|
||
|
int flag)
|
||
|
{
|
||
|
int ret;
|
||
|
char *wpt;
|
||
|
size_t size, num;
|
||
|
|
||
|
retry:;
|
||
|
if(aaip->first_is_name) {
|
||
|
wpt= name + *name_fill;
|
||
|
size= name_size - *name_fill;
|
||
|
} else {
|
||
|
wpt= value + *value_fill;
|
||
|
size= value_size - *value_fill;
|
||
|
}
|
||
|
ret= aaip_fetch_data(aaip, wpt, size, &num, 0);
|
||
|
if(ret == -2) { /* insufficient result size */
|
||
|
ret= aaip_skip_component(aaip, 0);
|
||
|
*name_fill= *value_fill= 0;
|
||
|
aaip->pairs_skipped++;
|
||
|
if(ret == 2) /* Skip performed, valid data pending */
|
||
|
goto retry;
|
||
|
} else if(ret == -1) { /* No data ready for delivery : may not happen */
|
||
|
return(-1);
|
||
|
} else if(ret == 0) { /* result holds the final part of a name */
|
||
|
(*name_fill)+= num;
|
||
|
/* peek for value data */
|
||
|
ret= aaip_submit_data(aaip, NULL, (size_t) 0, &num, 0);
|
||
|
if(ret == 2 || ret == 3) {
|
||
|
/* fetch value data */;
|
||
|
ret= aaip_advance_pair(aaip, name, name_size, name_fill,
|
||
|
value, value_size, value_fill, flag);
|
||
|
return ret;
|
||
|
} else if(ret == 4)
|
||
|
return(5);
|
||
|
} else if(ret == 1) { /* result holds an intermediate part of a name */
|
||
|
(*name_fill)+= num;
|
||
|
} else if(ret == 2) { /* result holds the final part of a value */
|
||
|
(*value_fill)+= num;
|
||
|
if(aaip->num_components >= 2)
|
||
|
return(3);
|
||
|
if(aaip->aa_ends == 2 && aaip->num_recs == 0)
|
||
|
aaip->aa_ends= 3;
|
||
|
if(aaip->aa_ends == 3)
|
||
|
return(4);
|
||
|
return(2);
|
||
|
} else if(ret == 3) {
|
||
|
/* result holds an intermediate part of a value */;
|
||
|
(*value_fill)+= num;
|
||
|
} else {
|
||
|
return(-1); /* unknown reply from aaip_fetch_data() */
|
||
|
}
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Accept raw input data and collect a pair of name and value.
|
||
|
The return value will indicate whether the pair is complete, whether more
|
||
|
pairs are complete or whether more data are desired. No input data will be
|
||
|
accepted as long as complete pairs are pending. The end of the attribute
|
||
|
list will be indicated.
|
||
|
@param aaip The AAIP decoder context
|
||
|
@param data The raw data to decode
|
||
|
@param num_data Number of data bytes provided
|
||
|
@param consumed Returns the number of consumed data bytes
|
||
|
@param name Buffer to build the name string
|
||
|
@param name_size Maximum number of bytes in name
|
||
|
@param name_fill Holds the current buffer fill of name
|
||
|
@param value Buffer to build the value string
|
||
|
@param value_size Maximum number of bytes in value
|
||
|
@param value_fill Holds the current buffer fill of value
|
||
|
@param flag Bitfield for control purposes - submit 0 for now
|
||
|
@return <0 error
|
||
|
0 data not accepted, first fetch pending pairs with num_data == 0
|
||
|
1 name and value are not valid yet, submit more data
|
||
|
2 name and value are valid, submit more data
|
||
|
3 name and value are valid, pairs pending, fetch with num_data == 0
|
||
|
4 name and value are valid, no more data expected
|
||
|
5 name and value are not valid, no more data expected
|
||
|
*/
|
||
|
int aaip_decode_pair(struct aaip_state *aaip,
|
||
|
unsigned char *data, size_t num_data, size_t *consumed,
|
||
|
char *name, size_t name_size, size_t *name_fill,
|
||
|
char *value, size_t value_size, size_t *value_fill,
|
||
|
int flag)
|
||
|
{
|
||
|
int ret;
|
||
|
size_t ready_bytes;
|
||
|
|
||
|
*consumed= 0;
|
||
|
if(aaip->pair_status < 0 || aaip->pair_status == 4 ||
|
||
|
aaip->pair_status == 5) { /* dead ends */
|
||
|
ret= aaip->pair_status;
|
||
|
goto ex;
|
||
|
} else if(aaip->pair_status == 2 || aaip->pair_status == 3) {
|
||
|
if(aaip->pair_status == 3 && num_data > 0)
|
||
|
{ret= 0; goto ex;}
|
||
|
/* Start a new pair */
|
||
|
if(!aaip->first_is_name) /* Eventually skip orphaned value */
|
||
|
aaip_fetch_data(aaip, NULL, (size_t) 0, NULL, 1);
|
||
|
*name_fill= *value_fill= 0;
|
||
|
}
|
||
|
|
||
|
if(num_data > 0) {
|
||
|
ret= aaip_submit_data(aaip, data, num_data, &ready_bytes, 0);
|
||
|
} else {
|
||
|
ret= 1;
|
||
|
if(aaip->num_components)
|
||
|
ret= 3;
|
||
|
else if(aaip->num_recs)
|
||
|
ret= 2;
|
||
|
}
|
||
|
if(ret < 0) { /* non-AA field detected */
|
||
|
*consumed= ready_bytes;
|
||
|
{ret= -1; goto ex;}
|
||
|
} else if(ret == 0) { /* buffer overflow */;
|
||
|
/* should not happen with correct usage */
|
||
|
{ret= -2; goto ex;}
|
||
|
} else if(ret == 1) { /* no component record complete */
|
||
|
goto ex;
|
||
|
} else if(ret == 2) { /* component record complete, may be delivered */
|
||
|
;
|
||
|
} else if(ret == 3) { /* component complete, may be delivered */
|
||
|
;
|
||
|
} else if(ret == 4) { /* no component available, no more data expected */
|
||
|
{ret= 5; goto ex;}
|
||
|
} else
|
||
|
{ret= -1; goto ex;} /* unknown reply from aaip_submit_data() */
|
||
|
|
||
|
*consumed= num_data;
|
||
|
ret= aaip_advance_pair(aaip, name, name_size, name_fill,
|
||
|
value, value_size, value_fill, 0);
|
||
|
if(aaip->aa_ends == 3) {
|
||
|
if(ret >= 2 && ret <= 4)
|
||
|
ret= 4;
|
||
|
else
|
||
|
ret= 5;
|
||
|
}
|
||
|
ex:;
|
||
|
aaip->pair_status= ret;
|
||
|
return(ret);
|
||
|
}
|
||
|
|
||
|
|
||
|
unsigned int aaip_get_pairs_skipped(struct aaip_state *aaip, int flag)
|
||
|
{
|
||
|
return(aaip->pairs_skipped);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* >>> Decoder for ACLs */;
|
||
|
|