1/* Copyright (C) 2007-2008 The Android Open Source Project
2**
3** This software is licensed under the terms of the GNU General Public
4** License version 2, as published by the Free Software Foundation, and
5** may be copied, distributed, and modified under those terms.
6**
7** This program is distributed in the hope that it will be useful,
8** but WITHOUT ANY WARRANTY; without even the implied warranty of
9** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10** GNU General Public License for more details.
11*/
12#include "android/cbuffer.h"
13#include "android/utils/stralloc.h"
14#include <string.h>
15#include <stdlib.h>
16#include <assert.h>
17#include <stdio.h>
18
19#define  DEBUG  0
20
21#if DEBUG
22#  define  ASSERT(cond,fmt,...)  ({ if (!(cond)) { fprintf(stderr, fmt, __VA_ARGS__); assert(cond); } })
23#else
24#  define  ASSERT(cond,fmt,...)  ((void)0)
25#endif
26
27#if DEBUG
28void
29cbuffer_assert( CBuffer*  cb, const char*  file, long  lineno )
30{
31    const char*  reason = NULL;
32
33    if (cb->rpos < 0 || cb->rpos >= cb->size) {
34        reason = "rpos is out of bounds";
35    }
36    else if (cb->count < 0 || cb->count > cb->size) {
37        reason = "count is incorrect";
38    }
39    if (!reason)
40        return;
41
42    fprintf(stderr, "assert:%s:%ld: assertion failed: %s (pos=%d count=%d size=%d)\n",
43            file, lineno, reason, cb->rpos, cb->count, cb->size);
44    assert(0);
45}
46#  define  CBUFFER_ASSERT(cb)  cbuffer_assert(cb,__FUNCTION__,__LINE__)
47#else
48#  define  CBUFFER_ASSERT(cb)  ((void)0)
49#endif
50
51int
52cbuffer_write_peek( CBuffer*  cb, uint8_t*  *pbase )
53{
54    int  wpos  = cb->rpos + cb->count;
55    int  avail = cb->size - cb->count;
56
57    CBUFFER_ASSERT(cb);
58
59    if (wpos >= cb->size)
60        wpos -= cb->size;
61
62    if (wpos + avail > cb->size)
63        avail = cb->size - wpos;
64
65    *pbase = cb->buff + wpos;
66    return avail;
67}
68
69void
70cbuffer_write_step( CBuffer*  cb, int  len )
71{
72    CBUFFER_ASSERT(cb);
73
74    cb->count += len;
75    if (cb->count > cb->size)
76        cb->count = cb->size;
77}
78
79
80int
81cbuffer_write( CBuffer*  cb, const void*  from, int  len )
82{
83    int  len2 = len;
84
85    CBUFFER_ASSERT(cb);
86
87    while (len2 > 0) {
88        int  avail = cb->size - cb->count;
89        int  wpos  = cb->rpos + cb->count;
90
91        ASSERT(avail >= 0, "avail is negative: %d", avail);
92
93        if (avail == 0)
94            break;
95
96        if (wpos >= cb->size)
97            wpos -= cb->size;
98
99        ASSERT( wpos >= 0 && wpos < cb->size, "wpos is out-of-bounds: %d (rpos=%d)", wpos, cb->rpos);
100
101        if (wpos + avail > cb->size)
102            avail = cb->size - wpos;
103
104        if (avail > len2)
105            avail = len2;
106
107        memcpy( cb->buff + wpos, (const char*)from, avail );
108
109        from  = (char*)from + avail;
110        len2 -= avail;
111        cb->count += avail;
112    }
113    return len - len2;
114}
115
116int
117cbuffer_read( CBuffer*  cb, void*  to, int  len )
118{
119    int   len2 = len;
120
121    CBUFFER_ASSERT(cb);
122
123    while (len2 > 0) {
124        int  avail = cb->count;
125        int  rpos = cb->rpos;
126
127        ASSERT(avail >= 0, "avail is negative: %d", avail);
128
129        if (avail == 0)
130            break;
131
132        ASSERT((rpos >= 0 && rpos < cb->size), "rpos is out-of-bounds: %d", rpos);
133
134        if (rpos+avail > cb->size)
135            avail = cb->size - rpos;
136
137        if (avail > len2)
138            avail = len2;
139
140        memcpy( (char*)to, (const char*)cb->buff + rpos, avail );
141        to    = (char*)to + avail;
142        len2 -= avail;
143        cb->count -= avail;
144        cb->rpos  += avail;
145        if (cb->rpos >= cb->size)
146            cb->rpos -= cb->size;
147    }
148    return len - len2;
149}
150
151int
152cbuffer_read_peek( CBuffer*  cb, uint8_t*  *pbase )
153{
154    int   rpos  = cb->rpos;
155    int   avail = cb->count;
156
157    CBUFFER_ASSERT(cb);
158
159    if (rpos + avail > cb->size)
160        avail = cb->size - rpos;
161
162    *pbase = cb->buff + rpos;
163    return avail;
164}
165
166
167void
168cbuffer_read_step( CBuffer*  cb, int  len )
169{
170    CBUFFER_ASSERT(cb);
171
172    if (len > cb->count)
173        len = cb->count;
174
175    cb->rpos  += len;
176    if (cb->rpos >= cb->size)
177        cb->rpos -= cb->size;
178
179    cb->count -= len;
180}
181
182const char*
183cbuffer_quote( CBuffer*  cb )
184{
185    STRALLOC_DEFINE(s);
186    char* q;
187
188    stralloc_format( s, "cbuffer %p (pos=%d count=%d size=%d)",
189                     cb, cb->rpos, cb->count, cb->size );
190
191    q = stralloc_to_tempstr( s );
192    stralloc_reset(s);
193
194    return q;
195}
196
197const char*
198cbuffer_quote_data( CBuffer*  cb )
199{
200    STRALLOC_DEFINE(s);
201    int   len  = cb->count;
202    int   rpos = cb->rpos;
203    char* result;
204
205    while (len > 0) {
206        int  avail = len;
207
208        if (rpos >= cb->size)
209            rpos -= cb->size;
210
211        if (rpos + avail > cb->size)
212            avail = cb->size - rpos;
213
214        stralloc_add_quote_bytes( s, cb->buff + rpos, avail );
215        rpos += avail;
216        len  -= avail;
217    }
218
219    result = stralloc_to_tempstr(s);
220    stralloc_reset(s);
221
222    return result;
223}
224
225void
226cbuffer_print( CBuffer*  cb )
227{
228    /* print the content of a cbuffer */
229    printf( "%s: %s", cbuffer_quote(cb), cbuffer_quote_data(cb) );
230}
231
232