1 /*---------------------------------------------------------------------------*
2  |              PDFlib - A library for generating PDF on the fly             |
3  +---------------------------------------------------------------------------+
4  | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. |
5  +---------------------------------------------------------------------------+
6  |                                                                           |
7  |    This software is subject to the PDFlib license. It is NOT in the       |
8  |    public domain. Extended versions and commercial licenses are           |
9  |    available, please check http://www.pdflib.com.                         |
10  |                                                                           |
11  *---------------------------------------------------------------------------*/
12 
13 /* $Id: pc_string.c,v 1.32.2.7 2007/12/13 15:58:38 kurt Exp $
14  *
15  * The core string classes.
16  *
17  */
18 
19 #include <string.h>
20 
21 #include "pc_util.h"
22 #include "pc_string.h"
23 #include "pc_ctype.h"
24 
25 #undef	SBUF_RESERVE
26 #define	SBUF_RESERVE	PDC_STR_INLINE_CAP
27 
28 
29 /* TODO:
30 
31     - think over the pdcore temporary memory model.
32 
33     - s->buf should be reference-counted (delayed copy).
34 */
35 
pdc_init_strings(pdc_core * pdc)36 void pdc_init_strings(pdc_core *pdc)
37 {
38     pdc->bstr_pool = pdc_mp_new(pdc, sizeof (pdc_bstr));
39     pdc->ustr_pool = pdc_mp_new(pdc, sizeof (pdc_ustr));
40 } /* pdc_init_strings */
41 
pdc_cleanup_strings(pdc_core * pdc)42 void pdc_cleanup_strings(pdc_core *pdc)
43 {
44     pdc_mp_delete(pdc->bstr_pool);
45     pdc_mp_delete(pdc->ustr_pool);
46 } /* pdc_cleanup_strings */
47 
48 
49 /************************************************************************/
50 /*									*/
51 /*  string object construction and deletion.				*/
52 /*									*/
53 /************************************************************************/
54 
55 void
pdc_bs_boot(pdc_core * pdc,pdc_bstr * s)56 pdc_bs_boot(pdc_core *pdc, pdc_bstr *s)
57 {
58     s->pdc = pdc;
59     s->buf = (pdc_byte *) 0;
60     s->len = 0;
61     s->cap = PDC_STR_INLINE_CAP;
62 } /* pdc_bs_boot */
63 
64 void
pdc_us_boot(pdc_core * pdc,pdc_ustr * s)65 pdc_us_boot(pdc_core *pdc, pdc_ustr *s)
66 {
67     s->pdc = pdc;
68     s->buf = (pdc_ucval *) 0;
69     s->len = 0;
70     s->cap = PDC_STR_INLINE_CAP;
71 } /* pdc_us_boot */
72 
73 
74 void
pdc_bs_shutdown(pdc_bstr * s)75 pdc_bs_shutdown(pdc_bstr *s)
76 {
77     if (s->buf != (pdc_byte *) 0)
78 	pdc_free(s->pdc, s->buf);
79 
80     pdc_bs_boot(s->pdc, s);
81 } /* pdc_bs_shutdown */
82 
83 void
pdc_us_shutdown(pdc_ustr * s)84 pdc_us_shutdown(pdc_ustr *s)
85 {
86     if (s->buf != (pdc_ucval *) 0)
87 	pdc_free(s->pdc, s->buf);
88 
89     pdc_us_boot(s->pdc, s);
90 } /* pdc_us_shutdown */
91 
92 
93 #undef	USE_POOL
94 #define	USE_POOL
95 
96 pdc_bstr *
pdc_bs_new(pdc_core * pdc)97 pdc_bs_new(pdc_core *pdc)
98 {
99 #ifndef	USE_POOL
100     static const char fn[] = "pdc_bs_new";
101 
102     pdc_bstr *result = (pdc_bstr *) pdc_malloc(pdc, sizeof (pdc_bstr), fn);
103 #else
104     pdc_bstr *result = (pdc_bstr *) pdc_mp_alloc(pdc->bstr_pool);
105 #endif
106 
107     pdc_bs_boot(pdc, result);
108     return result;
109 } /* pdc_bs_new */
110 
111 pdc_ustr *
pdc_us_new(pdc_core * pdc,const pdc_ucval * src,size_t len)112 pdc_us_new(pdc_core *pdc, const pdc_ucval *src, size_t len)
113 {
114 #ifndef	USE_POOL
115     static const char fn[] = "pdc_us_new";
116 
117     pdc_ustr *result = (pdc_ustr *) pdc_malloc(pdc, sizeof (pdc_ustr), fn);
118 #else
119     pdc_ustr *result = (pdc_ustr *) pdc_mp_alloc(pdc->ustr_pool);
120 #endif
121 
122     pdc_us_boot(pdc, result);
123     pdc_us_write(result, src, len);
124     return result;
125 } /* pdc_us_new */
126 
127 
128 pdc_bstr *
pdc_bs_dup(const pdc_bstr * src)129 pdc_bs_dup(const pdc_bstr *src)
130 {
131     const pdc_byte *	buf = src->buf ? src->buf : src->buf0;
132     pdc_bstr *		result = pdc_bs_new(src->pdc);
133 
134     pdc_bs_write(result, buf, src->len);
135     return result;
136 } /* pdc_bs_dup */
137 
138 pdc_ustr *
pdc_us_dup(const pdc_ustr * src)139 pdc_us_dup(const pdc_ustr *src)
140 {
141     const pdc_ucval *buf = src->buf ? src->buf : src->buf0;
142 
143     return pdc_us_new(src->pdc, buf, src->len);
144 } /* pdc_us_dup */
145 
146 
147 void
pdc_bs_delete(pdc_bstr * s)148 pdc_bs_delete(pdc_bstr *s)
149 {
150     pdc_bs_shutdown(s);
151 #ifndef	USE_POOL
152     pdc_free(s->pdc, s);
153 #else
154     pdc_mp_free(s->pdc->bstr_pool, s);
155 #endif
156 } /* pdc_bs_delete */
157 
158 void
pdc_us_delete(pdc_ustr * s)159 pdc_us_delete(pdc_ustr *s)
160 {
161     pdc_us_shutdown(s);
162 #ifndef	USE_POOL
163     pdc_free(s->pdc, s);
164 #else
165     pdc_mp_free(s->pdc->ustr_pool, s);
166 #endif
167 } /* pdc_bs_delete */
168 
169 
170 /************************************************************************/
171 /*									*/
172 /*  "getters".								*/
173 /*									*/
174 /************************************************************************/
175 
176 size_t
pdc_bs_length(const pdc_bstr * s)177 pdc_bs_length(const pdc_bstr *s)
178 {
179     return s->len;
180 } /* pdc_bs_length */
181 
182 size_t
pdc_us_length(const pdc_ustr * s)183 pdc_us_length(const pdc_ustr *s)
184 {
185     return s->len;
186 } /* pdc_us_length */
187 
188 
189 pdc_byte
pdc_bs_get(const pdc_bstr * s,int idx)190 pdc_bs_get(const pdc_bstr *s, int idx)
191 {
192     static const char fn[] = "pdc_bs_get";
193 
194     const pdc_byte *buf = s->buf ? s->buf : s->buf0;
195 
196     if (idx < 0 || s->len <= (size_t) idx)
197 	pdc_error(s->pdc, PDC_E_INT_ARRIDX,
198 	    pdc_errprintf(s->pdc, "%d", idx), fn, 0, 0);
199 
200     return buf[idx];
201 } /* pdc_bs_get */
202 
203 pdc_ucval
pdc_us_get(const pdc_ustr * s,int idx)204 pdc_us_get(const pdc_ustr *s, int idx)
205 {
206     static const char fn[] = "pdc_us_get";
207 
208     const pdc_ucval *buf = s->buf ? s->buf : s->buf0;
209 
210     if (idx < 0 || s->len <= (size_t) idx)
211 	pdc_error(s->pdc, PDC_E_INT_ARRIDX,
212 	    pdc_errprintf(s->pdc, "%d", idx), fn, 0, 0);
213 
214     return buf[idx];
215 } /* pdc_us_get */
216 
217 
218 const pdc_byte *
pdc_bs_get_cptr(const pdc_bstr * s)219 pdc_bs_get_cptr(const pdc_bstr *s)
220 {
221     static const pdc_byte empty = 0;
222 
223     /* TODO: avoid the ugly "un-const" cast. */
224     pdc_byte *buf = (pdc_byte *) (s->buf ? s->buf : s->buf0);
225 
226     if (!s->len)
227 	return &empty;
228 
229     buf[s->len] = 0;
230     return buf;
231 }
232 
233 const pdc_byte *
pdc_us_get_cptr(const pdc_ustr * s)234 pdc_us_get_cptr(const pdc_ustr *s)
235 {
236     static const pdc_byte empty = 0;
237 
238     const pdc_ucval *buf = s->buf ? s->buf : s->buf0;
239 
240     if (!s->len)
241 	return &empty;
242 
243     return (const pdc_byte *) buf;
244 }
245 
246 
247 /************************************************************************/
248 /*									*/
249 /*  "modifiers".							*/
250 /*									*/
251 /************************************************************************/
252 
253 void
pdc_bs_copy(pdc_bstr * dst,const pdc_bstr * src)254 pdc_bs_copy(pdc_bstr *dst, const pdc_bstr *src)
255 {
256     const pdc_byte *buf = src->buf ? src->buf : src->buf0;
257 
258     dst->len = 0;
259 
260     if (src->len)
261 	pdc_bs_write(dst, buf, src->len);
262 } /* pdc_bs_copy */
263 
264 void
pdc_us_copy(pdc_ustr * dst,const pdc_ustr * src)265 pdc_us_copy(pdc_ustr *dst, const pdc_ustr *src)
266 {
267     const pdc_ucval *buf = src->buf ? src->buf : src->buf0;
268 
269     dst->len = 0;
270 
271     if (src->len)
272 	pdc_us_write(dst, buf, src->len);
273 } /* pdc_us_copy */
274 
275 
276 void
pdc_bs_substr(pdc_bstr * dst,const pdc_bstr * src,size_t pos,size_t len)277 pdc_bs_substr(pdc_bstr *dst, const pdc_bstr *src, size_t pos, size_t len)
278 {
279     static const char fn[] = "pdc_bs_substr";
280 
281     const pdc_byte *buf = src->buf ? src->buf : src->buf0;
282 
283     if ((pos < 0) || (len < 0) || (pos > src->len) || ((pos + len) > src->len))
284 	pdc_error(src->pdc, PDC_E_INT_ILLARG, fn, 0, 0, 0);
285 
286     dst->len = 0;
287     pdc_bs_write(dst, buf + pos, len);
288 } /* pdc_bs_substr */
289 
290 void
pdc_us_substr(pdc_ustr * dst,const pdc_ustr * src,size_t pos,size_t len)291 pdc_us_substr(pdc_ustr *dst, const pdc_ustr *src, size_t pos, size_t len)
292 {
293     static const char fn[] = "pdc_us_substr";
294 
295     const pdc_ucval *buf = src->buf ? src->buf : src->buf0;
296 
297     if ((pos < 0) || (len < 0) || (pos > src->len) || ((pos + len) > src->len))
298 	pdc_error(src->pdc, PDC_E_INT_ILLARG, fn, 0, 0, 0);
299 
300     dst->len = 0;
301     pdc_us_write(dst, buf + pos, len);
302 } /* pdc_us_substr */
303 
304 
305 void
pdc_bs_concat(pdc_bstr * dst,const pdc_bstr * src)306 pdc_bs_concat(pdc_bstr *dst, const pdc_bstr *src)
307 {
308     const pdc_byte *buf = src->buf ? src->buf : src->buf0;
309 
310     if (src->len)
311 	pdc_bs_write(dst, buf, src->len);
312 } /* pdc_bs_concat */
313 
314 void
pdc_us_concat(pdc_ustr * dst,const pdc_ustr * src)315 pdc_us_concat(pdc_ustr *dst, const pdc_ustr *src)
316 {
317     const pdc_ucval *buf = src->buf ? src->buf : src->buf0;
318 
319     if (src->len)
320 	pdc_us_write(dst, buf, src->len);
321 } /* pdc_us_concat */
322 
323 
324 void
pdc_bs_set(pdc_bstr * s,int idx,pdc_byte val)325 pdc_bs_set(pdc_bstr *s, int idx, pdc_byte val)
326 {
327     static const char fn[] = "pdc_bs_set";
328 
329     pdc_byte *buf = s->buf ? s->buf : s->buf0;
330 
331     if (idx < 0 || s->len <= (size_t) idx)
332 	pdc_error(s->pdc, PDC_E_INT_ARRIDX,
333 	    pdc_errprintf(s->pdc, "%d", idx), fn, 0, 0);
334 
335     buf[idx] = val;
336 } /* pdc_bs_set */
337 
338 void
pdc_us_set(pdc_ustr * s,int idx,pdc_ucval val)339 pdc_us_set(pdc_ustr *s, int idx, pdc_ucval val)
340 {
341     static const char fn[] = "pdc_us_set";
342 
343     pdc_ucval *buf = s->buf ? s->buf : s->buf0;
344 
345     if (idx < 0 || s->len <= (size_t) idx)
346 	pdc_error(s->pdc, PDC_E_INT_ARRIDX,
347 	    pdc_errprintf(s->pdc, "%d", idx), fn, 0, 0);
348 
349     buf[idx] = val;
350 } /* pdc_us_set */
351 
352 
353 void
pdc_bs_tolower(pdc_bstr * s)354 pdc_bs_tolower(pdc_bstr *s)
355 {
356     pdc_byte *	buf = s->buf ? s->buf : s->buf0;
357     int		i;
358 
359     for (i = 0; i < (int) s->len; ++i)
360 	buf[i] = pdc_tolower(buf[i]);
361 } /* pdc_bs_tolower */
362 
363 void
pdc_bs_toupper(pdc_bstr * s)364 pdc_bs_toupper(pdc_bstr *s)
365 {
366     pdc_byte *	buf = s->buf ? s->buf : s->buf0;
367     int		i;
368 
369     for (i = 0; i < (int) s->len; ++i)
370         buf[i] = pdc_toupper(buf[i]);
371 } /* pdc_bs_toupper */
372 
373 
374 /************************************************************************/
375 /*									*/
376 /*  stream-like functions.						*/
377 /*									*/
378 /************************************************************************/
379 
380 void
pdc_bs_write(pdc_bstr * dst,const pdc_byte * src,size_t len)381 pdc_bs_write(pdc_bstr *dst, const pdc_byte *src, size_t len)
382 {
383     static const char fn[] = "pdc_bs_write";
384 
385     pdc_byte *buf = dst->buf ? dst->buf : dst->buf0;
386 
387     if (!src || !len)
388 	return;
389 
390     if (dst->cap < dst->len + len + 1)
391     {
392 	dst->cap = dst->len + len + 1 + SBUF_RESERVE;
393 
394 	if (!dst->buf)
395 	{
396 	    dst->buf = (pdc_byte *) pdc_malloc(dst->pdc, dst->cap, fn);
397 	    memcpy(dst->buf, dst->buf0, dst->len);
398 	}
399 	else
400 	{
401 	    dst->buf = (pdc_byte *) pdc_realloc(dst->pdc,
402 		dst->buf, dst->cap, fn);
403 	}
404 
405 	buf = dst->buf;
406     }
407 
408     memcpy(buf + dst->len, src, len);
409     dst->len += len;
410 } /* pdc_bs_write */
411 
412 
413 void
pdc_bs_puts(pdc_bstr * dst,const pdc_byte * src)414 pdc_bs_puts(pdc_bstr *dst, const pdc_byte *src)
415 {
416     if (!src)
417 	return;
418 
419     pdc_bs_write(dst, src, strlen((char *) src));
420 } /* pdc_bs_puts */
421 
422 
423 void
pdc_us_write(pdc_ustr * dst,const pdc_ucval * src,size_t len)424 pdc_us_write(pdc_ustr *dst, const pdc_ucval *src, size_t len)
425 {
426     static const char fn[] = "pdc_us_write";
427 
428     pdc_ucval *buf = dst->buf ? dst->buf : dst->buf0;
429 
430     if (!src || len == 0)
431 	return;
432 
433     if (dst->cap < dst->len + len)
434     {
435 	dst->cap = dst->len + len + SBUF_RESERVE;
436 
437 	if (!dst->buf)
438 	{
439 	    dst->buf = (pdc_ucval *)
440 		pdc_malloc(dst->pdc, dst->cap * sizeof (pdc_ucval), fn);
441 
442 	    memcpy(dst->buf, dst->buf0, dst->len * sizeof (pdc_ucval));
443 	}
444 	else
445 	{
446 	    dst->buf = (pdc_ucval *) pdc_realloc(dst->pdc,
447 		dst->buf, dst->cap * sizeof (pdc_ucval), fn);
448 	}
449 
450 	buf = dst->buf;
451     }
452 
453     memcpy(buf + dst->len, src, len * sizeof (pdc_ucval));
454     dst->len += len;
455 } /* pdc_us_write */
456 
457 
458 void
pdc_bs_rewrite(pdc_bstr * s)459 pdc_bs_rewrite(pdc_bstr *s)
460 {
461     s->len = 0;
462 } /* pdc_bs_rewrite */
463 
464 void
pdc_us_rewrite(pdc_ustr * s)465 pdc_us_rewrite(pdc_ustr *s)
466 {
467     s->len = 0;
468 } /* pdc_us_rewrite */
469 
470 
471 void
pdc_bs_putc(pdc_bstr * s,pdc_byte val)472 pdc_bs_putc(pdc_bstr *s, pdc_byte val)
473 {
474     pdc_bs_write(s, &val, 1);
475 } /* pdc_bs_putc */
476 
477 void
pdc_us_putc(pdc_ustr * s,pdc_ucval val)478 pdc_us_putc(pdc_ustr *s, pdc_ucval val)
479 {
480     pdc_us_write(s, &val, 1);
481 } /* pdc_us_putc */
482 
483 
484 /************************************************************************/
485 /*									*/
486 /*  other utilities.							*/
487 /*									*/
488 /************************************************************************/
489 
490 int
pdc_bs_compare(const pdc_bstr * s1,const pdc_bstr * s2)491 pdc_bs_compare(const pdc_bstr *s1, const pdc_bstr *s2)
492 {
493     const char *buf1 = (const char *) (s1->buf ? s1->buf : s1->buf0);
494     const char *buf2 = (const char *) (s2->buf ? s2->buf : s2->buf0);
495     int		result;
496 
497     if (s1->len < s2->len)
498     {
499 	if ((result = strncmp(buf1, buf2, s1->len)) != 0)
500 	    return result;
501 
502 	return -1;
503     }
504 
505     if (s2->len < s1->len)
506     {
507 	if ((result = strncmp(buf1, buf2, s2->len)) != 0)
508 	    return result;
509 
510 	return +1;
511     }
512 
513     return strncmp(buf1, buf2, s1->len);
514 } /* pdc_bs_compare */
515