fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
at master 382 lines 6.8 kB view raw
1/***************************************************************************** 2 * pce * 3 *****************************************************************************/ 4 5/***************************************************************************** 6 * File name: src/lib/srec.c * 7 * Created: 2005-03-28 by Hampa Hug <hampa@hampa.ch> * 8 * Copyright: (C) 2005-2013 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#include <string.h> 26 27#include "srec.h" 28 29 30typedef struct { 31 unsigned char type; 32 unsigned char cnt; 33 unsigned long addr; 34 unsigned asize; 35 unsigned char data[256]; 36 unsigned char cksum; 37} record_t; 38 39 40static unsigned srec_asize[16] = { 41 2, 2, 3, 4, 2, 2, 2, 4, 42 3, 2, 2, 2, 2, 2, 2, 2 43}; 44 45 46static 47int srec_skip_line (FILE *fp) 48{ 49 int c; 50 51 while (1) { 52 c = fgetc (fp); 53 54 if (c == EOF) { 55 return (1); 56 } 57 58 if ((c == 0x0a) || (c == 0x0d)) { 59 return (0); 60 } 61 } 62 63 return (0); 64} 65 66static 67int srec_get_hex4 (FILE *fp, unsigned char *val) 68{ 69 int c; 70 71 c = fgetc (fp); 72 73 if ((c >= '0') && (c <= '9')) { 74 *val = c - '0'; 75 } 76 else if ((c >= 'A') && (c <= 'F')) { 77 *val = c - 'A' + 10; 78 } 79 else if ((c >= 'a') && (c <= 'f')) { 80 *val = c - 'a' + 10; 81 } 82 else { 83 return (1); 84 } 85 86 return (0); 87} 88 89static 90int srec_get_hex8 (FILE *fp, unsigned char *val) 91{ 92 unsigned char v1, v2; 93 94 if (srec_get_hex4 (fp, &v1) || srec_get_hex4 (fp, &v2)) { 95 return (1); 96 } 97 98 *val = ((v1 & 0x0f) << 4) | (v2 & 0x0f); 99 100 return (0); 101} 102 103static 104void srec_set_hex4 (FILE *fp, unsigned val) 105{ 106 val &= 0x0f; 107 val += (val <= 9) ? '0' : ('A' - 10); 108 109 fputc (val, fp); 110} 111 112static 113void srec_set_hex8 (FILE *fp, unsigned val) 114{ 115 srec_set_hex4 (fp, (val >> 4) & 0x0f); 116 srec_set_hex4 (fp, val & 0x0f); 117} 118 119static 120unsigned char srec_get_cksum (record_t *rec) 121{ 122 unsigned i; 123 unsigned char ck; 124 125 ck = (rec->cnt + rec->asize + 1) & 0xff; 126 ck += rec->addr & 0xff; 127 ck += (rec->addr >> 8) & 0xff; 128 ck += (rec->addr >> 16) & 0xff; 129 ck += (rec->addr >> 24) & 0xff; 130 131 for (i = 0; i < rec->cnt; i++) { 132 ck += rec->data[i]; 133 } 134 135 ck = ~ck & 0xff; 136 137 return (ck); 138} 139 140static 141void srec_init_record (record_t *rec, unsigned type, unsigned cnt, unsigned long addr) 142{ 143 rec->type = type; 144 rec->cnt = cnt; 145 rec->addr = addr; 146 147 if (type < 16) { 148 rec->asize = srec_asize[type]; 149 } 150 else { 151 rec->asize = 2; 152 } 153} 154 155static 156int srec_get_record (FILE *fp, record_t *rec) 157{ 158 unsigned i; 159 int c; 160 unsigned char addr; 161 unsigned char type; 162 163 while (1) { 164 c = fgetc (fp); 165 166 if (c == EOF) { 167 return (1); 168 } 169 170 if (c == 'S') { 171 if (srec_get_hex4 (fp, &type) == 0) { 172 break; 173 } 174 } 175 176 if ((c != 0x0a) && (c != 0x0d)) { 177 srec_skip_line (fp); 178 } 179 } 180 181 rec->type = type; 182 rec->asize = srec_asize[type]; 183 184 if (srec_get_hex8 (fp, &rec->cnt)) { 185 return (1); 186 } 187 188 if (rec->cnt < (rec->asize + 1)) { 189 return (1); 190 } 191 192 rec->cnt -= rec->asize + 1; 193 rec->addr = 0; 194 195 for (i = 0; i < rec->asize; i++) { 196 if (srec_get_hex8 (fp, &addr)) { 197 return (1); 198 } 199 rec->addr = (rec->addr << 8) | (addr & 0xff); 200 } 201 202 for (i = 0; i < rec->cnt; i++) { 203 if (srec_get_hex8 (fp, &rec->data[i])) { 204 return (1); 205 } 206 } 207 208 if (srec_get_hex8 (fp, &rec->cksum)) { 209 return (1); 210 } 211 212 srec_skip_line (fp); 213 214 return (0); 215} 216 217static 218void srec_set_record (FILE *fp, record_t *rec) 219{ 220 unsigned i; 221 222 rec->cksum = srec_get_cksum (rec); 223 224 fputc ('S', fp); 225 226 srec_set_hex4 (fp, rec->type); 227 srec_set_hex8 (fp, rec->cnt + rec->asize + 1); 228 229 for (i = 0; i < rec->asize; i++) { 230 srec_set_hex8 (fp, 231 (rec->addr >> (8 * (rec->asize - i - 1))) & 0xff 232 ); 233 } 234 235 for (i = 0; i < rec->cnt; i++) { 236 srec_set_hex8 (fp, rec->data[i]); 237 } 238 239 srec_set_hex8 (fp, rec->cksum); 240 241 fputs ("\n", fp); 242} 243 244static 245void srec_set_hdr (FILE *fp, const char *name) 246{ 247 unsigned cnt; 248 record_t rec; 249 250 cnt = strlen (name); 251 252 if (cnt > 20) { 253 cnt = 20; 254 } 255 256 srec_init_record (&rec, 0, cnt, 0); 257 258 memcpy (rec.data, name, cnt); 259 260 srec_set_record (fp, &rec); 261} 262 263static 264void srec_set_end (FILE *fp, unsigned long saddr) 265{ 266 record_t rec; 267 268 if (saddr & 0xff000000) { 269 srec_init_record (&rec, 7, 0, saddr); 270 } 271 else if (saddr & 0xffff0000) { 272 srec_init_record (&rec, 8, 0, saddr); 273 } 274 else { 275 srec_init_record (&rec, 9, 0, saddr); 276 } 277 278 srec_set_record (fp, &rec); 279} 280 281int srec_load_fp (FILE *fp, void *ext, srec_set_f set) 282{ 283 unsigned i; 284 record_t rec; 285 286 while (1) { 287 if (srec_get_record (fp, &rec)) { 288 return (0); 289 } 290 291 if (rec.cksum != srec_get_cksum (&rec)) { 292 return (1); 293 } 294 295 if (rec.type == 0) { 296 /* header record */ 297 ; 298 } 299 else if ((rec.type == 1) || (rec.type == 2) || (rec.type == 3)) { 300 for (i = 0; i < rec.cnt; i++) { 301 set (ext, rec.addr + i, rec.data[i]); 302 } 303 } 304 else if (rec.type == 5) { 305 /* record count record */ 306 ; 307 } 308 else if ((rec.type == 7) || (rec.type == 8) || (rec.type == 9)) { 309 /* end record */ 310 return (0); 311 } 312 } 313 314 return (0); 315} 316 317int srec_load (const char *fname, void *ext, srec_set_f set) 318{ 319 int r; 320 FILE *fp; 321 322 fp = fopen (fname, "rb"); 323 if (fp == NULL) { 324 return (1); 325 } 326 327 r = srec_load_fp (fp, ext, set); 328 329 fclose (fp); 330 331 return (r); 332} 333 334int srec_save_start (FILE *fp, const char *name) 335{ 336 srec_set_hdr (fp, name); 337 338 return (0); 339} 340 341int srec_save (FILE *fp, unsigned long base, unsigned long size, void *ext, srec_get_f get) 342{ 343 unsigned i; 344 record_t rec; 345 346 while (size > 0) { 347 rec.cnt = (size < 16) ? size : 16; 348 349 if (base & 0xff000000) { 350 rec.type = 3; 351 rec.asize = 4; 352 } 353 else if (base & 0xffff0000) { 354 rec.type = 2; 355 rec.asize = 3; 356 } 357 else { 358 rec.type = 1; 359 rec.asize = 2; 360 } 361 362 rec.addr = base & 0xffffffff; 363 364 for (i = 0; i < rec.cnt; i++) { 365 rec.data[i] = get (ext, rec.addr + i); 366 } 367 368 srec_set_record (fp, &rec); 369 370 base += rec.cnt; 371 size -= rec.cnt; 372 } 373 374 return (0); 375} 376 377int srec_save_done (FILE *fp) 378{ 379 srec_set_end (fp, 0); 380 381 return (0); 382}