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