git subrepo clone https://github.com/libretro/libretro-common.git deps/libretro-common
[pcsx_rearmed.git] / deps / libretro-common / formats / libchdr / libchdr_flac_codec.c
CommitLineData
3719602c
PC
1/***************************************************************************
2
3 libchdr_flac_codec.c
4
5 MAME Compressed Hunks of Data file format
6
7****************************************************************************
8
9 Copyright Aaron Giles
10 All rights reserved.
11
12 Redistribution and use in source and binary forms, with or without
13 modification, are permitted provided that the following conditions are
14 met:
15
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
21 distribution.
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.
25
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.
37
38***************************************************************************/
39
40#include <stddef.h>
41#include <stdint.h>
42#include <stdio.h>
43#include <stdlib.h>
44#include <string.h>
45#include <libchdr/chd.h>
46#include <libchdr/minmax.h>
47#include <libchdr/cdrom.h>
48#include <libchdr/flac.h>
49#include <libchdr/huffman.h>
50#include <zlib.h>
51
52#include <retro_inline.h>
53#include <streams/file_stream.h>
54
55#define TRUE 1
56#define FALSE 0
57
58/***************************************************************************
59 * CD FLAC DECOMPRESSOR
60 ***************************************************************************
61 */
62
63/*------------------------------------------------------
64 * cdfl_codec_blocksize - return the optimal block size
65 *------------------------------------------------------
66 */
67
68static uint32_t cdfl_codec_blocksize(uint32_t bytes)
69{
70 /* determine FLAC block size, which must be 16-65535
71 * clamp to 2k since that's supposed to be the sweet spot */
72 uint32_t hunkbytes = bytes / 4;
73 while (hunkbytes > 2048)
74 hunkbytes /= 2;
75 return hunkbytes;
76}
77
78chd_error cdfl_codec_init(void *codec, uint32_t hunkbytes)
79{
80#ifdef WANT_SUBCODE
81 chd_error ret;
82#endif
83 uint16_t native_endian = 0;
84 cdfl_codec_data *cdfl = (cdfl_codec_data*)codec;
85
86 /* make sure the CHD's hunk size is an even multiple of the frame size */
87 if (hunkbytes % CD_FRAME_SIZE != 0)
88 return CHDERR_CODEC_ERROR;
89
90 cdfl->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes);
91 if (cdfl->buffer == NULL)
92 return CHDERR_OUT_OF_MEMORY;
93
94 /* determine whether we want native or swapped samples */
95 *(uint8_t *)(&native_endian) = 1;
96 cdfl->swap_endian = (native_endian & 1);
97
98#ifdef WANT_SUBCODE
99 /* init zlib inflater */
100 ret = zlib_codec_init(&cdfl->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA);
101 if (ret != CHDERR_NONE)
102 return ret;
103#endif
104
105 /* flac decoder init */
106 flac_decoder_init(&cdfl->decoder);
107 if (cdfl->decoder.decoder == NULL)
108 return CHDERR_OUT_OF_MEMORY;
109
110 return CHDERR_NONE;
111}
112
113void cdfl_codec_free(void *codec)
114{
115 cdfl_codec_data *cdfl = (cdfl_codec_data*)codec;
116 flac_decoder_free(&cdfl->decoder);
117#ifdef WANT_SUBCODE
118 zlib_codec_free(&cdfl->subcode_decompressor);
119#endif
120 if (cdfl->buffer)
121 free(cdfl->buffer);
122}
123
124chd_error cdfl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
125{
126 uint32_t framenum;
127 uint8_t *buffer;
128#ifdef WANT_SUBCODE
129 uint32_t offset;
130 chd_error ret;
131#endif
132 cdfl_codec_data *cdfl = (cdfl_codec_data*)codec;
133
134 /* reset and decode */
135 uint32_t frames = destlen / CD_FRAME_SIZE;
136
137 if (!flac_decoder_reset(&cdfl->decoder, 44100, 2, cdfl_codec_blocksize(frames * CD_MAX_SECTOR_DATA), src, complen))
138 return CHDERR_DECOMPRESSION_ERROR;
139 buffer = &cdfl->buffer[0];
140 if (!flac_decoder_decode_interleaved(&cdfl->decoder, (int16_t *)(buffer), frames * CD_MAX_SECTOR_DATA/4, cdfl->swap_endian))
141 return CHDERR_DECOMPRESSION_ERROR;
142
143#ifdef WANT_SUBCODE
144 /* inflate the subcode data */
145 offset = flac_decoder_finish(&cdfl->decoder);
146 ret = zlib_codec_decompress(&cdfl->subcode_decompressor, src + offset, complen - offset, &cdfl->buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA);
147 if (ret != CHDERR_NONE)
148 return ret;
149#else
150 flac_decoder_finish(&cdfl->decoder);
151#endif
152
153 /* reassemble the data */
154 for (framenum = 0; framenum < frames; framenum++)
155 {
156 memcpy(&dest[framenum * CD_FRAME_SIZE], &cdfl->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA);
157#ifdef WANT_SUBCODE
158 memcpy(&dest[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], &cdfl->buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], CD_MAX_SUBCODE_DATA);
159#endif
160 }
161
162 return CHDERR_NONE;
163}