Fixup fromcvs/togit conversion
[minix-pkgsrc.git] / emulators / gens / patches / patch-af
blob90b0e92ab7340f2304a4fd2840f9bcbb4d34400e
1 $NetBSD$
3 --- src/gens/util/chd.c.orig    2004-08-15 11:35:14.000000000 +0200
4 +++ src/gens/util/chd.c
5 @@ -0,0 +1,400 @@
6 +/*
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.
27 +*/
29 +\f
31 +#include <stdio.h>
32 +#include <stdlib.h>
33 +#include <string.h>
34 +#include <zlib.h>
36 +#include "chd.h"
38 +\f
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 *);
58 +\f
60 +void
61 +chd_close(struct chd *chd)
63 +    fclose(chd->f);
64 +    free(chd->name);
65 +    free(chd->map);
66 +    free(chd->buf);
67 +    free(chd->hbuf);
68 +    free(chd);
69 +}   
71 +\f
73 +struct chd *
74 +chd_open(const char *name, int *errp)
76 +    struct chd *chd;
77 +    FILE *f;
79 +    if ((f=fopen(name, "rb")) == NULL) {
80 +       if (errp)
81 +           *errp = CHD_ERR_OPEN;
82 +       return NULL;
83 +    }
85 +    if ((chd=malloc(sizeof(*chd))) == NULL) {
86 +       if (errp)
87 +           *errp = CHD_ERR_NOMEM;
88 +       return NULL;
89 +    }
90 +    chd->f = f;
91 +    if ((chd->name=strdup(name)) == NULL) {
92 +       if (errp)
93 +           *errp = CHD_ERR_NOMEM;
94 +       chd_close(chd);
95 +       return NULL;
96 +    }
97 +    chd->error = 0;
98 +    chd->map = NULL;
99 +    chd->buf = NULL;
100 +    chd->hno = -1;
101 +    chd->hbuf = NULL;
103 +    if (read_header(chd) < 0) {
104 +       if (errp)
105 +           *errp = chd->error;
106 +       chd_close(chd);
107 +       return NULL;
108 +    }
110 +    return chd;
115 +int
116 +chd_read_hunk(struct chd *chd, int idx, char *b)
118 +    int i, n, err;
120 +    if (idx < 0 || idx > chd->total_hunks) {
121 +       chd->error = CHD_ERR_INVAL;
122 +       return -1;
123 +    }
125 +    if (chd->map == NULL) {
126 +       if (read_map(chd) < 0)
127 +           return -1;
128 +    }
130 +    if (chd->map[idx].length > chd->hunk_len) {
131 +       chd->error = CHD_ERR_NOTSUP;
132 +       return -1;
133 +    }
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;
141 +           return -1;
142 +       }
144 +       if (chd->buf == NULL) {
145 +           if ((chd->buf=malloc(chd->hunk_len)) == NULL) {
146 +               chd->error = CHD_ERR_NOMEM;
147 +               return -1;
148 +           }
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);
154 +       }
155 +       else
156 +           err = inflateReset(&chd->z);
157 +       if (err != Z_OK) {
158 +           chd->error = CHD_ERR_ZLIB;
159 +           return -1;
160 +       }
162 +       if (fseek(chd->f, chd->map[idx].offset, SEEK_SET) == -1) {
163 +           chd->error = CHD_ERR_SEEK;
164 +           return -1;
165 +       }
166 +       if ((n=fread(chd->buf, 1, chd->map[idx].length, chd->f)) < 0) {
167 +           chd->error = CHD_ERR_READ;
168 +           return -1;
169 +       }
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;
178 +           return -1;
179 +       }
180 +       /* XXX: chd->z.avail_out should be 0 */
181 +       n = chd->hunk_len - chd->z.avail_out;
182 +       break;
184 +    case CHD_MAP_TYPE_UNCOMPRESSED:
185 +       if (fseek(chd->f, chd->map[idx].offset, SEEK_SET) == -1) {
186 +           chd->error = CHD_ERR_SEEK;
187 +           return -1;
188 +       }
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;
192 +           return -1;
193 +       }
194 +       break;
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;
205 +       n = chd->hunk_len;
206 +       for (i=8; i<n; i++)
207 +           b[i] = b[i-8];
208 +       break;
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;
216 +       return -1;
218 +    default:
219 +       chd->error = CHD_ERR_NOTSUP; /* XXX: wrong error */
220 +       return -1;
221 +    }
222 +    
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;
226 +           return -1;
227 +       }
228 +    }
229 +    
230 +    return n;
235 +int
236 +chd_read_range(struct chd *chd, char *b, int off, int len)
238 +    int i, s, n;
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;
246 +    copied = 0;
247 +    o2 = off % chd->hunk_len;
248 +    l2 = chd->hunk_len - o2;
250 +    for (i=0; i<n; i++) {
251 +       if (i == 1) {
252 +           o2 = 0;
253 +           l2 = chd->hunk_len;
254 +       }
255 +       if (i == n-1) {
256 +           if (l2 > len-copied)
257 +               l2 = len-copied;
258 +       }
259 +       if (o2 == 0 && l2 == chd->hunk_len && s+i != chd->hno) {
260 +           if (chd_read_hunk(chd, s+i, b+copied) < 0)
261 +               return -1;
262 +           copied += chd->hunk_len;
263 +       }
264 +       else {
265 +           if (chd->hbuf == NULL)
266 +               if ((chd->hbuf=malloc(chd->hunk_len)) == NULL) {
267 +                   chd->error = CHD_ERR_NOMEM;
268 +                   return -1;
269 +               }
270 +           if (s+i != chd->hno) {
271 +               if (chd_read_hunk(chd, s+i, chd->hbuf) < 0)
272 +                   return  -1;
273 +               chd->hno = s+i;
274 +           }
275 +           memcpy(b+copied, chd->hbuf+o2, l2);
276 +           copied += l2;
277 +       }
278 +    }
280 +    return len;
285 +static int
286 +read_header(struct chd *chd)
288 +    uint32_t len;
290 +    unsigned char b[MAX_HEADERLEN], *p;
292 +    if (fread(b, TAG_AND_LEN, 1, chd->f) != 1) {
293 +       chd->error = CHD_ERR_READ;
294 +       return -1;
295 +    }
297 +    if (memcmp(b, TAG, TAG_LEN) != 0) {
298 +       chd->error = CHD_ERR_NO_CHD;
299 +       return -1;
300 +    }
302 +    p = b+TAG_LEN;
303 +    len = GET_LONG(p);
304 +    if (len > MAX_HEADERLEN) {
305 +       chd->error = CHD_ERR_NO_CHD;
306 +       return -1;
307 +    }
308 +    if (fread(p, len-TAG_AND_LEN, 1, chd->f) != 1) {
309 +       chd->error = CHD_ERR_READ;
310 +       return -1;
311 +    }
312 +    
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;
320 +       return -1;
321 +    }
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;
335 +       else
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));
341 +    }
342 +    else {
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);
353 +    }
355 +    return 0;
360 +static int
361 +read_map(struct chd *chd)
363 +    unsigned char b[MAP_ENTRY_SIZE_V3], *p;
364 +    int i, len;
365 +    uint64_t v;
367 +    if ((chd->map=malloc(sizeof(*chd->map)*chd->total_hunks)) == NULL) {
368 +       chd->error = CHD_ERR_NOMEM;
369 +       return -1;
370 +    }
372 +    if (chd->version < 3)
373 +       len = MAP_ENTRY_SIZE_V12;
374 +    else
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;
380 +           return -1;
381 +       }
382 +       p = b;
384 +       if (i == 1832)
385 +           chd->version = 3;
387 +       if (chd->version < 3) {
388 +           v = GET_QUAD(p);
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);
395 +       }
396 +       else {
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);
401 +       }
402 +    }
404 +    return 0;