Files
pkgsrc-ng/emulators/gens/patches/patch-af
T
2013-09-26 17:14:40 +02:00

406 lines
9.4 KiB
Plaintext

$NetBSD: patch-af,v 1.2 2004/08/15 12:13:53 dillo Exp $
--- src/gens/util/chd.c.orig 2004-08-15 11:35:14.000000000 +0200
+++ src/gens/util/chd.c
@@ -0,0 +1,400 @@
+/*
+ NiH: chd.c,v 1.6 2004/06/25 23:31:08 dillo Exp
+
+ chd.c -- accessing chd files
+ Copyright (C) 2004 Dieter Baron and Thomas Klausner
+
+ This file is part of ckmame, a program to check rom sets for MAME.
+ The authors can be contacted at <nih@giga.or.at>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License, version 2, as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <zlib.h>
+
+#include "chd.h"
+
+
+
+#define MAX_HEADERLEN 120 /* maximum header length */
+#define TAG "MComprHD"
+#define TAG_LEN 8 /* length of tag */
+#define TAG_AND_LEN 12 /* length of tag + header length */
+
+#define MAP_ENTRY_SIZE_V12 8 /* size of map entry, versions 1 & 2 */
+#define MAP_ENTRY_SIZE_V3 16 /* size of map entry, version 3 */
+
+#define GET_LONG(b) (b+=4,((b)[-4]<<24)|((b)[-3]<<16)|((b)[-2]<<8)|(b)[-1])
+#define GET_QUAD(b) (b+=8,((uint64_t)(b)[-8]<<56)|((uint64_t)(b)[-7]<<48) \
+ |((uint64_t)(b)[-6]<<40)|((uint64_t)(b)[-5]<<32) \
+ |((uint64_t)(b)[-4]<<24)|((uint64_t)(b)[-3]<<16) \
+ |((uint64_t)(b)[-2]<<8)|((uint64_t)(b)[-1]))
+#define GET_SHORT(b) (b+=2,((b)[-2]<<8)|(b)[-1])
+
+static int read_header(struct chd *);
+static int read_map(struct chd *);
+
+
+
+void
+chd_close(struct chd *chd)
+{
+ fclose(chd->f);
+ free(chd->name);
+ free(chd->map);
+ free(chd->buf);
+ free(chd->hbuf);
+ free(chd);
+}
+
+
+
+struct chd *
+chd_open(const char *name, int *errp)
+{
+ struct chd *chd;
+ FILE *f;
+
+ if ((f=fopen(name, "rb")) == NULL) {
+ if (errp)
+ *errp = CHD_ERR_OPEN;
+ return NULL;
+ }
+
+ if ((chd=malloc(sizeof(*chd))) == NULL) {
+ if (errp)
+ *errp = CHD_ERR_NOMEM;
+ return NULL;
+ }
+ chd->f = f;
+ if ((chd->name=strdup(name)) == NULL) {
+ if (errp)
+ *errp = CHD_ERR_NOMEM;
+ chd_close(chd);
+ return NULL;
+ }
+ chd->error = 0;
+ chd->map = NULL;
+ chd->buf = NULL;
+ chd->hno = -1;
+ chd->hbuf = NULL;
+
+ if (read_header(chd) < 0) {
+ if (errp)
+ *errp = chd->error;
+ chd_close(chd);
+ return NULL;
+ }
+
+ return chd;
+}
+
+
+
+int
+chd_read_hunk(struct chd *chd, int idx, char *b)
+{
+ int i, n, err;
+
+ if (idx < 0 || idx > chd->total_hunks) {
+ chd->error = CHD_ERR_INVAL;
+ return -1;
+ }
+
+ if (chd->map == NULL) {
+ if (read_map(chd) < 0)
+ return -1;
+ }
+
+ if (chd->map[idx].length > chd->hunk_len) {
+ chd->error = CHD_ERR_NOTSUP;
+ return -1;
+ }
+
+ switch (chd->map[idx].flags & CHD_MAP_TYPE_MASK) {
+ case CHD_MAP_TYPE_COMPRESSED:
+ /* XXX: CHD_COMP_NONE? */
+ if (chd->compression != CHD_COMP_ZLIB
+ && chd->compression != CHD_COMP_ZLIB_PLUS) {
+ chd->error = CHD_ERR_NOTSUP;
+ return -1;
+ }
+
+ if (chd->buf == NULL) {
+ if ((chd->buf=malloc(chd->hunk_len)) == NULL) {
+ chd->error = CHD_ERR_NOMEM;
+ return -1;
+ }
+ chd->z.avail_in = 0;
+ chd->z.zalloc = Z_NULL;
+ chd->z.zfree = Z_NULL;
+ chd->z.opaque = NULL;
+ err = inflateInit2(&chd->z, -MAX_WBITS);
+ }
+ else
+ err = inflateReset(&chd->z);
+ if (err != Z_OK) {
+ chd->error = CHD_ERR_ZLIB;
+ return -1;
+ }
+
+ if (fseek(chd->f, chd->map[idx].offset, SEEK_SET) == -1) {
+ chd->error = CHD_ERR_SEEK;
+ return -1;
+ }
+ if ((n=fread(chd->buf, 1, chd->map[idx].length, chd->f)) < 0) {
+ chd->error = CHD_ERR_READ;
+ return -1;
+ }
+
+ chd->z.next_in = chd->buf;
+ chd->z.avail_in = n;
+ chd->z.next_out = b;
+ chd->z.avail_out = chd->hunk_len;
+ /* XXX: should use Z_FINISH, but that returns Z_BUF_ERROR */
+ if ((err=inflate(&chd->z, 0)) != Z_OK && err != Z_STREAM_END) {
+ chd->error = CHD_ERR_ZLIB;
+ return -1;
+ }
+ /* XXX: chd->z.avail_out should be 0 */
+ n = chd->hunk_len - chd->z.avail_out;
+ break;
+
+ case CHD_MAP_TYPE_UNCOMPRESSED:
+ if (fseek(chd->f, chd->map[idx].offset, SEEK_SET) == -1) {
+ chd->error = CHD_ERR_SEEK;
+ return -1;
+ }
+ /* XXX: use chd->hunk_len instead? */
+ if ((n=fread(b, 1, chd->map[idx].length, chd->f)) < 0) {
+ chd->error = CHD_ERR_READ;
+ return -1;
+ }
+ break;
+
+ case CHD_MAP_TYPE_MINI:
+ b[0] = (chd->map[idx].offset >> 56) & 0xff;
+ b[1] = (chd->map[idx].offset >> 48) & 0xff;
+ b[2] = (chd->map[idx].offset >> 40) & 0xff;
+ b[3] = (chd->map[idx].offset >> 32) & 0xff;
+ b[4] = (chd->map[idx].offset >> 24) & 0xff;
+ b[5] = (chd->map[idx].offset >> 16) & 0xff;
+ b[6] = (chd->map[idx].offset >> 8) & 0xff;
+ b[7] = chd->map[idx].offset & 0xff;
+ n = chd->hunk_len;
+ for (i=8; i<n; i++)
+ b[i] = b[i-8];
+ break;
+
+ case CHD_MAP_TYPE_SELF_HUNK:
+ /* XXX: check CRC here too? */
+ return chd_read_hunk(chd, chd->map[idx].offset, b);
+
+ case CHD_MAP_TYPE_PARENT_HUNK:
+ chd->error = CHD_ERR_NOTSUP;
+ return -1;
+
+ default:
+ chd->error = CHD_ERR_NOTSUP; /* XXX: wrong error */
+ return -1;
+ }
+
+ if ((chd->map[idx].flags & CHD_MAP_FL_NOCRC) == 0) {
+ if (crc32(0, b, n) != chd->map[idx].crc) {
+ chd->error = CHD_ERR_CRC;
+ return -1;
+ }
+ }
+
+ return n;
+}
+
+
+
+int
+chd_read_range(struct chd *chd, char *b, int off, int len)
+{
+ int i, s, n;
+ int copied, o2, l2;
+
+ /* XXX: error handling */
+
+ s = off/chd->hunk_len;
+ n = (off+len+chd->hunk_len-1)/chd->hunk_len - s;
+
+ copied = 0;
+ o2 = off % chd->hunk_len;
+ l2 = chd->hunk_len - o2;
+
+ for (i=0; i<n; i++) {
+ if (i == 1) {
+ o2 = 0;
+ l2 = chd->hunk_len;
+ }
+ if (i == n-1) {
+ if (l2 > len-copied)
+ l2 = len-copied;
+ }
+ if (o2 == 0 && l2 == chd->hunk_len && s+i != chd->hno) {
+ if (chd_read_hunk(chd, s+i, b+copied) < 0)
+ return -1;
+ copied += chd->hunk_len;
+ }
+ else {
+ if (chd->hbuf == NULL)
+ if ((chd->hbuf=malloc(chd->hunk_len)) == NULL) {
+ chd->error = CHD_ERR_NOMEM;
+ return -1;
+ }
+ if (s+i != chd->hno) {
+ if (chd_read_hunk(chd, s+i, chd->hbuf) < 0)
+ return -1;
+ chd->hno = s+i;
+ }
+ memcpy(b+copied, chd->hbuf+o2, l2);
+ copied += l2;
+ }
+ }
+
+ return len;
+}
+
+
+
+static int
+read_header(struct chd *chd)
+{
+ uint32_t len;
+
+ unsigned char b[MAX_HEADERLEN], *p;
+
+ if (fread(b, TAG_AND_LEN, 1, chd->f) != 1) {
+ chd->error = CHD_ERR_READ;
+ return -1;
+ }
+
+ if (memcmp(b, TAG, TAG_LEN) != 0) {
+ chd->error = CHD_ERR_NO_CHD;
+ return -1;
+ }
+
+ p = b+TAG_LEN;
+ len = GET_LONG(p);
+ if (len > MAX_HEADERLEN) {
+ chd->error = CHD_ERR_NO_CHD;
+ return -1;
+ }
+ if (fread(p, len-TAG_AND_LEN, 1, chd->f) != 1) {
+ chd->error = CHD_ERR_READ;
+ return -1;
+ }
+
+ chd->hdr_length = len;
+ chd->version = GET_LONG(p);
+ chd->flags = GET_LONG(p);
+ chd->compression = GET_LONG(p);
+
+ if (chd->version > 3) {
+ chd->error = CHD_ERR_VERSION;
+ return -1;
+ }
+ /* XXX: check chd->hdr_length against expected value for version */
+
+ if (chd->version < 3) {
+ chd->hunk_len = GET_LONG(p);
+ chd->total_hunks = GET_LONG(p);
+ p += 12; /* skip c/h/s */
+ memcpy(chd->md5, p, sizeof(chd->md5));
+ p += sizeof(chd->md5);
+ memcpy(chd->parent_md5, p, sizeof(chd->parent_md5));
+ p += sizeof(chd->parent_md5);
+
+ if (chd->version == 1)
+ chd->hunk_len *= 512;
+ else
+ chd->hunk_len *= GET_LONG(p);
+ chd->total_len = chd->hunk_len * chd->total_hunks;
+ chd->meta_offset = 0;
+ memset(chd->sha1, 0, sizeof(chd->sha1));
+ memset(chd->parent_sha1, 0, sizeof(chd->parent_sha1));
+ }
+ else {
+ chd->total_hunks = GET_LONG(p);
+ chd->total_len = GET_QUAD(p);
+ chd->meta_offset = GET_QUAD(p);
+ memcpy(chd->md5, p, sizeof(chd->md5));
+ p += sizeof(chd->md5);
+ memcpy(chd->parent_md5, p, sizeof(chd->parent_md5));
+ p += sizeof(chd->parent_md5);
+ chd->hunk_len = GET_LONG(p);
+ memcpy(chd->sha1, p, sizeof(chd->sha1));
+ p += sizeof(chd->sha1);
+ }
+
+ return 0;
+}
+
+
+
+static int
+read_map(struct chd *chd)
+{
+ unsigned char b[MAP_ENTRY_SIZE_V3], *p;
+ int i, len;
+ uint64_t v;
+
+ if ((chd->map=malloc(sizeof(*chd->map)*chd->total_hunks)) == NULL) {
+ chd->error = CHD_ERR_NOMEM;
+ return -1;
+ }
+
+ if (chd->version < 3)
+ len = MAP_ENTRY_SIZE_V12;
+ else
+ len = MAP_ENTRY_SIZE_V3;
+
+ for (i=0; i<chd->total_hunks; i++) {
+ if (fread(b, len, 1, chd->f) != 1) {
+ chd->error = CHD_ERR_READ;
+ return -1;
+ }
+ p = b;
+
+ if (i == 1832)
+ chd->version = 3;
+
+ if (chd->version < 3) {
+ v = GET_QUAD(p);
+ chd->map[i].offset = v & 0xFFFFFFFFFFFLL;
+ chd->map[i].crc = 0;
+ chd->map[i].length = v >> 44;
+ chd->map[i].flags = CHD_MAP_FL_NOCRC
+ | (chd->map[i].length == chd->hunk_len
+ ? CHD_MAP_TYPE_UNCOMPRESSED : CHD_MAP_TYPE_COMPRESSED);
+ }
+ else {
+ chd->map[i].offset = GET_QUAD(p);
+ chd->map[i].crc = GET_LONG(p);
+ chd->map[i].length = GET_SHORT(p);
+ chd->map[i].flags = GET_SHORT(p);
+ }
+ }
+
+ return 0;
+}