fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
1/*****************************************************************************
2 * pce *
3 *****************************************************************************/
4
5/*****************************************************************************
6 * File name: src/lib/ciff.c *
7 * Created: 2022-02-12 by Hampa Hug <hampa@hampa.ch> *
8 * Copyright: (C) 2022 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 <config.h>
24
25#include <lib/ciff.h>
26#include <lib/endian.h>
27
28#include <stdint.h>
29#include <stdio.h>
30
31
32#define CIFF_CRC_POLY 0x1edc6f41
33
34
35static char crc_tab_ok = 0;
36static uint32_t crc_tab[256];
37
38
39static
40void ciff_init_crc_tab (void)
41{
42 unsigned i, j;
43 uint32_t val;
44
45 if (crc_tab_ok) {
46 return;
47 }
48
49 for (i = 0; i < 256; i++) {
50 val = (uint32_t) i << 24;
51
52 for (j = 0; j < 8; j++) {
53 if (val & 0x80000000) {
54 val = (val << 1) ^ CIFF_CRC_POLY;
55 }
56 else {
57 val = val << 1;
58 }
59 }
60
61 crc_tab[i] = val;
62 }
63
64 crc_tab_ok = 1;
65}
66
67static
68void ciff_crc (ciff_t *ciff, const void *buf, uint32_t cnt)
69{
70 uint32_t crc;
71 const uint8_t *src;
72
73 if (crc_tab_ok == 0) {
74 ciff_init_crc_tab();
75 }
76
77 src = buf;
78 crc = ciff->crc;
79
80 while (cnt-- > 0) {
81 crc = (crc << 8) ^ crc_tab[((crc >> 24) ^ *(src++)) & 0xff];
82 }
83
84 ciff->crc = crc & 0xffffffff;
85}
86
87void ciff_init (ciff_t *ciff, FILE *fp, int use_crc)
88{
89 ciff->fp = fp;
90
91 ciff->crc = 0;
92
93 ciff->ckid = 0;
94 ciff->cksize = 0;
95
96 ciff->size = 0;
97
98 ciff->in_chunk = 0;
99 ciff->use_crc = (use_crc != 0);
100 ciff->crc_error = 0;
101}
102
103void ciff_free (ciff_t *ciff)
104{
105}
106
107int ciff_read (ciff_t *ciff, void *buf, uint32_t cnt)
108{
109 uint32_t ret;
110
111 if (cnt > ciff->size) {
112 return (1);
113 }
114
115 ret = fread (buf, 1, cnt, ciff->fp);
116
117 ciff->size -= ret;
118
119 if (ciff->use_crc) {
120 ciff_crc (ciff, buf, ret);
121 }
122
123 return (ret != cnt);
124}
125
126int ciff_read_id (ciff_t *ciff)
127{
128 unsigned char buf[8];
129
130 if (ciff->in_chunk) {
131 if (ciff_read_crc (ciff)) {
132 return (1);
133 }
134 }
135
136 ciff->crc = 0;
137 ciff->size = 8;
138
139 if (ciff_read (ciff, buf, 8)) {
140 return (1);
141 }
142
143 ciff->ckid = get_uint32_be (buf, 0);
144 ciff->cksize = get_uint32_be (buf, 4);
145
146 ciff->size = ciff->cksize;
147
148 ciff->in_chunk = 1;
149
150 return (0);
151}
152
153int ciff_read_crc (ciff_t *ciff)
154{
155 unsigned cnt;
156 uint32_t crc;
157 unsigned char buf[256];
158
159 while (ciff->size > 0) {
160 cnt = (ciff->size < 256) ? ciff->size : 256;
161
162 if (ciff_read (ciff, buf, cnt)) {
163 return (1);
164 }
165 }
166
167 if (ciff->use_crc) {
168 crc = ciff->crc;
169 ciff->size = 4;
170
171 if (ciff_read (ciff, buf, 4)) {
172 return (1);
173 }
174
175 if (get_uint32_be (buf, 0) != crc) {
176 ciff->crc_error = 1;
177 return (1);
178 }
179 }
180
181 ciff->in_chunk = 0;
182
183 return (0);
184}
185
186int ciff_read_chunk (ciff_t *ciff, void *buf, uint32_t size)
187{
188 if (ciff_read (ciff, buf, size)) {
189 return (1);
190 }
191
192 if (ciff_read_crc (ciff)) {
193 return (1);
194 }
195
196 return (0);
197}
198
199int ciff_write (ciff_t *ciff, const void *buf, uint32_t cnt)
200{
201 uint32_t ret;
202
203 if (cnt > ciff->size) {
204 return (1);
205 }
206
207 ret = fwrite (buf, 1, cnt, ciff->fp);
208
209 ciff->size -= ret;
210
211 if (ciff->use_crc) {
212 ciff_crc (ciff, buf, cnt);
213 }
214
215 return (ret != cnt);
216}
217
218int ciff_write_id (ciff_t *ciff, uint32_t ckid, uint32_t size)
219{
220 unsigned char buf[8];
221
222 if (ciff->in_chunk) {
223 if (ciff_write_crc (ciff)) {
224 return (1);
225 }
226 }
227
228 ciff->ckid = ckid;
229 ciff->cksize = size;
230
231 set_uint32_be (buf, 0, ckid);
232 set_uint32_be (buf, 4, size);
233
234 ciff->crc = 0;
235 ciff->size = 8;
236
237 if (ciff_write (ciff, buf, 8)) {
238 return (1);
239 }
240
241 ciff->size = size;
242
243 ciff->in_chunk = 1;
244
245 return (0);
246}
247
248int ciff_write_crc (ciff_t *ciff)
249{
250 unsigned char buf[4];
251
252 if (ciff->size != 0) {
253 return (1);
254 }
255
256 if (ciff->use_crc) {
257 set_uint32_be (buf, 0, ciff->crc);
258
259 ciff->size = 4;
260
261 if (ciff_write (ciff, buf, 4)) {
262 return (1);
263 }
264 }
265
266 ciff->in_chunk = 0;
267
268 return (0);
269}
270
271int ciff_write_chunk (ciff_t *ciff, uint32_t ckid, const void *buf, uint32_t size)
272{
273 if (ciff_write_id (ciff, ckid, size)) {
274 return (1);
275 }
276
277 if (ciff_write (ciff, buf, size)) {
278 return (1);
279 }
280
281 if (ciff_write_crc (ciff)) {
282 return (1);
283 }
284
285 return (0);
286}