blob: c030ba8ec3d3d2a1a0019c235dd51507f40defae [file] [log] [blame]
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define ADK_INTERNAL
#include "fwk.h"
#include "sgBuf.h"
#include <string.h>
#define INFO_MASK_NEEDS_FREE 0x80000000
#define INFO_MASK_SIZE 0x00FFFFFF
void sg_init(sg_buf* buf){
buf->first = NULL;
buf->last = NULL;
buf->totalLen = 0;
}
sg_buf* sg_alloc(void){
sg_buf* b = malloc(sizeof(sg_buf));
if(b) sg_init(b);
return b;
}
void sg_free(sg_buf* buf){
sg_buf_node* n = buf->first;
sg_buf_node* t;
while(n){
if(n->info & INFO_MASK_NEEDS_FREE) free(n->data);
t = n->next;
free(n);
n = t;
}
}
uint32_t sg_length(const sg_buf* buf){
return buf->totalLen;
}
static sg_buf_node* sg_alloc_node(const uint8_t* data, uint32_t len, uint8_t flags){
sg_buf_node* n;
uint32_t sz;
if(len &~ INFO_MASK_SIZE) return NULL; //too big
sz = sizeof(sg_buf_node);
if(flags & SG_FLAG_MAKE_A_COPY) sz += len;
n = malloc(sz);
if(n){
if(flags & SG_FLAG_MAKE_A_COPY){
uint8_t* ptr = (uint8_t*)(n + 1);
memcpy(ptr, data, len);
data = ptr;
flags &=~ SG_FLAG_NEEDS_FREEING; //definitely not
}
n->info = len | ((flags & SG_FLAG_NEEDS_FREEING) ? INFO_MASK_NEEDS_FREE : 0);
n->data = data;
}
return n;
}
char sg_add_front(sg_buf* buf, const uint8_t* data, uint32_t len, uint8_t flags){
sg_buf_node* n = sg_alloc_node(data, len, flags);
if(!n) return 0;
n->next = buf->first;
buf->first = n;
if(!buf->last) buf->last = n;
buf->totalLen += len;
return 1;
}
char sg_add_back(sg_buf* buf, const uint8_t* data, uint32_t len, uint8_t flags){
sg_buf_node* n = sg_alloc_node(data, len, flags);
if(!n) return 0;
n->next = NULL;
if(buf->last) buf->last->next = n;
else buf->first = n;
buf->last = n;
buf->totalLen += len;
return 1;
}
void sg_concat_back(sg_buf* buf, sg_buf* second){
buf->totalLen += second->totalLen;
if(buf->last) buf->last->next = second->first;
else buf->first = second->first;
buf->last = second->last;
sg_init(second);
}
void sg_concat_front(sg_buf* buf, sg_buf* second){
sg_concat_back(second, buf);
*buf = *second;
sg_init(buf);
}
sg_iter sg_iter_start(const sg_buf* buf){
return (sg_iter)(buf->first);
}
char sg_iter_next(sg_iter* iterP, const uint8_t** buf, uint32_t* sz){
sg_buf_node* n = (sg_buf_node*)*iterP;
if(!n) return 0; //end of line
if(buf) *buf = n->data;
if(sz) *sz = n->info & INFO_MASK_SIZE;
*iterP = n->next;
return 1;
}
void sg_copyto(const sg_buf* buf, uint8_t* dst){
sg_buf_node* n = buf->first;
uint32_t len;
while(n){
len = n->info & INFO_MASK_SIZE;
memcpy(dst, n->data, len);
dst += len;
n = n->next;
}
}