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.

568 lines
14KB

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