data.c revision 204433
1204431Sraj/*
2204431Sraj * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005.
3204431Sraj *
4204431Sraj *
5204431Sraj * This program is free software; you can redistribute it and/or
6204431Sraj * modify it under the terms of the GNU General Public License as
7204431Sraj * published by the Free Software Foundation; either version 2 of the
8204431Sraj * License, or (at your option) any later version.
9204431Sraj *
10204431Sraj *  This program is distributed in the hope that it will be useful,
11204431Sraj *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12204431Sraj *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13204431Sraj *  General Public License for more details.
14204431Sraj *
15204431Sraj *  You should have received a copy of the GNU General Public License
16204431Sraj *  along with this program; if not, write to the Free Software
17204431Sraj *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
18204431Sraj *                                                                   USA
19204431Sraj */
20204431Sraj
21204431Sraj#include "dtc.h"
22204431Sraj
23204431Srajvoid data_free(struct data d)
24204431Sraj{
25204431Sraj	struct marker *m, *nm;
26204431Sraj
27204431Sraj	m = d.markers;
28204431Sraj	while (m) {
29204431Sraj		nm = m->next;
30204431Sraj		free(m->ref);
31204431Sraj		free(m);
32204431Sraj		m = nm;
33204431Sraj	}
34204431Sraj
35204431Sraj	if (d.val)
36204431Sraj		free(d.val);
37204431Sraj}
38204431Sraj
39204431Srajstruct data data_grow_for(struct data d, int xlen)
40204431Sraj{
41204431Sraj	struct data nd;
42204431Sraj	int newsize;
43204431Sraj
44204431Sraj	if (xlen == 0)
45204431Sraj		return d;
46204431Sraj
47204431Sraj	nd = d;
48204431Sraj
49204431Sraj	newsize = xlen;
50204431Sraj
51204431Sraj	while ((d.len + xlen) > newsize)
52204431Sraj		newsize *= 2;
53204431Sraj
54204431Sraj	nd.val = xrealloc(d.val, newsize);
55204431Sraj
56204431Sraj	return nd;
57204431Sraj}
58204431Sraj
59204431Srajstruct data data_copy_mem(const char *mem, int len)
60204431Sraj{
61204431Sraj	struct data d;
62204431Sraj
63204431Sraj	d = data_grow_for(empty_data, len);
64204431Sraj
65204431Sraj	d.len = len;
66204431Sraj	memcpy(d.val, mem, len);
67204431Sraj
68204431Sraj	return d;
69204431Sraj}
70204431Sraj
71204431Srajstatic char get_oct_char(const char *s, int *i)
72204431Sraj{
73204431Sraj	char x[4];
74204431Sraj	char *endx;
75204431Sraj	long val;
76204431Sraj
77204431Sraj	x[3] = '\0';
78204431Sraj	strncpy(x, s + *i, 3);
79204431Sraj
80204431Sraj	val = strtol(x, &endx, 8);
81204431Sraj
82204431Sraj	assert(endx > x);
83204431Sraj
84204431Sraj	(*i) += endx - x;
85204431Sraj	return val;
86204431Sraj}
87204431Sraj
88204431Srajstatic char get_hex_char(const char *s, int *i)
89204431Sraj{
90204431Sraj	char x[3];
91204431Sraj	char *endx;
92204431Sraj	long val;
93204431Sraj
94204431Sraj	x[2] = '\0';
95204431Sraj	strncpy(x, s + *i, 2);
96204431Sraj
97204431Sraj	val = strtol(x, &endx, 16);
98204431Sraj	if (!(endx  > x))
99204431Sraj		die("\\x used with no following hex digits\n");
100204431Sraj
101204431Sraj	(*i) += endx - x;
102204431Sraj	return val;
103204431Sraj}
104204431Sraj
105204431Srajstruct data data_copy_escape_string(const char *s, int len)
106204431Sraj{
107204431Sraj	int i = 0;
108204431Sraj	struct data d;
109204431Sraj	char *q;
110204431Sraj
111204431Sraj	d = data_grow_for(empty_data, strlen(s)+1);
112204431Sraj
113204431Sraj	q = d.val;
114204431Sraj	while (i < len) {
115204431Sraj		char c = s[i++];
116204431Sraj
117204431Sraj		if (c != '\\') {
118204431Sraj			q[d.len++] = c;
119204431Sraj			continue;
120204431Sraj		}
121204431Sraj
122204431Sraj		c = s[i++];
123204431Sraj		assert(c);
124204431Sraj		switch (c) {
125204431Sraj		case 'a':
126204431Sraj			q[d.len++] = '\a';
127204431Sraj			break;
128204431Sraj		case 'b':
129204431Sraj			q[d.len++] = '\b';
130204431Sraj			break;
131204431Sraj		case 't':
132204431Sraj			q[d.len++] = '\t';
133204431Sraj			break;
134204431Sraj		case 'n':
135204431Sraj			q[d.len++] = '\n';
136204431Sraj			break;
137204431Sraj		case 'v':
138204431Sraj			q[d.len++] = '\v';
139204431Sraj			break;
140204431Sraj		case 'f':
141204431Sraj			q[d.len++] = '\f';
142204431Sraj			break;
143204431Sraj		case 'r':
144204431Sraj			q[d.len++] = '\r';
145204431Sraj			break;
146204431Sraj		case '0':
147204431Sraj		case '1':
148204431Sraj		case '2':
149204431Sraj		case '3':
150204431Sraj		case '4':
151204431Sraj		case '5':
152204431Sraj		case '6':
153204431Sraj		case '7':
154204431Sraj			i--; /* need to re-read the first digit as
155204431Sraj			      * part of the octal value */
156204431Sraj			q[d.len++] = get_oct_char(s, &i);
157204431Sraj			break;
158204431Sraj		case 'x':
159204431Sraj			q[d.len++] = get_hex_char(s, &i);
160204431Sraj			break;
161204431Sraj		default:
162204431Sraj			q[d.len++] = c;
163204431Sraj		}
164204431Sraj	}
165204431Sraj
166204431Sraj	q[d.len++] = '\0';
167204431Sraj	return d;
168204431Sraj}
169204431Sraj
170204431Srajstruct data data_copy_file(FILE *f, size_t maxlen)
171204431Sraj{
172204431Sraj	struct data d = empty_data;
173204431Sraj
174204431Sraj	while (!feof(f) && (d.len < maxlen)) {
175204431Sraj		size_t chunksize, ret;
176204431Sraj
177204431Sraj		if (maxlen == -1)
178204431Sraj			chunksize = 4096;
179204431Sraj		else
180204431Sraj			chunksize = maxlen - d.len;
181204431Sraj
182204431Sraj		d = data_grow_for(d, chunksize);
183204431Sraj		ret = fread(d.val + d.len, 1, chunksize, f);
184204431Sraj
185204431Sraj		if (ferror(f))
186204431Sraj			die("Error reading file into data: %s", strerror(errno));
187204431Sraj
188204431Sraj		if (d.len + ret < d.len)
189204431Sraj			die("Overflow reading file into data\n");
190204431Sraj
191204431Sraj		d.len += ret;
192204431Sraj	}
193204431Sraj
194204431Sraj	return d;
195204431Sraj}
196204431Sraj
197204431Srajstruct data data_append_data(struct data d, const void *p, int len)
198204431Sraj{
199204431Sraj	d = data_grow_for(d, len);
200204431Sraj	memcpy(d.val + d.len, p, len);
201204431Sraj	d.len += len;
202204431Sraj	return d;
203204431Sraj}
204204431Sraj
205204431Srajstruct data data_insert_at_marker(struct data d, struct marker *m,
206204431Sraj				  const void *p, int len)
207204431Sraj{
208204431Sraj	d = data_grow_for(d, len);
209204431Sraj	memmove(d.val + m->offset + len, d.val + m->offset, d.len - m->offset);
210204431Sraj	memcpy(d.val + m->offset, p, len);
211204431Sraj	d.len += len;
212204431Sraj
213204431Sraj	/* Adjust all markers after the one we're inserting at */
214204431Sraj	m = m->next;
215204431Sraj	for_each_marker(m)
216204431Sraj		m->offset += len;
217204431Sraj	return d;
218204431Sraj}
219204431Sraj
220204433Srajstatic struct data data_append_markers(struct data d, struct marker *m)
221204431Sraj{
222204431Sraj	struct marker **mp = &d.markers;
223204431Sraj
224204431Sraj	/* Find the end of the markerlist */
225204431Sraj	while (*mp)
226204431Sraj		mp = &((*mp)->next);
227204431Sraj	*mp = m;
228204431Sraj	return d;
229204431Sraj}
230204431Sraj
231204431Srajstruct data data_merge(struct data d1, struct data d2)
232204431Sraj{
233204431Sraj	struct data d;
234204431Sraj	struct marker *m2 = d2.markers;
235204431Sraj
236204431Sraj	d = data_append_markers(data_append_data(d1, d2.val, d2.len), m2);
237204431Sraj
238204431Sraj	/* Adjust for the length of d1 */
239204431Sraj	for_each_marker(m2)
240204431Sraj		m2->offset += d1.len;
241204431Sraj
242204431Sraj	d2.markers = NULL; /* So data_free() doesn't clobber them */
243204431Sraj	data_free(d2);
244204431Sraj
245204431Sraj	return d;
246204431Sraj}
247204431Sraj
248204431Srajstruct data data_append_cell(struct data d, cell_t word)
249204431Sraj{
250204431Sraj	cell_t beword = cpu_to_fdt32(word);
251204431Sraj
252204431Sraj	return data_append_data(d, &beword, sizeof(beword));
253204431Sraj}
254204431Sraj
255204431Srajstruct data data_append_re(struct data d, const struct fdt_reserve_entry *re)
256204431Sraj{
257204431Sraj	struct fdt_reserve_entry bere;
258204431Sraj
259204431Sraj	bere.address = cpu_to_fdt64(re->address);
260204431Sraj	bere.size = cpu_to_fdt64(re->size);
261204431Sraj
262204431Sraj	return data_append_data(d, &bere, sizeof(bere));
263204431Sraj}
264204431Sraj
265204431Srajstruct data data_append_addr(struct data d, uint64_t addr)
266204431Sraj{
267204431Sraj	uint64_t beaddr = cpu_to_fdt64(addr);
268204431Sraj
269204431Sraj	return data_append_data(d, &beaddr, sizeof(beaddr));
270204431Sraj}
271204431Sraj
272204431Srajstruct data data_append_byte(struct data d, uint8_t byte)
273204431Sraj{
274204431Sraj	return data_append_data(d, &byte, 1);
275204431Sraj}
276204431Sraj
277204431Srajstruct data data_append_zeroes(struct data d, int len)
278204431Sraj{
279204431Sraj	d = data_grow_for(d, len);
280204431Sraj
281204431Sraj	memset(d.val + d.len, 0, len);
282204431Sraj	d.len += len;
283204431Sraj	return d;
284204431Sraj}
285204431Sraj
286204431Srajstruct data data_append_align(struct data d, int align)
287204431Sraj{
288204431Sraj	int newlen = ALIGN(d.len, align);
289204431Sraj	return data_append_zeroes(d, newlen - d.len);
290204431Sraj}
291204431Sraj
292204431Srajstruct data data_add_marker(struct data d, enum markertype type, char *ref)
293204431Sraj{
294204431Sraj	struct marker *m;
295204431Sraj
296204431Sraj	m = xmalloc(sizeof(*m));
297204431Sraj	m->offset = d.len;
298204431Sraj	m->type = type;
299204431Sraj	m->ref = ref;
300204431Sraj	m->next = NULL;
301204431Sraj
302204431Sraj	return data_append_markers(d, m);
303204431Sraj}
304204431Sraj
305204431Srajint data_is_one_string(struct data d)
306204431Sraj{
307204431Sraj	int i;
308204431Sraj	int len = d.len;
309204431Sraj
310204431Sraj	if (len == 0)
311204431Sraj		return 0;
312204431Sraj
313204431Sraj	for (i = 0; i < len-1; i++)
314204431Sraj		if (d.val[i] == '\0')
315204431Sraj			return 0;
316204431Sraj
317204431Sraj	if (d.val[len-1] != '\0')
318204431Sraj		return 0;
319204431Sraj
320204431Sraj	return 1;
321204431Sraj}
322