A first implementation of AAIP 0.2 encoding and decoding

This commit is contained in:
Thomas Schmitt 2008-12-21 10:19:16 +00:00
parent f348faeb5f
commit ef5a1c48ba
3 changed files with 1054 additions and 0 deletions

688
test/aaip_0_2.c Normal file
View File

@ -0,0 +1,688 @@
/*
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 */;

187
test/aaip_0_2.h Normal file
View File

@ -0,0 +1,187 @@
/*
Arbitrary Attribute Interchange Protocol , AAIP version 0.2
Demonstration program for encoding and decoding EA and ACL.
See http://libburnia-project.org/wiki/AAIP
test/aaip_0.2.h - Public declarations
*/
#ifndef Aaip_h_is_includeD
#define Aaip_h_is_includeD yes
/* --------------------------------- Encoder ---------------------------- */
/* 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);
/* >>> Encoder for ACLs */;
/* --------------------------------- Decoder ---------------------------- */
/*
The AAIP decoder avoids the use of dynamic memory. It rather provides a
stateful decoding context with a small buffer which delivers results to
caller provided memory locations.
This may be done stream-like via the Component Level Interface or to
fixly sized storage for name and value via the Pair Level Interface.
*/
/* The AAIP decoder context.
*/
struct aaip_state;
/* Obtain the size in bytes of an aaip_state object.
*/
size_t aaip_sizeof_aaip_state(void);
/* Initialize a AAIP decoder context.
This has to be done before the first AA field of a node is processed.
The caller has to provide the storage of the struct aaip_state.
*/
int aaip_init(struct aaip_state *aaip, char aa_name[2], int flag);
/* ------------------------------------------------------------------------- */
/* Component Level Interface
Provides support for unlimited component size but demands the caller
to have a growing storage facility resp. to do own oversize handling.
This interface expects moderatly sized input pieces and will hand out
moderately sized result pieces. The number of ransactions is virtually
unlimited.
*/
/* 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
@param 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);
/* 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);
/* 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);
/* ------------------------------------------------------------------------- */
/* Pair Level Interface
Provides support for names and values of limited size. The limits are
given by the caller who has to provide the storage for name and value.
This interface expects moderatly sized input pieces.
The number of input transcations is virtually unlimited.
The number of pair transactions after aaip_init() should be limited
to 4 billion.
*/
/* Accept raw input data and collect a pair of name and value.
The return value iwill 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);
/* Inquire the number of pairs which were skipped because being oversized.
@param aaip The AAIP decoder context
@param flag Bitfield for control purposes - submit 0 for now
@return The number of pairs skipped since aaip_init()
*/
unsigned int aaip_get_pairs_skipped(struct aaip_state *aaip, int flag);
#endif /* ! Aaip_h_is_includeD */

179
test/aaip_0_2_test.c Normal file
View File

