| /* Copyright (C) 2007-2008 The Android Open Source Project |
| ** |
| ** This software is licensed under the terms of the GNU General Public |
| ** License version 2, as published by the Free Software Foundation, and |
| ** may be copied, distributed, and modified under those terms. |
| ** |
| ** This program is distributed in the hope that it will be useful, |
| ** but WITHOUT ANY WARRANTY; without even the implied warranty of |
| ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| ** GNU General Public License for more details. |
| */ |
| #include "cbuffer.h" |
| #include "android/utils/stralloc.h" |
| #include <string.h> |
| #include <stdlib.h> |
| #include <assert.h> |
| #include <stdio.h> |
| |
| #define DEBUG 0 |
| |
| #if DEBUG |
| # define ASSERT(cond,fmt,...) ({ if (!(cond)) { fprintf(stderr, fmt, __VA_ARGS__); assert(cond); } }) |
| #else |
| # define ASSERT(cond,fmt,...) ((void)0) |
| #endif |
| |
| #if DEBUG |
| void |
| cbuffer_assert( CBuffer* cb, const char* file, long lineno ) |
| { |
| const char* reason = NULL; |
| |
| if (cb->rpos < 0 || cb->rpos >= cb->size) { |
| reason = "rpos is out of bounds"; |
| } |
| else if (cb->count < 0 || cb->count > cb->size) { |
| reason = "count is incorrect"; |
| } |
| if (!reason) |
| return; |
| |
| fprintf(stderr, "assert:%s:%ld: assertion failed: %s (pos=%d count=%d size=%d)\n", |
| file, lineno, reason, cb->rpos, cb->count, cb->size); |
| assert(0); |
| } |
| # define CBUFFER_ASSERT(cb) cbuffer_assert(cb,__FUNCTION__,__LINE__) |
| #else |
| # define CBUFFER_ASSERT(cb) ((void)0) |
| #endif |
| |
| int |
| cbuffer_write_peek( CBuffer* cb, uint8_t* *pbase ) |
| { |
| int wpos = cb->rpos + cb->count; |
| int avail = cb->size - cb->count; |
| |
| CBUFFER_ASSERT(cb); |
| |
| if (wpos >= cb->size) |
| wpos -= cb->size; |
| |
| if (wpos + avail > cb->size) |
| avail = cb->size - wpos; |
| |
| *pbase = cb->buff + wpos; |
| return avail; |
| } |
| |
| void |
| cbuffer_write_step( CBuffer* cb, int len ) |
| { |
| CBUFFER_ASSERT(cb); |
| |
| cb->count += len; |
| if (cb->count > cb->size) |
| cb->count = cb->size; |
| } |
| |
| |
| int |
| cbuffer_write( CBuffer* cb, const void* from, int len ) |
| { |
| int len2 = len; |
| |
| CBUFFER_ASSERT(cb); |
| |
| while (len2 > 0) { |
| int avail = cb->size - cb->count; |
| int wpos = cb->rpos + cb->count; |
| |
| ASSERT(avail >= 0, "avail is negative: %d", avail); |
| |
| if (avail == 0) |
| break; |
| |
| if (wpos >= cb->size) |
| wpos -= cb->size; |
| |
| ASSERT( wpos >= 0 && wpos < cb->size, "wpos is out-of-bounds: %d (rpos=%d)", wpos, cb->rpos); |
| |
| if (wpos + avail > cb->size) |
| avail = cb->size - wpos; |
| |
| if (avail > len2) |
| avail = len2; |
| |
| memcpy( cb->buff + wpos, (const char*)from, avail ); |
| |
| from = (char*)from + avail; |
| len2 -= avail; |
| cb->count += avail; |
| } |
| return len - len2; |
| } |
| |
| int |
| cbuffer_read( CBuffer* cb, void* to, int len ) |
| { |
| int len2 = len; |
| |
| CBUFFER_ASSERT(cb); |
| |
| while (len2 > 0) { |
| int avail = cb->count; |
| int rpos = cb->rpos; |
| |
| ASSERT(avail >= 0, "avail is negative: %d", avail); |
| |
| if (avail == 0) |
| break; |
| |
| ASSERT((rpos >= 0 && rpos < cb->size), "rpos is out-of-bounds: %d", rpos); |
| |
| if (rpos+avail > cb->size) |
| avail = cb->size - rpos; |
| |
| if (avail > len2) |
| avail = len2; |
| |
| memcpy( (char*)to, (const char*)cb->buff + rpos, avail ); |
| to = (char*)to + avail; |
| len2 -= avail; |
| cb->count -= avail; |
| cb->rpos += avail; |
| if (cb->rpos >= cb->size) |
| cb->rpos -= cb->size; |
| } |
| return len - len2; |
| } |
| |
| int |
| cbuffer_read_peek( CBuffer* cb, uint8_t* *pbase ) |
| { |
| int rpos = cb->rpos; |
| int avail = cb->count; |
| |
| CBUFFER_ASSERT(cb); |
| |
| if (rpos + avail > cb->size) |
| avail = cb->size - rpos; |
| |
| *pbase = cb->buff + rpos; |
| return avail; |
| } |
| |
| |
| void |
| cbuffer_read_step( CBuffer* cb, int len ) |
| { |
| CBUFFER_ASSERT(cb); |
| |
| if (len > cb->count) |
| len = cb->count; |
| |
| cb->rpos += len; |
| if (cb->rpos >= cb->size) |
| cb->rpos -= cb->size; |
| |
| cb->count -= len; |
| } |
| |
| const char* |
| cbuffer_quote( CBuffer* cb ) |
| { |
| STRALLOC_DEFINE(s); |
| char* q; |
| |
| stralloc_format( s, "cbuffer %p (pos=%d count=%d size=%d)", |
| cb, cb->rpos, cb->count, cb->size ); |
| |
| q = stralloc_to_tempstr( s ); |
| stralloc_reset(s); |
| |
| return q; |
| } |
| |
| const char* |
| cbuffer_quote_data( CBuffer* cb ) |
| { |
| STRALLOC_DEFINE(s); |
| int len = cb->count; |
| int rpos = cb->rpos; |
| char* result; |
| |
| while (len > 0) { |
| int avail = len; |
| |
| if (rpos >= cb->size) |
| rpos -= cb->size; |
| |
| if (rpos + avail > cb->size) |
| avail = cb->size - rpos; |
| |
| stralloc_add_quote_bytes( s, cb->buff + rpos, avail ); |
| rpos += avail; |
| len -= avail; |
| } |
| |
| result = stralloc_to_tempstr(s); |
| stralloc_reset(s); |
| |
| return result; |
| } |
| |
| void |
| cbuffer_print( CBuffer* cb ) |
| { |
| /* print the content of a cbuffer */ |
| printf( "%s: %s", cbuffer_quote(cb), cbuffer_quote_data(cb) ); |
| } |
| |