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.

424 lines
10KB

  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. struct databuf * dbuf_alloc(uint32_t size)
  31. {
  32. struct databuf *dbuf = malloc(sizeof(struct databuf) + size);
  33. if (dbuf == NULL) {
  34. perror("dbuf_alloc");
  35. return NULL;
  36. }
  37. memset(dbuf->data, 0xFF, size);
  38. dbuf->size = size;
  39. dbuf->length = 0;
  40. return dbuf;
  41. }
  42. void dbuf_free(struct databuf *dbuf)
  43. {
  44. free(dbuf);
  45. }
  46. static void dbuf_dump(struct databuf *dbuf)
  47. {
  48. int pos = 0, oldskip = 0;
  49. while (pos < dbuf->length) {
  50. char buf[128];
  51. int j, i = 0;
  52. int skip = 1;
  53. for (j = 0; j < 16; j++) {
  54. if (pos + j < dbuf->length)
  55. i += sprintf(buf + i, "%02X", dbuf->data[pos + j]);
  56. else
  57. i += sprintf(buf + i, " ");
  58. if (j % 2)
  59. buf[i++] = ' ';
  60. }
  61. for (j = 0; j < 16; j++) {
  62. if (pos + j < dbuf->length) {
  63. unsigned char val = dbuf->data[pos + j];
  64. if (val >= 0x20 && val < 0x7F)
  65. buf[i++] = val;
  66. else
  67. buf[i++] = '.';
  68. if (val != 0xFF)
  69. skip = 0;
  70. } else {
  71. buf[i++] = ' ';
  72. }
  73. }
  74. if (pos == 0 || (pos + 16) >= dbuf->length || skip == 0) {
  75. buf[i++] = '\0';
  76. printf("%04X: %s\r\n", pos, buf);
  77. oldskip = 0;
  78. } else if (skip == 1 && oldskip == 0) {
  79. printf("****\n");
  80. oldskip = 1;
  81. }
  82. pos += 16;
  83. }
  84. }
  85. static int binfile_getsize(const char *filename, uint32_t *size)
  86. {
  87. int fd = open(filename, O_RDONLY);
  88. if (fd < 0) {
  89. perror("binfile_getsize(): open()");
  90. return -1;
  91. }
  92. struct stat filestat;
  93. if (fstat(fd, &filestat) < 0) {
  94. perror("binfile_getsize(): fstat()");
  95. close(fd);
  96. return -1;
  97. }
  98. *size = filestat.st_size;
  99. close(fd);
  100. return 0;
  101. }
  102. static int binfile_read(const char *filename, struct databuf *dbuf)
  103. {
  104. int fd = open(filename, O_RDONLY);
  105. if (fd < 0) {
  106. perror("binfile_read(): open()");
  107. return -1;
  108. }
  109. ssize_t readsize = read(fd, dbuf->data, dbuf->size);
  110. if (readsize <= 0) {
  111. perror("binfile_read(): read()");
  112. close(fd);
  113. return -1;
  114. }
  115. dbuf->length = readsize;
  116. close(fd);
  117. return 0;
  118. }
  119. static int binfile_write(const char *filename, struct databuf *dbuf)
  120. {
  121. int fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0644);
  122. if (fd < 0) {
  123. perror("binfile_write(): open()");
  124. return -1;
  125. }
  126. ssize_t writesize = write(fd, dbuf->data, dbuf->length);
  127. if (writesize != dbuf->length) {
  128. perror("binfile_write(): write()");
  129. close(fd);
  130. return -1;
  131. }
  132. close(fd);
  133. return 0;
  134. }
  135. struct ihex_record {
  136. uint8_t byte_count;
  137. uint16_t address;
  138. uint8_t type;
  139. uint8_t *data;
  140. uint8_t chksum;
  141. };
  142. static uint8_t hex2byte(const char *ptr)
  143. {
  144. int i;
  145. uint8_t result = 0;
  146. for (i = 0; i < 2; i++) {
  147. result <<= 4;
  148. result |= (ptr[i] >= '0' && ptr[i] <= '9') ? (ptr[i] - '0') :
  149. (((ptr[i] & 0xDF) >= 'A' && (ptr[i] & 0xDF) <= 'F') ? (ptr[i] - 'A' + 0x0A) :
  150. 0x00);
  151. }
  152. return result;
  153. }
  154. static int hexfile_getrecord(FILE *stream, struct ihex_record *record)
  155. {
  156. char *hexline = NULL;
  157. size_t size;
  158. ssize_t length = getline(&hexline, &size, stream);
  159. if (length == -1) {
  160. if (!feof(stream)) {
  161. perror("hexfile_getrecord(): getline()");
  162. }
  163. return -1;
  164. }
  165. if (length < 12) {
  166. fprintf(stderr, "record too short (%d)\n", length);
  167. free(hexline);
  168. return -1;
  169. }
  170. int pos = 0;
  171. if (hexline[pos] != ':') {
  172. fprintf(stderr, "invalid startcode\n");
  173. free(hexline);
  174. return -1;
  175. }
  176. pos++;
  177. uint8_t chksum = 0x00;
  178. record->byte_count = hex2byte(&hexline[pos]);
  179. chksum += record->byte_count;
  180. pos += 2;
  181. if (record->byte_count > 0) {
  182. record->data = malloc(record->byte_count);
  183. if (record->data == NULL) {
  184. perror("hexfile_getrecord(): malloc()");
  185. free(hexline);
  186. return -1;
  187. }
  188. }
  189. uint8_t hiaddr = hex2byte(&hexline[pos]);
  190. uint8_t loaddr = hex2byte(&hexline[pos +2]);
  191. record->address = (hiaddr << 8) + loaddr;
  192. chksum += hiaddr + loaddr;
  193. pos += 4;
  194. record->type = hex2byte(&hexline[pos]);
  195. chksum += record->type;
  196. pos += 2;
  197. int i;
  198. for (i = 0; i < record->byte_count; i++) {
  199. record->data[i] = hex2byte(&hexline[pos]);
  200. chksum += record->data[i];
  201. pos += 2;
  202. }
  203. record->chksum = hex2byte(&hexline[pos]);
  204. chksum += record->chksum;
  205. pos += 2;
  206. if (chksum != 0x00) {
  207. fprintf(stderr, "invalid checksum (0x%02X)\n", chksum);
  208. if (record->byte_count > 0)
  209. free(record->data);
  210. free(hexline);
  211. return -1;
  212. }
  213. free(hexline);
  214. return 0;
  215. }
  216. static int hexfile_putrecord(FILE *stream, struct ihex_record *record)
  217. {
  218. uint8_t chksum = record->byte_count;
  219. chksum += (record->address >> 8) & 0xFF;
  220. chksum += (record->address & 0xFF);
  221. chksum += record->type;
  222. int i, len = 0;
  223. char buf[64];
  224. buf[0] = '\0';
  225. for (i = 0; i < record->byte_count; i++) {
  226. len += snprintf(buf + len, sizeof(buf) - len, "%02X", record->data[i]);
  227. chksum += record->data[i];
  228. }
  229. fprintf(stream, ":%02X%04X%02X%s%02X\n", record->byte_count, record->address, record->type, buf, (uint8_t)(0x100 - chksum));
  230. return -1;
  231. }
  232. static int hexfile_getsize(const char *filename, uint32_t *size)
  233. {
  234. *size = 0x10000;
  235. return 0;
  236. }
  237. static int hexfile_read(const char *filename, struct databuf *dbuf)
  238. {
  239. FILE *stream = fopen(filename, "r");
  240. if (stream == NULL) {
  241. perror("hexfile_read(): fopen()");
  242. return -1;
  243. }
  244. while (1) {
  245. struct ihex_record record;
  246. memset(&record, 0x00, sizeof(struct ihex_record));
  247. int result = hexfile_getrecord(stream, &record);
  248. if (result == -1)
  249. break;
  250. if (record.type == 0x00) {
  251. if (record.address > dbuf->size || record.address + record.byte_count > dbuf->size) {
  252. fprintf(stderr, "hexfile_read(): data out of bounds\n");
  253. break;
  254. }
  255. memcpy(&dbuf->data[record.address], record.data, record.byte_count);
  256. dbuf->length = record.address + record.byte_count;
  257. }
  258. }
  259. fclose(stream);
  260. return 0;
  261. }
  262. static int hexfile_write(const char *filename, struct databuf *dbuf)
  263. {
  264. FILE *stream = fopen(filename, "w");
  265. if (stream == NULL) {
  266. perror("hexfile_write(): fopen()");
  267. return -1;
  268. }
  269. int i;
  270. int addr_min = dbuf->length;
  271. int addr_max = 0;
  272. for (i = 0; i < dbuf->length; i++) {
  273. if (dbuf->data[i] == 0xFF)
  274. continue;
  275. if (addr_min > i)
  276. addr_min = i;
  277. if (addr_max < i)
  278. addr_max = i;
  279. }
  280. addr_min = addr_min & ~0x0F;
  281. addr_max = (addr_max + 0x0F) & ~0x0F;
  282. struct ihex_record record;
  283. for (i = addr_min; i < addr_max; i += 0x10) {
  284. record.byte_count = 0x10;
  285. record.address = i;
  286. record.type = 0x00;
  287. record.data = &dbuf->data[i];
  288. hexfile_putrecord(stream, &record);
  289. }
  290. record.byte_count = 0x00;
  291. record.address = addr_min;
  292. record.type = 0x01;
  293. record.data = NULL;
  294. hexfile_putrecord(stream, &record);
  295. fclose(stream);
  296. return 0;
  297. }
  298. static int get_filetype(const char *filename)
  299. {
  300. const char *ext = filename + (strlen(filename) -4);
  301. if (ext < filename)
  302. return FILETYPE_UNKNOWN;
  303. if (strncmp(ext, ".bin", 4) == 0)
  304. return FILETYPE_BINARY;
  305. if (strncmp(ext, ".hex", 4) == 0)
  306. return FILETYPE_INTELHEX;
  307. return FILETYPE_UNKNOWN;
  308. }
  309. int file_getsize(const char *filename, uint32_t *size)
  310. {
  311. switch (get_filetype(filename)) {
  312. case FILETYPE_BINARY:
  313. return binfile_getsize(filename, size);
  314. case FILETYPE_INTELHEX:
  315. return hexfile_getsize(filename, size);
  316. default:
  317. return -1;
  318. }
  319. }
  320. int file_read(const char *filename, struct databuf *dbuf)
  321. {
  322. switch (get_filetype(filename)) {
  323. case FILETYPE_BINARY:
  324. return binfile_read(filename, dbuf);
  325. case FILETYPE_INTELHEX:
  326. return hexfile_read(filename, dbuf);
  327. default:
  328. return -1;
  329. }
  330. }
  331. int file_write(const char *filename, struct databuf *dbuf)
  332. {
  333. if (strncmp(filename, "-", 1) == 0) {
  334. dbuf_dump(dbuf);
  335. return 0;
  336. }
  337. switch (get_filetype(filename)) {
  338. case FILETYPE_BINARY:
  339. return binfile_write(filename, dbuf);
  340. case FILETYPE_INTELHEX:
  341. return hexfile_write(filename, dbuf);
  342. default:
  343. return -1;
  344. }
  345. }