2008-12-21 10:19:16 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
Arbitrary Attribute Interchange Protocol , AAIP version 0.2
|
2008-12-23 14:47:00 +00:00
|
|
|
Demonstration implementation of encoding and decoding EA and ACL.
|
2008-12-21 10:19:16 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2008-12-23 14:47:00 +00:00
|
|
|
/* Enough for one full component record and three empty ones which might get
|
|
|
|
added in case of unclean end of attribute list.
|
|
|
|
*/
|
|
|
|
#define Aaip_buffer_reservE (257 + 3 * 2)
|
|
|
|
|
|
|
|
|
2008-12-21 10:19:16 +00:00
|
|
|
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 */
|
2008-12-23 14:47:00 +00:00
|
|
|
unsigned char recs[Aaip_buffer_sizE + Aaip_buffer_reservE];
|
2008-12-21 10:19:16 +00:00
|
|
|
size_t recs_fill;
|
2008-12-23 14:47:00 +00:00
|
|
|
unsigned char *recs_start;
|
2008-12-21 10:19:16 +00:00
|
|
|
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;
|
2008-12-23 14:47:00 +00:00
|
|
|
size_t end_of_components; /* start index of eventual incomplete component */
|
2008-12-21 10:19:16 +00:00
|
|
|
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;
|
2008-12-23 14:47:00 +00:00
|
|
|
memset(aaip->recs, 0, Aaip_buffer_sizE + Aaip_buffer_reservE);
|
2008-12-21 10:19:16 +00:00
|
|
|
aaip->recs_fill= 0;
|
2008-12-23 14:47:00 +00:00
|
|
|
aaip->recs_start= aaip->recs;
|
2008-12-21 10:19:16 +00:00
|
|
|
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;
|
2008-12-23 14:47:00 +00:00
|
|
|
aaip->end_of_components= 0;
|
2008-12-21 10:19:16 +00:00
|
|
|
aaip->first_is_name= 1;
|
|
|
|
|
2008-12-23 14:47:00 +00:00
|
|
|
aaip->pair_status= 2;
|
2008-12-21 10:19:16 +00:00
|
|
|
aaip->pairs_skipped= 0;
|
|
|
|
|
|
|
|
return(1);
|
|
|
|
}
|
|
|
|
|
2008-12-23 14:47:00 +00:00
|
|
|
/*
|
|
|
|
*/
|
|
|
|
#define Aaip_with_ring_buffeR yes
|
|
|
|
|
|
|
|
#ifdef Aaip_with_ring_buffeR
|
|
|
|
|
|
|
|
/* Compute the one or two byte intervals in the ring buffer which form a
|
|
|
|
given byte interval in the virtual shift fifo.
|
|
|
|
@param idx The byte start index in the virtual shift fifo.
|
|
|
|
@param todo Number of bytes to cover
|
|
|
|
@param start_pt Will return the start address of the first interval
|
|
|
|
@param at_start_pt Will return the size of the first interval
|
|
|
|
@param at_recs Will return the size of the second interval which
|
|
|
|
always starts at aaip->recs
|
|
|
|
@param flag Bitfield for control purposes
|
|
|
|
@return 1= next start_pt is *start_pt + *at_start_pt
|
|
|
|
2= next start_pt is aaip->recs + *at_recs
|
|
|
|
*/
|
|
|
|
static int aaip_ring_adr(struct aaip_state *aaip, size_t idx, size_t todo,
|
|
|
|
unsigned char **start_pt, size_t *at_start_pt,
|
|
|
|
size_t *at_recs, int flag)
|
|
|
|
{
|
|
|
|
size_t ahead;
|
|
|
|
|
|
|
|
ahead= Aaip_buffer_sizE + Aaip_buffer_reservE
|
|
|
|
- (aaip->recs_start - aaip->recs);
|
|
|
|
if(idx < ahead)
|
|
|
|
*start_pt= (aaip->recs_start + idx);
|
|
|
|
else
|
|
|
|
*start_pt= aaip->recs + (idx - ahead);
|
|
|
|
ahead= Aaip_buffer_sizE + Aaip_buffer_reservE - (*start_pt - aaip->recs);
|
|
|
|
if(todo >= ahead) {
|
|
|
|
*at_start_pt= ahead;
|
|
|
|
*at_recs= todo - ahead;
|
|
|
|
return(2);
|
|
|
|
}
|
|
|
|
*at_start_pt= todo;
|
|
|
|
*at_recs= 0;
|
|
|
|
return(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@param flag Bitfield for control purposes
|
|
|
|
bit0= count as ready_bytes
|
|
|
|
*/
|
|
|
|
static int aaip_push_to_recs(struct aaip_state *aaip, unsigned char *data,
|
|
|
|
size_t todo, int flag)
|
|
|
|
{
|
|
|
|
unsigned char *start_pt;
|
|
|
|
size_t at_start_pt, at_recs;
|
|
|
|
|
|
|
|
aaip_ring_adr(aaip, aaip->recs_fill, todo,
|
|
|
|
&start_pt, &at_start_pt, &at_recs, 0);
|
|
|
|
if(at_start_pt > 0)
|
|
|
|
memcpy(start_pt, data, at_start_pt);
|
|
|
|
if(at_recs > 0)
|
|
|
|
memcpy(aaip->recs, data + at_start_pt, at_recs);
|
|
|
|
aaip->recs_fill+= todo;
|
|
|
|
if(flag & 1)
|
|
|
|
aaip->ready_bytes+= todo;
|
|
|
|
return(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int aaip_read_from_recs(struct aaip_state *aaip, size_t idx,
|
|
|
|
unsigned char *data, size_t num_data, int flag)
|
|
|
|
{
|
|
|
|
unsigned char *start_pt;
|
|
|
|
size_t at_start_pt, at_recs;
|
|
|
|
|
|
|
|
aaip_ring_adr(aaip, idx, num_data,
|
|
|
|
&start_pt, &at_start_pt, &at_recs, 0);
|
|
|
|
if(at_start_pt > 0)
|
|
|
|
memcpy(data, start_pt, at_start_pt);
|
|
|
|
if(at_recs > 0)
|
|
|
|
memcpy(data + at_start_pt, aaip->recs, at_recs);
|
|
|
|
return(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int aaip_set_buffer_byte(struct aaip_state *aaip, size_t idx,
|
|
|
|
unsigned char data, int flag)
|
|
|
|
{
|
|
|
|
unsigned char *start_pt;
|
|
|
|
size_t at_start_pt, at_recs;
|
|
|
|
|
|
|
|
aaip_ring_adr(aaip, idx, 1,
|
|
|
|
&start_pt, &at_start_pt, &at_recs, 0);
|
|
|
|
*start_pt= data;
|
|
|
|
return(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int aaip_get_buffer_byte(struct aaip_state *aaip, size_t idx, int flag)
|
|
|
|
{
|
|
|
|
unsigned char *start_pt;
|
|
|
|
size_t at_start_pt, at_recs;
|
|
|
|
|
|
|
|
aaip_ring_adr(aaip, idx, 1,
|
|
|
|
&start_pt, &at_start_pt, &at_recs, 0);
|
|
|
|
return((int) *start_pt);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int aaip_shift_recs(struct aaip_state *aaip, size_t todo, int flag)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
unsigned char *start_pt;
|
|
|
|
size_t at_start_pt, at_recs;
|
|
|
|
|
|
|
|
if(todo < aaip->recs_fill) {
|
|
|
|
ret= aaip_ring_adr(aaip, 0, todo, &start_pt, &at_start_pt, &at_recs, 0);
|
|
|
|
if(ret == 1)
|
|
|
|
aaip->recs_start= start_pt + todo;
|
|
|
|
else
|
|
|
|
aaip->recs_start= aaip->recs + at_recs;
|
|
|
|
} else {
|
|
|
|
aaip->recs_start= aaip->recs;
|
|
|
|
}
|
|
|
|
aaip->recs_fill-= todo;
|
|
|
|
if(aaip->end_of_components >= todo)
|
|
|
|
aaip->end_of_components-= todo;
|
|
|
|
else
|
|
|
|
aaip->end_of_components= 0;
|
|
|
|
return(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#else /* Aaip_with_ring_buffeR */
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@param flag Bitfield for control purposes
|
|
|
|
bit0= count as ready_bytes
|
|
|
|
*/
|
|
|
|
static int aaip_push_to_recs(struct aaip_state *aaip, unsigned char *data,
|
|
|
|
size_t todo, int flag)
|
|
|
|
{
|
|
|
|
memcpy(aaip->recs + aaip->recs_fill, data, todo);
|
|
|
|
aaip->recs_fill+= todo;
|
|
|
|
if(flag & 1)
|
|
|
|
aaip->ready_bytes+= todo;
|
|
|
|
return(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int aaip_read_from_recs(struct aaip_state *aaip, size_t idx,
|
|
|
|
unsigned char *data, size_t num_data, int flag)
|
|
|
|
{
|
|
|
|
memcpy(data, aaip->recs + idx, num_data);
|
|
|
|
return(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int aaip_set_buffer_byte(struct aaip_state *aaip, size_t idx,
|
|
|
|
unsigned char data, int flag)
|
|
|
|
{
|
|
|
|
aaip->recs[idx]= data;
|
|
|
|
return(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int aaip_get_buffer_byte(struct aaip_state *aaip, size_t idx, int flag)
|
|
|
|
{
|
|
|
|
return((int) aaip->recs[idx]);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int aaip_shift_recs(struct aaip_state *aaip, size_t todo, int flag)
|
|
|
|
{
|
|
|
|
if(todo < aaip->recs_fill)
|
|
|
|
memmove(aaip->recs, aaip->recs + todo, aaip->recs_fill - todo);
|
|
|
|
aaip->recs_fill-= todo;
|
|
|
|
|
|
|
|
if(aaip->end_of_components >= todo)
|
|
|
|
aaip->end_of_components-= todo;
|
|
|
|
else
|
|
|
|
aaip->end_of_components= 0;
|
|
|
|
return(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endif /* ! Aaip_with_ring_buffeR */
|
|
|
|
|
2008-12-21 10:19:16 +00:00
|
|
|
|
|
|
|
static int aaip_consume_rec_head(struct aaip_state *aaip,
|
|
|
|
unsigned char **data, size_t *num_data, int flag)
|
|
|
|
{
|
2008-12-23 14:47:00 +00:00
|
|
|
size_t todo;
|
2008-12-21 10:19:16 +00:00
|
|
|
|
|
|
|
todo= *num_data;
|
|
|
|
if(todo > aaip->aa_missing)
|
|
|
|
todo= aaip->aa_missing;
|
|
|
|
if(todo >= aaip->rec_head_missing)
|
|
|
|
todo= aaip->rec_head_missing;
|
2008-12-23 14:47:00 +00:00
|
|
|
if(!aaip->recs_invalid)
|
|
|
|
aaip_push_to_recs(aaip, *data, todo, 0);
|
2008-12-21 10:19:16 +00:00
|
|
|
aaip->rec_head_missing-= todo;
|
|
|
|
if(aaip->rec_head_missing == 0) {
|
2008-12-23 14:47:00 +00:00
|
|
|
aaip->rec_missing= aaip_get_buffer_byte(aaip, aaip->recs_fill - 1, 0);
|
|
|
|
aaip->rec_ends= !(aaip_get_buffer_byte(aaip, aaip->recs_fill - 2, 0) & 1);
|
2008-12-21 10:19:16 +00:00
|
|
|
}
|
|
|
|
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)
|
|
|
|
{
|
2008-12-23 14:47:00 +00:00
|
|
|
size_t todo;
|
2008-12-21 10:19:16 +00:00
|
|
|
|
|
|
|
todo= *num_data;
|
|
|
|
if(todo > aaip->aa_missing)
|
|
|
|
todo= aaip->aa_missing;
|
|
|
|
if(todo > aaip->rec_missing)
|
|
|
|
todo= aaip->rec_missing;
|
2008-12-23 14:47:00 +00:00
|
|
|
if(!aaip->recs_invalid)
|
|
|
|
aaip_push_to_recs(aaip, *data, todo, 1);
|
2008-12-21 10:19:16 +00:00
|
|
|
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++;
|
2008-12-23 14:47:00 +00:00
|
|
|
if(aaip->rec_ends) {
|
2008-12-21 10:19:16 +00:00
|
|
|
aaip->num_components++;
|
2008-12-23 14:47:00 +00:00
|
|
|
aaip->end_of_components= aaip->recs_fill;
|
|
|
|
}
|
2008-12-21 10:19:16 +00:00
|
|
|
}
|
|
|
|
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)
|
|
|
|
{
|
2008-12-23 14:47:00 +00:00
|
|
|
size_t todo;
|
|
|
|
unsigned char aa_head[5];
|
2008-12-21 10:19:16 +00:00
|
|
|
|
|
|
|
todo= *num_data;
|
|
|
|
if(todo >= aaip->aa_head_missing)
|
|
|
|
todo= aaip->aa_head_missing;
|
2008-12-23 14:47:00 +00:00
|
|
|
aaip_push_to_recs(aaip, *data, todo, 0);
|
2008-12-21 10:19:16 +00:00
|
|
|
aaip->aa_head_missing-= todo;
|
|
|
|
if(aaip->aa_head_missing == 0) {
|
2008-12-23 14:47:00 +00:00
|
|
|
aaip_read_from_recs(aaip, aaip->recs_fill - 5, aa_head, 5, 0);
|
|
|
|
if(aa_head[0] != aaip->aa_name[0] || aa_head[1] != aaip->aa_name[1] ||
|
|
|
|
aa_head[3] != 1)
|
2008-12-21 10:19:16 +00:00
|
|
|
return(-1);
|
2008-12-23 14:47:00 +00:00
|
|
|
aaip->aa_missing= aa_head[2];
|
|
|
|
aaip->aa_ends= !(aa_head[4] & 1);
|
2008-12-21 10:19:16 +00:00
|
|
|
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)
|
|
|
|
{
|
2008-12-23 14:47:00 +00:00
|
|
|
size_t i;
|
|
|
|
static unsigned char zero_char[2]= {0, 0};
|
|
|
|
|
2008-12-21 10:19:16 +00:00
|
|
|
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) {
|
2008-12-23 14:47:00 +00:00
|
|
|
/* Check for incomplete pair and eventually make emergency closure */
|
|
|
|
if(aaip->rec_head_missing != 2) { /* incomplete record detected */
|
|
|
|
if(aaip->rec_head_missing) {
|
|
|
|
/* fake 0 length record */
|
|
|
|
aaip_set_buffer_byte(aaip, aaip->recs_fill - 1, (unsigned char) 0, 0);
|
|
|
|
aaip_push_to_recs(aaip, zero_char, 1, 0);
|
|
|
|
} else {
|
|
|
|
/* fill in missing btes */
|
|
|
|
for(i= 0; i < aaip->rec_missing; i++)
|
|
|
|
aaip_push_to_recs(aaip, zero_char, 1, 1);
|
|
|
|
}
|
|
|
|
aaip->rec_head_missing= 2;
|
|
|
|
aaip->rec_missing= 0;
|
|
|
|
aaip->num_recs++;
|
|
|
|
if(aaip->rec_ends) {
|
|
|
|
aaip->num_components++;
|
|
|
|
aaip->end_of_components= aaip->recs_fill;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(aaip->end_of_components != aaip->recs_fill &&
|
|
|
|
aaip->end_of_components != 0) {
|
|
|
|
/* incomplete component detected */
|
|
|
|
/* add empty end record */
|
|
|
|
aaip_push_to_recs(aaip, zero_char, 2, 0);
|
|
|
|
aaip->num_recs++;
|
|
|
|
aaip->num_components++;
|
|
|
|
aaip->end_of_components= aaip->recs_fill;
|
|
|
|
}
|
|
|
|
if(!(aaip->first_is_name ^ (aaip->num_components % 2))) {
|
|
|
|
/* value component is missing */
|
|
|
|
/* add dummy component */
|
|
|
|
aaip_push_to_recs(aaip, zero_char, 2, 0);
|
|
|
|
aaip->num_recs++;
|
|
|
|
aaip->num_components++;
|
|
|
|
aaip->end_of_components= aaip->recs_fill;
|
|
|
|
}
|
2008-12-21 10:19:16 +00:00
|
|
|
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);
|
|
|
|
|
2008-12-23 14:47:00 +00:00
|
|
|
while(num_data > 0) {
|
2008-12-21 10:19:16 +00:00
|
|
|
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);
|
2008-12-23 14:47:00 +00:00
|
|
|
if(aaip->aa_missing)
|
|
|
|
break;
|
2008-12-21 10:19:16 +00:00
|
|
|
}
|
|
|
|
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)
|
|
|
|
{
|
2008-12-23 14:47:00 +00:00
|
|
|
int ret= -1, complete= 0, payload;
|
2008-12-21 10:19:16 +00:00
|
|
|
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++) {
|
2008-12-23 14:47:00 +00:00
|
|
|
payload= aaip_get_buffer_byte(aaip, h + 1, 0);
|
2008-12-21 10:19:16 +00:00
|
|
|
if(!(flag & 1)) {
|
2008-12-23 14:47:00 +00:00
|
|
|
if(num_bytes + payload > result_size)
|
2008-12-21 10:19:16 +00:00
|
|
|
return(-2);
|
2008-12-23 14:47:00 +00:00
|
|
|
aaip_read_from_recs(aaip, h + 2, (unsigned char *) (result + num_bytes),
|
|
|
|
payload, 0);
|
|
|
|
*num_result= num_bytes + payload;
|
2008-12-21 10:19:16 +00:00
|
|
|
}
|
2008-12-23 14:47:00 +00:00
|
|
|
num_bytes+= payload;
|
|
|
|
if(!(aaip_get_buffer_byte(aaip, h, 0) & 1))
|
2008-12-21 10:19:16 +00:00
|
|
|
complete= 1;
|
2008-12-23 14:47:00 +00:00
|
|
|
h+= payload + 2;
|
2008-12-21 10:19:16 +00:00
|
|
|
}
|
|
|
|
aaip->ready_bytes-= num_bytes;
|
2008-12-23 14:47:00 +00:00
|
|
|
aaip->num_recs-= i;
|
2008-12-21 10:19:16 +00:00
|
|
|
|
|
|
|
/* Shift buffer */
|
2008-12-23 14:47:00 +00:00
|
|
|
aaip_shift_recs(aaip, h, 0);
|
2008-12-21 10:19:16 +00:00
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
2008-12-23 14:47:00 +00:00
|
|
|
if(aaip->first_is_name && !(flag & 1))
|
|
|
|
to_skip= 2;
|
2008-12-21 10:19:16 +00:00
|
|
|
if(aaip->recs_invalid) {
|
2008-12-23 14:47:00 +00:00
|
|
|
aaip->recs_invalid+= to_skip;
|
2008-12-21 10:19:16 +00:00
|
|
|
return(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
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 */;
|
|
|
|
|