Shorten memory_ functions prefix to mem_ in memory.c
[emu8051.git] / src / common / hexfile.c
index c879c89..9fef693 100644 (file)
@@ -4,19 +4,7 @@
  * Copyright (C) 1999 Jonathan St-AndrĂ©
  * Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ * This file is released under the GPLv2
  */
 
 #if HAVE_CONFIG_H
@@ -26,6 +14,7 @@
 #include <unistd.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <stdbool.h>
 
 #if STDC_HEADERS
 #  include <string.h>
 #include "common.h"
 #include "memory.h"
 
+/* Maximum of 75 digits with 32-bytes data records. */
+#define HEXFILE_LINE_BUFFER_LEN 128
+
+static int asciihex2int_error;
+
 /* Convert integer to ASCII hex string. */
 void
 int2asciihex(int val, char *str, int width)
@@ -55,15 +49,21 @@ int
 asciihex2int(char *str)
 {
        int val;
+       int rc;
+
+       rc = sscanf(str, "%X", &val);
 
-       sscanf(str, "%X", &val);
+       if (rc == 0) {
+               log_err("ASCII to hex conversion failure");
+               asciihex2int_error = true;
+       }
 
        return val;
 }
 
 /* Convert an ascii string to an hexadecimal number. */
-unsigned int
-Ascii2Hex(char *istring, int length)
+static unsigned int
+asciihex2int_len(char *istring, int length)
 {
        unsigned int result = 0;
        int i, ascii_code;
@@ -77,7 +77,7 @@ Ascii2Hex(char *istring, int length)
                        ascii_code &= 0xDF;
 
                if ((ascii_code >= 0x30 && ascii_code <= 0x39) ||
-                    (ascii_code >= 0x41 && ascii_code <= 0x46)) {
+                   (ascii_code >= 0x41 && ascii_code <= 0x46)) {
                        ascii_code -= 0x30;
                        if (ascii_code > 9)
                                ascii_code -= 7;
@@ -85,22 +85,29 @@ Ascii2Hex(char *istring, int length)
                        result <<= 4;
                        result += ascii_code;
                } else {
-                       log_fail("Error converting ASCII string <%s> to hex"
-                                " (len=%d)", istring, length);
+                       log_err("ASCII to hex conversion failure");
+                       asciihex2int_error = true;
                }
        }
        return result;
 }
 
-void
-LoadHexFile(const char *filename)
+/*
+ * Return value:
+ *   true:  success
+ *   false: failure
+ */
+int
+hexfile_load(const char *filename)
 {
-       int i, j, RecLength, LoadOffset, RecType, Data, Checksum;
-
-#define LINE_BUFFER_LEN 256
+       int i, j, rec_len, load_offset, rec_type, data, checksum;
        FILE *fp;
        int status;
-       char line[LINE_BUFFER_LEN];
+       char line[HEXFILE_LINE_BUFFER_LEN];
+       int valid = false;
+       int line_num = 1;
+
+       log_debug("LoadHexFile");
 
        if (filename == NULL)
                log_fail("No file specified");
@@ -117,62 +124,71 @@ LoadHexFile(const char *filename)
           stored into the buffer.  A '\0'  is  stored after the last character
           in the buffer.
        */
-       while (fgets(line, LINE_BUFFER_LEN, fp) != NULL) {
+       while (fgets(line, HEXFILE_LINE_BUFFER_LEN, fp) != NULL) {
                i = 0;
-               Checksum = 0;
+               checksum = 0;
 
                if (line[i++] != ':') {
                        log_err("hexfile line not beginning with \":\"");
                        goto close_file;
                }
 
-               RecLength = Ascii2Hex(&line[i], 2);
+               rec_len = asciihex2int_len(&line[i], 2);
                i += 2;
-               Checksum += RecLength;
+               checksum += rec_len;
 
-               LoadOffset = Ascii2Hex(&line[i], 4);
-               Checksum += LoadOffset / 256;
-               Checksum += LoadOffset % 256;
+               load_offset = asciihex2int_len(&line[i], 4);
+               checksum += load_offset / 256;
+               checksum += load_offset % 256;
                i += 4;
 
-               RecType = Ascii2Hex(&line[i], 2);
+               rec_type = asciihex2int_len(&line[i], 2);
                i += 2;
-               Checksum += RecType;
-
-               if (RecType == 1) {
-                       Checksum += Ascii2Hex(&line[i], 2);
-                       Checksum &= 0x000000FF;
-
-                       if (Checksum) {
-                               log_err("hexfile invalid format");
-                               goto close_file;
-                       } else {
-                               /* OK */
-                               goto close_file;
+               checksum += rec_type;
+
+               if (rec_type == 0) {
+                       for (j = 0; j < rec_len; j++) {
+                               data = asciihex2int_len(&line[i], 2);
+                               mem_write8(PGM_MEM_ID,
+                                          (unsigned int) (load_offset + j),
+                                          (unsigned char) data);
+                               i += 2;
+                               checksum += data;
                        }
                }
 
-               for (j = 0; j < RecLength; j++) {
-                       Data = Ascii2Hex(&line[i], 2);
-                       memory_write8(PGM_MEM_ID,
-                                     (unsigned int)(LoadOffset + j),
-                                     (unsigned char)Data);
-                       i += 2;
-                       Checksum += Data;
-               }
-
-               RecType = Ascii2Hex(&line[i], 2);
-               Checksum += RecType;
-               Checksum &= 0x000000FF;
+               /* Read and add checksum value */
+               checksum += asciihex2int_len(&line[i], 2);
+               checksum &= 0x000000FF;
 
-               if (Checksum) {
+               if (asciihex2int_error) {
+                       log_err("hexfile parse error at line %d", line_num);
+                       goto close_file;
+               } else if (checksum) {
                        log_err("hexfile checksum mismatch");
                        goto close_file;
                }
+
+               if (rec_type == 0) {
+                       log_debug("hex record: data");
+               } else if (rec_type == 1) {
+                       log_debug("hex record: End Of File");
+                       valid = true;
+                       goto close_file;
+               } else {
+                       log_warn("hex record: Unsupported ($%02X)", rec_type);
+               }
+
+               line_num++;
        }
 
 close_file:
        status = fclose(fp);
        if (status != EXIT_SUCCESS)
                log_fail("Error closing hex file");
+
+       if (!valid)
+               log_err("Error parsing hex file");
+
+       return valid;
 }