3 --- src/gens/util/chd.c.orig 2004-08-15 11:35:14.000000000 +0200
4 +++ src/gens/util/chd.c
7 + NiH: chd.c,v 1.6 2004/06/25 23:31:08 dillo Exp
9 + chd.c -- accessing chd files
10 + Copyright (C) 2004 Dieter Baron and Thomas Klausner
12 + This file is part of ckmame, a program to check rom sets for MAME.
13 + The authors can be contacted at <nih@giga.or.at>
15 + This program is free software; you can redistribute it and/or modify
16 + it under the terms of the GNU General Public License, version 2, as
17 + published by the Free Software Foundation.
19 + This program is distributed in the hope that it will be useful,
20 + but WITHOUT ANY WARRANTY; without even the implied warranty of
21 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 + GNU General Public License for more details.
24 + You should have received a copy of the GNU General Public License
25 + along with this program; if not, write to the Free Software
26 + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
40 +#define MAX_HEADERLEN 120 /* maximum header length */
41 +#define TAG "MComprHD"
42 +#define TAG_LEN 8 /* length of tag */
43 +#define TAG_AND_LEN 12 /* length of tag + header length */
45 +#define MAP_ENTRY_SIZE_V12 8 /* size of map entry, versions 1 & 2 */
46 +#define MAP_ENTRY_SIZE_V3 16 /* size of map entry, version 3 */
48 +#define GET_LONG(b) (b+=4,((b)[-4]<<24)|((b)[-3]<<16)|((b)[-2]<<8)|(b)[-1])
49 +#define GET_QUAD(b) (b+=8,((uint64_t)(b)[-8]<<56)|((uint64_t)(b)[-7]<<48) \
50 + |((uint64_t)(b)[-6]<<40)|((uint64_t)(b)[-5]<<32) \
51 + |((uint64_t)(b)[-4]<<24)|((uint64_t)(b)[-3]<<16) \
52 + |((uint64_t)(b)[-2]<<8)|((uint64_t)(b)[-1]))
53 +#define GET_SHORT(b) (b+=2,((b)[-2]<<8)|(b)[-1])
55 +static int read_header(struct chd *);
56 +static int read_map(struct chd *);
61 +chd_close(struct chd *chd)
74 +chd_open(const char *name, int *errp)
79 + if ((f=fopen(name, "rb")) == NULL) {
81 + *errp = CHD_ERR_OPEN;
85 + if ((chd=malloc(sizeof(*chd))) == NULL) {
87 + *errp = CHD_ERR_NOMEM;
91 + if ((chd->name=strdup(name)) == NULL) {
93 + *errp = CHD_ERR_NOMEM;
103 + if (read_header(chd) < 0) {
105 + *errp = chd->error;
116 +chd_read_hunk(struct chd *chd, int idx, char *b)
120 + if (idx < 0 || idx > chd->total_hunks) {
121 + chd->error = CHD_ERR_INVAL;
125 + if (chd->map == NULL) {
126 + if (read_map(chd) < 0)
130 + if (chd->map[idx].length > chd->hunk_len) {
131 + chd->error = CHD_ERR_NOTSUP;
135 + switch (chd->map[idx].flags & CHD_MAP_TYPE_MASK) {
136 + case CHD_MAP_TYPE_COMPRESSED:
137 + /* XXX: CHD_COMP_NONE? */
138 + if (chd->compression != CHD_COMP_ZLIB
139 + && chd->compression != CHD_COMP_ZLIB_PLUS) {
140 + chd->error = CHD_ERR_NOTSUP;
144 + if (chd->buf == NULL) {
145 + if ((chd->buf=malloc(chd->hunk_len)) == NULL) {
146 + chd->error = CHD_ERR_NOMEM;
149 + chd->z.avail_in = 0;
150 + chd->z.zalloc = Z_NULL;
151 + chd->z.zfree = Z_NULL;
152 + chd->z.opaque = NULL;
153 + err = inflateInit2(&chd->z, -MAX_WBITS);
156 + err = inflateReset(&chd->z);
158 + chd->error = CHD_ERR_ZLIB;
162 + if (fseek(chd->f, chd->map[idx].offset, SEEK_SET) == -1) {
163 + chd->error = CHD_ERR_SEEK;
166 + if ((n=fread(chd->buf, 1, chd->map[idx].length, chd->f)) < 0) {
167 + chd->error = CHD_ERR_READ;
171 + chd->z.next_in = chd->buf;
172 + chd->z.avail_in = n;
173 + chd->z.next_out = b;
174 + chd->z.avail_out = chd->hunk_len;
175 + /* XXX: should use Z_FINISH, but that returns Z_BUF_ERROR */
176 + if ((err=inflate(&chd->z, 0)) != Z_OK && err != Z_STREAM_END) {
177 + chd->error = CHD_ERR_ZLIB;
180 + /* XXX: chd->z.avail_out should be 0 */
181 + n = chd->hunk_len - chd->z.avail_out;
184 + case CHD_MAP_TYPE_UNCOMPRESSED:
185 + if (fseek(chd->f, chd->map[idx].offset, SEEK_SET) == -1) {
186 + chd->error = CHD_ERR_SEEK;
189 + /* XXX: use chd->hunk_len instead? */
190 + if ((n=fread(b, 1, chd->map[idx].length, chd->f)) < 0) {
191 + chd->error = CHD_ERR_READ;
196 + case CHD_MAP_TYPE_MINI:
197 + b[0] = (chd->map[idx].offset >> 56) & 0xff;
198 + b[1] = (chd->map[idx].offset >> 48) & 0xff;
199 + b[2] = (chd->map[idx].offset >> 40) & 0xff;
200 + b[3] = (chd->map[idx].offset >> 32) & 0xff;
201 + b[4] = (chd->map[idx].offset >> 24) & 0xff;
202 + b[5] = (chd->map[idx].offset >> 16) & 0xff;
203 + b[6] = (chd->map[idx].offset >> 8) & 0xff;
204 + b[7] = chd->map[idx].offset & 0xff;
206 + for (i=8; i<n; i++)
210 + case CHD_MAP_TYPE_SELF_HUNK:
211 + /* XXX: check CRC here too? */
212 + return chd_read_hunk(chd, chd->map[idx].offset, b);
214 + case CHD_MAP_TYPE_PARENT_HUNK:
215 + chd->error = CHD_ERR_NOTSUP;
219 + chd->error = CHD_ERR_NOTSUP; /* XXX: wrong error */
223 + if ((chd->map[idx].flags & CHD_MAP_FL_NOCRC) == 0) {
224 + if (crc32(0, b, n) != chd->map[idx].crc) {
225 + chd->error = CHD_ERR_CRC;
236 +chd_read_range(struct chd *chd, char *b, int off, int len)
239 + int copied, o2, l2;
241 + /* XXX: error handling */
243 + s = off/chd->hunk_len;
244 + n = (off+len+chd->hunk_len-1)/chd->hunk_len - s;
247 + o2 = off % chd->hunk_len;
248 + l2 = chd->hunk_len - o2;
250 + for (i=0; i<n; i++) {
253 + l2 = chd->hunk_len;
256 + if (l2 > len-copied)
259 + if (o2 == 0 && l2 == chd->hunk_len && s+i != chd->hno) {
260 + if (chd_read_hunk(chd, s+i, b+copied) < 0)
262 + copied += chd->hunk_len;
265 + if (chd->hbuf == NULL)
266 + if ((chd->hbuf=malloc(chd->hunk_len)) == NULL) {
267 + chd->error = CHD_ERR_NOMEM;
270 + if (s+i != chd->hno) {
271 + if (chd_read_hunk(chd, s+i, chd->hbuf) < 0)
275 + memcpy(b+copied, chd->hbuf+o2, l2);
286 +read_header(struct chd *chd)
290 + unsigned char b[MAX_HEADERLEN], *p;
292 + if (fread(b, TAG_AND_LEN, 1, chd->f) != 1) {
293 + chd->error = CHD_ERR_READ;
297 + if (memcmp(b, TAG, TAG_LEN) != 0) {
298 + chd->error = CHD_ERR_NO_CHD;
304 + if (len > MAX_HEADERLEN) {
305 + chd->error = CHD_ERR_NO_CHD;
308 + if (fread(p, len-TAG_AND_LEN, 1, chd->f) != 1) {
309 + chd->error = CHD_ERR_READ;
313 + chd->hdr_length = len;
314 + chd->version = GET_LONG(p);
315 + chd->flags = GET_LONG(p);
316 + chd->compression = GET_LONG(p);
318 + if (chd->version > 3) {
319 + chd->error = CHD_ERR_VERSION;
322 + /* XXX: check chd->hdr_length against expected value for version */
324 + if (chd->version < 3) {
325 + chd->hunk_len = GET_LONG(p);
326 + chd->total_hunks = GET_LONG(p);
327 + p += 12; /* skip c/h/s */
328 + memcpy(chd->md5, p, sizeof(chd->md5));
329 + p += sizeof(chd->md5);
330 + memcpy(chd->parent_md5, p, sizeof(chd->parent_md5));
331 + p += sizeof(chd->parent_md5);
333 + if (chd->version == 1)
334 + chd->hunk_len *= 512;
336 + chd->hunk_len *= GET_LONG(p);
337 + chd->total_len = chd->hunk_len * chd->total_hunks;
338 + chd->meta_offset = 0;
339 + memset(chd->sha1, 0, sizeof(chd->sha1));
340 + memset(chd->parent_sha1, 0, sizeof(chd->parent_sha1));
343 + chd->total_hunks = GET_LONG(p);
344 + chd->total_len = GET_QUAD(p);
345 + chd->meta_offset = GET_QUAD(p);
346 + memcpy(chd->md5, p, sizeof(chd->md5));
347 + p += sizeof(chd->md5);
348 + memcpy(chd->parent_md5, p, sizeof(chd->parent_md5));
349 + p += sizeof(chd->parent_md5);
350 + chd->hunk_len = GET_LONG(p);
351 + memcpy(chd->sha1, p, sizeof(chd->sha1));
352 + p += sizeof(chd->sha1);
361 +read_map(struct chd *chd)
363 + unsigned char b[MAP_ENTRY_SIZE_V3], *p;
367 + if ((chd->map=malloc(sizeof(*chd->map)*chd->total_hunks)) == NULL) {
368 + chd->error = CHD_ERR_NOMEM;
372 + if (chd->version < 3)
373 + len = MAP_ENTRY_SIZE_V12;
375 + len = MAP_ENTRY_SIZE_V3;
377 + for (i=0; i<chd->total_hunks; i++) {
378 + if (fread(b, len, 1, chd->f) != 1) {
379 + chd->error = CHD_ERR_READ;
387 + if (chd->version < 3) {
389 + chd->map[i].offset = v & 0xFFFFFFFFFFFLL;
390 + chd->map[i].crc = 0;
391 + chd->map[i].length = v >> 44;
392 + chd->map[i].flags = CHD_MAP_FL_NOCRC
393 + | (chd->map[i].length == chd->hunk_len
394 + ? CHD_MAP_TYPE_UNCOMPRESSED : CHD_MAP_TYPE_COMPRESSED);
397 + chd->map[i].offset = GET_QUAD(p);
398 + chd->map[i].crc = GET_LONG(p);
399 + chd->map[i].length = GET_SHORT(p);
400 + chd->map[i].flags = GET_SHORT(p);