-
Notifications
You must be signed in to change notification settings - Fork 8
/
cbin.c
152 lines (124 loc) · 3.56 KB
/
cbin.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "cbin.h"
typedef struct cbin_state {
const char* name;
FILE *fp;
int errored;
int finished;
int idx;
int sector;
uint8_t checksum_sum;
uint8_t buffer[SECTOR_SIZE];
struct cbin_record record;
} cbin_state;
unsigned cbin_finished(cbin_state* cbin) {
return !cbin->errored && cbin->finished;
}
unsigned cbin_errored(cbin_state* cbin) {
return cbin->errored;
}
// Print common error message and mark cbin as errored
void cbin_error(cbin_state* cbin) {
size_t file_offset = cbin->sector * SECTOR_SIZE + cbin->sector;
fprintf(stderr, " at sector %i + %x (file offset: 0x%04zx)\n",
cbin->sector, cbin->idx, file_offset);
fprintf(stderr, "\n%s: centurion binary format load failed\n",
cbin->name);
cbin->errored = 1;
}
static uint8_t cbin_read8(cbin_state* cbin) {
if (cbin->idx+1 > SECTOR_SIZE) {
fprintf(stderr, "sector overrun");
cbin_error(cbin);
return 0;
}
uint8_t byte = cbin->buffer[cbin->idx++];
cbin->checksum_sum += byte;
return byte;
}
static uint16_t cbin_read16(cbin_state* cbin) {
return (cbin_read8(cbin) << 8) | cbin_read8(cbin);
}
void cbin_next_sector(cbin_state* cbin) {
if (cbin->fp == NULL)
return;
cbin->sector++;
cbin->idx = 0;
size_t read_len = fread(cbin->buffer, 1, SECTOR_SIZE, cbin->fp);
if (read_len != SECTOR_SIZE) {
if (read_len == 0) {
perror("fread");
fprintf(stderr, "read error");
} else {
fprintf(stderr, "sector too small, only got %zu bytes", read_len);
}
cbin_error(cbin);
}
}
struct cbin_state* cbin_open(const char *name) {
// create state object
cbin_state* state = malloc(sizeof(cbin_state));
assert(state != NULL);
memset(state, 0, sizeof(cbin_state));
// Open file
state->fp = fopen(name, "rb");
if (state->fp == NULL) {
perror("fopen");
cbin_error(state);
}
// Setup initial state
state->name = name;
state->sector = -1; // nextsector will increment
cbin_next_sector(state);
return state;
}
void cbin_free(cbin_state* cbin) {
assert(cbin != NULL);
if (cbin->fp) {
fclose(cbin->fp);
}
free(cbin);
}
struct cbin_record* cbin_next_record(cbin_state* cbin) {
if (cbin->errored)
return NULL;
while(1) {
cbin->checksum_sum = 0;
cbin->record.type = cbin_read8(cbin);
if (cbin->record.type == CBIN_END_FILE) {
cbin->finished = 1;
return NULL;
}
if (cbin->record.type == CBIN_END_SECTOR) {
cbin_next_sector(cbin);
continue;
}
uint8_t len = cbin_read8(cbin);
cbin->record.len = len;
cbin->record.addr = cbin_read16(cbin);
if((cbin->idx + len + 1) > SECTOR_SIZE) {
fprintf(stderr, "record too big, %i bytes", len);
cbin_error(cbin);
return NULL;
}
// copy data;
for (int i = 0; i < len; i++) {
// reading calculates checksum
cbin->record.data[i] = cbin_read8(cbin);
}
uint8_t checksum = -cbin->checksum_sum; // Negated
uint8_t expected = cbin_read8(cbin);
if (expected != checksum) {
fprintf(stderr, "checksum error. Got %02x, Expected %02x",
checksum, expected);
cbin_error(cbin);
}
if (cbin->errored)
return NULL;
return &cbin->record;
}
}