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 will 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 
19 #include <math.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include "gd.h"
23 
24 #define TRUE 1
25 #define FALSE 0
26 
27 /* this is used for creating images in main memory*/
28 typedef struct dpStruct {
29   void* data;
30   int logicalSize;
31   int realSize;
32   int dataGood;
33   int pos;
34 } dynamicPtr;
35 
36 typedef struct dpIOCtx {
37   gdIOCtx		ctx;
38   dynamicPtr 	*dp;
39 } dpIOCtx;
40 
41 typedef struct dpIOCtx	*dpIOCtxPtr;
42 
43 
44 /* these functions operate on in-memory dynamic pointers */
45 static int allocDynamic (dynamicPtr* dp,int initialSize, void *data);
46 static int appendDynamic (dynamicPtr* dp, const void* src, int size);
47 static int reallocDynamic (dynamicPtr* dp, int required);
48 static int trimDynamic (dynamicPtr* dp);
49 static void freeDynamicCtx(struct gdIOCtx* ctx);
50 static dynamicPtr* newDynamic(int initialSize, void *data);
51 
52 static int dynamicPutbuf( struct gdIOCtx*, const void *, int );
53 static void dynamicPutchar( struct gdIOCtx*, int a );
54 
55 static int dynamicGetbuf( gdIOCtxPtr ctx, void *buf, int len);
56 static int dynamicGetchar( gdIOCtxPtr ctx );
57 
58 static int dynamicSeek(struct gdIOCtx*, const int);
59 static long dynamicTell(struct gdIOCtx*);
60 
61 /* return data as a dynamic pointer */
gdNewDynamicCtx(int initialSize,void * data)62 gdIOCtx* gdNewDynamicCtx (int initialSize, void *data) {
63   dpIOCtx 	*ctx;
64   dynamicPtr* 	dp;
65 
66   ctx = (dpIOCtx*) malloc(sizeof(dpIOCtx));
67   if (ctx == NULL) {
68     return NULL;
69   }
70 
71   dp = newDynamic(initialSize, data);
72   if (!dp) {
73     free(ctx);
74     return NULL;
75   };
76 
77   ctx->dp = dp;
78 
79   ctx->ctx.getC = dynamicGetchar;
80   ctx->ctx.putC = dynamicPutchar;
81 
82   ctx->ctx.getBuf = dynamicGetbuf;
83   ctx->ctx.putBuf = dynamicPutbuf;
84 
85   ctx->ctx.seek = dynamicSeek;
86   ctx->ctx.tell = dynamicTell;
87 
88   ctx->ctx.free = freeDynamicCtx;
89 
90   return (gdIOCtx*)ctx;
91 };
92 
gdDPExtractData(struct gdIOCtx * ctx,int * size)93 void* gdDPExtractData(struct gdIOCtx* ctx, int *size)
94 {
95   dynamicPtr            *dp;
96   dpIOCtx               *dctx;
97   void                  *data;
98 
99   dctx = (dpIOCtx*) ctx;
100   dp = dctx->dp;
101 
102   /* clean up the data block and return it */
103   if (dp->dataGood) {
104     trimDynamic(dp);
105     *size = dp->logicalSize;
106     data = dp->data;
107   } else {
108     *size = 0;
109     data = NULL;
110     if (dp->data != NULL) {
111       free(dp->data);
112     }
113   }
114 
115   dp->data = NULL;
116   dp->realSize=0;
117   dp->logicalSize=0;
118 
119   return data;
120 }
121 
122 static
freeDynamicCtx(struct gdIOCtx * ctx)123 void freeDynamicCtx(struct gdIOCtx* ctx)
124 {
125   dynamicPtr            *dp;
126   dpIOCtx               *dctx;
127 
128   dctx = (dpIOCtx*) ctx;
129   dp = dctx->dp;
130 
131   free(ctx);
132 
133   /* clean up the data block and return it */
134   if (dp->data != NULL) {
135     free(dp->data);
136     dp->data = NULL;
137   }
138 
139   dp->realSize=0;
140   dp->logicalSize=0;
141 
142   free(dp);
143 
144 }
145 
dynamicTell(struct gdIOCtx * ctx)146 static long dynamicTell(struct gdIOCtx* ctx)
147 {
148   dpIOCtx               *dctx;
149 
150   dctx = (dpIOCtx*) ctx;
151   return (dctx->dp->pos);
152 }
153 
dynamicSeek(struct gdIOCtx * ctx,const int pos)154 static int dynamicSeek(struct gdIOCtx* ctx, const int pos)
155 {
156   int 			bytesNeeded;
157   dynamicPtr		*dp;
158   dpIOCtx  		*dctx;
159 
160   dctx = (dpIOCtx*) ctx;
161   dp = dctx->dp;
162 
163   if (!dp->dataGood) return FALSE;
164 
165   bytesNeeded = pos;
166   if (bytesNeeded > dp->realSize) {
167     if (!reallocDynamic(dp,dp->realSize*2)) {
168       dp->dataGood = FALSE;
169       return FALSE;
170     }
171   }
172 
173   /* if we get here, we can be sure that we have enough bytes
174      to copy safely */
175 
176   /* Extend the logical size if we seek beyond EOF. */
177   if (pos > dp->logicalSize) {
178     dp->logicalSize = pos;
179   };
180 
181   dp->pos = pos;
182 
183   return TRUE;
184 }
185 
186 /* return data as a dynamic pointer */
newDynamic(int initialSize,void * data)187 static dynamicPtr* newDynamic (int initialSize, void *data) {
188   dynamicPtr* dp;
189   dp = (dynamicPtr*) malloc(sizeof(dynamicPtr));
190   if (dp == NULL) {
191     return NULL;
192   }
193 
194   if (!allocDynamic(dp,initialSize, data))
195     return NULL;
196 
197   dp->pos = 0;
198 
199   return dp;
200 };
201 
202 static int
dynamicPutbuf(struct gdIOCtx * ctx,const void * buf,int size)203 dynamicPutbuf( struct gdIOCtx* ctx, const void *buf, int size )
204 {
205   dpIOCtx  *dctx;
206   dctx = (dpIOCtx*) ctx;
207 
208   appendDynamic(dctx->dp,buf,size);
209 
210   if (dctx->dp->dataGood) {
211 	return size;
212   } else {
213 	return -1;
214   };
215 
216 }
217 
218 static void
dynamicPutchar(struct gdIOCtx * ctx,int a)219 dynamicPutchar( struct gdIOCtx* ctx, int a )
220 {
221   unsigned char b;
222   dpIOCtxPtr    dctx;
223 
224   b = a;
225   dctx = (dpIOCtxPtr) ctx;
226 
227   appendDynamic(dctx->dp,&b,1);
228 }
229 
230 static int
dynamicGetbuf(gdIOCtxPtr ctx,void * buf,int len)231 dynamicGetbuf( gdIOCtxPtr ctx, void *buf, int len)
232 {
233 	int		rlen, remain;
234 	dpIOCtxPtr	dctx;
235 	dynamicPtr* 	dp;
236 
237 	dctx = (dpIOCtxPtr) ctx;
238 	dp = dctx->dp;
239 
240 	remain = dp->logicalSize - dp->pos;
241 	if (remain >= len) {
242 		rlen = len;
243 	} else {
244 		if (remain == 0) {
245 			return EOF;
246 		}
247 		rlen = remain;
248 	}
249 
250 	memcpy(buf, (void*)((char*)dp->data + dp->pos), rlen);
251 	dp->pos += rlen;
252 
253 	return rlen;
254 }
255 
256 static int
dynamicGetchar(gdIOCtxPtr ctx)257 dynamicGetchar( gdIOCtxPtr ctx )
258 {
259 	unsigned char	b;
260 	int	rv;
261 
262 	rv = dynamicGetbuf(ctx, &b, 1);
263 
264 	if (rv != 1) {
265 		return EOF;
266 	} else {
267 		return b ;/* (b & 0xff); */
268 	}
269 }
270 
271 /* *********************************************************************
272  *
273  * InitDynamic - Return a dynamically resizable void*
274  *
275  * *********************************************************************
276  */
277 static int
allocDynamic(dynamicPtr * dp,int initialSize,void * data)278 allocDynamic (dynamicPtr* dp,int initialSize, void *data) {
279 
280   if (data == NULL) {
281       dp->logicalSize = 0;
282       dp->dataGood = FALSE;
283       dp->data = malloc(initialSize);
284   } else {
285       dp->logicalSize = initialSize;
286       dp->dataGood = TRUE;
287       dp->data = data;
288   }
289 
290   if (dp->data !=NULL) {
291     dp->realSize = initialSize;
292     dp->dataGood = TRUE;
293     dp->pos = 0;
294     return TRUE;
295   } else {
296     dp->realSize = 0;
297     return FALSE;
298   }
299 }
300 
301 /* append bytes to the end of a dynamic pointer */
302 static int
appendDynamic(dynamicPtr * dp,const void * src,int size)303 appendDynamic (dynamicPtr* dp, const void* src, int size) {
304   int bytesNeeded;
305   char* tmp;
306 
307   if (!dp->dataGood) return FALSE;
308 
309 /*  bytesNeeded = dp->logicalSize + size; */
310   bytesNeeded = dp->pos + size;
311 
312   if (bytesNeeded > dp->realSize) {
313     if (!reallocDynamic(dp,bytesNeeded*2)) {
314       dp->dataGood = FALSE;
315       return FALSE;
316     }
317   }
318 
319   /* if we get here, we can be sure that we have enough bytes
320      to copy safely */
321   /*printf("Mem OK Size: %d, Pos: %d\n", dp->realSize, dp->pos); */
322 
323   tmp = (char*)dp->data;
324   memcpy((void*)(tmp+(dp->pos)),src,size);
325   dp->pos += size;
326 
327   if (dp->pos > dp->logicalSize) {
328     dp->logicalSize = dp->pos;
329   };
330 
331   return TRUE;
332 }
333 
334 /* grow (or shrink) dynamic pointer */
335 static int
reallocDynamic(dynamicPtr * dp,int required)336 reallocDynamic (dynamicPtr* dp, int required) {
337   void* newPtr;
338 
339   /* First try realloc().  If that doesn't work, make a new
340      memory block and copy. */
341   if ( (newPtr = realloc(dp->data,required)) ) {
342     dp->realSize = required;
343     dp->data = newPtr;
344     return TRUE;
345   }
346 
347   /* create a new pointer */
348   newPtr = malloc(required);
349   if (!newPtr) {
350     dp->dataGood = FALSE;
351     return FALSE;
352   }
353 
354   /* copy the old data into it */
355   memcpy(newPtr,dp->data,dp->logicalSize);
356   free(dp->data);
357   dp->data = newPtr;
358 
359   dp->realSize = required;
360   return TRUE;
361 }
362 
363 /* trim pointer so that its real and logical sizes match */
364 static int
trimDynamic(dynamicPtr * dp)365 trimDynamic (dynamicPtr* dp) {
366   return reallocDynamic(dp,dp->logicalSize);
367 }
368 
369