xref: /freebsd/usr.bin/dtc/input_buffer.hh (revision 39ee7a7a6bdd1557b1c3532abf60d139798ac88b)
1 /*-
2  * Copyright (c) 2013 David Chisnall
3  * All rights reserved.
4  *
5  * This software was developed by SRI International and the University of
6  * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
7  * ("CTSRD"), as part of the DARPA CRASH research programme.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  * $FreeBSD$
31  */
32 
33 #ifndef _INPUT_BUFFER_HH_
34 #define _INPUT_BUFFER_HH_
35 #include "util.hh"
36 #include <assert.h>
37 
38 namespace dtc
39 {
40 
41 /**
42  * Class encapsulating the input file.  Can be used as a const char*, but has
43  * range checking.  Attempting to access anything out of range will return a 0
44  * byte.  The input buffer can be cheaply copied, without copying the
45  * underlying memory, however it is the user's responsibility to ensure that
46  * such copies do not persist beyond the lifetime of the underlying memory.
47  *
48  * This also contains methods for reporting errors and for consuming the token
49  * stream.
50  */
51 class input_buffer
52 {
53 	protected:
54 	/**
55 	 * The buffer.  This class doesn't own the buffer, but the
56 	 * mmap_input_buffer subclass does.
57 	 */
58 	const char* buffer;
59 	/**
60 	 * The size of the buffer.
61 	 */
62 	int size;
63 	private:
64 	/**
65 	 * The current place in the buffer where we are reading.  This class
66 	 * keeps a separate size, pointer, and cursor so that we can move
67 	 * forwards and backwards and still have checks that we haven't fallen
68 	 * off either end.
69 	 */
70 	int cursor;
71 	/**
72 	 * Private constructor.  This is used to create input buffers that
73 	 * refer to the same memory, but have different cursors.
74 	 */
75 	input_buffer(const char* b, int s, int c) : buffer(b), size(s),
76 		cursor(c) {}
77 	/**
78 	 * Reads forward past any spaces.  The DTS format is not whitespace
79 	 * sensitive and so we want to scan past whitespace when reading it.
80 	 */
81 	void skip_spaces();
82 	public:
83 	/**
84 	 * Return whether all input has been consumed.
85 	 */
86 	bool finished() { return cursor >= size; }
87 	/**
88 	 * Virtual destructor.  Does nothing, but exists so that subclasses
89 	 * that own the memory can run cleanup code for deallocating it.
90 	 */
91 	virtual ~input_buffer() {};
92 	/**
93 	 * Constructs an empty buffer.
94 	 */
95 	input_buffer() : buffer(0), size(0), cursor(0) {}
96 	/**
97 	 * Constructs a new buffer with a specified memory region and size.
98 	 */
99 	input_buffer(const char* b, int s) : buffer(b), size(s), cursor(0){}
100 	/**
101 	 * Returns a new input buffer referring into this input, clamped to the
102 	 * specified size.  If the requested buffer would fall outside the
103 	 * range of this one, then it returns an empty buffer.
104 	 *
105 	 * The returned buffer shares the same underlying storage as the
106 	 * original.  This is intended to be used for splitting up the various
107 	 * sections of a device tree blob.  Requesting a size of 0 will give a
108 	 * buffer that extends to the end of the available memory.
109 	 */
110 	input_buffer buffer_from_offset(int offset, int s=0);
111 	/**
112 	 * Returns true if this buffer has no unconsumed space in it.
113 	 */
114 	inline bool empty()
115 	{
116 		return cursor >= size;
117 	}
118 	/**
119 	 * Dereferencing operator, allows the buffer to be treated as a char*
120 	 * and dereferenced to give a character.  This returns a null byte if
121 	 * the cursor is out of range.
122 	 */
123 	inline char operator*()
124 	{
125 		if (cursor >= size) { return '\0'; }
126 		if (cursor < 0) { return '\0'; }
127 		return buffer[cursor];
128 	}
129 	/**
130 	 * Array subscripting operator, returns a character at the specified
131 	 * index offset from the current cursor.  The offset may be negative,
132 	 * to reread characters that have already been read.  If the current
133 	 * cursor plus offset is outside of the range, this returns a nul
134 	 * byte.
135 	 */
136 	inline char operator[](int offset)
137 	{
138 		if (cursor + offset >= size) { return '\0'; }
139 		if (cursor + offset < 0) { return '\0'; }
140 		return buffer[cursor + offset];
141 	}
142 	/**
143 	 * Increments the cursor, iterating forward in the buffer.
144 	 */
145 	inline input_buffer &operator++()
146 	{
147 		cursor++;
148 		return *this;
149 	}
150 	/**
151 	 * Cast to char* operator.  Returns a pointer into the buffer that can
152 	 * be used for constructing strings.
153 	 */
154 	inline operator const char*()
155 	{
156 		if (cursor >= size) { return 0; }
157 		if (cursor < 0) { return 0; }
158 		return &buffer[cursor];
159 	}
160 	/**
161 	 * Consumes a character.  Moves the cursor one character forward if the
162 	 * next character matches the argument, returning true.  If the current
163 	 * character does not match the argument, returns false.
164 	 */
165 	inline bool consume(char c)
166 	{
167 		if ((*this)[0] == c)
168 		{
169 			++(*this);
170 			return true;
171 		}
172 		return false;
173 	}
174 	/**
175 	 * Consumes a string.  If the (null-terminated) string passed as the
176 	 * argument appears in the input, advances the cursor to the end and
177 	 * returns true.  Returns false if the string does not appear at the
178 	 * current point in the input.
179 	 */
180 	bool consume(const char *str);
181 	/**
182 	 * Reads an integer in base 8, 10, or 16.  Returns true and advances
183 	 * the cursor to the end of the integer if the cursor points to an
184 	 * integer, returns false and does not move the cursor otherwise.
185 	 *
186 	 * The parsed value is returned via the argument.
187 	 */
188 	bool consume_integer(unsigned long long &outInt);
189 	/**
190 	 * Template function that consumes a binary value in big-endian format
191 	 * from the input stream.  Returns true and advances the cursor if
192 	 * there is a value of the correct size.  This function assumes that
193 	 * all values must be natively aligned, and so advances the cursor to
194 	 * the correct alignment before reading.
195 	 */
196 	template<typename T>
197 	bool consume_binary(T &out)
198 	{
199 		int align = 0;
200 		int type_size = sizeof(T);
201 		if (cursor % type_size != 0)
202 		{
203 			align = type_size - (cursor % type_size);
204 		}
205 		if (size < cursor + align + type_size)
206 		{
207 			return false;
208 		}
209 		cursor += align;
210 		assert(cursor % type_size == 0);
211 		out = 0;
212 		for (int i=0 ; i<type_size ; ++i)
213 		{
214 			out <<= 8;
215 			out |= (((T)buffer[cursor++]) & 0xff);
216 		}
217 		return true;
218 	}
219 	/**
220 	 * Consumes two hex digits and return the resulting byte via the first
221 	 * argument.  If the next two characters are hex digits, returns true
222 	 * and advances the cursor.  If not, then returns false and leaves the
223 	 * cursor in place.
224 	 */
225 	bool consume_hex_byte(uint8_t &outByte);
226 	/**
227 	 * Advances the cursor to the start of the next token, skipping
228 	 * comments and whitespace.  If the cursor already points to the start
229 	 * of a token, then this function does nothing.
230 	 */
231 	input_buffer &next_token();
232 	/**
233 	 * Prints a message indicating the location of a parse error.
234 	 */
235 	void parse_error(const char *msg);
236 	/**
237 	 * Dumps the current cursor value and the unconsumed values in the
238 	 * input buffer to the standard error.  This method is intended solely
239 	 * for debugging.
240 	 */
241 	void dump();
242 };
243 /**
244  * Explicit specialisation for reading a single byte.
245  */
246 template<>
247 inline bool input_buffer::consume_binary(uint8_t &out)
248 {
249 	if (size < cursor + 1)
250 	{
251 		return false;
252 	}
253 	out = buffer[cursor++];
254 	return true;
255 }
256 
257 /**
258  * Subclass of input_buffer that mmap()s a file and owns the resulting memory.
259  * When this object is destroyed, the memory is unmapped.
260  */
261 struct mmap_input_buffer : public input_buffer
262 {
263 	/**
264 	 * Constructs a new buffer from the file passed in as a file
265 	 * descriptor.
266 	 */
267 	mmap_input_buffer(int fd);
268 	/**
269 	 * Unmaps the buffer, if one exists.
270 	 */
271 	virtual ~mmap_input_buffer();
272 };
273 /**
274  * Input buffer read from standard input.  This is used for reading device tree
275  * blobs and source from standard input.  It reads the entire input into
276  * malloc'd memory, so will be very slow for large inputs.  DTS and DTB files
277  * are very rarely more than 10KB though, so this is probably not a problem.
278  */
279 struct stream_input_buffer : public input_buffer
280 {
281 	/**
282 	 * The buffer that will store the data read from the standard input.
283 	 */
284 	std::vector<char> b;
285 	/**
286 	 * Constructs a new buffer from the standard input.
287 	 */
288 	stream_input_buffer();
289 };
290 
291 } // namespace dtc
292 
293 #endif // !_INPUT_BUFFER_HH_
294