1 /***************************************************************************
5 MAME Compressed Hunks of Data file format
7 ****************************************************************************
12 Redistribution and use in source and binary forms, with or without
13 modification, are permitted provided that the following conditions are
16 * Redistributions of source code must retain the above copyright
17 notice, this list of conditions and the following disclaimer.
18 * Redistributions in binary form must reproduce the above copyright
19 notice, this list of conditions and the following disclaimer in
20 the documentation and/or other materials provided with the
22 * Neither the name 'MAME' nor the names of its contributors may be
23 used to endorse or promote products derived from this software
24 without specific prior written permission.
26 THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
27 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
28 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
29 DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
30 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
31 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
34 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
35 IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 POSSIBILITY OF SUCH DAMAGE.
38 ***************************************************************************/
45 #include <libchdr/chd.h>
46 #include <libchdr/minmax.h>
47 #include <libchdr/cdrom.h>
48 #include <libchdr/huffman.h>
49 #include <libchdr/libchdr_zlib.h>
52 #include <retro_inline.h>
53 #include <streams/file_stream.h>
60 chd_error cdzl_codec_init(void *codec, uint32_t hunkbytes)
63 cdzl_codec_data* cdzl = (cdzl_codec_data*)codec;
65 /* make sure the CHD's hunk size is an even multiple of the frame size */
66 if (hunkbytes % CD_FRAME_SIZE != 0)
67 return CHDERR_CODEC_ERROR;
69 cdzl->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes);
70 if (cdzl->buffer == NULL)
71 return CHDERR_OUT_OF_MEMORY;
73 ret = zlib_codec_init(&cdzl->base_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA);
74 if (ret != CHDERR_NONE)
78 ret = zlib_codec_init(&cdzl->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA);
79 if (ret != CHDERR_NONE)
86 void cdzl_codec_free(void *codec)
88 cdzl_codec_data* cdzl = (cdzl_codec_data*)codec;
90 zlib_codec_free(&cdzl->base_decompressor);
92 zlib_codec_free(&cdzl->subcode_decompressor);
98 chd_error cdzl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
100 #ifdef WANT_RAW_DATA_SECTOR
104 cdzl_codec_data* cdzl = (cdzl_codec_data*)codec;
106 /* determine header bytes */
107 uint32_t frames = destlen / CD_FRAME_SIZE;
108 uint32_t complen_bytes = (destlen < 65536) ? 2 : 3;
109 uint32_t ecc_bytes = (frames + 7) / 8;
110 uint32_t header_bytes = ecc_bytes + complen_bytes;
112 /* extract compressed length of base */
113 uint32_t complen_base = (src[ecc_bytes + 0] << 8) | src[ecc_bytes + 1];
114 if (complen_bytes > 2)
115 complen_base = (complen_base << 8) | src[ecc_bytes + 2];
117 /* reset and decode */
118 zlib_codec_decompress(&cdzl->base_decompressor, &src[header_bytes], complen_base, &cdzl->buffer[0], frames * CD_MAX_SECTOR_DATA);
120 zlib_codec_decompress(&cdzl->subcode_decompressor, &src[header_bytes + complen_base], complen - complen_base - header_bytes, &cdzl->buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA);
123 /* reassemble the data */
124 for (framenum = 0; framenum < frames; framenum++)
126 memcpy(&dest[framenum * CD_FRAME_SIZE], &cdzl->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA);
128 memcpy(&dest[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], &cdzl->buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], CD_MAX_SUBCODE_DATA);
131 #ifdef WANT_RAW_DATA_SECTOR
132 /* reconstitute the ECC data and sync header */
133 sector = (uint8_t *)&dest[framenum * CD_FRAME_SIZE];
134 if ((src[framenum / 8] & (1 << (framenum % 8))) != 0)
136 memcpy(sector, s_cd_sync_header, sizeof(s_cd_sync_header));
137 ecc_generate(sector);
144 /***************************************************************************
145 ZLIB COMPRESSION CODEC
146 ***************************************************************************/
148 /*-------------------------------------------------
149 zlib_codec_init - initialize the ZLIB codec
150 -------------------------------------------------*/
152 chd_error zlib_codec_init(void *codec, uint32_t hunkbytes)
156 zlib_codec_data *data = (zlib_codec_data*)codec;
158 /* clear the buffers */
159 memset(data, 0, sizeof(zlib_codec_data));
161 /* init the inflater first */
162 data->inflater.next_in = (Bytef *)data; /* bogus, but that's ok */
163 data->inflater.avail_in = 0;
164 data->inflater.zalloc = zlib_fast_alloc;
165 data->inflater.zfree = zlib_fast_free;
166 data->inflater.opaque = &data->allocator;
167 zerr = inflateInit2(&data->inflater, -MAX_WBITS);
170 if (zerr == Z_MEM_ERROR)
171 err = CHDERR_OUT_OF_MEMORY;
172 else if (zerr != Z_OK)
173 err = CHDERR_CODEC_ERROR;
177 /* handle an error */
178 if (err != CHDERR_NONE)
179 zlib_codec_free(data);
184 /*-------------------------------------------------
185 zlib_codec_free - free data for the ZLIB
187 -------------------------------------------------*/
189 void zlib_codec_free(void *codec)
191 zlib_codec_data *data = (zlib_codec_data *)codec;
193 /* deinit the streams */
197 zlib_allocator alloc;
199 inflateEnd(&data->inflater);
201 /* free our fast memory */
202 alloc = data->allocator;
203 for (i = 0; i < MAX_ZLIB_ALLOCS; i++)
204 if (alloc.allocptr[i])
205 free(alloc.allocptr[i]);
209 /*-------------------------------------------------
210 zlib_codec_decompress - decomrpess data using
212 -------------------------------------------------*/
214 chd_error zlib_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
216 zlib_codec_data *data = (zlib_codec_data *)codec;
219 /* reset the decompressor */
220 data->inflater.next_in = (Bytef *)src;
221 data->inflater.avail_in = complen;
222 data->inflater.total_in = 0;
223 data->inflater.next_out = (Bytef *)dest;
224 data->inflater.avail_out = destlen;
225 data->inflater.total_out = 0;
226 zerr = inflateReset(&data->inflater);
228 return CHDERR_DECOMPRESSION_ERROR;
231 zerr = inflate(&data->inflater, Z_FINISH);
233 if (data->inflater.total_out != destlen)
234 return CHDERR_DECOMPRESSION_ERROR;
239 /*-------------------------------------------------
240 zlib_fast_alloc - fast malloc for ZLIB, which
241 allocates and frees memory frequently
242 -------------------------------------------------*/
244 /* Huge alignment values for possible SIMD optimization by compiler (NEON, SSE, AVX) */
245 #define ZLIB_MIN_ALIGNMENT_BITS 512
246 #define ZLIB_MIN_ALIGNMENT_BYTES (ZLIB_MIN_ALIGNMENT_BITS / 8)
248 voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size)
250 zlib_allocator *alloc = (zlib_allocator *)opaque;
255 /* compute the size, rounding to the nearest 1k */
256 size = (size * items + 0x3ff) & ~0x3ff;
258 /* reuse a hunk if we can */
259 for (i = 0; i < MAX_ZLIB_ALLOCS; i++)
261 ptr = alloc->allocptr[i];
262 if (ptr && size == *ptr)
264 /* set the low bit of the size so we don't match next time */
267 /* return aligned block address */
268 return (voidpf)(alloc->allocptr2[i]);
272 /* alloc a new one */
273 ptr = (UINT32 *)malloc(size + sizeof(UINT32) + ZLIB_MIN_ALIGNMENT_BYTES);
277 /* put it into the list */
278 for (i = 0; i < MAX_ZLIB_ALLOCS; i++)
279 if (!alloc->allocptr[i])
281 alloc->allocptr[i] = ptr;
282 paddr = (((uintptr_t)ptr) + sizeof(UINT32) + (ZLIB_MIN_ALIGNMENT_BYTES-1)) & (~(ZLIB_MIN_ALIGNMENT_BYTES-1));
283 alloc->allocptr2[i] = (uint32_t*)paddr;
287 /* set the low bit of the size so we don't match next time */
290 /* return aligned block address */
291 return (voidpf)paddr;
294 /*-------------------------------------------------
295 zlib_fast_free - fast free for ZLIB, which
296 allocates and frees memory frequently
297 -------------------------------------------------*/
299 void zlib_fast_free(voidpf opaque, voidpf address)
301 zlib_allocator *alloc = (zlib_allocator *)opaque;
302 UINT32 *ptr = (UINT32 *)address;
306 for (i = 0; i < MAX_ZLIB_ALLOCS; i++)
307 if (ptr == alloc->allocptr2[i])
309 /* clear the low bit of the size to allow matches */
310 *(alloc->allocptr[i]) &= ~1;