Merge branch 'Lyberta/VersionInfo' into 'master'
[xonotic/d0_blind_id.git] / d0_iobuf.c
1 /*
2  * FILE:        d0_iobuf.c
3  * AUTHOR:      Rudolf Polzer - divVerent@xonotic.org
4  * 
5  * Copyright (c) 2010, Rudolf Polzer
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the copyright holder nor the names of contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  * 
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  * $Format:commit %H$
33  * $Id$
34  */
35
36 #include "d0_iobuf.h"
37
38 #include <string.h>
39
40 struct d0_iobuf_s
41 {
42         const unsigned char *inbuf;
43         unsigned char *outbuf;
44         unsigned char **outbufp;
45         size_t inpos, outpos, inbuflen, outbuflen;
46         D0_BOOL ok;
47         D0_BOOL pdata;
48 };
49
50 d0_iobuf_t *d0_iobuf_open_read(const void *buf, size_t len)
51 {
52         d0_iobuf_t *b = d0_malloc(sizeof(d0_iobuf_t));
53         b->inbuf = (const unsigned char *) buf;
54         b->outbuf = NULL;
55         b->outbufp = NULL;
56         b->inpos = b->outpos = 0;
57         b->inbuflen = len;
58         b->outbuflen = 0;
59         b->ok = 1;
60         return b;
61 }
62
63 d0_iobuf_t *d0_iobuf_open_write(void *buf, size_t len)
64 {
65         d0_iobuf_t *b = d0_malloc(sizeof(d0_iobuf_t));
66         b->inbuf = (const unsigned char *) buf;
67         b->outbuf = (unsigned char *) buf;
68         b->outbufp = NULL;
69         b->inpos = b->outpos = 0;
70         b->inbuflen = 0;
71         b->outbuflen = len;
72         b->ok = 1;
73         return b;
74 }
75
76 d0_iobuf_t *d0_iobuf_open_write_p(void **buf, size_t len)
77 {
78         d0_iobuf_t *b = d0_malloc(sizeof(d0_iobuf_t));
79         b->inbuf = (const unsigned char *) *buf;
80         b->outbuf = (unsigned char *) *buf;
81         b->outbufp = (unsigned char **) buf;
82         b->inpos = b->outpos = 0;
83         b->inbuflen = 0;
84         b->outbuflen = len;
85         b->ok = 1;
86         return b;
87 }
88
89 D0_BOOL d0_iobuf_close(d0_iobuf_t *buf, size_t *len)
90 {
91         D0_BOOL r = buf->ok;
92         if(len)
93                 *len = buf->outpos;
94         d0_free(buf);
95         return r;
96 }
97
98 size_t d0_iobuf_write_raw(d0_iobuf_t *buf, const void *s, size_t n)
99 {
100         size_t nreal = n;
101
102         // if packet doesn't fit, expand buffer
103         if(buf->outbufp && nreal > buf->outbuflen - buf->outpos)
104         {
105                 size_t newsize = 1;
106                 while(nreal + buf->outpos > newsize)
107                         newsize <<= 1;
108
109                 {
110                         char *newbuf = d0_malloc(newsize);
111                         if(buf->outbuf)
112                         {
113                                 memcpy(newbuf, buf->outbuf, buf->outbuflen);
114                                 d0_free(buf->outbuf);
115                         }
116                         buf->outbuf = newbuf;
117                         *buf->outbufp = newbuf;
118                         buf->outbuflen = newsize;
119                 }
120         }
121
122         if(nreal > buf->outbuflen - buf->outpos)
123         {
124                 buf->ok = 0;
125                 nreal = buf->outbuflen - buf->outpos;
126         }
127         memcpy(buf->outbuf + buf->outpos, s, nreal);
128         buf->outpos += nreal;
129         buf->inbuflen = buf->outpos;
130         return nreal;
131 }
132
133 size_t d0_iobuf_read_raw(d0_iobuf_t *buf, void *s, size_t n)
134 {
135         size_t nreal = n;
136         if(nreal > buf->inbuflen - buf->inpos)
137         {
138                 buf->ok = 0;
139                 nreal = buf->inbuflen - buf->inpos;
140         }
141         memcpy(s, buf->inbuf + buf->inpos, nreal);
142         buf->inpos += nreal;
143         return nreal;
144 }
145
146 D0_BOOL d0_iobuf_write_packet(d0_iobuf_t *buf, const void *s, size_t n)
147 {
148         unsigned char c;
149         size_t nn = n;
150         while(nn)
151         {
152                 c = nn & 0x7F;
153                 nn >>= 7;
154                 if(nn)
155                         c |= 0x80;
156                 if(d0_iobuf_write_raw(buf, &c, 1) != 1)
157                         return 0;
158         }
159         if(d0_iobuf_write_raw(buf, s, n) != n)
160                 return 0;
161         return 1;
162 }
163
164 D0_BOOL d0_iobuf_read_packet(d0_iobuf_t *buf, void *s, size_t *np)
165 {
166         unsigned char c;
167         size_t n = 0;
168         size_t nn = 1;
169         do
170         {
171                 if(d0_iobuf_read_raw(buf, &c, 1) != 1)
172                         return 0;
173                 n |= nn * (c & 0x7F);
174                 nn <<= 7;
175         }
176         while(c & 0x80);
177         if(n > *np)
178                 return 0;
179         if(d0_iobuf_read_raw(buf, s, n) != n)
180                 return 0;
181         *np = n;
182         return 1;
183 }
184
185 D0_BOOL d0_iobuf_conv_base64_in(d0_iobuf_t *buf)
186 {
187         // compand the in-buffer
188         return 0;
189 }
190
191 static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
192 static void base64_3to4(const unsigned char *in, unsigned char *out, int bytes)
193 {
194         unsigned char i0 = (bytes > 0) ? in[0] : 0;
195         unsigned char i1 = (bytes > 1) ? in[1] : 0;
196         unsigned char i2 = (bytes > 2) ? in[2] : 0;
197         unsigned char o0 = base64[i0 >> 2];
198         unsigned char o1 = base64[((i0 << 4) | (i1 >> 4)) & 077];
199         unsigned char o2 = base64[((i1 << 2) | (i2 >> 6)) & 077];
200         unsigned char o3 = base64[i2 & 077];
201         out[0] = (bytes > 0) ? o0 : '?';
202         out[1] = (bytes > 0) ? o1 : '?';
203         out[2] = (bytes > 1) ? o2 : '=';
204         out[3] = (bytes > 2) ? o3 : '=';
205 }
206
207 D0_BOOL d0_iobuf_conv_base64_out(d0_iobuf_t *buf)
208 {
209         size_t blocks, i;
210         // expand the out-buffer
211         blocks = ((buf->outpos + 2) / 3);
212         if(blocks*4 > buf->outbuflen)
213                 return 0;
214         for(i = blocks; i > 0; )
215         {
216                 --i;
217                 base64_3to4(buf->outbuf + 3*i, buf->outbuf + 4*i, buf->outpos - 3*i);
218         }
219         buf->outpos = blocks * 4;
220         return 1;
221 }