@ -0,0 +1,179 @@
/*
Arbitrary Attribute Interchange Protocol , AAIP version 0.2
Demonstration program for encoding and decoding EA and ACL.
See http://libburnia-project.org/wiki/AAIP
test/aaip_0_2_test.c - Main program for test binary
Compile: cc -g -Wall -o test/aaip test/aaip_0_2.c test/aaip_0_2_test.c
Usage: ./aaip name value
Long parameters ./aaip -name"x100" -value"x100"
>>> ACLs
*/
#include <ctype.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "aaip_0_2.h"
int main(int argc, char **argv)
{
int ret, l, mult= 0, k;
size_t result_len, i;
unsigned char *result= NULL;
char **names= NULL, **values= NULL, *cpt, **param;
size_t *value_lengths= NULL;
struct aaip_state *aaip;
size_t consumed= 0;
char name[1025];
size_t name_size= 4;
size_t name_fill;
char value[1025];
size_t value_size= 1024;
size_t value_fill;
size_t todo;
int submit_data, is_done;
unsigned char *rpt;
unsigned int skipped, was_skipped= 0;
if(argc < 3 || (argc % 2) == 0) {
fprintf(stderr, "usage: %s [-]name[xNNN] [-]value[xNNN] ...\n", argv[0]);
exit(1);
}
aaip= (struct aaip_state *) calloc(aaip_sizeof_aaip_state(), 1);
names= calloc(sizeof(char *), (argc - 1) / 2);
values= calloc(sizeof(char *), (argc - 1) / 2);
value_lengths= calloc(sizeof(size_t), (argc - 1) / 2);
for(i= 0; i < argc - 1; i++) {
if(i % 2)
param= values + i / 2;
else
param= names + i / 2;
(*param)= argv[i + 1];
if(argv[i + 1][0] == '-') {
cpt= strchr(argv[i + 1], 'x');
if(cpt != NULL) {
l= cpt - argv[i + 1] - 1;
if(l > 0)
sscanf(cpt + 1, "%d", &mult);
if(l > 0 && mult > 0) {
(*param)= calloc(1, l * mult + 1);
if((*param) != NULL) {
for(k= 0; k < mult; k++)
memcpy((*param) + k * l, argv[i + 1] + 1, l);
(*param)[mult * l]= 0;
} else
(*param)= argv[i + 1];
}
}
}
if(i % 2)
value_lengths[i / 2]= strlen(values[i / 2]);
}
ret= aaip_encode("AA", (unsigned int) ((argc - 1) / 2), names,
value_lengths, values,
&result_len, &result, 0);
if(ret <= 0) {
fprintf(stderr, "%s : aaip_encode failed with ret= %d\n", argv[0], ret);
exit(2);
}
printf(
" - - - - - - 0 - - 1 - - 2 - - 3 - - 4 - - 5 - - 6 - - 7 - - 8 - - 9\n");
printf("\n");
printf("%4u : ", 0);
for(i= 0; i < result_len; i++) {
if(result[i] >= 32 && result[i] <= 126)
printf("'%c' ", result[i]);
else
printf("%3u ", (unsigned int) ((unsigned char *) result)[i]);
if((i % 10) == 9)
printf("\n%4u : ", (unsigned int) (i + 1));
}
printf("\n\n");
printf(
" - - - - - - 0 - - 1 - - 2 - - 3 - - 4 - - 5 - - 6 - - 7 - - 8 - - 9\n");
printf("\n");
aaip_init(aaip, "AA", 0);
rpt= result;
submit_data= 1;
is_done= 0;
while(!is_done) {
if(submit_data) {
todo= result_len - (rpt - result);
if(todo > 2048)
todo= 2048;
if(todo == 0) {
fprintf(stderr, "%s : Out of data while still prompted to submit\n",
argv[0]);
exit(5);
}
} else
todo= 0;
ret= aaip_decode_pair(aaip, rpt, todo, &consumed,
name, name_size, &name_fill,
value, value_size, &value_fill, 0);
skipped= aaip_get_pairs_skipped(aaip, 0);
if(skipped > was_skipped) {
printf("- skipped %d pair%s -\n\n", skipped - was_skipped,
skipped - was_skipped > 1 ? "s" : "");
was_skipped= skipped;
}
if(ret < 0) {
fprintf(stderr, "%s : aaip_decode_pair failed with ret= %d\n",
argv[0], ret);
exit(3);
}
rpt+= todo;
if(ret == 0) {
rpt-= todo;
submit_data= 0;
continue;
} else if(ret == 1) {
submit_data= 1;
continue;
} else if(ret == 2) {
submit_data= 1;
} else if(ret == 3) {
submit_data= 0;
} else if(ret == 4) {
is_done= 1;
} else if(ret == 5) {
is_done= 1;
break;
} else {
fprintf(stderr, "%s : Unknown return %d from aaip_decode_pair()\n",
argv[0], ret);
exit(4);
}
name[name_fill]= 0;
value[value_fill]= 0;
if((name_fill < 1000 && value_fill < 1000)) {
printf("name = '%s' (%lu)\n", name, (unsigned long) name_fill);
printf("value= '%s' (%lu)\n", value, (unsigned long) value_fill);
} else {
printf("name = (%lu)\n", (unsigned long) name_fill);
printf("value= (%lu)\n", (unsigned long) value_fill);
}
printf("\n");
}
exit(0);
}