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