fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
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}