1 /*
2 * io_dp.c
3 *
4 * Implements the dynamic pointer interface.
5 *
6 * Based on GD.pm code by Lincoln Stein for interfacing to libgd.
7 * Added support for reading as well as support for 'tell' and 'seek'.
8 *
9 * As with all I/O modules, most functions are for local use only (called
10 * via function pointers in the I/O context).
11 *
12 * gdDPExtractData is the exception to this: it will return the pointer to
13 * the internal data, and reset the internal storage.
14 *
15 * Written/Modified 1999, Philip Warner.
16 */
17
18 #ifdef HAVE_CONFIG_H
19 # include "config.h"
20 #endif
21
22 #include <math.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include "gd.h"
26 #include "gdhelpers.h"
27
28 #define TRUE 1
29 #define FALSE 0
30
31 /* this is used for creating images in main memory */
32 typedef struct dpStruct {
33 void *data;
34 int logicalSize;
35 int realSize;
36 int dataGood;
37 int pos;
38 int freeOK;
39 }
40 dynamicPtr;
41
42 typedef struct dpIOCtx {
43 gdIOCtx ctx;
44 dynamicPtr *dp;
45 }
46 dpIOCtx;
47
48 typedef struct dpIOCtx *dpIOCtxPtr;
49
50 /* these functions operate on in-memory dynamic pointers */
51 static int allocDynamic(dynamicPtr *dp, int initialSize, void *data);
52 static int appendDynamic(dynamicPtr *dp, const void *src, int size);
53 static int gdReallocDynamic(dynamicPtr *dp, int required);
54 static int trimDynamic(dynamicPtr *dp);
55 static void gdFreeDynamicCtx(struct gdIOCtx *ctx);
56 static dynamicPtr *newDynamic(int initialSize, void *data, int freeOKFlag);
57
58 static int dynamicPutbuf(struct gdIOCtx *, const void *, int);
59 static void dynamicPutchar(struct gdIOCtx *, int a);
60
61 static int dynamicGetbuf(gdIOCtxPtr ctx, void *buf, int len);
62 static int dynamicGetchar(gdIOCtxPtr ctx);
63
64 static int dynamicSeek(struct gdIOCtx *, const int);
65 static long dynamicTell(struct gdIOCtx *);
66
67 /*
68 Function: gdNewDynamicCtx
69
70 Return data as a dynamic pointer.
71 */
gdNewDynamicCtx(int initialSize,void * data)72 BGD_DECLARE(gdIOCtx *) gdNewDynamicCtx(int initialSize, void *data)
73 {
74 /* 2.0.23: Phil Moore: 'return' keyword was missing! */
75 return gdNewDynamicCtxEx(initialSize, data, 1);
76 }
77
78 /*
79 Function: gdNewDynamicCtxEx
80 */
gdNewDynamicCtxEx(int initialSize,void * data,int freeOKFlag)81 BGD_DECLARE(gdIOCtx *) gdNewDynamicCtxEx(int initialSize, void *data, int freeOKFlag)
82 {
83 dpIOCtx *ctx;
84 dynamicPtr *dp;
85
86 ctx = (dpIOCtx *)gdMalloc(sizeof (dpIOCtx));
87 if(ctx == NULL) {
88 return NULL;
89 }
90
91 dp = newDynamic(initialSize, data, freeOKFlag);
92 if(!dp) {
93 gdFree (ctx);
94 return NULL;
95 };
96
97 ctx->dp = dp;
98
99 ctx->ctx.getC = dynamicGetchar;
100 ctx->ctx.putC = dynamicPutchar;
101
102 ctx->ctx.getBuf = dynamicGetbuf;
103 ctx->ctx.putBuf = dynamicPutbuf;
104
105 ctx->ctx.seek = dynamicSeek;
106 ctx->ctx.tell = dynamicTell;
107
108 ctx->ctx.gd_free = gdFreeDynamicCtx;
109
110 return (gdIOCtx *)ctx;
111 }
112
113 /*
114 Function: gdDPExtractData
115 */
gdDPExtractData(struct gdIOCtx * ctx,int * size)116 BGD_DECLARE(void *) gdDPExtractData (struct gdIOCtx *ctx, int *size)
117 {
118 dynamicPtr *dp;
119 dpIOCtx *dctx;
120 void *data;
121
122 dctx = (dpIOCtx *)ctx;
123 dp = dctx->dp;
124
125 /* clean up the data block and return it */
126 if(dp->dataGood) {
127 trimDynamic(dp);
128 *size = dp->logicalSize;
129 data = dp->data;
130 } else {
131 *size = 0;
132 data = NULL;
133 /* 2.0.21: never free memory we don't own */
134 if((dp->data != NULL) && (dp->freeOK)) {
135 gdFree(dp->data);
136 }
137 }
138
139 dp->data = NULL;
140 dp->realSize = 0;
141 dp->logicalSize = 0;
142
143 return data;
144 }
145
gdFreeDynamicCtx(struct gdIOCtx * ctx)146 static void gdFreeDynamicCtx(struct gdIOCtx *ctx)
147 {
148 dynamicPtr *dp;
149 dpIOCtx *dctx;
150
151 dctx = (dpIOCtx *)ctx;
152 dp = dctx->dp;
153
154 gdFree(ctx);
155
156 /* clean up the data block and return it */
157 /* 2.0.21: never free memory we don't own */
158 if((dp->data != NULL) && (dp->freeOK)) {
159 gdFree(dp->data);
160 dp->data = NULL;
161 }
162
163 dp->realSize = 0;
164 dp->logicalSize = 0;
165
166 gdFree(dp);
167 }
168
dynamicTell(struct gdIOCtx * ctx)169 static long dynamicTell(struct gdIOCtx *ctx)
170 {
171 dpIOCtx *dctx;
172
173 dctx = (dpIOCtx *)ctx;
174 return (dctx->dp->pos);
175 }
176
dynamicSeek(struct gdIOCtx * ctx,const int pos)177 static int dynamicSeek(struct gdIOCtx *ctx, const int pos)
178 {
179 int bytesNeeded;
180 dynamicPtr *dp;
181 dpIOCtx *dctx;
182
183 if (pos < 0) {
184 return FALSE;
185 }
186 dctx = (dpIOCtx *)ctx;
187 dp = dctx->dp;
188
189 if(!dp->dataGood) {
190 return FALSE;
191 }
192
193 bytesNeeded = pos;
194 if(bytesNeeded > dp->realSize) {
195 /* 2.0.21 */
196 if(!dp->freeOK) {
197 return FALSE;
198 }
199
200 if(overflow2(dp->realSize, 2)) {
201 return FALSE;
202 }
203
204 if(!gdReallocDynamic(dp, dp->realSize * 2)) {
205 dp->dataGood = FALSE;
206 return FALSE;
207 }
208 }
209
210 /* if we get here, we can be sure that we have enough bytes
211 * to copy safely */
212
213 /* Extend the logical size if we seek beyond EOF. */
214 if(pos > dp->logicalSize) {
215 dp->logicalSize = pos;
216 };
217
218 dp->pos = pos;
219
220 return TRUE;
221 }
222
223 /* return data as a dynamic pointer */
newDynamic(int initialSize,void * data,int freeOKFlag)224 static dynamicPtr *newDynamic(int initialSize, void *data, int freeOKFlag)
225 {
226 dynamicPtr *dp;
227
228 dp = (dynamicPtr *) gdMalloc(sizeof (dynamicPtr));
229 if(dp == NULL) {
230 return NULL;
231 }
232
233 if(!allocDynamic(dp, initialSize, data)) {
234 gdFree(dp);
235 return NULL;
236 }
237
238 dp->pos = 0;
239 dp->freeOK = freeOKFlag;
240
241 return dp;
242 }
243
dynamicPutbuf(struct gdIOCtx * ctx,const void * buf,int size)244 static int dynamicPutbuf(struct gdIOCtx *ctx, const void *buf, int size)
245 {
246 dpIOCtx *dctx;
247 dctx = (dpIOCtx *)ctx;
248
249 appendDynamic(dctx->dp, buf, size);
250
251 if(dctx->dp->dataGood) {
252 return size;
253 } else {
254 return -1;
255 };
256 }
257
dynamicPutchar(struct gdIOCtx * ctx,int a)258 static void dynamicPutchar(struct gdIOCtx *ctx, int a)
259 {
260 unsigned char b;
261 dpIOCtxPtr dctx;
262
263 b = a;
264 dctx = (dpIOCtxPtr) ctx;
265
266 appendDynamic(dctx->dp, &b, 1);
267 }
268
269 /* returns the number of bytes actually read; 0 on EOF and error */
dynamicGetbuf(gdIOCtxPtr ctx,void * buf,int len)270 static int dynamicGetbuf(gdIOCtxPtr ctx, void *buf, int len)
271 {
272 int rlen, remain;
273 dpIOCtxPtr dctx;
274 dynamicPtr *dp;
275
276 dctx = (dpIOCtxPtr) ctx;
277 dp = dctx->dp;
278
279 if (dp->pos < 0 || dp->pos >= dp->realSize) {
280 return 0;
281 }
282
283 remain = dp->logicalSize - dp->pos;
284 if(remain >= len) {
285 rlen = len;
286 } else {
287 if(remain <= 0) {
288 return 0;
289 }
290
291 rlen = remain;
292 }
293
294 if (dp->pos + rlen > dp->realSize) {
295 rlen = dp->realSize - dp->pos;
296 }
297
298 if (rlen < 0) {
299 return 0;
300 }
301
302 memcpy(buf, (void *) ((char *)dp->data + dp->pos), rlen);
303 dp->pos += rlen;
304
305 return rlen;
306 }
307
dynamicGetchar(gdIOCtxPtr ctx)308 static int dynamicGetchar(gdIOCtxPtr ctx)
309 {
310 unsigned char b;
311 int rv;
312
313 rv = dynamicGetbuf(ctx, &b, 1);
314
315 if(rv != 1) {
316 return EOF;
317 } else {
318 return b; /* (b & 0xff); */
319 }
320 }
321
322 /**********************************************************************
323 * InitDynamic - Return a dynamically resizable void*
324 **********************************************************************/
allocDynamic(dynamicPtr * dp,int initialSize,void * data)325 static int allocDynamic(dynamicPtr *dp, int initialSize, void *data)
326 {
327 if(data == NULL) {
328 dp->logicalSize = 0;
329 dp->dataGood = FALSE;
330 dp->data = gdMalloc(initialSize);
331 } else {
332 dp->logicalSize = initialSize;
333 dp->dataGood = TRUE;
334 dp->data = data;
335 }
336
337 if(dp->data != NULL) {
338 dp->realSize = initialSize;
339 dp->dataGood = TRUE;
340 dp->pos = 0;
341 return TRUE;
342 } else {
343 dp->realSize = 0;
344 return FALSE;
345 }
346 }
347
348 /* append bytes to the end of a dynamic pointer */
appendDynamic(dynamicPtr * dp,const void * src,int size)349 static int appendDynamic(dynamicPtr * dp, const void *src, int size)
350 {
351 int bytesNeeded;
352 char *tmp;
353
354 if(!dp->dataGood) {
355 return FALSE;
356 }
357
358 /* bytesNeeded = dp->logicalSize + size; */
359 bytesNeeded = dp->pos + size;
360
361 if(bytesNeeded > dp->realSize) {
362 /* 2.0.21 */
363 if(!dp->freeOK) {
364 return FALSE;
365 }
366
367 if(overflow2(dp->realSize, 2)) {
368 return FALSE;
369 }
370
371 if(!gdReallocDynamic(dp, bytesNeeded * 2)) {
372 dp->dataGood = FALSE;
373 return FALSE;
374 }
375 }
376
377 /* if we get here, we can be sure that we have enough bytes
378 * to copy safely */
379
380 /*printf("Mem OK Size: %d, Pos: %d\n", dp->realSize, dp->pos); */
381
382 tmp = (char *)dp->data;
383 memcpy ((void *)(tmp + (dp->pos)), src, size);
384 dp->pos += size;
385
386 if(dp->pos > dp->logicalSize) {
387 dp->logicalSize = dp->pos;
388 };
389
390 return TRUE;
391 }
392
393 /* grow (or shrink) dynamic pointer */
gdReallocDynamic(dynamicPtr * dp,int required)394 static int gdReallocDynamic(dynamicPtr *dp, int required)
395 {
396 void *newPtr;
397
398 /* First try gdRealloc(). If that doesn't work, make a new
399 * memory block and copy. */
400 if((newPtr = gdRealloc(dp->data, required))) {
401 dp->realSize = required;
402 dp->data = newPtr;
403 return TRUE;
404 }
405
406 /* create a new pointer */
407 newPtr = gdMalloc(required);
408 if(!newPtr) {
409 dp->dataGood = FALSE;
410 return FALSE;
411 }
412
413 /* copy the old data into it */
414 memcpy(newPtr, dp->data, dp->logicalSize);
415 gdFree(dp->data);
416 dp->data = newPtr;
417
418 dp->realSize = required;
419 return TRUE;
420 }
421
422 /* trim pointer so that its real and logical sizes match */
trimDynamic(dynamicPtr * dp)423 static int trimDynamic(dynamicPtr *dp)
424 {
425 /* 2.0.21: we don't reallocate memory we don't own */
426 if(!dp->freeOK) {
427 return TRUE;
428 }
429
430 return gdReallocDynamic(dp, dp->logicalSize);
431 }
432