You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

578 lines
14 KiB

  1. /***************************************************************************
  2. * Copyright (C) 10/2010 by Olaf Rempel *
  3. * razzor@kopf-tisch.de *
  4. * *
  5. * This program is free software; you can redistribute it and/or modify *
  6. * it under the terms of the GNU General Public License as published by *
  7. * the Free Software Foundation; version 2 of the License, *
  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 *
  16. * Free Software Foundation, Inc., *
  17. * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
  18. ***************************************************************************/
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <unistd.h>
  22. #include <string.h>
  23. #include <sys/types.h>
  24. #include <sys/stat.h>
  25. #include <fcntl.h>
  26. #include "filedata.h"
  27. #define FILETYPE_UNKNOWN 0
  28. #define FILETYPE_BINARY 1
  29. #define FILETYPE_INTELHEX 2
  30. /* *************************************************************************
  31. * dbuf_alloc
  32. * ************************************************************************* */
  33. struct databuf * dbuf_alloc(uint32_t size)
  34. {
  35. struct databuf *dbuf = malloc(sizeof(struct databuf) + size);
  36. if (dbuf == NULL)
  37. {
  38. perror("dbuf_alloc");
  39. return NULL;
  40. }
  41. memset(dbuf->data, 0xFF, size);
  42. dbuf->size = size;
  43. dbuf->length = 0;
  44. return dbuf;
  45. } /* dbuf_alloc */
  46. /* *************************************************************************
  47. * dbuf_free
  48. * ************************************************************************* */
  49. void dbuf_free(struct databuf *dbuf)
  50. {
  51. free(dbuf);
  52. } /* dbuf_free */
  53. /* *************************************************************************
  54. * dbuf_dump
  55. * ************************************************************************* */
  56. static void dbuf_dump(struct databuf *dbuf)
  57. {
  58. uint32_t pos = 0;
  59. int oldskip = 0;
  60. while (pos < dbuf->length)
  61. {
  62. char buf[128];
  63. int j, i = 0;
  64. int skip = 1;
  65. for (j = 0; j < 16; j++)
  66. {
  67. if (pos + j < dbuf->length)
  68. {
  69. i += sprintf(buf + i, "%02X", dbuf->data[pos + j]);
  70. } else {
  71. i += sprintf(buf + i, " ");
  72. }
  73. if (j % 2)
  74. {
  75. buf[i++] = ' ';
  76. }
  77. }
  78. for (j = 0; j < 16; j++)
  79. {
  80. if (pos + j < dbuf->length)
  81. {
  82. unsigned char val = dbuf->data[pos + j];
  83. if (val >= 0x20 && val < 0x7F)
  84. {
  85. buf[i++] = val;
  86. } else {
  87. buf[i++] = '.';
  88. }
  89. if (val != 0xFF)
  90. {
  91. skip = 0;
  92. }
  93. }
  94. else
  95. {
  96. buf[i++] = ' ';
  97. }
  98. }
  99. if ((pos == 0) ||
  100. ((pos + 16) >= dbuf->length) ||
  101. (skip == 0)
  102. )
  103. {
  104. buf[i++] = '\0';
  105. printf("%04X: %s\r\n", pos, buf);
  106. oldskip = 0;
  107. }
  108. else if ((skip == 1) &&
  109. (oldskip == 0)
  110. )
  111. {
  112. printf("****\n");
  113. oldskip = 1;
  114. }
  115. pos += 16;
  116. }
  117. } /* dbuf_dump */
  118. /* *************************************************************************
  119. * binfile_getsize
  120. * ************************************************************************* */
  121. static int binfile_getsize(const char *filename, uint32_t *size)
  122. {
  123. int fd = open(filename, O_RDONLY);
  124. if (fd < 0)
  125. {
  126. perror("binfile_getsize(): open()");
  127. return -1;
  128. }
  129. struct stat filestat;
  130. if (fstat(fd, &filestat) < 0)
  131. {
  132. perror("binfile_getsize(): fstat()");
  133. close(fd);
  134. return -1;
  135. }
  136. *size = filestat.st_size;
  137. close(fd);
  138. return 0;
  139. } /* binfile_getsize */
  140. /* *************************************************************************
  141. * binfile_read
  142. * ************************************************************************* */
  143. static int binfile_read(const char *filename, struct databuf *dbuf)
  144. {
  145. int fd = open(filename, O_RDONLY);
  146. if (fd < 0)
  147. {
  148. perror("binfile_read(): open()");
  149. return -1;
  150. }
  151. ssize_t readsize = read(fd, dbuf->data, dbuf->size);
  152. if (readsize <= 0)
  153. {
  154. perror("binfile_read(): read()");
  155. close(fd);
  156. return -1;
  157. }
  158. dbuf->length = readsize;
  159. close(fd);
  160. return 0;
  161. } /* binfile_read */
  162. /* *************************************************************************
  163. * binfile_write
  164. * ************************************************************************* */
  165. static int binfile_write(const char *filename, struct databuf *dbuf)
  166. {
  167. int fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0644);
  168. if (fd < 0)
  169. {
  170. perror("binfile_write(): open()");
  171. return -1;
  172. }
  173. ssize_t writesize = write(fd, dbuf->data, dbuf->length);
  174. if (writesize != dbuf->length)
  175. {
  176. perror("binfile_write(): write()");
  177. close(fd);
  178. return -1;
  179. }
  180. close(fd);
  181. return 0;
  182. } /* binfile_write */
  183. struct ihex_record
  184. {
  185. uint8_t byte_count;
  186. uint16_t address;
  187. uint8_t type;
  188. uint8_t *data;
  189. uint8_t chksum;
  190. };
  191. /* *************************************************************************
  192. * hex2byte
  193. * ************************************************************************* */
  194. static uint8_t hex2byte(const char *ptr)
  195. {
  196. int i;
  197. uint8_t result = 0;
  198. for (i = 0; i < 2; i++)
  199. {
  200. result <<= 4;
  201. result |= (ptr[i] >= '0' && ptr[i] <= '9') ? (ptr[i] - '0')
  202. : (((ptr[i] & 0xDF) >= 'A' && (ptr[i] & 0xDF) <= 'F') ? (ptr[i] - 'A' + 0x0A)
  203. : 0x00);
  204. }
  205. return result;
  206. } /* hex2byte */
  207. /* *************************************************************************
  208. * hexfile_getrecord
  209. * ************************************************************************* */
  210. static int hexfile_getrecord(FILE *stream, struct ihex_record *record)
  211. {
  212. char *hexline = NULL;
  213. size_t size;
  214. ssize_t length = getline(&hexline, &size, stream);
  215. if (length == -1)
  216. {
  217. if (!feof(stream))
  218. {
  219. perror("hexfile_getrecord(): getline()");
  220. }
  221. return -1;
  222. }
  223. if (length < 12)
  224. {
  225. fprintf(stderr, "record too short (%ld)\n", length);
  226. free(hexline);
  227. return -1;
  228. }
  229. int pos = 0;
  230. if (hexline[pos] != ':')
  231. {
  232. fprintf(stderr, "invalid startcode\n");
  233. free(hexline);
  234. return -1;
  235. }
  236. pos++;
  237. uint8_t chksum = 0x00;
  238. record->byte_count = hex2byte(&hexline[pos]);
  239. chksum += record->byte_count;
  240. pos += 2;
  241. if (record->byte_count > 0)
  242. {
  243. record->data = malloc(record->byte_count);
  244. if (record->data == NULL)
  245. {
  246. perror("hexfile_getrecord(): malloc()");
  247. free(hexline);
  248. return -1;
  249. }
  250. }
  251. uint8_t hiaddr = hex2byte(&hexline[pos]);
  252. uint8_t loaddr = hex2byte(&hexline[pos +2]);
  253. record->address = (hiaddr << 8) + loaddr;
  254. chksum += hiaddr + loaddr;
  255. pos += 4;
  256. record->type = hex2byte(&hexline[pos]);
  257. chksum += record->type;
  258. pos += 2;
  259. int i;
  260. for (i = 0; i < record->byte_count; i++)
  261. {
  262. record->data[i] = hex2byte(&hexline[pos]);
  263. chksum += record->data[i];
  264. pos += 2;
  265. }
  266. record->chksum = hex2byte(&hexline[pos]);
  267. chksum += record->chksum;
  268. pos += 2;
  269. if (chksum != 0x00)
  270. {
  271. fprintf(stderr, "invalid checksum (0x%02X)\n", chksum);
  272. if (record->byte_count > 0)
  273. {
  274. free(record->data);
  275. }
  276. free(hexline);
  277. return -1;
  278. }
  279. free(hexline);
  280. return 0;
  281. } /* hexfile_getrecord */
  282. /* *************************************************************************
  283. * hexfile_putrecord
  284. * ************************************************************************* */
  285. static int hexfile_putrecord(FILE *stream, struct ihex_record *record)
  286. {
  287. uint8_t chksum = record->byte_count;
  288. chksum += (record->address >> 8) & 0xFF;
  289. chksum += (record->address & 0xFF);
  290. chksum += record->type;
  291. int i, len = 0;
  292. char buf[64];
  293. buf[0] = '\0';
  294. for (i = 0; i < record->byte_count; i++)
  295. {
  296. len += snprintf(buf + len, sizeof(buf) - len, "%02X", record->data[i]);
  297. chksum += record->data[i];
  298. }
  299. fprintf(stream, ":%02X%04X%02X%s%02X\n",
  300. record->byte_count,
  301. record->address,
  302. record->type,
  303. buf,
  304. (uint8_t)(0x100 - chksum));
  305. return -1;
  306. } /* hexfile_putrecord */
  307. /* *************************************************************************
  308. * hexfile_getsize
  309. * ************************************************************************* */
  310. static int hexfile_getsize(const char *filename, uint32_t *size)
  311. {
  312. /* unused parameter */
  313. (void)filename;
  314. *size = 0x10000;
  315. return 0;
  316. } /* hexfile_getsize */
  317. /* *************************************************************************
  318. * hexfile_read
  319. * ************************************************************************* */
  320. static int hexfile_read(const char *filename, struct databuf *dbuf)
  321. {
  322. FILE *stream = fopen(filename, "r");
  323. if (stream == NULL)
  324. {
  325. perror("hexfile_read(): fopen()");
  326. return -1;
  327. }
  328. while (1)
  329. {
  330. struct ihex_record record;
  331. memset(&record, 0x00, sizeof(struct ihex_record));
  332. int result = hexfile_getrecord(stream, &record);
  333. if (result == -1)
  334. {
  335. break;
  336. }
  337. if (record.type == 0x00)
  338. {
  339. if ((record.address > dbuf->size) ||
  340. (record.address + record.byte_count > dbuf->size)
  341. )
  342. {
  343. fprintf(stderr, "hexfile_read(): data out of bounds\n");
  344. break;
  345. }
  346. memcpy(&dbuf->data[record.address], record.data, record.byte_count);
  347. dbuf->length = record.address + record.byte_count;
  348. }
  349. }
  350. fclose(stream);
  351. return 0;
  352. } /* hexfile_read */
  353. /* *************************************************************************
  354. * hexfile_write
  355. * ************************************************************************* */
  356. static int hexfile_write(const char *filename, struct databuf *dbuf)
  357. {
  358. FILE *stream = fopen(filename, "w");
  359. if (stream == NULL)
  360. {
  361. perror("hexfile_write(): fopen()");
  362. return -1;
  363. }
  364. uint32_t i;
  365. uint32_t addr_min = dbuf->length;
  366. uint32_t addr_max = 0;
  367. for (i = 0; i < dbuf->length; i++)
  368. {
  369. if (dbuf->data[i] == 0xFF)
  370. {
  371. continue;
  372. }
  373. if (addr_min > i)
  374. {
  375. addr_min = i;
  376. }
  377. if (addr_max < i)
  378. {
  379. addr_max = i;
  380. }
  381. }
  382. if (addr_min >= addr_max)
  383. {
  384. addr_min = 0;
  385. addr_max = dbuf->length;
  386. }
  387. addr_min = addr_min & ~0x0F;
  388. addr_max = (addr_max + 0x0F) & ~0x0F;
  389. struct ihex_record record;
  390. for (i = addr_min; i < addr_max; i += 0x10)
  391. {
  392. record.byte_count = 0x10;
  393. record.address = i;
  394. record.type = 0x00;
  395. record.data = &dbuf->data[i];
  396. hexfile_putrecord(stream, &record);
  397. }
  398. record.byte_count = 0x00;
  399. record.address = addr_min;
  400. record.type = 0x01;
  401. record.data = NULL;
  402. hexfile_putrecord(stream, &record);
  403. fclose(stream);
  404. return 0;
  405. } /* hexfile_write */
  406. /* *************************************************************************
  407. * get_filetype
  408. * ************************************************************************* */
  409. static int get_filetype(const char *filename)
  410. {
  411. const char *ext = filename + (strlen(filename) -4);
  412. if (ext < filename)
  413. {
  414. return FILETYPE_UNKNOWN;
  415. }
  416. if (strncmp(ext, ".bin", 4) == 0)
  417. {
  418. return FILETYPE_BINARY;
  419. }
  420. if (strncmp(ext, ".hex", 4) == 0)
  421. {
  422. return FILETYPE_INTELHEX;
  423. }
  424. return FILETYPE_UNKNOWN;
  425. } /* get_filetype */
  426. /* *************************************************************************
  427. * file_getsize
  428. * ************************************************************************* */
  429. int file_getsize(const char *filename, uint32_t *size)
  430. {
  431. switch (get_filetype(filename))
  432. {
  433. case FILETYPE_BINARY:
  434. return binfile_getsize(filename, size);
  435. case FILETYPE_INTELHEX:
  436. return hexfile_getsize(filename, size);
  437. default:
  438. return -1;
  439. }
  440. } /* file_getsize */
  441. /* *************************************************************************
  442. * file_read
  443. * ************************************************************************* */
  444. int file_read(const char *filename, struct databuf *dbuf)
  445. {
  446. switch (get_filetype(filename))
  447. {
  448. case FILETYPE_BINARY:
  449. return binfile_read(filename, dbuf);
  450. case FILETYPE_INTELHEX:
  451. return hexfile_read(filename, dbuf);
  452. default:
  453. return -1;
  454. }
  455. } /* file_read */
  456. /* *************************************************************************
  457. * file_write
  458. * ************************************************************************* */
  459. int file_write(const char *filename, struct databuf *dbuf)
  460. {
  461. if (strncmp(filename, "-", 1) == 0)
  462. {
  463. dbuf_dump(dbuf);
  464. return 0;
  465. }
  466. switch (get_filetype(filename))
  467. {
  468. case FILETYPE_BINARY:
  469. return binfile_write(filename, dbuf);
  470. case FILETYPE_INTELHEX:
  471. return hexfile_write(filename, dbuf);
  472. default:
  473. return -1;
  474. }
  475. } /* file_write */