fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
at master 254 lines 5.0 kB view raw
1/***************************************************************************** 2 * pce * 3 *****************************************************************************/ 4 5/***************************************************************************** 6 * File name: src/lib/mhex.c * 7 * Created: 2020-05-02 by Hampa Hug <hampa@hampa.ch> * 8 * Copyright: (C) 2020 Hampa Hug <hampa@hampa.ch> * 9 *****************************************************************************/ 10 11/***************************************************************************** 12 * This program is free software. You can redistribute it and / or modify it * 13 * under the terms of the GNU General Public License version 2 as published * 14 * by the Free Software Foundation. * 15 * * 16 * This program is distributed in the hope that it will be useful, but * 17 * WITHOUT ANY WARRANTY, without even the implied warranty of * 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * 19 * Public License for more details. * 20 *****************************************************************************/ 21 22 23#include <stdlib.h> 24#include <stdio.h> 25 26#include "mhex.h" 27 28 29static 30int mhex_skip_line (FILE *fp) 31{ 32 int c; 33 34 while ((c = fgetc (fp)) != EOF) { 35 if ((c == 0x0a) || (c == 0x0d)) { 36 return (0); 37 } 38 } 39 40 return (1); 41} 42 43static 44unsigned mhex_get_cksum (unsigned addr, const unsigned char *buf, unsigned cnt) 45{ 46 unsigned val; 47 48 val = (addr & 0xff) + ((addr >> 8) & 0xff); 49 val += cnt & 0xff; 50 51 while (cnt-- > 0) { 52 val += *(buf++) & 0xff; 53 } 54 55 return (val & 0xffff); 56} 57 58static 59int mhex_read_hex (FILE *fp, unsigned char *buf, unsigned cnt) 60{ 61 int c; 62 unsigned i, j, s; 63 64 cnt *= 2; 65 66 for (i = 0; i < cnt; i++) { 67 if ((c = fgetc (fp)) == EOF) { 68 return (1); 69 } 70 71 j = i >> 1; 72 s = (~i & 1) << 2; 73 74 buf[j] &= 0xf0 << s; 75 76 if ((c >= '0') && (c <= '9')) { 77 buf[j] |= (c - '0') << s; 78 } 79 else if ((c >= 'A') && (c <= 'F')) { 80 buf[j] |= (c - 'A' + 10) << s; 81 } 82 else if ((c >= 'a') && (c <= 'f')) { 83 buf[j] |= (c - 'a' + 10) << s; 84 } 85 else { 86 return (1); 87 } 88 } 89 90 return (0); 91} 92 93static 94int mhex_read_record (FILE *fp, unsigned *addr, unsigned char *buf, unsigned *cnt, int *check) 95{ 96 int c; 97 unsigned ck; 98 unsigned char tmp[2]; 99 100 while ((c = fgetc (fp)) != ';') { 101 if (c == EOF) { 102 return (1); 103 } 104 105 if ((c != 0x0a) && (c != 0x0d)) { 106 mhex_skip_line (fp); 107 } 108 } 109 110 if (mhex_read_hex (fp, tmp, 1)) { 111 return (1); 112 } 113 114 *cnt = tmp[0]; 115 116 if (mhex_read_hex (fp, tmp, 2)) { 117 return (1); 118 } 119 120 *addr = ((tmp[0] & 0xff) << 8) | (tmp[1] & 0xff); 121 122 if (mhex_read_hex (fp, buf, *cnt)) { 123 return (1); 124 } 125 126 if (mhex_read_hex (fp, tmp, 2)) { 127 return (1); 128 } 129 130 ck = ((tmp[0] & 0xff) << 8) | (tmp[1] & 0xff); 131 132 *check = (mhex_get_cksum (*addr, buf, *cnt) != ck); 133 134 mhex_skip_line (fp); 135 136 return (0); 137} 138 139int mhex_load_fp (FILE *fp, void *ext, mhex_set_f set) 140{ 141 int check; 142 unsigned i, addr, cnt, rcnt; 143 unsigned char buf[256]; 144 145 rcnt = 0; 146 147 while (1) { 148 if (mhex_read_record (fp, &addr, buf, &cnt, &check)) { 149 break; 150 } 151 152 rcnt += 1; 153 154 if (check) { 155 return (1); 156 } 157 158 if (cnt == 0) { 159 if ((addr + 1) != rcnt) { 160 return (1); 161 } 162 163 rcnt = 0; 164 } 165 166 for (i = 0; i < cnt; i++) { 167 set (ext, addr + i, buf[i]); 168 } 169 } 170 171 if (rcnt > 0) { 172 return (1); 173 } 174 175 return (0); 176} 177 178int mhex_load (const char *fname, void *ext, mhex_set_f set) 179{ 180 int r; 181 FILE *fp; 182 183 if ((fp = fopen (fname, "rb")) == NULL) { 184 return (1); 185 } 186 187 r = mhex_load_fp (fp, ext, set); 188 189 fclose (fp); 190 191 return (r); 192} 193 194static 195void mhex_write_record (FILE *fp, unsigned addr, const unsigned char *buf, unsigned cnt) 196{ 197 unsigned ck; 198 199 ck = mhex_get_cksum (addr, buf, cnt); 200 201 fprintf (fp, ";%02X%04X", cnt & 0xff, addr & 0xffff); 202 203 while (cnt-- > 0) { 204 fprintf (fp, "%02X", *(buf++)); 205 } 206 207 fprintf (fp, "%04X\n", ck & 0xffff); 208} 209 210int mhex_save_fp (FILE *fp, unsigned long base, unsigned addr, unsigned size, void *ext, mhex_get_f get) 211{ 212 unsigned i, cnt, rcnt; 213 unsigned char buf[16]; 214 215 rcnt = 0; 216 217 while (size > 0) { 218 cnt = (size < 16) ? size : 16; 219 220 if (((addr + cnt) & 0xffff) < (addr & 0xffff)) { 221 cnt = -addr & 0xffff; 222 } 223 224 for (i = 0; i < cnt; i++) { 225 buf[i] = get (ext, base + ((addr + i) & 0xffff)); 226 } 227 228 mhex_write_record (fp, addr, buf, cnt); 229 230 rcnt += 1; 231 addr += cnt; 232 size -= cnt; 233 } 234 235 mhex_write_record (fp, rcnt, NULL, 0); 236 237 return (0); 238} 239 240int mhex_save (const char *fname, unsigned long base, unsigned addr, unsigned size, void *ext, mhex_get_f set) 241{ 242 int r; 243 FILE *fp; 244 245 if ((fp = fopen (fname, "wb")) == NULL) { 246 return (1); 247 } 248 249 r = mhex_save_fp (fp, base, addr, size, ext, set); 250 251 fclose (fp); 252 253 return (r); 254}