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