154 lines · 3.1 KB · C
RawDownload
/* Parcel-handling code */#include <sys/types.h>#include <cutils/jstring.h>#include <string.h>#include <endian.h> #define PAD_SIZE(s) (((s)+3)&~3) struct parcel {	char *data;	size_t offset;	size_t capacity;	size_t size;}; intparcel_init(struct parcel *p){	p->data = malloc(sizeof(int32_t)); // arbitrary size to start with	if(p->data == NULL) return -1;	p->size = 0;	p->capacity = sizeof(int32_t);	p->offset = 0;	return 0;} intparcel_grow(struct parcel *p, size_t size){	char *new = realloc(p->data, p->capacity + size); 	if(new == NULL) {		return -1;	}	p->data = new;	p->capacity += size;	return 0;} voidparcel_free(struct parcel *p){	free(p->data);	p->size = 0;	p->capacity = 0;	p->offset = 0;} int32_tparcel_r_int32(struct parcel *p){	int32_t ret;	ret = *((int32_t *) (p->data + p->offset));	p->offset += sizeof(int32_t);	return ret;} intparcel_w_int32(struct parcel *p, int32_t val){	for(;;) {/*		printf("parcel_w_int32(%d): offset = %d, cap = %d, size = %d\n",		val, p->offset, p->capacity, p->size);*/		if(p->offset + sizeof(int32_t) < p->capacity) {			// There's enough space			*((int32_t *) (p->data + p->offset)) = val;			p->offset += sizeof(int32_t);			p->size += sizeof(int32_t);			break;		} else {			// Grow data and retry			if(parcel_grow(p, sizeof(int32_t)) == -1) {				return -1;			}		}	}	return 0;} intparcel_w_string(struct parcel *p, char *str){	char16_t *s16;	size_t s16_len;	size_t len; 	if(str == NULL) {		parcel_w_int32(p, -1);		return 0;	}	s16_len = strlen8to16(str);	s16 = malloc(sizeof(char16_t) * s16_len);	strcpy8to16(s16, str, &s16_len);	if(parcel_w_int32(p, s16_len) == -1) {		return -1;	}	len = (s16_len + 1) * sizeof(char16_t);	for(;;) {		size_t padded = PAD_SIZE(len);		/*printf("parcel_w_string(\"%s\"): offset %d, cap %d, size %d\n",		  str, p->offset, p->capacity, p->size);*/		if(p->offset + len < p->capacity) {			// There's enough space			memcpy(p->data + p->offset, s16, s16_len * sizeof(char16_t));			*((char16_t *) (p->data + p->offset + len)) = 0;			p->offset += padded;			p->size += padded;			if (padded != len) {				//printf("Writing %ld bytes, padded to %ld\n", len, padded);#if BYTE_ORDER == BIG_ENDIAN				static const uint32_t mask[4] = {					0x00000000, 0xffffff00, 0xffff0000, 0xff000000				};#endif#if BYTE_ORDER == LITTLE_ENDIAN				static const uint32_t mask[4] = {					0x00000000, 0x00ffffff, 0x0000ffff, 0x000000ff				};#endif				*((uint32_t*)(p->data+p->offset+padded-4)) &= mask[padded-len];			}			break;		} else {			// Grow data and retry			if(parcel_grow(p, padded) == -1) {				free(s16);				return -1;			}		}	}	free(s16);	return 0;} char*parcel_r_string(struct parcel *p){	char *ret;	int len16 = parcel_r_int32(p);	size_t len8;	if(len16 < 0) return NULL; // this is how a null string is sent	len8 = strnlen16to8((char16_t *) (p->data + p->offset), len16);	ret = malloc(len8 + 1);	if(ret == NULL) return NULL;	strncpy16to8(ret, (char16_t *) (p->data + p->offset), len16);	p->offset += PAD_SIZE((len16 + 1) * sizeof(char16_t));	return ret;} size_tparcel_data_avail(struct parcel *p){	return (p->size - p->offset);}