summaryrefslogtreecommitdiff
path: root/lib/x1000-installer/src/xf_flashmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/x1000-installer/src/xf_flashmap.c')
-rw-r--r--lib/x1000-installer/src/xf_flashmap.c327
1 files changed, 0 insertions, 327 deletions
diff --git a/lib/x1000-installer/src/xf_flashmap.c b/lib/x1000-installer/src/xf_flashmap.c
deleted file mode 100644
index 972bf320ad..0000000000
--- a/lib/x1000-installer/src/xf_flashmap.c
+++ /dev/null
@@ -1,327 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 Aidan MacDonald
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "xf_flashmap.h"
23#include "xf_error.h"
24#include <stdbool.h>
25#include <stdlib.h>
26#include <ctype.h>
27#include <string.h>
28
29static int xdigit_to_int(char c)
30{
31 if(c >= 'a' && c <= 'f')
32 return 10 + (c - 'a');
33 if(c >= 'A' && c <= 'F')
34 return 10 + (c - 'A');
35 if(c >= '0' && c <= '9')
36 return c - '0';
37 return -1;
38}
39
40static int isfilenamechar(char c)
41{
42 return (c >= 'a' && c <= 'z') ||
43 (c >= 'A' && c <= 'Z') ||
44 (c >= '0' && c <= '9') ||
45 c == '$' || c == '%' || c == '\'' || c == '-' || c == '_' ||
46 c == '@' || c == '~' || c == '`' || c == '!' || c == '(' ||
47 c == ')' || c == '{' || c == '}' || c == '^' || c == '#' ||
48 c == '&' || c == '+' || c == ',' || c == ';' || c == '=' ||
49 c == '[' || c == ']' || c == '.';
50}
51
52int xf_map_parseline(const char* line, struct xf_map* map)
53{
54 enum {
55 s_name,
56 s_md5,
57 s_first_num,
58 s_file_len = s_first_num,
59 s_offset,
60 s_length,
61 s_done,
62 };
63
64#define skipws() do { while(*line == ' ' || *line == '\t') ++line; } while(0)
65#define nextstate() do { ++state; length = 0; ++line; skipws(); } while(0)
66
67 int state = s_name;
68 int length = 0;
69 int digit_val;
70 uint32_t int_val;
71 uint32_t* num_ptr[3] = {&map->file_length, &map->offset, &map->length};
72 bool has_md5 = true;
73
74 skipws();
75 while(*line && *line != '\n') {
76 switch(state) {
77 case s_name:
78 if(*line == ' ' || *line == '\t') {
79 nextstate();
80 continue;
81 } else if(isfilenamechar(*line)) {
82 if(length == XF_MAP_NAMELEN)
83 return XF_E_FILENAME_TOO_LONG;
84
85 map->name[length++] = *line++;
86 map->name[length] = '\0';
87 continue;
88 } else {
89 return XF_E_SYNTAX_ERROR;
90 }
91
92 case s_md5:
93 if(*line == '-') {
94 memset(map->md5, 0, 16);
95 map->file_length = 0;
96 has_md5 = false;
97 ++line;
98 } else {
99 for(int i = 0; i < 16; ++i) {
100 int_val = 0;
101 for(int j = 0; j < 2; ++j) {
102 digit_val = xdigit_to_int(*line++);
103 if(digit_val < 0)
104 return XF_E_SYNTAX_ERROR;
105
106 int_val <<= 4;
107 int_val |= digit_val;
108 }
109
110 map->md5[i] = int_val;
111 }
112 }
113
114 if(*line == ' ' || *line == '\t') {
115 /* skip file length if md5 is not present */
116 if(!has_md5)
117 ++state;
118
119 nextstate();
120 continue;
121 } else {
122 return XF_E_SYNTAX_ERROR;
123 }
124
125 case s_file_len:
126 case s_offset:
127 case s_length:
128 int_val = 0;
129
130 if(*line == '0') {
131 ++line;
132 if(*line == 'x' || *line == 'X') {
133 ++line;
134 while((digit_val = xdigit_to_int(*line)) >= 0) {
135 ++line;
136
137 if(int_val > UINT32_MAX/16)
138 return XF_E_INT_OVERFLOW;
139
140 int_val *= 16;
141 int_val |= digit_val;
142 }
143 }
144 } else if(*line >= '1' && *line <= '9') {
145 do {
146 if(int_val > UINT32_MAX/10)
147 return XF_E_INT_OVERFLOW;
148 int_val *= 10;
149
150 digit_val = *line++ - '0';
151 if(int_val > UINT32_MAX - digit_val)
152 return XF_E_INT_OVERFLOW;
153
154 int_val += digit_val;
155 } while(*line >= '0' && *line <= '9');
156 }
157
158 *num_ptr[state - s_first_num] = int_val;
159
160 if(*line == ' ' || *line == '\t') {
161 nextstate();
162 continue;
163 } else if(state+1 == s_done && *line == '\0') {
164 /* end of input */
165 continue;
166 } else {
167 return XF_E_SYNTAX_ERROR;
168 }
169
170 case s_done:
171 if(isspace(*line)) {
172 line++;
173 continue; /* swallow trailing spaces, carriage return, etc */
174 } else
175 return XF_E_SYNTAX_ERROR;
176 }
177 }
178
179#undef skipws
180#undef nextstate
181
182 /* one last overflow check - ensure mapped range is addressable */
183 if(map->offset > UINT32_MAX - map->length)
184 return XF_E_INT_OVERFLOW;
185
186 if(has_md5)
187 map->flags = XF_MAP_HAS_MD5 | XF_MAP_HAS_FILE_LENGTH;
188 else
189 map->flags = 0;
190
191 return XF_E_SUCCESS;
192}
193
194struct map_parse_args {
195 struct xf_map* map;
196 int num;
197 int maxnum;
198};
199
200int map_parse_line_cb(int n, char* buf, void* arg)
201{
202 (void)n;
203
204 struct map_parse_args* args = arg;
205
206 /* skip whitespace */
207 while(*buf && isspace(*buf))
208 ++buf;
209
210 /* ignore comments and blank lines */
211 if(*buf == '#' || *buf == '\0')
212 return 0;
213
214 struct xf_map dummy_map;
215 struct xf_map* dst_map;
216 if(args->num < args->maxnum)
217 dst_map = &args->map[args->num];
218 else
219 dst_map = &dummy_map;
220
221 int rc = xf_map_parseline(buf, dst_map);
222 if(rc)
223 return rc;
224
225 args->num++;
226 return 0;
227}
228
229int xf_map_parse(struct xf_stream* s, struct xf_map* map, int maxnum)
230{
231 char buf[200];
232 struct map_parse_args args;
233 args.map = map;
234 args.num = 0;
235 args.maxnum = maxnum;
236
237 int rc = xf_stream_read_lines(s, buf, sizeof(buf),
238 map_parse_line_cb, &args);
239 if(rc < 0)
240 return rc;
241
242 return args.num;
243}
244
245static int xf_map_compare(const void* a, const void* b)
246{
247 const struct xf_map* mapA = a;
248 const struct xf_map* mapB = b;
249
250 if(mapA->offset < mapB->offset)
251 return -1;
252 else if(mapA->offset == mapB->offset)
253 return 0;
254 else
255 return 1;
256}
257
258int xf_map_sort(struct xf_map* map, int num)
259{
260 qsort(map, num, sizeof(struct xf_map), xf_map_compare);
261 return xf_map_validate(map, num);
262}
263
264int xf_map_validate(const struct xf_map* map, int num)
265{
266 for(int i = 1; i < num; ++i)
267 if(map[i].offset <= map[i-1].offset)
268 return -1;
269
270 for(int i = 1; i < num; ++i)
271 if(map[i-1].offset + map[i-1].length > map[i].offset)
272 return i;
273
274 return 0;
275}
276
277int xf_map_write(struct xf_map* map, int num, struct xf_stream* s)
278{
279 static const char hex[] = "0123456789abcdef";
280 char buf[200];
281 char md5str[33];
282 int total_len = 0;
283
284 md5str[32] = '\0';
285
286 for(int i = 0; i < num; ++i) {
287 bool has_md5 = false;
288 if(map->flags & XF_MAP_HAS_MD5) {
289 if(!(map->flags & XF_MAP_HAS_FILE_LENGTH))
290 return XF_E_INVALID_PARAMETER;
291
292 has_md5 = true;
293 for(int j = 0; j < 16; ++j) {
294 uint8_t byte = map[i].md5[j];
295 md5str[2*j] = hex[(byte >> 4) & 0xf];
296 md5str[2*j+1] = hex[byte & 0xf];
297 }
298 }
299
300 int len;
301 if(!has_md5) {
302 len = snprintf(buf, sizeof(buf), "%s - %lx %lu\n",
303 map[i].name,
304 (unsigned long)map[i].offset,
305 (unsigned long)map[i].length);
306 } else {
307 len = snprintf(buf, sizeof(buf), "%s %s %lu 0x%lx %lu\n",
308 map[i].name, md5str,
309 (unsigned long)map[i].file_length,
310 (unsigned long)map[i].offset,
311 (unsigned long)map[i].length);
312 }
313
314 if(len < 0 || (size_t)len >= sizeof(buf))
315 return XF_E_LINE_TOO_LONG;
316
317 if(s) {
318 int rc = xf_stream_write(s, buf, len);
319 if(rc != len)
320 return XF_E_IO;
321 }
322
323 total_len += len;
324 }
325
326 return total_len;
327}