PageRenderTime 54ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/update_tool/src/ihex.c

https://github.com/zeldin/xu1541
C | 530 lines | 351 code | 111 blank | 68 comment | 81 complexity | f44cd382be0d0d2a60cd9e25c6733f5a MD5 | raw file
  1. /*
  2. ihex.c
  3. */
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include "ihex.h"
  8. #define RECORD_DATA 0
  9. #define RECORD_END 1
  10. #define RECORD_START_SEGMENT_ADDRESS 3
  11. static int ihex_iswhite(unsigned char c) {
  12. return( (c == ' ')||(c == '\n')||(c == '\r')||(c == '\t'));
  13. }
  14. static int ihex_line_is_white(char *line) {
  15. int is_white = 1;
  16. while(*line)
  17. if(!(ihex_iswhite(*line++)))
  18. is_white = 0;
  19. return is_white;
  20. }
  21. static int hex2bin(unsigned char c) {
  22. if((c >= '0') && (c <= '9')) return(c - '0');
  23. if((c >= 'a') && (c <= 'f')) return(c - 'a' + 10);
  24. if((c >= 'A') && (c <= 'F')) return(c - 'A' + 10);
  25. return -1;
  26. }
  27. /* convert two digits hex byte into binary, return NULL on error */
  28. static char *ihex_parse_byte(char *line, int *crc, int *value) {
  29. int b0 = hex2bin(line[0]);
  30. int b1 = hex2bin(line[1]);
  31. if((b0 < 0) || (b1 < 0))
  32. return NULL;
  33. if(value) *value = 16*b0 + b1;
  34. *crc = (*crc + (16*b0 + b1))&0xff;
  35. return line+2;
  36. }
  37. /* convert four digits hex word into binary, return NULL on error */
  38. static char *ihex_parse_word(char *line, int *crc, int *value) {
  39. int b0 = hex2bin(line[0]);
  40. int b1 = hex2bin(line[1]);
  41. int b2 = hex2bin(line[2]);
  42. int b3 = hex2bin(line[3]);
  43. if((b0 < 0) || (b1 < 0) || (b2 < 0) || (b3 < 0))
  44. return NULL;
  45. if(value) *value = 4096 * b0 + 256 * b1 + 16*b2 + b3;
  46. *crc = (*crc + (16 * b0 + b1 + 16*b2 + b3))&0xff;
  47. return line+4;
  48. }
  49. static void ihex_free_line(ihex_line_t *iline) {
  50. if(iline) {
  51. if(iline->data)
  52. free(iline->data);
  53. free(iline);
  54. }
  55. }
  56. /* parse a single line from the intel hex file */
  57. static ihex_line_t *ihex_parse_line(char *line, int line_num) {
  58. ihex_line_t *iline = NULL;
  59. int tmp;
  60. if(!(iline = malloc(sizeof(ihex_line_t)))) {
  61. fprintf(stderr, "ERROR: Out of memory parsing line %d\n", line_num);
  62. return NULL;
  63. }
  64. memset(iline, 0, sizeof(ihex_line_t));
  65. /* skip white space up to start delimiter ':' */
  66. while(*line != ':') {
  67. if(!ihex_iswhite(*line))
  68. line++;
  69. else {
  70. fprintf(stderr, "ERROR: Missing start delimiter in line %d\n", line_num);
  71. ihex_free_line(iline);
  72. return NULL;
  73. }
  74. }
  75. /* skip ':' */
  76. line++;
  77. /* parse line "header" which needs at least 10 more bytes */
  78. if(strlen(line) < 10) {
  79. fprintf(stderr, "ERROR: Insufficient header data in line %d\n", line_num);
  80. ihex_free_line(iline);
  81. return NULL;
  82. }
  83. /* parse header fields */
  84. if(!(line = ihex_parse_byte(line, &iline->crc, &iline->length))) {
  85. fprintf(stderr, "ERROR: Illegal length in line %d\n", line_num);
  86. ihex_free_line(iline);
  87. return NULL;
  88. }
  89. if(!(line = ihex_parse_word(line, &iline->crc, &iline->address))) {
  90. fprintf(stderr, "ERROR: Illegal address in line %d\n", line_num);
  91. ihex_free_line(iline);
  92. return NULL;
  93. }
  94. if(!(line = ihex_parse_byte(line, &iline->crc, &iline->type))) {
  95. fprintf(stderr, "ERROR: Illegal type in line %d\n", line_num);
  96. ihex_free_line(iline);
  97. return NULL;
  98. }
  99. /* (always) process the data bytes */
  100. {
  101. int i;
  102. /* check if remaining line is long enough for data + crc */
  103. if(strlen(line) < 2 * (1+iline->length)) {
  104. fprintf(stderr, "ERROR: Line to short in line %d\n", line_num);
  105. ihex_free_line(iline);
  106. return NULL;
  107. }
  108. /* allocate space for data */
  109. if(!(iline->data = malloc(iline->length))) {
  110. fprintf(stderr, "ERROR: Out of memory allocating data for line %d\n",
  111. line_num);
  112. ihex_free_line(iline);
  113. return NULL;
  114. }
  115. for(i=0;i<iline->length;i++) {
  116. if(!(line = ihex_parse_byte(line, &iline->crc, &tmp))) {
  117. fprintf(stderr, "ERROR: Illegal data in line %d\n", line_num);
  118. ihex_free_line(iline);
  119. return NULL;
  120. }
  121. /* store byte */
  122. iline->data[i] = tmp;
  123. }
  124. }
  125. /* special handling for RECORD_START_SEGMENT_ADDRESS */
  126. if(iline->type == RECORD_START_SEGMENT_ADDRESS) {
  127. if(iline->length != 4) {
  128. fprintf(stderr, "wrong length of start address: %d.\n", iline->length);
  129. }
  130. else {
  131. fprintf(stderr, "start address from file: 0x%02x%02x:0x%02x%02x.\n", iline->data[0], iline->data[1], iline->data[2], iline->data[3]);
  132. }
  133. }
  134. /* read crc ... */
  135. if(!(line = ihex_parse_byte(line, &iline->crc, NULL))) {
  136. fprintf(stderr, "ERROR: Illegal crc in line %d\n", line_num);
  137. ihex_free_line(iline);
  138. return NULL;
  139. }
  140. /* ... and verify it */
  141. if(iline->crc) {
  142. fprintf(stderr, "ERROR: CRC (%x) mismatch in line %d\n",
  143. iline->crc, line_num);
  144. ihex_free_line(iline);
  145. return NULL;
  146. }
  147. /* the remaining data must only be whitespace */
  148. while(*line) {
  149. if(!ihex_iswhite(*line)) {
  150. fprintf(stderr, "ERROR: garbage after line in line %d\n", line_num);
  151. ihex_free_line(iline);
  152. return NULL;
  153. }
  154. line++;
  155. }
  156. return(iline);
  157. }
  158. static ihex_chunk_t *ihex_new_chunk(ihex_line_t *iline) {
  159. ihex_chunk_t *ichunk = NULL;
  160. if(!(ichunk = malloc(sizeof(ihex_chunk_t)))) {
  161. fprintf(stderr, "ERROR: Out of memory allocating %d bytes chunk\n",
  162. sizeof(ihex_chunk_t));
  163. return NULL;
  164. }
  165. memset(ichunk, 0, sizeof(ihex_chunk_t));
  166. /* also allocate buffer for data if required */
  167. if(iline->length) {
  168. if(!(ichunk->data = malloc(iline->length))) {
  169. fprintf(stderr, "ERROR: Out of memory allocating %d bytes chunk data\n",
  170. iline->length);
  171. return NULL;
  172. }
  173. /* copy data if successful */
  174. memcpy(ichunk->data, iline->data, iline->length);
  175. }
  176. /* store chunk address */
  177. ichunk->length = iline->length;
  178. ichunk->address = iline->address;
  179. return ichunk;
  180. }
  181. /* insert data from line into file structure */
  182. static int ihex_insert(ihex_file_t *ifile, ihex_line_t *iline) {
  183. ihex_chunk_t **ichunk = &ifile->first;
  184. /* walk chunk chain to find insertion point */
  185. while(*ichunk) {
  186. ihex_chunk_t *next = (*ichunk)->next;
  187. /* check if new chunk begins within this one */
  188. if((iline->address >= (*ichunk)->address) &&
  189. (iline->address < (*ichunk)->address + (*ichunk)->length)) {
  190. fprintf(stderr, "ERROR: data overlap at address 0x%04x!\n",
  191. iline->address);
  192. return -1;
  193. }
  194. /* check if we can append the chunk directly */
  195. if(iline->address == (*ichunk)->address + (*ichunk)->length) {
  196. unsigned char *old_data = (*ichunk)->data;
  197. (*ichunk)->data = malloc((*ichunk)->length + iline->length);
  198. if(!((*ichunk)->data)) {
  199. fprintf(stderr, "ERROR: Out of memory increasing chunk to %d bytes!\n",
  200. (*ichunk)->length + iline->length);
  201. return -1;
  202. }
  203. /* copy old data */
  204. memcpy((*ichunk)->data, old_data, (*ichunk)->length);
  205. free(old_data);
  206. /* and new data */
  207. memcpy((*ichunk)->data+(*ichunk)->length, iline->data, iline->length);
  208. /* and adjust new size */
  209. (*ichunk)->length += iline->length;
  210. /* check if the following chunk can be attached as well */
  211. if(next) {
  212. if(next->address == (*ichunk)->address + (*ichunk)->length) {
  213. unsigned char *old_data = (*ichunk)->data;
  214. (*ichunk)->data = malloc((*ichunk)->length + next->length);
  215. if(!((*ichunk)->data)) {
  216. fprintf(stderr, "ERROR: Out of memory increasing chunk to "
  217. "%d bytes!\n", (*ichunk)->length + next->length);
  218. return -1;
  219. }
  220. /* copy old data */
  221. memcpy((*ichunk)->data, old_data, (*ichunk)->length);
  222. free(old_data);
  223. /* and new data */
  224. memcpy((*ichunk)->data+(*ichunk)->length, next->data, next->length);
  225. /* and adjust new size */
  226. (*ichunk)->length += next->length;
  227. /* adjust next pointer */
  228. (*ichunk)->next = next->next;
  229. /* free old chunk */
  230. free(next->data);
  231. free(next);
  232. }
  233. }
  234. return 0;
  235. }
  236. /* check if this line has to be inserted before the next chunk */
  237. if(next && (iline->address <= next->address)) {
  238. /* check if chunk overlaps next one */
  239. if(iline->address+iline->length-1 >= next->address) {
  240. fprintf(stderr, "ERROR: data overlap at address 0x%04x!\n",
  241. iline->address);
  242. return -1;
  243. }
  244. ichunk = &(*ichunk)->next;
  245. if(!((*ichunk) = ihex_new_chunk(iline))) {
  246. fprintf(stderr, "ERROR: Error appending new chunk\n");
  247. return -1;
  248. }
  249. /* close chain again */
  250. (*ichunk)->next = next;
  251. /* check if the following chunk can be attached as well */
  252. if(next->address == (*ichunk)->address + (*ichunk)->length) {
  253. unsigned char *old_data = (*ichunk)->data;
  254. (*ichunk)->data = malloc((*ichunk)->length + next->length);
  255. if(!((*ichunk)->data)) {
  256. fprintf(stderr, "ERROR: Out of memory increasing chunk to "
  257. "%d bytes!\n", (*ichunk)->length + next->length);
  258. return -1;
  259. }
  260. /* copy old data */
  261. memcpy((*ichunk)->data, old_data, (*ichunk)->length);
  262. free(old_data);
  263. /* and new data */
  264. memcpy((*ichunk)->data+(*ichunk)->length, next->data, next->length);
  265. /* and adjust new size */
  266. (*ichunk)->length += next->length;
  267. /* adjust next pointer */
  268. (*ichunk)->next = next->next;
  269. /* free old chunk */
  270. free(next->data);
  271. free(next);
  272. }
  273. return 0;
  274. }
  275. /* search next chunk */
  276. ichunk = &((*ichunk)->next);
  277. }
  278. /* we walked all chunks without finding an entry point -> attach to end */
  279. if(!(*ichunk = ihex_new_chunk(iline))) {
  280. fprintf(stderr, "ERROR: Error appending new chunk\n");
  281. return -1;
  282. }
  283. return 0;
  284. }
  285. /* walk chunk chain and free it */
  286. static void ihex_free_chunk(ihex_chunk_t *ichunk) {
  287. if(ichunk) {
  288. ihex_free_chunk((ihex_chunk_t*)ichunk->next);
  289. if(ichunk->data) free(ichunk->data);
  290. free(ichunk);
  291. }
  292. }
  293. void ihex_free_file(ihex_file_t *ifile) {
  294. if(ifile) {
  295. /* free chunk chain */
  296. ihex_free_chunk(ifile->first);
  297. free(ifile);
  298. }
  299. }
  300. ihex_file_t *ihex_parse_file(char *filename) {
  301. ihex_file_t *ifile = NULL;
  302. FILE *file = NULL;
  303. char line[128];
  304. ifile = malloc(sizeof(ihex_file_t));
  305. if(!ifile) {
  306. fprintf(stderr, "ERROR: Out of memory allocating file structure\n");
  307. return NULL;
  308. }
  309. memset(ifile, 0, sizeof(ihex_file_t));
  310. file = fopen(filename, "r");
  311. if(!file) {
  312. fprintf(stderr, "ERROR: Unable to open file %s\n", filename);
  313. ihex_free_file(ifile);
  314. return(NULL);
  315. }
  316. while(fgets(line, sizeof(line), file) != NULL) {
  317. ihex_line_t *iline;
  318. ifile->lines++;
  319. /* force line termination */
  320. line[sizeof(line)-1] = 0;
  321. /* if line is completely white, just skip it */
  322. if(!ihex_line_is_white(line)) {
  323. /* parse line */
  324. if(!(iline = ihex_parse_line(line, ifile->lines))) {
  325. fprintf(stderr, "ERROR: Hex parsing failed\n");
  326. ihex_free_file(ifile);
  327. fclose(file);
  328. return(NULL);
  329. }
  330. /* data must not occur after and marker */
  331. if(ifile->ended) {
  332. fprintf(stderr, "ERROR: Data after end marker\n");
  333. ihex_free_file(ifile);
  334. fclose(file);
  335. return(NULL);
  336. }
  337. /* remember that the end marker has been found */
  338. if(iline->type == RECORD_END)
  339. ifile->ended = 1;
  340. /* insert data chunks into structure */
  341. if(iline->type == RECORD_DATA) {
  342. /* integrate line into file structure */
  343. if(ihex_insert(ifile, iline) != 0) {
  344. fprintf(stderr, "ERROR: Insertion failed\n");
  345. ihex_free_file(ifile);
  346. fclose(file);
  347. return(NULL);
  348. }
  349. }
  350. ihex_free_line(iline);
  351. }
  352. }
  353. if(!ifile->ended) {
  354. fprintf(stderr, "ERROR: No end marker found\n");
  355. ihex_free_file(ifile);
  356. fclose(file);
  357. return(NULL);
  358. }
  359. fclose(file);
  360. return ifile;
  361. }
  362. int ihex_file_get_chunks(ihex_file_t *ifile) {
  363. ihex_chunk_t **ichunk = &ifile->first;
  364. int chunks = 0;
  365. /* walk chunk chain to count chunks */
  366. while(*ichunk) {
  367. chunks++;
  368. /* search next chunk */
  369. ichunk = &((*ichunk)->next);
  370. }
  371. return chunks;
  372. }
  373. int ihex_file_get_start_address(ihex_file_t *ifile) {
  374. if(!ifile->first)
  375. return -1;
  376. return ifile->first->address;
  377. }
  378. int ihex_file_get_end_address(ihex_file_t *ifile) {
  379. ihex_chunk_t **ichunk = &ifile->first;
  380. int address = -1;
  381. /* walk chunk chain to count chunks */
  382. while(*ichunk) {
  383. address = (*ichunk)->address + (*ichunk)->length - 1;
  384. /* search next chunk */
  385. ichunk = &((*ichunk)->next);
  386. }
  387. return address;
  388. }
  389. int ihex_file_get_mem(ihex_file_t *ifile, int start, int len, char *data) {
  390. ihex_chunk_t **ichunk = &ifile->first;
  391. /* walk chunk chain to count chunks */
  392. while(*ichunk) {
  393. int soffset = 0, doffset = 0;
  394. int bytes2copy = (*ichunk)->length;
  395. /* is anything of this chunk to be copied? */
  396. /* (is start of chunk before end of requested area and */
  397. /* end of chunk after start of requested area?) */
  398. if(((*ichunk)->address <= (start + len - 1)) &&
  399. ((*ichunk)->address + (*ichunk)->length >= start )) {
  400. /* calculate source and destination offset */
  401. if(start > (*ichunk)->address) {
  402. /* shift beginning of area to be copied */
  403. soffset = start - (*ichunk)->address;
  404. bytes2copy -= soffset;
  405. }
  406. if((*ichunk)->address > start)
  407. doffset = (*ichunk)->address - start;
  408. /* calculate number of bytes to be copied */
  409. if(bytes2copy > len-doffset)
  410. bytes2copy = len-doffset;
  411. /* and finally copy ... */
  412. memcpy(data + doffset, (*ichunk)->data + soffset, bytes2copy);
  413. }
  414. /* search next chunk */
  415. ichunk = &((*ichunk)->next);
  416. }
  417. return 0;
  418. }