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 "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
28 void
cbuffer_assert(CBuffer * cb,const char * file,long lineno)29 cbuffer_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
51 int
cbuffer_write_peek(CBuffer * cb,uint8_t ** pbase)52 cbuffer_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
69 void
cbuffer_write_step(CBuffer * cb,int len)70 cbuffer_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
80 int
cbuffer_write(CBuffer * cb,const void * from,int len)81 cbuffer_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
116 int
cbuffer_read(CBuffer * cb,void * to,int len)117 cbuffer_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
151 int
cbuffer_read_peek(CBuffer * cb,uint8_t ** pbase)152 cbuffer_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
167 void
cbuffer_read_step(CBuffer * cb,int len)168 cbuffer_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
182 const char*
cbuffer_quote(CBuffer * cb)183 cbuffer_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
197 const char*
cbuffer_quote_data(CBuffer * cb)198 cbuffer_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
225 void
cbuffer_print(CBuffer * cb)226 cbuffer_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