#include <libchdr/cdrom.h>
#include <libchdr/flac.h>
#include <libchdr/huffman.h>
+#include <zstd.h>
#include "LzmaEnc.h"
#include "LzmaDec.h"
#if defined(__PS3__) || defined(__PSL1GHT__)
#define __MACTYPES__
#endif
-#include "zlib.h"
+#include <zlib.h>
#undef TRUE
#undef FALSE
struct huffman_decoder* decoder;
};
+typedef struct _zstd_codec_data zstd_codec_data;
+struct _zstd_codec_data
+{
+ ZSTD_DStream *dstream;
+};
+
/* codec-private data for the CDZL codec */
typedef struct _cdzl_codec_data cdzl_codec_data;
struct _cdzl_codec_data {
uint8_t* buffer;
};
+typedef struct _cdzs_codec_data cdzs_codec_data;
+struct _cdzs_codec_data
+{
+ zstd_codec_data base_decompressor;
+#ifdef WANT_SUBCODE
+ zstd_codec_data subcode_decompressor;
+#endif
+ uint8_t* buffer;
+};
+
/* internal representation of an open CHD file */
struct _chd_file
{
lzma_codec_data lzma_codec_data; /* lzma codec data */
huff_codec_data huff_codec_data; /* huff codec data */
flac_codec_data flac_codec_data; /* flac codec data */
+ zstd_codec_data zstd_codec_data; /* zstd codec data */
cdzl_codec_data cdzl_codec_data; /* cdzl codec data */
cdlz_codec_data cdlz_codec_data; /* cdlz codec data */
cdfl_codec_data cdfl_codec_data; /* cdfl codec data */
+ cdzs_codec_data cdzs_codec_data; /* cdzs codec data */
#ifdef NEED_CACHE_HUNK
UINT32 maxhunk; /* maximum hunk accessed */
static void flac_codec_free(void *codec);
static chd_error flac_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);
+/* zstd compression codec */
+static chd_error zstd_codec_init(void *codec, uint32_t hunkbytes);
+static void zstd_codec_free(void *codec);
+static chd_error zstd_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);
+
+
/* cdzl compression codec */
static chd_error cdzl_codec_init(void* codec, uint32_t hunkbytes);
static void cdzl_codec_free(void* codec);
static void cdfl_codec_free(void* codec);
static chd_error cdfl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);
+/* cdzs compression codec */
+static chd_error cdzs_codec_init(void *codec, uint32_t hunkbytes);
+static void cdzs_codec_free(void *codec);
+static chd_error cdzs_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);
+
/***************************************************************************
* LZMA ALLOCATOR HELPER
***************************************************************************
if (err != HUFFERR_NONE)
{
free(bitbuf);
- return err;
+ return CHDERR_DECOMPRESSION_ERROR;
}
// then decode the data
- for (uint32_t cur = 0; cur < destlen; cur++)
+ uint32_t cur;
+ for (cur = 0; cur < destlen; cur++)
dest[cur] = huffman_decode_one(huff_codec->decoder, bitbuf);
bitstream_flush(bitbuf);
chd_error result = bitstream_overflow(bitbuf) ? CHDERR_DECOMPRESSION_ERROR : CHDERR_NONE;
return CHDERR_NONE;
}
+
+
+/***************************************************************************
+ * ZSTD DECOMPRESSOR
+ ***************************************************************************
+ */
+
+/*-------------------------------------------------
+ * zstd_codec_init - constructor
+ *-------------------------------------------------
+ */
+
+static chd_error zstd_codec_init(void* codec, uint32_t hunkbytes)
+{
+ zstd_codec_data* zstd_codec = (zstd_codec_data*) codec;
+
+ zstd_codec->dstream = ZSTD_createDStream();
+ if (!zstd_codec->dstream) {
+ printf("NO DSTREAM CREATED!\n");
+ return CHDERR_DECOMPRESSION_ERROR;
+ }
+ return CHDERR_NONE;
+}
+
+/*-------------------------------------------------
+ * zstd_codec_free
+ *-------------------------------------------------
+ */
+
+static void zstd_codec_free(void* codec)
+{
+ zstd_codec_data* zstd_codec = (zstd_codec_data*) codec;
+
+ ZSTD_freeDStream(zstd_codec->dstream);
+}
+
+/*-------------------------------------------------
+ * decompress - decompress data using the ZSTD
+ * codec
+ *-------------------------------------------------
+ */
+static chd_error zstd_codec_decompress(void* codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
+{
+ /* initialize */
+ zstd_codec_data* zstd_codec = (zstd_codec_data*) codec;
+ //reset decompressor
+ size_t zstd_res = ZSTD_initDStream(zstd_codec->dstream);
+ if (ZSTD_isError(zstd_res))
+ {
+ printf("INITI DSTREAM FAILED!\n");
+ return CHDERR_DECOMPRESSION_ERROR;
+ }
+
+ ZSTD_inBuffer input = {src, complen, 0};
+ ZSTD_outBuffer output = {dest, destlen, 0 };
+
+ while ((input.pos < input.size) && (output.pos < output.size))
+ {
+ zstd_res = ZSTD_decompressStream(zstd_codec->dstream, &output, &input);
+ if (ZSTD_isError(zstd_res))
+ {
+ printf("DECOMPRESSION ERROR IN LOOP\n");
+ return CHDERR_DECOMPRESSION_ERROR;
+ }
+ }
+ if (output.pos != output.size)
+ {
+ printf("OUTPUT DOESN'T MATCH!\n");
+ return CHDERR_DECOMPRESSION_ERROR;
+ }
+ return CHDERR_NONE;
+
+}
+
+/* cdzs */
+static chd_error cdzs_codec_init(void* codec, uint32_t hunkbytes)
+{
+ chd_error ret;
+ cdzs_codec_data* cdzs = (cdzs_codec_data*) codec;
+
+ /* allocate buffer */
+ cdzs->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes);
+ if (cdzs->buffer == NULL)
+ return CHDERR_OUT_OF_MEMORY;
+
+ /* make sure the CHD's hunk size is an even multiple of the frame size */
+ ret = zstd_codec_init(&cdzs->base_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA);
+ if (ret != CHDERR_NONE)
+ return ret;
+
+#ifdef WANT_SUBCODE
+ ret = zstd_codec_init(&cdzs->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SUBCODE_DATA);
+ if (ret != CHDERR_NONE)
+ return ret;
+#endif
+
+ if (hunkbytes % CD_FRAME_SIZE != 0)
+ return CHDERR_CODEC_ERROR;
+
+ return CHDERR_NONE;
+}
+
+static void cdzs_codec_free(void* codec)
+{
+ cdzs_codec_data* cdzs = (cdzs_codec_data*) codec;
+ free(cdzs->buffer);
+ zstd_codec_free(&cdzs->base_decompressor);
+#ifdef WANT_SUBCODE
+ zstd_codec_free(&cdzs->subcode_decompressor);
+#endif
+}
+
+static chd_error cdzs_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
+{
+ uint32_t framenum;
+ cdzs_codec_data* cdzs = (cdzs_codec_data*)codec;
+
+ /* determine header bytes */
+ uint32_t frames = destlen / CD_FRAME_SIZE;
+ uint32_t complen_bytes = (destlen < 65536) ? 2 : 3;
+ uint32_t ecc_bytes = (frames + 7) / 8;
+ uint32_t header_bytes = ecc_bytes + complen_bytes;
+
+ /* extract compressed length of base */
+ uint32_t complen_base = (src[ecc_bytes + 0] << 8) | src[ecc_bytes + 1];
+ if (complen_bytes > 2)
+ complen_base = (complen_base << 8) | src[ecc_bytes + 2];
+
+ /* reset and decode */
+ zstd_codec_decompress(&cdzs->base_decompressor, &src[header_bytes], complen_base, &cdzs->buffer[0], frames * CD_MAX_SECTOR_DATA);
+#ifdef WANT_SUBCODE
+ zstd_codec_decompress(&cdzs->subcode_decompressor, &src[header_bytes + complen_base], complen - complen_base - header_bytes, &cdzs->buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA);
+#endif
+
+ /* reassemble the data */
+ for (framenum = 0; framenum < frames; framenum++)
+ {
+ uint8_t *sector;
+
+ memcpy(&dest[framenum * CD_FRAME_SIZE], &cdzs->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA);
+#ifdef WANT_SUBCODE
+ memcpy(&dest[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], &cdzs->buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], CD_MAX_SUBCODE_DATA);
+#endif
+
+#ifdef WANT_RAW_DATA_SECTOR
+ /* reconstitute the ECC data and sync header */
+ sector = (uint8_t *)&dest[framenum * CD_FRAME_SIZE];
+ if ((src[framenum / 8] & (1 << (framenum % 8))) != 0)
+ {
+ memcpy(sector, s_cd_sync_header, sizeof(s_cd_sync_header));
+ ecc_generate(sector);
+ }
+#endif
+ }
+ return CHDERR_NONE;
+}
+
/***************************************************************************
CODEC INTERFACES
***************************************************************************/
flac_codec_decompress,
NULL
},
+ /* V5 zstd compression */
+ {
+ CHD_CODEC_ZSTD,
+ "ZStandard",
+ FALSE,
+ zstd_codec_init,
+ zstd_codec_free,
+ zstd_codec_decompress,
+ NULL
+ },
/* V5 CD zlib compression */
{
cdfl_codec_decompress,
NULL
},
+ /* V5 CD zstd compression */
+ {
+ CHD_CODEC_CD_ZSTD,
+ "cdzs (CD ZStandard)",
+ FALSE,
+ cdzs_codec_init,
+ cdzs_codec_free,
+ cdzs_codec_decompress,
+ NULL
+ }
+
};
/***************************************************************************
codec = &newchd->flac_codec_data;
break;
+ case CHD_CODEC_ZSTD:
+ codec = &newchd->zstd_codec_data;
+ break;
+
case CHD_CODEC_CD_ZLIB:
codec = &newchd->cdzl_codec_data;
break;
case CHD_CODEC_CD_FLAC:
codec = &newchd->cdfl_codec_data;
break;
+
+ case CHD_CODEC_CD_ZSTD:
+ codec = &newchd->cdzs_codec_data;
+ break;
}
if (codec == NULL)
codec = &chd->flac_codec_data;
break;
+ case CHD_CODEC_ZSTD:
+ codec = &chd->zstd_codec_data;
+ break;
+
case CHD_CODEC_CD_ZLIB:
codec = &chd->cdzl_codec_data;
break;
case CHD_CODEC_CD_FLAC:
codec = &chd->cdfl_codec_data;
break;
+
+ case CHD_CODEC_CD_ZSTD:
+ codec = &chd->cdzs_codec_data;
+ break;
}
if (codec)
/* read it into the decompression buffer */
compressed_bytes = hunk_read_compressed(chd, entry->offset, entry->length);
if (compressed_bytes == NULL)
+ {
return CHDERR_READ_ERROR;
+ }
/* now decompress using the codec */
err = CHDERR_NONE;
codec = &chd->flac_codec_data;
break;
+ case CHD_CODEC_ZSTD:
+ codec = &chd->zstd_codec_data;
+ break;
+
case CHD_CODEC_CD_ZLIB:
codec = &chd->cdzl_codec_data;
break;
case CHD_CODEC_CD_FLAC:
codec = &chd->cdfl_codec_data;
break;
+
+ case CHD_CODEC_CD_ZSTD:
+ codec = &chd->cdzs_codec_data;
+ break;
}
if (codec==NULL)
return CHDERR_CODEC_ERROR;