xref: /PHP-7.1/ext/gd/libgd/gd_io_dp.c (revision 08649155)
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 */
gdNewDynamicCtx(int initialSize,void * data)65 gdIOCtx * gdNewDynamicCtx (int initialSize, void *data)
66 {
67 	return gdNewDynamicCtxEx(initialSize, data, 1);
68 }
69 
gdNewDynamicCtxEx(int initialSize,void * data,int freeOKFlag)70 gdIOCtx * gdNewDynamicCtxEx (int initialSize, void *data, int freeOKFlag)
71 {
72 	dpIOCtx *ctx;
73 	dynamicPtr *dp;
74 
75 	ctx = (dpIOCtx *) gdMalloc (sizeof (dpIOCtx));
76 
77 	dp = newDynamic(initialSize, data, freeOKFlag);
78 
79 	ctx->dp = dp;
80 
81 	ctx->ctx.getC = dynamicGetchar;
82 	ctx->ctx.putC = dynamicPutchar;
83 
84 	ctx->ctx.getBuf = dynamicGetbuf;
85 	ctx->ctx.putBuf = dynamicPutbuf;
86 
87 	ctx->ctx.seek = dynamicSeek;
88 	ctx->ctx.tell = dynamicTell;
89 
90 	ctx->ctx.gd_free = gdFreeDynamicCtx;
91 
92 	return (gdIOCtx *) ctx;
93 }
94 
gdDPExtractData(struct gdIOCtx * ctx,int * size)95 void * gdDPExtractData (struct gdIOCtx *ctx, int *size)
96 {
97 	dynamicPtr *dp;
98 	dpIOCtx *dctx;
99 	void *data;
100 
101 	dctx = (dpIOCtx *) ctx;
102 	dp = dctx->dp;
103 
104 	/* clean up the data block and return it */
105 	if (dp->dataGood) {
106 		trimDynamic (dp);
107 		*size = dp->logicalSize;
108 		data = dp->data;
109 	} else {
110 		*size = 0;
111 		data = NULL;
112 		if (dp->data != NULL && dp->freeOK) {
113 			gdFree(dp->data);
114 		}
115 	}
116 
117 	dp->data = NULL;
118 	dp->realSize = 0;
119 	dp->logicalSize = 0;
120 
121 	return data;
122 }
123 
gdFreeDynamicCtx(struct gdIOCtx * ctx)124 static void gdFreeDynamicCtx (struct gdIOCtx *ctx)
125 {
126 	dynamicPtr *dp;
127 	dpIOCtx *dctx;
128 
129 	dctx = (dpIOCtx *) ctx;
130 	dp = dctx->dp;
131 
132 	gdFree(ctx);
133 
134 	dp->realSize = 0;
135 	dp->logicalSize = 0;
136 
137 	gdFree(dp);
138 }
139 
dynamicTell(struct gdIOCtx * ctx)140 static long dynamicTell (struct gdIOCtx *ctx)
141 {
142 	dpIOCtx *dctx;
143 
144 	dctx = (dpIOCtx *) ctx;
145 
146 	return (dctx->dp->pos);
147 }
148 
dynamicSeek(struct gdIOCtx * ctx,const int pos)149 static int dynamicSeek (struct gdIOCtx *ctx, const int pos)
150 {
151 	int bytesNeeded;
152 	dynamicPtr *dp;
153 	dpIOCtx *dctx;
154 
155 	dctx = (dpIOCtx *) ctx;
156 	dp = dctx->dp;
157 
158 	if (!dp->dataGood) {
159 		return FALSE;
160 	}
161 
162 	bytesNeeded = pos;
163 	if (bytesNeeded > dp->realSize) {
164 		/* 2.0.21 */
165 		if (!dp->freeOK) {
166 			return FALSE;
167 		}
168 		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 	if (pos > dp->logicalSize) {
175 		dp->logicalSize = pos;
176 	}
177 
178 	dp->pos = pos;
179 
180 	return TRUE;
181 }
182 
183 /* return data as a dynamic pointer */
newDynamic(int initialSize,void * data,int freeOKFlag)184 static dynamicPtr * newDynamic (int initialSize, void *data, int freeOKFlag)
185 {
186 	dynamicPtr *dp;
187 	dp = (dynamicPtr *) gdMalloc (sizeof (dynamicPtr));
188 
189 	allocDynamic (dp, initialSize, data);
190 
191 	dp->pos = 0;
192 	dp->freeOK = freeOKFlag;
193 
194 	return dp;
195 }
196 
197 static int
dynamicPutbuf(struct gdIOCtx * ctx,const void * buf,int size)198 dynamicPutbuf (struct gdIOCtx *ctx, const void *buf, int size)
199 {
200   dpIOCtx *dctx;
201   dctx = (dpIOCtx *) ctx;
202 
203   appendDynamic (dctx->dp, buf, size);
204 
205   if (dctx->dp->dataGood)
206     {
207       return size;
208     }
209   else
210     {
211       return -1;
212     };
213 
214 }
215 
dynamicPutchar(struct gdIOCtx * ctx,int a)216 static void dynamicPutchar (struct gdIOCtx *ctx, int a)
217 {
218 	unsigned char b;
219 	dpIOCtxPtr dctx;
220 
221 	b = a;
222 	dctx = (dpIOCtxPtr) ctx;
223 
224 	appendDynamic(dctx->dp, &b, 1);
225 }
226 
dynamicGetbuf(gdIOCtxPtr ctx,void * buf,int len)227 static int dynamicGetbuf (gdIOCtxPtr ctx, void *buf, int len)
228 {
229 	int rlen, remain;
230 	dpIOCtxPtr dctx;
231 	dynamicPtr *dp;
232 
233 	dctx = (dpIOCtxPtr) ctx;
234 	dp = dctx->dp;
235 
236 	remain = dp->logicalSize - dp->pos;
237 	if (remain >= len) {
238 		rlen = len;
239 	} else {
240 		if (remain <= 0) {
241 			return EOF;
242 		}
243 		rlen = remain;
244 	}
245 
246 	memcpy(buf, (void *) ((char *) dp->data + dp->pos), rlen);
247 	dp->pos += rlen;
248 
249 	return rlen;
250 }
251 
dynamicGetchar(gdIOCtxPtr ctx)252 static int dynamicGetchar (gdIOCtxPtr ctx)
253 {
254 	unsigned char b;
255 	int rv;
256 
257 	rv = dynamicGetbuf (ctx, &b, 1);
258 	if (rv != 1) {
259 		return EOF;
260 	} else {
261 		return b; 		/* (b & 0xff); */
262 	}
263 }
264 
265 /* *********************************************************************
266 
267  * InitDynamic - Return a dynamically resizable void*
268  *
269  * *********************************************************************
270  */
271 static int
allocDynamic(dynamicPtr * dp,int initialSize,void * data)272 allocDynamic (dynamicPtr * dp, int initialSize, void *data)
273 {
274 
275 	if (data == NULL) {
276 		dp->logicalSize = 0;
277 		dp->dataGood = FALSE;
278 		dp->data = gdMalloc(initialSize);
279 	} else {
280 		dp->logicalSize = initialSize;
281 		dp->dataGood = TRUE;
282 		dp->data = data;
283 	}
284 
285 	dp->realSize = initialSize;
286 	dp->dataGood = TRUE;
287 	dp->pos = 0;
288 
289 	return TRUE;
290 }
291 
292 /* append bytes to the end of a dynamic pointer */
appendDynamic(dynamicPtr * dp,const void * src,int size)293 static int appendDynamic (dynamicPtr * dp, const void *src, int size)
294 {
295 	int bytesNeeded;
296 	char *tmp;
297 
298 	if (!dp->dataGood) {
299 		return FALSE;
300 	}
301 
302 	/*  bytesNeeded = dp->logicalSize + size; */
303 	bytesNeeded = dp->pos + size;
304 
305 	if (bytesNeeded > dp->realSize) {
306 		/* 2.0.21 */
307 		if (!dp->freeOK) {
308 			return FALSE;
309 		}
310 		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 	tmp = (char *) dp->data;
317 	memcpy((void *) (tmp + (dp->pos)), src, size);
318 	dp->pos += size;
319 
320 	if (dp->pos > dp->logicalSize) {
321 		dp->logicalSize = dp->pos;
322 	}
323 
324 	return TRUE;
325 }
326 
327 /* grow (or shrink) dynamic pointer */
gdReallocDynamic(dynamicPtr * dp,int required)328 static int gdReallocDynamic (dynamicPtr * dp, int required)
329 {
330 	void *newPtr;
331 
332 	/* First try gdRealloc(). If that doesn't work, make a new memory block and copy. */
333 	if ((newPtr = gdRealloc(dp->data, required))) {
334 		dp->realSize = required;
335 		dp->data = newPtr;
336 		return TRUE;
337 	}
338 
339 	/* create a new pointer */
340 	newPtr = gdMalloc(required);
341 
342 	/* copy the old data into it */
343 	memcpy(newPtr, dp->data, dp->logicalSize);
344 	gdFree(dp->data);
345 	dp->data = newPtr;
346 
347 	dp->realSize = required;
348 
349 	return TRUE;
350 }
351 
352 /* trim pointer so that its real and logical sizes match */
trimDynamic(dynamicPtr * dp)353 static int trimDynamic (dynamicPtr * dp)
354 {
355 	/* 2.0.21: we don't reallocate memory we don't own */
356 	if (!dp->freeOK) {
357 		return FALSE;
358 	}
359 	return gdReallocDynamic(dp, dp->logicalSize);
360 }
361