1 /* pool.c - create a file in memeory to write to
2    Copyright (C) 1996-2017 Paul Sheer
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2 of the License, or
7    (at your option) any later version.
8 
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17    02111-1307, USA.
18 */
19 
20 #include <config.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdarg.h>
24 #include "stringtools.h"
25 #include "pool.h"
26 #include "mad.h"
27 
28 #define min(x,y) ((x)<=(y)?(x):(y))
29 
30 /* returns NULL on error */
31 #ifdef HAVE_MAD
mad_pool_init(char * file,int line)32 POOL *mad_pool_init (char *file, int line)
33 #else
34 POOL *pool_init (void)
35 #endif
36 {
37     POOL *p;
38     p = malloc (sizeof (POOL));
39     if (!p)
40 	return 0;
41 #ifdef HAVE_MAD
42     p->current = p->start = mad_alloc (START_SIZE, file, line);
43 #else
44     p->current = p->start = malloc (START_SIZE);
45 #endif
46     if (!p->start)
47 	return 0;
48     p->end = p->start + START_SIZE;
49     p->length = START_SIZE;
50     return p;
51 }
52 
53 /* free's a pool except for the actual data which is returned */
54 /* result must be free'd by the caller even if the pool_length is zero */
pool_break(POOL * p)55 unsigned char *pool_break (POOL * p)
56 {
57     unsigned char *d;
58     d = p->start;
59     free (p);
60     return d;
61 }
62 
63 /* free's a pool and all its data */
pool_free(POOL * p)64 void pool_free (POOL * p)
65 {
66     if (!p)
67 	return;
68     if (p->start)
69 	free (p->start);
70     free (p);
71 }
72 
73 /* make space for a forthcoming write of l bytes. leaves current untouched */
74 #ifdef HAVE_MAD
mad_pool_advance(POOL * p,unsigned long l,char * file,int line)75 unsigned long mad_pool_advance (POOL * p, unsigned long l, char *file, int line)
76 #else
77 unsigned long pool_advance (POOL * p, unsigned long l)
78 #endif
79 {
80     if ((unsigned long) p->current + l > (unsigned long) p->end) {
81 	unsigned char *t;
82 	unsigned long old_length;
83 	old_length = p->length;
84 	do {
85 	    p->length *= 2;
86 	    p->end = p->start + p->length;
87 	} while ((unsigned long) p->current + l > (unsigned long) p->end);
88 #ifdef HAVE_MAD
89 	t = mad_alloc (p->length, file, line);
90 #else
91 	t = malloc (p->length);
92 #endif
93 	if (!t)
94 	    return 0;
95 	memcpy (t, p->start, old_length);
96 	p->current = t + (unsigned long) p->current - (unsigned long) p->start;
97 	free (p->start);
98 	p->start = t;
99 	p->end = p->start + p->length;
100     }
101     return l;
102 }
103 
104 /* returns the number of bytes written into p */
105 #ifdef HAVE_MAD
mad_pool_write(POOL * p,unsigned char * d,unsigned long l,char * file,int line)106 unsigned long mad_pool_write (POOL * p, unsigned char *d, unsigned long l, char *file, int line)
107 #else
108 unsigned long pool_write (POOL * p, unsigned char *d, unsigned long l)
109 #endif
110 {
111     unsigned long a;
112 #ifdef HAVE_MAD
113     a = mad_pool_advance (p, l, file, line);
114 #else
115     a = pool_advance (p, l);
116 #endif
117     memcpy (p->current, d, a);
118     p->current += a;
119     return a;
120 }
121 
122 /* returns the number of bytes read into d */
pool_read(POOL * p,unsigned char * d,unsigned long l)123 unsigned long pool_read (POOL * p, unsigned char *d, unsigned long l)
124 {
125     unsigned long m;
126     m = min (l, (unsigned long) p->end - (unsigned long) p->current);
127     memcpy (d, p->current, m);
128     p->current += m;
129     return m;
130 }
131 
132 /* sets the position in the pool */
pool_seek(POOL * p,unsigned long l)133 unsigned long pool_seek (POOL * p, unsigned long l)
134 {
135     unsigned long m;
136     m = min (l, p->length);
137     p->current = p->start + m;
138     return m;
139 }
140 
141 /* used like sprintf */
pool_printf(POOL * p,const char * fmt,...)142 unsigned long pool_printf (POOL * p, const char *fmt,...)
143 {
144     unsigned long l;
145     va_list ap;
146     va_start (ap, fmt);
147     l = vfmtlen (fmt, ap) + 1;
148     va_end (ap);
149     if (pool_advance (p, l) != l)
150 	return 0;
151     va_start (ap, fmt);
152     vsprintf ((char *) p->current, fmt, ap);
153     va_end (ap);
154     l = strlen ((char *) p->current);
155     p->current += l;
156     return l;
157 }
158 
159 /* zero the char after the last char written/read */
pool_null(POOL * p)160 int pool_null (POOL * p)
161 {
162     if (pool_advance (p, 1) != 1)
163 	return 0;
164     p->current[0] = 0;
165     return 1;
166 }
167 
168 /* removes the last line from the length, and null-terminates */
pool_drop_last_line(POOL * p)169 void pool_drop_last_line (POOL * p)
170 {
171     char *q;
172     q = (char *) strrchr ((char *) pool_start (p), '\n');
173     if (!q)
174         pool_seek (p, 0);
175     else
176         pool_seek (p, (int) (q - (char *) pool_start (p)) + 1);
177     pool_null (p);
178 }
179 
180