libchdr: Update to latest upstream
authornegativeExponent <negativeExponent@users.noreply.github.com>
Fri, 5 Jun 2020 11:56:44 +0000 (19:56 +0800)
committernegativeExponent <negativeExponent@users.noreply.github.com>
Fri, 5 Jun 2020 11:59:07 +0000 (19:59 +0800)
Update libchdr based from latest upstream sources. Fixes some issues as noted.

- Latest upstream commit: https://github.com/rtissera/libchdr/tree/6117d59d00ef8620de4cff4d6ecae46368cae881

- Fix https://github.com/libretro/pcsx_rearmed/issues/301
- Specific commit that fixes above problem: https://github.com/rtissera/libchdr/commit/e1acac6d83b36531e543e39a9e1a363e681083e6

deps/libchdr/bitstream.c
deps/libchdr/bitstream.h
deps/libchdr/cdrom.c
deps/libchdr/cdrom.h
deps/libchdr/chd.c
deps/libchdr/chd.h
deps/libchdr/coretypes.h
deps/libchdr/flac.c
deps/libchdr/flac.h
deps/libchdr/huffman.c
deps/libchdr/huffman.h

index 735b97f..3f61c93 100644 (file)
@@ -1,6 +1,6 @@
-// license:BSD-3-Clause
-// copyright-holders:Aaron Giles
-/***************************************************************************
+/* license:BSD-3-Clause
+ * copyright-holders:Aaron Giles
+***************************************************************************
 
     bitstream.c
 
 #include "bitstream.h"
 #include <stdlib.h>
 
-//**************************************************************************
-//  INLINE FUNCTIONS
-//**************************************************************************
+/***************************************************************************
+ *  INLINE FUNCTIONS
+ ***************************************************************************
+ */
 
 int bitstream_overflow(struct bitstream* bitstream) { return ((bitstream->doffset - bitstream->bits / 8) > bitstream->dlength); }
 
-//-------------------------------------------------
-//  create_bitstream - constructor
-//-------------------------------------------------
+/*-------------------------------------------------
+ *  create_bitstream - constructor
+ *-------------------------------------------------
+ */
 
 struct bitstream* create_bitstream(const void *src, uint32_t srclength)
 {
@@ -33,17 +35,18 @@ struct bitstream* create_bitstream(const void *src, uint32_t srclength)
 }
 
 
-//-----------------------------------------------------
-//  bitstream_peek - fetch the requested number of bits
-//  but don't advance the input pointer
-//-----------------------------------------------------
+/*-----------------------------------------------------
+ *  bitstream_peek - fetch the requested number of bits
+ *  but don't advance the input pointer
+ *-----------------------------------------------------
+ */
 
 uint32_t bitstream_peek(struct bitstream* bitstream, int numbits)
 {
        if (numbits == 0)
                return 0;
 
-       // fetch data if we need more
+       /* fetch data if we need more */
        if (numbits > bitstream->bits)
        {
                while (bitstream->bits <= 24)
@@ -55,15 +58,16 @@ uint32_t bitstream_peek(struct bitstream* bitstream, int numbits)
                }
        }
 
-       // return the data
+       /* return the data */
        return bitstream->buffer >> (32 - numbits);
 }
 
 
-//-----------------------------------------------------
-//  bitstream_remove - advance the input pointer by the
-//  specified number of bits
-//-----------------------------------------------------
+/*-----------------------------------------------------
+ *  bitstream_remove - advance the input pointer by the
+ *  specified number of bits
+ *-----------------------------------------------------
+ */
 
 void bitstream_remove(struct bitstream* bitstream, int numbits)
 {
@@ -72,9 +76,10 @@ void bitstream_remove(struct bitstream* bitstream, int numbits)
 }
 
 
-//-----------------------------------------------------
-//  bitstream_read - fetch the requested number of bits
-//-----------------------------------------------------
+/*-----------------------------------------------------
+ *  bitstream_read - fetch the requested number of bits
+ *-----------------------------------------------------
+ */
 
 uint32_t bitstream_read(struct bitstream* bitstream, int numbits)
 {
@@ -84,9 +89,10 @@ uint32_t bitstream_read(struct bitstream* bitstream, int numbits)
 }
 
 
-//-------------------------------------------------
-//  read_offset - return the current read offset
-//-------------------------------------------------
+/*-------------------------------------------------
+ *  read_offset - return the current read offset
+ *-------------------------------------------------
+ */
 
 uint32_t bitstream_read_offset(struct bitstream* bitstream)
 {
@@ -101,9 +107,10 @@ uint32_t bitstream_read_offset(struct bitstream* bitstream)
 }
 
 
-//-------------------------------------------------
-//  flush - flush to the nearest byte
-//-------------------------------------------------
+/*-------------------------------------------------
+ *  flush - flush to the nearest byte
+ *-------------------------------------------------
+ */
 
 uint32_t bitstream_flush(struct bitstream* bitstream)
 {
index 9250d33..d376373 100644 (file)
@@ -1,42 +1,43 @@
-// license:BSD-3-Clause\r
-// copyright-holders:Aaron Giles\r
-/***************************************************************************\r
-\r
-    bitstream.h\r
-\r
-    Helper classes for reading/writing at the bit level.\r
-\r
-***************************************************************************/\r
-\r
-#pragma once\r
-\r
-#ifndef __BITSTREAM_H__\r
-#define __BITSTREAM_H__\r
-\r
-#include <stdint.h>\r
-\r
-//**************************************************************************\r
-//  TYPE DEFINITIONS\r
-//**************************************************************************\r
-\r
-// helper class for reading from a bit buffer\r
-struct bitstream\r
-{\r
-       uint32_t          buffer;       // current bit accumulator\r
-       int               bits;         // number of bits in the accumulator\r
-       const uint8_t *   read;         // read pointer\r
-       uint32_t          doffset;      // byte offset within the data\r
-       uint32_t          dlength;      // length of the data\r
-};\r
-\r
-struct bitstream*      create_bitstream(const void *src, uint32_t srclength);\r
-int                            bitstream_overflow(struct bitstream* bitstream);\r
-uint32_t                       bitstream_read_offset(struct bitstream* bitstream);\r
-\r
-uint32_t                       bitstream_read(struct bitstream* bitstream, int numbits);\r
-uint32_t                       bitstream_peek(struct bitstream* bitstream, int numbits);\r
-void                           bitstream_remove(struct bitstream* bitstream, int numbits);\r
-uint32_t                       bitstream_flush(struct bitstream* bitstream);\r
-\r
-\r
-#endif\r
+/* license:BSD-3-Clause
+ * copyright-holders:Aaron Giles
+***************************************************************************
+
+    bitstream.h
+
+    Helper classes for reading/writing at the bit level.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __BITSTREAM_H__
+#define __BITSTREAM_H__
+
+#include <stdint.h>
+
+/***************************************************************************
+ *  TYPE DEFINITIONS
+ ***************************************************************************
+ */
+
+/* helper class for reading from a bit buffer */
+struct bitstream
+{
+       uint32_t          buffer;       /* current bit accumulator */
+       int               bits;         /* number of bits in the accumulator */
+       const uint8_t *   read;         /* read pointer */
+       uint32_t          doffset;      /* byte offset within the data */
+       uint32_t          dlength;      /* length of the data */
+};
+
+struct bitstream*      create_bitstream(const void *src, uint32_t srclength);
+int                            bitstream_overflow(struct bitstream* bitstream);
+uint32_t                       bitstream_read_offset(struct bitstream* bitstream);
+
+uint32_t                       bitstream_read(struct bitstream* bitstream, int numbits);
+uint32_t                       bitstream_peek(struct bitstream* bitstream, int numbits);
+void                           bitstream_remove(struct bitstream* bitstream, int numbits);
+uint32_t                       bitstream_flush(struct bitstream* bitstream);
+
+
+#endif
index 6c120cb..74a0786 100644 (file)
-// license:BSD-3-Clause\r
-// copyright-holders:Aaron Giles\r
-/***************************************************************************\r
-\r
-    cdrom.c\r
-\r
-    Generic MAME CD-ROM utilties - build IDE and SCSI CD-ROMs on top of this\r
-\r
-****************************************************************************\r
-\r
-    IMPORTANT:\r
-    "physical" block addresses are the actual addresses on the emulated CD.\r
-    "chd" block addresses are the block addresses in the CHD file.\r
-    Because we pad each track to a 4-frame boundary, these addressing\r
-    schemes will differ after track 1!\r
-\r
-***************************************************************************/\r
-\r
-#include <assert.h>\r
-#include <string.h>\r
-\r
-#include "cdrom.h"\r
-\r
-/***************************************************************************\r
-    DEBUGGING\r
-***************************************************************************/\r
-\r
-/** @brief  The verbose. */\r
-#define VERBOSE (0)\r
-#if VERBOSE\r
-\r
-/**\r
- * @def LOG(x) do\r
- *\r
- * @brief   A macro that defines log.\r
- *\r
- * @param   x   The void to process.\r
- */\r
-\r
-#define LOG(x) do { if (VERBOSE) logerror x; } while (0)\r
-\r
-/**\r
- * @fn  void CLIB_DECL logerror(const char *text, ...) ATTR_PRINTF(1,2);\r
- *\r
- * @brief   Logerrors the given text.\r
- *\r
- * @param   text    The text.\r
- *\r
- * @return  A CLIB_DECL.\r
- */\r
-\r
-void CLIB_DECL logerror(const char *text, ...) ATTR_PRINTF(1,2);\r
-#else\r
-\r
-/**\r
- * @def LOG(x);\r
- *\r
- * @brief   A macro that defines log.\r
- *\r
- * @param   x   The void to process.\r
- */\r
-\r
-#define LOG(x)\r
-#endif\r
-\r
-\r
-\r
-/***************************************************************************\r
-    CONSTANTS\r
-***************************************************************************/\r
-\r
-/** @brief  offset within sector. */\r
-#define SYNC_OFFSET 0x000\r
-/** @brief  12 bytes. */\r
-#define SYNC_NUM_BYTES 12\r
-\r
-/** @brief  offset within sector. */\r
-#define MODE_OFFSET 0x00f\r
-\r
-/** @brief  offset within sector. */\r
-#define ECC_P_OFFSET 0x81c\r
-/** @brief  2 lots of 86. */\r
-#define ECC_P_NUM_BYTES 86\r
-/** @brief  24 bytes each. */\r
-#define ECC_P_COMP 24\r
-\r
-/** @brief  The ECC q offset. */\r
-#define ECC_Q_OFFSET (ECC_P_OFFSET + 2 * ECC_P_NUM_BYTES)\r
-/** @brief  2 lots of 52. */\r
-#define ECC_Q_NUM_BYTES 52\r
-/** @brief  43 bytes each. */\r
-#define ECC_Q_COMP 43\r
-\r
-\r
-\r
-/**\r
- * @brief   -------------------------------------------------\r
- *            ECC lookup tables pre-calculated tables for ECC data calcs\r
- *          -------------------------------------------------.\r
- */\r
-\r
-static const uint8_t ecclow[256] =\r
-{\r
-       0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,\r
-       0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e,\r
-       0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e,\r
-       0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e,\r
-       0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e,\r
-       0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe,\r
-       0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,\r
-       0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe,\r
-       0x1d, 0x1f, 0x19, 0x1b, 0x15, 0x17, 0x11, 0x13, 0x0d, 0x0f, 0x09, 0x0b, 0x05, 0x07, 0x01, 0x03,\r
-       0x3d, 0x3f, 0x39, 0x3b, 0x35, 0x37, 0x31, 0x33, 0x2d, 0x2f, 0x29, 0x2b, 0x25, 0x27, 0x21, 0x23,\r
-       0x5d, 0x5f, 0x59, 0x5b, 0x55, 0x57, 0x51, 0x53, 0x4d, 0x4f, 0x49, 0x4b, 0x45, 0x47, 0x41, 0x43,\r
-       0x7d, 0x7f, 0x79, 0x7b, 0x75, 0x77, 0x71, 0x73, 0x6d, 0x6f, 0x69, 0x6b, 0x65, 0x67, 0x61, 0x63,\r
-       0x9d, 0x9f, 0x99, 0x9b, 0x95, 0x97, 0x91, 0x93, 0x8d, 0x8f, 0x89, 0x8b, 0x85, 0x87, 0x81, 0x83,\r
-       0xbd, 0xbf, 0xb9, 0xbb, 0xb5, 0xb7, 0xb1, 0xb3, 0xad, 0xaf, 0xa9, 0xab, 0xa5, 0xa7, 0xa1, 0xa3,\r
-       0xdd, 0xdf, 0xd9, 0xdb, 0xd5, 0xd7, 0xd1, 0xd3, 0xcd, 0xcf, 0xc9, 0xcb, 0xc5, 0xc7, 0xc1, 0xc3,\r
-       0xfd, 0xff, 0xf9, 0xfb, 0xf5, 0xf7, 0xf1, 0xf3, 0xed, 0xef, 0xe9, 0xeb, 0xe5, 0xe7, 0xe1, 0xe3\r
-};\r
-\r
-/** @brief  The ecchigh[ 256]. */\r
-static const uint8_t ecchigh[256] =\r
-{\r
-       0x00, 0xf4, 0xf5, 0x01, 0xf7, 0x03, 0x02, 0xf6, 0xf3, 0x07, 0x06, 0xf2, 0x04, 0xf0, 0xf1, 0x05,\r
-       0xfb, 0x0f, 0x0e, 0xfa, 0x0c, 0xf8, 0xf9, 0x0d, 0x08, 0xfc, 0xfd, 0x09, 0xff, 0x0b, 0x0a, 0xfe,\r
-       0xeb, 0x1f, 0x1e, 0xea, 0x1c, 0xe8, 0xe9, 0x1d, 0x18, 0xec, 0xed, 0x19, 0xef, 0x1b, 0x1a, 0xee,\r
-       0x10, 0xe4, 0xe5, 0x11, 0xe7, 0x13, 0x12, 0xe6, 0xe3, 0x17, 0x16, 0xe2, 0x14, 0xe0, 0xe1, 0x15,\r
-       0xcb, 0x3f, 0x3e, 0xca, 0x3c, 0xc8, 0xc9, 0x3d, 0x38, 0xcc, 0xcd, 0x39, 0xcf, 0x3b, 0x3a, 0xce,\r
-       0x30, 0xc4, 0xc5, 0x31, 0xc7, 0x33, 0x32, 0xc6, 0xc3, 0x37, 0x36, 0xc2, 0x34, 0xc0, 0xc1, 0x35,\r
-       0x20, 0xd4, 0xd5, 0x21, 0xd7, 0x23, 0x22, 0xd6, 0xd3, 0x27, 0x26, 0xd2, 0x24, 0xd0, 0xd1, 0x25,\r
-       0xdb, 0x2f, 0x2e, 0xda, 0x2c, 0xd8, 0xd9, 0x2d, 0x28, 0xdc, 0xdd, 0x29, 0xdf, 0x2b, 0x2a, 0xde,\r
-       0x8b, 0x7f, 0x7e, 0x8a, 0x7c, 0x88, 0x89, 0x7d, 0x78, 0x8c, 0x8d, 0x79, 0x8f, 0x7b, 0x7a, 0x8e,\r
-       0x70, 0x84, 0x85, 0x71, 0x87, 0x73, 0x72, 0x86, 0x83, 0x77, 0x76, 0x82, 0x74, 0x80, 0x81, 0x75,\r
-       0x60, 0x94, 0x95, 0x61, 0x97, 0x63, 0x62, 0x96, 0x93, 0x67, 0x66, 0x92, 0x64, 0x90, 0x91, 0x65,\r
-       0x9b, 0x6f, 0x6e, 0x9a, 0x6c, 0x98, 0x99, 0x6d, 0x68, 0x9c, 0x9d, 0x69, 0x9f, 0x6b, 0x6a, 0x9e,\r
-       0x40, 0xb4, 0xb5, 0x41, 0xb7, 0x43, 0x42, 0xb6, 0xb3, 0x47, 0x46, 0xb2, 0x44, 0xb0, 0xb1, 0x45,\r
-       0xbb, 0x4f, 0x4e, 0xba, 0x4c, 0xb8, 0xb9, 0x4d, 0x48, 0xbc, 0xbd, 0x49, 0xbf, 0x4b, 0x4a, 0xbe,\r
-       0xab, 0x5f, 0x5e, 0xaa, 0x5c, 0xa8, 0xa9, 0x5d, 0x58, 0xac, 0xad, 0x59, 0xaf, 0x5b, 0x5a, 0xae,\r
-       0x50, 0xa4, 0xa5, 0x51, 0xa7, 0x53, 0x52, 0xa6, 0xa3, 0x57, 0x56, 0xa2, 0x54, 0xa0, 0xa1, 0x55\r
-};\r
-\r
-/**\r
- * @brief   -------------------------------------------------\r
- *            poffsets - each row represents the addresses used to calculate a byte of the ECC P\r
- *            data 86 (*2) ECC P bytes, 24 values represented by each\r
- *          -------------------------------------------------.\r
- */\r
-\r
-static const uint16_t poffsets[ECC_P_NUM_BYTES][ECC_P_COMP] =\r
-{\r
-       { 0x000,0x056,0x0ac,0x102,0x158,0x1ae,0x204,0x25a,0x2b0,0x306,0x35c,0x3b2,0x408,0x45e,0x4b4,0x50a,0x560,0x5b6,0x60c,0x662,0x6b8,0x70e,0x764,0x7ba },\r
-       { 0x001,0x057,0x0ad,0x103,0x159,0x1af,0x205,0x25b,0x2b1,0x307,0x35d,0x3b3,0x409,0x45f,0x4b5,0x50b,0x561,0x5b7,0x60d,0x663,0x6b9,0x70f,0x765,0x7bb },\r
-       { 0x002,0x058,0x0ae,0x104,0x15a,0x1b0,0x206,0x25c,0x2b2,0x308,0x35e,0x3b4,0x40a,0x460,0x4b6,0x50c,0x562,0x5b8,0x60e,0x664,0x6ba,0x710,0x766,0x7bc },\r
-       { 0x003,0x059,0x0af,0x105,0x15b,0x1b1,0x207,0x25d,0x2b3,0x309,0x35f,0x3b5,0x40b,0x461,0x4b7,0x50d,0x563,0x5b9,0x60f,0x665,0x6bb,0x711,0x767,0x7bd },\r
-       { 0x004,0x05a,0x0b0,0x106,0x15c,0x1b2,0x208,0x25e,0x2b4,0x30a,0x360,0x3b6,0x40c,0x462,0x4b8,0x50e,0x564,0x5ba,0x610,0x666,0x6bc,0x712,0x768,0x7be },\r
-       { 0x005,0x05b,0x0b1,0x107,0x15d,0x1b3,0x209,0x25f,0x2b5,0x30b,0x361,0x3b7,0x40d,0x463,0x4b9,0x50f,0x565,0x5bb,0x611,0x667,0x6bd,0x713,0x769,0x7bf },\r
-       { 0x006,0x05c,0x0b2,0x108,0x15e,0x1b4,0x20a,0x260,0x2b6,0x30c,0x362,0x3b8,0x40e,0x464,0x4ba,0x510,0x566,0x5bc,0x612,0x668,0x6be,0x714,0x76a,0x7c0 },\r
-       { 0x007,0x05d,0x0b3,0x109,0x15f,0x1b5,0x20b,0x261,0x2b7,0x30d,0x363,0x3b9,0x40f,0x465,0x4bb,0x511,0x567,0x5bd,0x613,0x669,0x6bf,0x715,0x76b,0x7c1 },\r
-       { 0x008,0x05e,0x0b4,0x10a,0x160,0x1b6,0x20c,0x262,0x2b8,0x30e,0x364,0x3ba,0x410,0x466,0x4bc,0x512,0x568,0x5be,0x614,0x66a,0x6c0,0x716,0x76c,0x7c2 },\r
-       { 0x009,0x05f,0x0b5,0x10b,0x161,0x1b7,0x20d,0x263,0x2b9,0x30f,0x365,0x3bb,0x411,0x467,0x4bd,0x513,0x569,0x5bf,0x615,0x66b,0x6c1,0x717,0x76d,0x7c3 },\r
-       { 0x00a,0x060,0x0b6,0x10c,0x162,0x1b8,0x20e,0x264,0x2ba,0x310,0x366,0x3bc,0x412,0x468,0x4be,0x514,0x56a,0x5c0,0x616,0x66c,0x6c2,0x718,0x76e,0x7c4 },\r
-       { 0x00b,0x061,0x0b7,0x10d,0x163,0x1b9,0x20f,0x265,0x2bb,0x311,0x367,0x3bd,0x413,0x469,0x4bf,0x515,0x56b,0x5c1,0x617,0x66d,0x6c3,0x719,0x76f,0x7c5 },\r
-       { 0x00c,0x062,0x0b8,0x10e,0x164,0x1ba,0x210,0x266,0x2bc,0x312,0x368,0x3be,0x414,0x46a,0x4c0,0x516,0x56c,0x5c2,0x618,0x66e,0x6c4,0x71a,0x770,0x7c6 },\r
-       { 0x00d,0x063,0x0b9,0x10f,0x165,0x1bb,0x211,0x267,0x2bd,0x313,0x369,0x3bf,0x415,0x46b,0x4c1,0x517,0x56d,0x5c3,0x619,0x66f,0x6c5,0x71b,0x771,0x7c7 },\r
-       { 0x00e,0x064,0x0ba,0x110,0x166,0x1bc,0x212,0x268,0x2be,0x314,0x36a,0x3c0,0x416,0x46c,0x4c2,0x518,0x56e,0x5c4,0x61a,0x670,0x6c6,0x71c,0x772,0x7c8 },\r
-       { 0x00f,0x065,0x0bb,0x111,0x167,0x1bd,0x213,0x269,0x2bf,0x315,0x36b,0x3c1,0x417,0x46d,0x4c3,0x519,0x56f,0x5c5,0x61b,0x671,0x6c7,0x71d,0x773,0x7c9 },\r
-       { 0x010,0x066,0x0bc,0x112,0x168,0x1be,0x214,0x26a,0x2c0,0x316,0x36c,0x3c2,0x418,0x46e,0x4c4,0x51a,0x570,0x5c6,0x61c,0x672,0x6c8,0x71e,0x774,0x7ca },\r
-       { 0x011,0x067,0x0bd,0x113,0x169,0x1bf,0x215,0x26b,0x2c1,0x317,0x36d,0x3c3,0x419,0x46f,0x4c5,0x51b,0x571,0x5c7,0x61d,0x673,0x6c9,0x71f,0x775,0x7cb },\r
-       { 0x012,0x068,0x0be,0x114,0x16a,0x1c0,0x216,0x26c,0x2c2,0x318,0x36e,0x3c4,0x41a,0x470,0x4c6,0x51c,0x572,0x5c8,0x61e,0x674,0x6ca,0x720,0x776,0x7cc },\r
-       { 0x013,0x069,0x0bf,0x115,0x16b,0x1c1,0x217,0x26d,0x2c3,0x319,0x36f,0x3c5,0x41b,0x471,0x4c7,0x51d,0x573,0x5c9,0x61f,0x675,0x6cb,0x721,0x777,0x7cd },\r
-       { 0x014,0x06a,0x0c0,0x116,0x16c,0x1c2,0x218,0x26e,0x2c4,0x31a,0x370,0x3c6,0x41c,0x472,0x4c8,0x51e,0x574,0x5ca,0x620,0x676,0x6cc,0x722,0x778,0x7ce },\r
-       { 0x015,0x06b,0x0c1,0x117,0x16d,0x1c3,0x219,0x26f,0x2c5,0x31b,0x371,0x3c7,0x41d,0x473,0x4c9,0x51f,0x575,0x5cb,0x621,0x677,0x6cd,0x723,0x779,0x7cf },\r
-       { 0x016,0x06c,0x0c2,0x118,0x16e,0x1c4,0x21a,0x270,0x2c6,0x31c,0x372,0x3c8,0x41e,0x474,0x4ca,0x520,0x576,0x5cc,0x622,0x678,0x6ce,0x724,0x77a,0x7d0 },\r
-       { 0x017,0x06d,0x0c3,0x119,0x16f,0x1c5,0x21b,0x271,0x2c7,0x31d,0x373,0x3c9,0x41f,0x475,0x4cb,0x521,0x577,0x5cd,0x623,0x679,0x6cf,0x725,0x77b,0x7d1 },\r
-       { 0x018,0x06e,0x0c4,0x11a,0x170,0x1c6,0x21c,0x272,0x2c8,0x31e,0x374,0x3ca,0x420,0x476,0x4cc,0x522,0x578,0x5ce,0x624,0x67a,0x6d0,0x726,0x77c,0x7d2 },\r
-       { 0x019,0x06f,0x0c5,0x11b,0x171,0x1c7,0x21d,0x273,0x2c9,0x31f,0x375,0x3cb,0x421,0x477,0x4cd,0x523,0x579,0x5cf,0x625,0x67b,0x6d1,0x727,0x77d,0x7d3 },\r
-       { 0x01a,0x070,0x0c6,0x11c,0x172,0x1c8,0x21e,0x274,0x2ca,0x320,0x376,0x3cc,0x422,0x478,0x4ce,0x524,0x57a,0x5d0,0x626,0x67c,0x6d2,0x728,0x77e,0x7d4 },\r
-       { 0x01b,0x071,0x0c7,0x11d,0x173,0x1c9,0x21f,0x275,0x2cb,0x321,0x377,0x3cd,0x423,0x479,0x4cf,0x525,0x57b,0x5d1,0x627,0x67d,0x6d3,0x729,0x77f,0x7d5 },\r
-       { 0x01c,0x072,0x0c8,0x11e,0x174,0x1ca,0x220,0x276,0x2cc,0x322,0x378,0x3ce,0x424,0x47a,0x4d0,0x526,0x57c,0x5d2,0x628,0x67e,0x6d4,0x72a,0x780,0x7d6 },\r
-       { 0x01d,0x073,0x0c9,0x11f,0x175,0x1cb,0x221,0x277,0x2cd,0x323,0x379,0x3cf,0x425,0x47b,0x4d1,0x527,0x57d,0x5d3,0x629,0x67f,0x6d5,0x72b,0x781,0x7d7 },\r
-       { 0x01e,0x074,0x0ca,0x120,0x176,0x1cc,0x222,0x278,0x2ce,0x324,0x37a,0x3d0,0x426,0x47c,0x4d2,0x528,0x57e,0x5d4,0x62a,0x680,0x6d6,0x72c,0x782,0x7d8 },\r
-       { 0x01f,0x075,0x0cb,0x121,0x177,0x1cd,0x223,0x279,0x2cf,0x325,0x37b,0x3d1,0x427,0x47d,0x4d3,0x529,0x57f,0x5d5,0x62b,0x681,0x6d7,0x72d,0x783,0x7d9 },\r
-       { 0x020,0x076,0x0cc,0x122,0x178,0x1ce,0x224,0x27a,0x2d0,0x326,0x37c,0x3d2,0x428,0x47e,0x4d4,0x52a,0x580,0x5d6,0x62c,0x682,0x6d8,0x72e,0x784,0x7da },\r
-       { 0x021,0x077,0x0cd,0x123,0x179,0x1cf,0x225,0x27b,0x2d1,0x327,0x37d,0x3d3,0x429,0x47f,0x4d5,0x52b,0x581,0x5d7,0x62d,0x683,0x6d9,0x72f,0x785,0x7db },\r
-       { 0x022,0x078,0x0ce,0x124,0x17a,0x1d0,0x226,0x27c,0x2d2,0x328,0x37e,0x3d4,0x42a,0x480,0x4d6,0x52c,0x582,0x5d8,0x62e,0x684,0x6da,0x730,0x786,0x7dc },\r
-       { 0x023,0x079,0x0cf,0x125,0x17b,0x1d1,0x227,0x27d,0x2d3,0x329,0x37f,0x3d5,0x42b,0x481,0x4d7,0x52d,0x583,0x5d9,0x62f,0x685,0x6db,0x731,0x787,0x7dd },\r
-       { 0x024,0x07a,0x0d0,0x126,0x17c,0x1d2,0x228,0x27e,0x2d4,0x32a,0x380,0x3d6,0x42c,0x482,0x4d8,0x52e,0x584,0x5da,0x630,0x686,0x6dc,0x732,0x788,0x7de },\r
-       { 0x025,0x07b,0x0d1,0x127,0x17d,0x1d3,0x229,0x27f,0x2d5,0x32b,0x381,0x3d7,0x42d,0x483,0x4d9,0x52f,0x585,0x5db,0x631,0x687,0x6dd,0x733,0x789,0x7df },\r
-       { 0x026,0x07c,0x0d2,0x128,0x17e,0x1d4,0x22a,0x280,0x2d6,0x32c,0x382,0x3d8,0x42e,0x484,0x4da,0x530,0x586,0x5dc,0x632,0x688,0x6de,0x734,0x78a,0x7e0 },\r
-       { 0x027,0x07d,0x0d3,0x129,0x17f,0x1d5,0x22b,0x281,0x2d7,0x32d,0x383,0x3d9,0x42f,0x485,0x4db,0x531,0x587,0x5dd,0x633,0x689,0x6df,0x735,0x78b,0x7e1 },\r
-       { 0x028,0x07e,0x0d4,0x12a,0x180,0x1d6,0x22c,0x282,0x2d8,0x32e,0x384,0x3da,0x430,0x486,0x4dc,0x532,0x588,0x5de,0x634,0x68a,0x6e0,0x736,0x78c,0x7e2 },\r
-       { 0x029,0x07f,0x0d5,0x12b,0x181,0x1d7,0x22d,0x283,0x2d9,0x32f,0x385,0x3db,0x431,0x487,0x4dd,0x533,0x589,0x5df,0x635,0x68b,0x6e1,0x737,0x78d,0x7e3 },\r
-       { 0x02a,0x080,0x0d6,0x12c,0x182,0x1d8,0x22e,0x284,0x2da,0x330,0x386,0x3dc,0x432,0x488,0x4de,0x534,0x58a,0x5e0,0x636,0x68c,0x6e2,0x738,0x78e,0x7e4 },\r
-       { 0x02b,0x081,0x0d7,0x12d,0x183,0x1d9,0x22f,0x285,0x2db,0x331,0x387,0x3dd,0x433,0x489,0x4df,0x535,0x58b,0x5e1,0x637,0x68d,0x6e3,0x739,0x78f,0x7e5 },\r
-       { 0x02c,0x082,0x0d8,0x12e,0x184,0x1da,0x230,0x286,0x2dc,0x332,0x388,0x3de,0x434,0x48a,0x4e0,0x536,0x58c,0x5e2,0x638,0x68e,0x6e4,0x73a,0x790,0x7e6 },\r
-       { 0x02d,0x083,0x0d9,0x12f,0x185,0x1db,0x231,0x287,0x2dd,0x333,0x389,0x3df,0x435,0x48b,0x4e1,0x537,0x58d,0x5e3,0x639,0x68f,0x6e5,0x73b,0x791,0x7e7 },\r
-       { 0x02e,0x084,0x0da,0x130,0x186,0x1dc,0x232,0x288,0x2de,0x334,0x38a,0x3e0,0x436,0x48c,0x4e2,0x538,0x58e,0x5e4,0x63a,0x690,0x6e6,0x73c,0x792,0x7e8 },\r
-       { 0x02f,0x085,0x0db,0x131,0x187,0x1dd,0x233,0x289,0x2df,0x335,0x38b,0x3e1,0x437,0x48d,0x4e3,0x539,0x58f,0x5e5,0x63b,0x691,0x6e7,0x73d,0x793,0x7e9 },\r
-       { 0x030,0x086,0x0dc,0x132,0x188,0x1de,0x234,0x28a,0x2e0,0x336,0x38c,0x3e2,0x438,0x48e,0x4e4,0x53a,0x590,0x5e6,0x63c,0x692,0x6e8,0x73e,0x794,0x7ea },\r
-       { 0x031,0x087,0x0dd,0x133,0x189,0x1df,0x235,0x28b,0x2e1,0x337,0x38d,0x3e3,0x439,0x48f,0x4e5,0x53b,0x591,0x5e7,0x63d,0x693,0x6e9,0x73f,0x795,0x7eb },\r
-       { 0x032,0x088,0x0de,0x134,0x18a,0x1e0,0x236,0x28c,0x2e2,0x338,0x38e,0x3e4,0x43a,0x490,0x4e6,0x53c,0x592,0x5e8,0x63e,0x694,0x6ea,0x740,0x796,0x7ec },\r
-       { 0x033,0x089,0x0df,0x135,0x18b,0x1e1,0x237,0x28d,0x2e3,0x339,0x38f,0x3e5,0x43b,0x491,0x4e7,0x53d,0x593,0x5e9,0x63f,0x695,0x6eb,0x741,0x797,0x7ed },\r
-       { 0x034,0x08a,0x0e0,0x136,0x18c,0x1e2,0x238,0x28e,0x2e4,0x33a,0x390,0x3e6,0x43c,0x492,0x4e8,0x53e,0x594,0x5ea,0x640,0x696,0x6ec,0x742,0x798,0x7ee },\r
-       { 0x035,0x08b,0x0e1,0x137,0x18d,0x1e3,0x239,0x28f,0x2e5,0x33b,0x391,0x3e7,0x43d,0x493,0x4e9,0x53f,0x595,0x5eb,0x641,0x697,0x6ed,0x743,0x799,0x7ef },\r
-       { 0x036,0x08c,0x0e2,0x138,0x18e,0x1e4,0x23a,0x290,0x2e6,0x33c,0x392,0x3e8,0x43e,0x494,0x4ea,0x540,0x596,0x5ec,0x642,0x698,0x6ee,0x744,0x79a,0x7f0 },\r
-       { 0x037,0x08d,0x0e3,0x139,0x18f,0x1e5,0x23b,0x291,0x2e7,0x33d,0x393,0x3e9,0x43f,0x495,0x4eb,0x541,0x597,0x5ed,0x643,0x699,0x6ef,0x745,0x79b,0x7f1 },\r
-       { 0x038,0x08e,0x0e4,0x13a,0x190,0x1e6,0x23c,0x292,0x2e8,0x33e,0x394,0x3ea,0x440,0x496,0x4ec,0x542,0x598,0x5ee,0x644,0x69a,0x6f0,0x746,0x79c,0x7f2 },\r
-       { 0x039,0x08f,0x0e5,0x13b,0x191,0x1e7,0x23d,0x293,0x2e9,0x33f,0x395,0x3eb,0x441,0x497,0x4ed,0x543,0x599,0x5ef,0x645,0x69b,0x6f1,0x747,0x79d,0x7f3 },\r
-       { 0x03a,0x090,0x0e6,0x13c,0x192,0x1e8,0x23e,0x294,0x2ea,0x340,0x396,0x3ec,0x442,0x498,0x4ee,0x544,0x59a,0x5f0,0x646,0x69c,0x6f2,0x748,0x79e,0x7f4 },\r
-       { 0x03b,0x091,0x0e7,0x13d,0x193,0x1e9,0x23f,0x295,0x2eb,0x341,0x397,0x3ed,0x443,0x499,0x4ef,0x545,0x59b,0x5f1,0x647,0x69d,0x6f3,0x749,0x79f,0x7f5 },\r
-       { 0x03c,0x092,0x0e8,0x13e,0x194,0x1ea,0x240,0x296,0x2ec,0x342,0x398,0x3ee,0x444,0x49a,0x4f0,0x546,0x59c,0x5f2,0x648,0x69e,0x6f4,0x74a,0x7a0,0x7f6 },\r
-       { 0x03d,0x093,0x0e9,0x13f,0x195,0x1eb,0x241,0x297,0x2ed,0x343,0x399,0x3ef,0x445,0x49b,0x4f1,0x547,0x59d,0x5f3,0x649,0x69f,0x6f5,0x74b,0x7a1,0x7f7 },\r
-       { 0x03e,0x094,0x0ea,0x140,0x196,0x1ec,0x242,0x298,0x2ee,0x344,0x39a,0x3f0,0x446,0x49c,0x4f2,0x548,0x59e,0x5f4,0x64a,0x6a0,0x6f6,0x74c,0x7a2,0x7f8 },\r
-       { 0x03f,0x095,0x0eb,0x141,0x197,0x1ed,0x243,0x299,0x2ef,0x345,0x39b,0x3f1,0x447,0x49d,0x4f3,0x549,0x59f,0x5f5,0x64b,0x6a1,0x6f7,0x74d,0x7a3,0x7f9 },\r
-       { 0x040,0x096,0x0ec,0x142,0x198,0x1ee,0x244,0x29a,0x2f0,0x346,0x39c,0x3f2,0x448,0x49e,0x4f4,0x54a,0x5a0,0x5f6,0x64c,0x6a2,0x6f8,0x74e,0x7a4,0x7fa },\r
-       { 0x041,0x097,0x0ed,0x143,0x199,0x1ef,0x245,0x29b,0x2f1,0x347,0x39d,0x3f3,0x449,0x49f,0x4f5,0x54b,0x5a1,0x5f7,0x64d,0x6a3,0x6f9,0x74f,0x7a5,0x7fb },\r
-       { 0x042,0x098,0x0ee,0x144,0x19a,0x1f0,0x246,0x29c,0x2f2,0x348,0x39e,0x3f4,0x44a,0x4a0,0x4f6,0x54c,0x5a2,0x5f8,0x64e,0x6a4,0x6fa,0x750,0x7a6,0x7fc },\r
-       { 0x043,0x099,0x0ef,0x145,0x19b,0x1f1,0x247,0x29d,0x2f3,0x349,0x39f,0x3f5,0x44b,0x4a1,0x4f7,0x54d,0x5a3,0x5f9,0x64f,0x6a5,0x6fb,0x751,0x7a7,0x7fd },\r
-       { 0x044,0x09a,0x0f0,0x146,0x19c,0x1f2,0x248,0x29e,0x2f4,0x34a,0x3a0,0x3f6,0x44c,0x4a2,0x4f8,0x54e,0x5a4,0x5fa,0x650,0x6a6,0x6fc,0x752,0x7a8,0x7fe },\r
-       { 0x045,0x09b,0x0f1,0x147,0x19d,0x1f3,0x249,0x29f,0x2f5,0x34b,0x3a1,0x3f7,0x44d,0x4a3,0x4f9,0x54f,0x5a5,0x5fb,0x651,0x6a7,0x6fd,0x753,0x7a9,0x7ff },\r
-       { 0x046,0x09c,0x0f2,0x148,0x19e,0x1f4,0x24a,0x2a0,0x2f6,0x34c,0x3a2,0x3f8,0x44e,0x4a4,0x4fa,0x550,0x5a6,0x5fc,0x652,0x6a8,0x6fe,0x754,0x7aa,0x800 },\r
-       { 0x047,0x09d,0x0f3,0x149,0x19f,0x1f5,0x24b,0x2a1,0x2f7,0x34d,0x3a3,0x3f9,0x44f,0x4a5,0x4fb,0x551,0x5a7,0x5fd,0x653,0x6a9,0x6ff,0x755,0x7ab,0x801 },\r
-       { 0x048,0x09e,0x0f4,0x14a,0x1a0,0x1f6,0x24c,0x2a2,0x2f8,0x34e,0x3a4,0x3fa,0x450,0x4a6,0x4fc,0x552,0x5a8,0x5fe,0x654,0x6aa,0x700,0x756,0x7ac,0x802 },\r
-       { 0x049,0x09f,0x0f5,0x14b,0x1a1,0x1f7,0x24d,0x2a3,0x2f9,0x34f,0x3a5,0x3fb,0x451,0x4a7,0x4fd,0x553,0x5a9,0x5ff,0x655,0x6ab,0x701,0x757,0x7ad,0x803 },\r
-       { 0x04a,0x0a0,0x0f6,0x14c,0x1a2,0x1f8,0x24e,0x2a4,0x2fa,0x350,0x3a6,0x3fc,0x452,0x4a8,0x4fe,0x554,0x5aa,0x600,0x656,0x6ac,0x702,0x758,0x7ae,0x804 },\r
-       { 0x04b,0x0a1,0x0f7,0x14d,0x1a3,0x1f9,0x24f,0x2a5,0x2fb,0x351,0x3a7,0x3fd,0x453,0x4a9,0x4ff,0x555,0x5ab,0x601,0x657,0x6ad,0x703,0x759,0x7af,0x805 },\r
-       { 0x04c,0x0a2,0x0f8,0x14e,0x1a4,0x1fa,0x250,0x2a6,0x2fc,0x352,0x3a8,0x3fe,0x454,0x4aa,0x500,0x556,0x5ac,0x602,0x658,0x6ae,0x704,0x75a,0x7b0,0x806 },\r
-       { 0x04d,0x0a3,0x0f9,0x14f,0x1a5,0x1fb,0x251,0x2a7,0x2fd,0x353,0x3a9,0x3ff,0x455,0x4ab,0x501,0x557,0x5ad,0x603,0x659,0x6af,0x705,0x75b,0x7b1,0x807 },\r
-       { 0x04e,0x0a4,0x0fa,0x150,0x1a6,0x1fc,0x252,0x2a8,0x2fe,0x354,0x3aa,0x400,0x456,0x4ac,0x502,0x558,0x5ae,0x604,0x65a,0x6b0,0x706,0x75c,0x7b2,0x808 },\r
-       { 0x04f,0x0a5,0x0fb,0x151,0x1a7,0x1fd,0x253,0x2a9,0x2ff,0x355,0x3ab,0x401,0x457,0x4ad,0x503,0x559,0x5af,0x605,0x65b,0x6b1,0x707,0x75d,0x7b3,0x809 },\r
-       { 0x050,0x0a6,0x0fc,0x152,0x1a8,0x1fe,0x254,0x2aa,0x300,0x356,0x3ac,0x402,0x458,0x4ae,0x504,0x55a,0x5b0,0x606,0x65c,0x6b2,0x708,0x75e,0x7b4,0x80a },\r
-       { 0x051,0x0a7,0x0fd,0x153,0x1a9,0x1ff,0x255,0x2ab,0x301,0x357,0x3ad,0x403,0x459,0x4af,0x505,0x55b,0x5b1,0x607,0x65d,0x6b3,0x709,0x75f,0x7b5,0x80b },\r
-       { 0x052,0x0a8,0x0fe,0x154,0x1aa,0x200,0x256,0x2ac,0x302,0x358,0x3ae,0x404,0x45a,0x4b0,0x506,0x55c,0x5b2,0x608,0x65e,0x6b4,0x70a,0x760,0x7b6,0x80c },\r
-       { 0x053,0x0a9,0x0ff,0x155,0x1ab,0x201,0x257,0x2ad,0x303,0x359,0x3af,0x405,0x45b,0x4b1,0x507,0x55d,0x5b3,0x609,0x65f,0x6b5,0x70b,0x761,0x7b7,0x80d },\r
-       { 0x054,0x0aa,0x100,0x156,0x1ac,0x202,0x258,0x2ae,0x304,0x35a,0x3b0,0x406,0x45c,0x4b2,0x508,0x55e,0x5b4,0x60a,0x660,0x6b6,0x70c,0x762,0x7b8,0x80e },\r
-       { 0x055,0x0ab,0x101,0x157,0x1ad,0x203,0x259,0x2af,0x305,0x35b,0x3b1,0x407,0x45d,0x4b3,0x509,0x55f,0x5b5,0x60b,0x661,0x6b7,0x70d,0x763,0x7b9,0x80f }\r
-};\r
-\r
-/**\r
- * @brief   -------------------------------------------------\r
- *            qoffsets - each row represents the addresses used to calculate a byte of the ECC Q\r
- *            data 52 (*2) ECC Q bytes, 43 values represented by each\r
- *          -------------------------------------------------.\r
- */\r
-\r
-static const uint16_t qoffsets[ECC_Q_NUM_BYTES][ECC_Q_COMP] =\r
-{\r
-       { 0x000,0x058,0x0b0,0x108,0x160,0x1b8,0x210,0x268,0x2c0,0x318,0x370,0x3c8,0x420,0x478,0x4d0,0x528,0x580,0x5d8,0x630,0x688,0x6e0,0x738,0x790,0x7e8,0x840,0x898,0x034,0x08c,0x0e4,0x13c,0x194,0x1ec,0x244,0x29c,0x2f4,0x34c,0x3a4,0x3fc,0x454,0x4ac,0x504,0x55c,0x5b4 },\r
-       { 0x001,0x059,0x0b1,0x109,0x161,0x1b9,0x211,0x269,0x2c1,0x319,0x371,0x3c9,0x421,0x479,0x4d1,0x529,0x581,0x5d9,0x631,0x689,0x6e1,0x739,0x791,0x7e9,0x841,0x899,0x035,0x08d,0x0e5,0x13d,0x195,0x1ed,0x245,0x29d,0x2f5,0x34d,0x3a5,0x3fd,0x455,0x4ad,0x505,0x55d,0x5b5 },\r
-       { 0x056,0x0ae,0x106,0x15e,0x1b6,0x20e,0x266,0x2be,0x316,0x36e,0x3c6,0x41e,0x476,0x4ce,0x526,0x57e,0x5d6,0x62e,0x686,0x6de,0x736,0x78e,0x7e6,0x83e,0x896,0x032,0x08a,0x0e2,0x13a,0x192,0x1ea,0x242,0x29a,0x2f2,0x34a,0x3a2,0x3fa,0x452,0x4aa,0x502,0x55a,0x5b2,0x60a },\r
-       { 0x057,0x0af,0x107,0x15f,0x1b7,0x20f,0x267,0x2bf,0x317,0x36f,0x3c7,0x41f,0x477,0x4cf,0x527,0x57f,0x5d7,0x62f,0x687,0x6df,0x737,0x78f,0x7e7,0x83f,0x897,0x033,0x08b,0x0e3,0x13b,0x193,0x1eb,0x243,0x29b,0x2f3,0x34b,0x3a3,0x3fb,0x453,0x4ab,0x503,0x55b,0x5b3,0x60b },\r
-       { 0x0ac,0x104,0x15c,0x1b4,0x20c,0x264,0x2bc,0x314,0x36c,0x3c4,0x41c,0x474,0x4cc,0x524,0x57c,0x5d4,0x62c,0x684,0x6dc,0x734,0x78c,0x7e4,0x83c,0x894,0x030,0x088,0x0e0,0x138,0x190,0x1e8,0x240,0x298,0x2f0,0x348,0x3a0,0x3f8,0x450,0x4a8,0x500,0x558,0x5b0,0x608,0x660 },\r
-       { 0x0ad,0x105,0x15d,0x1b5,0x20d,0x265,0x2bd,0x315,0x36d,0x3c5,0x41d,0x475,0x4cd,0x525,0x57d,0x5d5,0x62d,0x685,0x6dd,0x735,0x78d,0x7e5,0x83d,0x895,0x031,0x089,0x0e1,0x139,0x191,0x1e9,0x241,0x299,0x2f1,0x349,0x3a1,0x3f9,0x451,0x4a9,0x501,0x559,0x5b1,0x609,0x661 },\r
-       { 0x102,0x15a,0x1b2,0x20a,0x262,0x2ba,0x312,0x36a,0x3c2,0x41a,0x472,0x4ca,0x522,0x57a,0x5d2,0x62a,0x682,0x6da,0x732,0x78a,0x7e2,0x83a,0x892,0x02e,0x086,0x0de,0x136,0x18e,0x1e6,0x23e,0x296,0x2ee,0x346,0x39e,0x3f6,0x44e,0x4a6,0x4fe,0x556,0x5ae,0x606,0x65e,0x6b6 },\r
-       { 0x103,0x15b,0x1b3,0x20b,0x263,0x2bb,0x313,0x36b,0x3c3,0x41b,0x473,0x4cb,0x523,0x57b,0x5d3,0x62b,0x683,0x6db,0x733,0x78b,0x7e3,0x83b,0x893,0x02f,0x087,0x0df,0x137,0x18f,0x1e7,0x23f,0x297,0x2ef,0x347,0x39f,0x3f7,0x44f,0x4a7,0x4ff,0x557,0x5af,0x607,0x65f,0x6b7 },\r
-       { 0x158,0x1b0,0x208,0x260,0x2b8,0x310,0x368,0x3c0,0x418,0x470,0x4c8,0x520,0x578,0x5d0,0x628,0x680,0x6d8,0x730,0x788,0x7e0,0x838,0x890,0x02c,0x084,0x0dc,0x134,0x18c,0x1e4,0x23c,0x294,0x2ec,0x344,0x39c,0x3f4,0x44c,0x4a4,0x4fc,0x554,0x5ac,0x604,0x65c,0x6b4,0x70c },\r
-       { 0x159,0x1b1,0x209,0x261,0x2b9,0x311,0x369,0x3c1,0x419,0x471,0x4c9,0x521,0x579,0x5d1,0x629,0x681,0x6d9,0x731,0x789,0x7e1,0x839,0x891,0x02d,0x085,0x0dd,0x135,0x18d,0x1e5,0x23d,0x295,0x2ed,0x345,0x39d,0x3f5,0x44d,0x4a5,0x4fd,0x555,0x5ad,0x605,0x65d,0x6b5,0x70d },\r
-       { 0x1ae,0x206,0x25e,0x2b6,0x30e,0x366,0x3be,0x416,0x46e,0x4c6,0x51e,0x576,0x5ce,0x626,0x67e,0x6d6,0x72e,0x786,0x7de,0x836,0x88e,0x02a,0x082,0x0da,0x132,0x18a,0x1e2,0x23a,0x292,0x2ea,0x342,0x39a,0x3f2,0x44a,0x4a2,0x4fa,0x552,0x5aa,0x602,0x65a,0x6b2,0x70a,0x762 },\r
-       { 0x1af,0x207,0x25f,0x2b7,0x30f,0x367,0x3bf,0x417,0x46f,0x4c7,0x51f,0x577,0x5cf,0x627,0x67f,0x6d7,0x72f,0x787,0x7df,0x837,0x88f,0x02b,0x083,0x0db,0x133,0x18b,0x1e3,0x23b,0x293,0x2eb,0x343,0x39b,0x3f3,0x44b,0x4a3,0x4fb,0x553,0x5ab,0x603,0x65b,0x6b3,0x70b,0x763 },\r
-       { 0x204,0x25c,0x2b4,0x30c,0x364,0x3bc,0x414,0x46c,0x4c4,0x51c,0x574,0x5cc,0x624,0x67c,0x6d4,0x72c,0x784,0x7dc,0x834,0x88c,0x028,0x080,0x0d8,0x130,0x188,0x1e0,0x238,0x290,0x2e8,0x340,0x398,0x3f0,0x448,0x4a0,0x4f8,0x550,0x5a8,0x600,0x658,0x6b0,0x708,0x760,0x7b8 },\r
-       { 0x205,0x25d,0x2b5,0x30d,0x365,0x3bd,0x415,0x46d,0x4c5,0x51d,0x575,0x5cd,0x625,0x67d,0x6d5,0x72d,0x785,0x7dd,0x835,0x88d,0x029,0x081,0x0d9,0x131,0x189,0x1e1,0x239,0x291,0x2e9,0x341,0x399,0x3f1,0x449,0x4a1,0x4f9,0x551,0x5a9,0x601,0x659,0x6b1,0x709,0x761,0x7b9 },\r
-       { 0x25a,0x2b2,0x30a,0x362,0x3ba,0x412,0x46a,0x4c2,0x51a,0x572,0x5ca,0x622,0x67a,0x6d2,0x72a,0x782,0x7da,0x832,0x88a,0x026,0x07e,0x0d6,0x12e,0x186,0x1de,0x236,0x28e,0x2e6,0x33e,0x396,0x3ee,0x446,0x49e,0x4f6,0x54e,0x5a6,0x5fe,0x656,0x6ae,0x706,0x75e,0x7b6,0x80e },\r
-       { 0x25b,0x2b3,0x30b,0x363,0x3bb,0x413,0x46b,0x4c3,0x51b,0x573,0x5cb,0x623,0x67b,0x6d3,0x72b,0x783,0x7db,0x833,0x88b,0x027,0x07f,0x0d7,0x12f,0x187,0x1df,0x237,0x28f,0x2e7,0x33f,0x397,0x3ef,0x447,0x49f,0x4f7,0x54f,0x5a7,0x5ff,0x657,0x6af,0x707,0x75f,0x7b7,0x80f },\r
-       { 0x2b0,0x308,0x360,0x3b8,0x410,0x468,0x4c0,0x518,0x570,0x5c8,0x620,0x678,0x6d0,0x728,0x780,0x7d8,0x830,0x888,0x024,0x07c,0x0d4,0x12c,0x184,0x1dc,0x234,0x28c,0x2e4,0x33c,0x394,0x3ec,0x444,0x49c,0x4f4,0x54c,0x5a4,0x5fc,0x654,0x6ac,0x704,0x75c,0x7b4,0x80c,0x864 },\r
-       { 0x2b1,0x309,0x361,0x3b9,0x411,0x469,0x4c1,0x519,0x571,0x5c9,0x621,0x679,0x6d1,0x729,0x781,0x7d9,0x831,0x889,0x025,0x07d,0x0d5,0x12d,0x185,0x1dd,0x235,0x28d,0x2e5,0x33d,0x395,0x3ed,0x445,0x49d,0x4f5,0x54d,0x5a5,0x5fd,0x655,0x6ad,0x705,0x75d,0x7b5,0x80d,0x865 },\r
-       { 0x306,0x35e,0x3b6,0x40e,0x466,0x4be,0x516,0x56e,0x5c6,0x61e,0x676,0x6ce,0x726,0x77e,0x7d6,0x82e,0x886,0x022,0x07a,0x0d2,0x12a,0x182,0x1da,0x232,0x28a,0x2e2,0x33a,0x392,0x3ea,0x442,0x49a,0x4f2,0x54a,0x5a2,0x5fa,0x652,0x6aa,0x702,0x75a,0x7b2,0x80a,0x862,0x8ba },\r
-       { 0x307,0x35f,0x3b7,0x40f,0x467,0x4bf,0x517,0x56f,0x5c7,0x61f,0x677,0x6cf,0x727,0x77f,0x7d7,0x82f,0x887,0x023,0x07b,0x0d3,0x12b,0x183,0x1db,0x233,0x28b,0x2e3,0x33b,0x393,0x3eb,0x443,0x49b,0x4f3,0x54b,0x5a3,0x5fb,0x653,0x6ab,0x703,0x75b,0x7b3,0x80b,0x863,0x8bb },\r
-       { 0x35c,0x3b4,0x40c,0x464,0x4bc,0x514,0x56c,0x5c4,0x61c,0x674,0x6cc,0x724,0x77c,0x7d4,0x82c,0x884,0x020,0x078,0x0d0,0x128,0x180,0x1d8,0x230,0x288,0x2e0,0x338,0x390,0x3e8,0x440,0x498,0x4f0,0x548,0x5a0,0x5f8,0x650,0x6a8,0x700,0x758,0x7b0,0x808,0x860,0x8b8,0x054 },\r
-       { 0x35d,0x3b5,0x40d,0x465,0x4bd,0x515,0x56d,0x5c5,0x61d,0x675,0x6cd,0x725,0x77d,0x7d5,0x82d,0x885,0x021,0x079,0x0d1,0x129,0x181,0x1d9,0x231,0x289,0x2e1,0x339,0x391,0x3e9,0x441,0x499,0x4f1,0x549,0x5a1,0x5f9,0x651,0x6a9,0x701,0x759,0x7b1,0x809,0x861,0x8b9,0x055 },\r
-       { 0x3b2,0x40a,0x462,0x4ba,0x512,0x56a,0x5c2,0x61a,0x672,0x6ca,0x722,0x77a,0x7d2,0x82a,0x882,0x01e,0x076,0x0ce,0x126,0x17e,0x1d6,0x22e,0x286,0x2de,0x336,0x38e,0x3e6,0x43e,0x496,0x4ee,0x546,0x59e,0x5f6,0x64e,0x6a6,0x6fe,0x756,0x7ae,0x806,0x85e,0x8b6,0x052,0x0aa },\r
-       { 0x3b3,0x40b,0x463,0x4bb,0x513,0x56b,0x5c3,0x61b,0x673,0x6cb,0x723,0x77b,0x7d3,0x82b,0x883,0x01f,0x077,0x0cf,0x127,0x17f,0x1d7,0x22f,0x287,0x2df,0x337,0x38f,0x3e7,0x43f,0x497,0x4ef,0x547,0x59f,0x5f7,0x64f,0x6a7,0x6ff,0x757,0x7af,0x807,0x85f,0x8b7,0x053,0x0ab },\r
-       { 0x408,0x460,0x4b8,0x510,0x568,0x5c0,0x618,0x670,0x6c8,0x720,0x778,0x7d0,0x828,0x880,0x01c,0x074,0x0cc,0x124,0x17c,0x1d4,0x22c,0x284,0x2dc,0x334,0x38c,0x3e4,0x43c,0x494,0x4ec,0x544,0x59c,0x5f4,0x64c,0x6a4,0x6fc,0x754,0x7ac,0x804,0x85c,0x8b4,0x050,0x0a8,0x100 },\r
-       { 0x409,0x461,0x4b9,0x511,0x569,0x5c1,0x619,0x671,0x6c9,0x721,0x779,0x7d1,0x829,0x881,0x01d,0x075,0x0cd,0x125,0x17d,0x1d5,0x22d,0x285,0x2dd,0x335,0x38d,0x3e5,0x43d,0x495,0x4ed,0x545,0x59d,0x5f5,0x64d,0x6a5,0x6fd,0x755,0x7ad,0x805,0x85d,0x8b5,0x051,0x0a9,0x101 },\r
-       { 0x45e,0x4b6,0x50e,0x566,0x5be,0x616,0x66e,0x6c6,0x71e,0x776,0x7ce,0x826,0x87e,0x01a,0x072,0x0ca,0x122,0x17a,0x1d2,0x22a,0x282,0x2da,0x332,0x38a,0x3e2,0x43a,0x492,0x4ea,0x542,0x59a,0x5f2,0x64a,0x6a2,0x6fa,0x752,0x7aa,0x802,0x85a,0x8b2,0x04e,0x0a6,0x0fe,0x156 },\r
-       { 0x45f,0x4b7,0x50f,0x567,0x5bf,0x617,0x66f,0x6c7,0x71f,0x777,0x7cf,0x827,0x87f,0x01b,0x073,0x0cb,0x123,0x17b,0x1d3,0x22b,0x283,0x2db,0x333,0x38b,0x3e3,0x43b,0x493,0x4eb,0x543,0x59b,0x5f3,0x64b,0x6a3,0x6fb,0x753,0x7ab,0x803,0x85b,0x8b3,0x04f,0x0a7,0x0ff,0x157 },\r
-       { 0x4b4,0x50c,0x564,0x5bc,0x614,0x66c,0x6c4,0x71c,0x774,0x7cc,0x824,0x87c,0x018,0x070,0x0c8,0x120,0x178,0x1d0,0x228,0x280,0x2d8,0x330,0x388,0x3e0,0x438,0x490,0x4e8,0x540,0x598,0x5f0,0x648,0x6a0,0x6f8,0x750,0x7a8,0x800,0x858,0x8b0,0x04c,0x0a4,0x0fc,0x154,0x1ac },\r
-       { 0x4b5,0x50d,0x565,0x5bd,0x615,0x66d,0x6c5,0x71d,0x775,0x7cd,0x825,0x87d,0x019,0x071,0x0c9,0x121,0x179,0x1d1,0x229,0x281,0x2d9,0x331,0x389,0x3e1,0x439,0x491,0x4e9,0x541,0x599,0x5f1,0x649,0x6a1,0x6f9,0x751,0x7a9,0x801,0x859,0x8b1,0x04d,0x0a5,0x0fd,0x155,0x1ad },\r
-       { 0x50a,0x562,0x5ba,0x612,0x66a,0x6c2,0x71a,0x772,0x7ca,0x822,0x87a,0x016,0x06e,0x0c6,0x11e,0x176,0x1ce,0x226,0x27e,0x2d6,0x32e,0x386,0x3de,0x436,0x48e,0x4e6,0x53e,0x596,0x5ee,0x646,0x69e,0x6f6,0x74e,0x7a6,0x7fe,0x856,0x8ae,0x04a,0x0a2,0x0fa,0x152,0x1aa,0x202 },\r
-       { 0x50b,0x563,0x5bb,0x613,0x66b,0x6c3,0x71b,0x773,0x7cb,0x823,0x87b,0x017,0x06f,0x0c7,0x11f,0x177,0x1cf,0x227,0x27f,0x2d7,0x32f,0x387,0x3df,0x437,0x48f,0x4e7,0x53f,0x597,0x5ef,0x647,0x69f,0x6f7,0x74f,0x7a7,0x7ff,0x857,0x8af,0x04b,0x0a3,0x0fb,0x153,0x1ab,0x203 },\r
-       { 0x560,0x5b8,0x610,0x668,0x6c0,0x718,0x770,0x7c8,0x820,0x878,0x014,0x06c,0x0c4,0x11c,0x174,0x1cc,0x224,0x27c,0x2d4,0x32c,0x384,0x3dc,0x434,0x48c,0x4e4,0x53c,0x594,0x5ec,0x644,0x69c,0x6f4,0x74c,0x7a4,0x7fc,0x854,0x8ac,0x048,0x0a0,0x0f8,0x150,0x1a8,0x200,0x258 },\r
-       { 0x561,0x5b9,0x611,0x669,0x6c1,0x719,0x771,0x7c9,0x821,0x879,0x015,0x06d,0x0c5,0x11d,0x175,0x1cd,0x225,0x27d,0x2d5,0x32d,0x385,0x3dd,0x435,0x48d,0x4e5,0x53d,0x595,0x5ed,0x645,0x69d,0x6f5,0x74d,0x7a5,0x7fd,0x855,0x8ad,0x049,0x0a1,0x0f9,0x151,0x1a9,0x201,0x259 },\r
-       { 0x5b6,0x60e,0x666,0x6be,0x716,0x76e,0x7c6,0x81e,0x876,0x012,0x06a,0x0c2,0x11a,0x172,0x1ca,0x222,0x27a,0x2d2,0x32a,0x382,0x3da,0x432,0x48a,0x4e2,0x53a,0x592,0x5ea,0x642,0x69a,0x6f2,0x74a,0x7a2,0x7fa,0x852,0x8aa,0x046,0x09e,0x0f6,0x14e,0x1a6,0x1fe,0x256,0x2ae },\r
-       { 0x5b7,0x60f,0x667,0x6bf,0x717,0x76f,0x7c7,0x81f,0x877,0x013,0x06b,0x0c3,0x11b,0x173,0x1cb,0x223,0x27b,0x2d3,0x32b,0x383,0x3db,0x433,0x48b,0x4e3,0x53b,0x593,0x5eb,0x643,0x69b,0x6f3,0x74b,0x7a3,0x7fb,0x853,0x8ab,0x047,0x09f,0x0f7,0x14f,0x1a7,0x1ff,0x257,0x2af },\r
-       { 0x60c,0x664,0x6bc,0x714,0x76c,0x7c4,0x81c,0x874,0x010,0x068,0x0c0,0x118,0x170,0x1c8,0x220,0x278,0x2d0,0x328,0x380,0x3d8,0x430,0x488,0x4e0,0x538,0x590,0x5e8,0x640,0x698,0x6f0,0x748,0x7a0,0x7f8,0x850,0x8a8,0x044,0x09c,0x0f4,0x14c,0x1a4,0x1fc,0x254,0x2ac,0x304 },\r
-       { 0x60d,0x665,0x6bd,0x715,0x76d,0x7c5,0x81d,0x875,0x011,0x069,0x0c1,0x119,0x171,0x1c9,0x221,0x279,0x2d1,0x329,0x381,0x3d9,0x431,0x489,0x4e1,0x539,0x591,0x5e9,0x641,0x699,0x6f1,0x749,0x7a1,0x7f9,0x851,0x8a9,0x045,0x09d,0x0f5,0x14d,0x1a5,0x1fd,0x255,0x2ad,0x305 },\r
-       { 0x662,0x6ba,0x712,0x76a,0x7c2,0x81a,0x872,0x00e,0x066,0x0be,0x116,0x16e,0x1c6,0x21e,0x276,0x2ce,0x326,0x37e,0x3d6,0x42e,0x486,0x4de,0x536,0x58e,0x5e6,0x63e,0x696,0x6ee,0x746,0x79e,0x7f6,0x84e,0x8a6,0x042,0x09a,0x0f2,0x14a,0x1a2,0x1fa,0x252,0x2aa,0x302,0x35a },\r
-       { 0x663,0x6bb,0x713,0x76b,0x7c3,0x81b,0x873,0x00f,0x067,0x0bf,0x117,0x16f,0x1c7,0x21f,0x277,0x2cf,0x327,0x37f,0x3d7,0x42f,0x487,0x4df,0x537,0x58f,0x5e7,0x63f,0x697,0x6ef,0x747,0x79f,0x7f7,0x84f,0x8a7,0x043,0x09b,0x0f3,0x14b,0x1a3,0x1fb,0x253,0x2ab,0x303,0x35b },\r
-       { 0x6b8,0x710,0x768,0x7c0,0x818,0x870,0x00c,0x064,0x0bc,0x114,0x16c,0x1c4,0x21c,0x274,0x2cc,0x324,0x37c,0x3d4,0x42c,0x484,0x4dc,0x534,0x58c,0x5e4,0x63c,0x694,0x6ec,0x744,0x79c,0x7f4,0x84c,0x8a4,0x040,0x098,0x0f0,0x148,0x1a0,0x1f8,0x250,0x2a8,0x300,0x358,0x3b0 },\r
-       { 0x6b9,0x711,0x769,0x7c1,0x819,0x871,0x00d,0x065,0x0bd,0x115,0x16d,0x1c5,0x21d,0x275,0x2cd,0x325,0x37d,0x3d5,0x42d,0x485,0x4dd,0x535,0x58d,0x5e5,0x63d,0x695,0x6ed,0x745,0x79d,0x7f5,0x84d,0x8a5,0x041,0x099,0x0f1,0x149,0x1a1,0x1f9,0x251,0x2a9,0x301,0x359,0x3b1 },\r
-       { 0x70e,0x766,0x7be,0x816,0x86e,0x00a,0x062,0x0ba,0x112,0x16a,0x1c2,0x21a,0x272,0x2ca,0x322,0x37a,0x3d2,0x42a,0x482,0x4da,0x532,0x58a,0x5e2,0x63a,0x692,0x6ea,0x742,0x79a,0x7f2,0x84a,0x8a2,0x03e,0x096,0x0ee,0x146,0x19e,0x1f6,0x24e,0x2a6,0x2fe,0x356,0x3ae,0x406 },\r
-       { 0x70f,0x767,0x7bf,0x817,0x86f,0x00b,0x063,0x0bb,0x113,0x16b,0x1c3,0x21b,0x273,0x2cb,0x323,0x37b,0x3d3,0x42b,0x483,0x4db,0x533,0x58b,0x5e3,0x63b,0x693,0x6eb,0x743,0x79b,0x7f3,0x84b,0x8a3,0x03f,0x097,0x0ef,0x147,0x19f,0x1f7,0x24f,0x2a7,0x2ff,0x357,0x3af,0x407 },\r
-       { 0x764,0x7bc,0x814,0x86c,0x008,0x060,0x0b8,0x110,0x168,0x1c0,0x218,0x270,0x2c8,0x320,0x378,0x3d0,0x428,0x480,0x4d8,0x530,0x588,0x5e0,0x638,0x690,0x6e8,0x740,0x798,0x7f0,0x848,0x8a0,0x03c,0x094,0x0ec,0x144,0x19c,0x1f4,0x24c,0x2a4,0x2fc,0x354,0x3ac,0x404,0x45c },\r
-       { 0x765,0x7bd,0x815,0x86d,0x009,0x061,0x0b9,0x111,0x169,0x1c1,0x219,0x271,0x2c9,0x321,0x379,0x3d1,0x429,0x481,0x4d9,0x531,0x589,0x5e1,0x639,0x691,0x6e9,0x741,0x799,0x7f1,0x849,0x8a1,0x03d,0x095,0x0ed,0x145,0x19d,0x1f5,0x24d,0x2a5,0x2fd,0x355,0x3ad,0x405,0x45d },\r
-       { 0x7ba,0x812,0x86a,0x006,0x05e,0x0b6,0x10e,0x166,0x1be,0x216,0x26e,0x2c6,0x31e,0x376,0x3ce,0x426,0x47e,0x4d6,0x52e,0x586,0x5de,0x636,0x68e,0x6e6,0x73e,0x796,0x7ee,0x846,0x89e,0x03a,0x092,0x0ea,0x142,0x19a,0x1f2,0x24a,0x2a2,0x2fa,0x352,0x3aa,0x402,0x45a,0x4b2 },\r
-       { 0x7bb,0x813,0x86b,0x007,0x05f,0x0b7,0x10f,0x167,0x1bf,0x217,0x26f,0x2c7,0x31f,0x377,0x3cf,0x427,0x47f,0x4d7,0x52f,0x587,0x5df,0x637,0x68f,0x6e7,0x73f,0x797,0x7ef,0x847,0x89f,0x03b,0x093,0x0eb,0x143,0x19b,0x1f3,0x24b,0x2a3,0x2fb,0x353,0x3ab,0x403,0x45b,0x4b3 },\r
-       { 0x810,0x868,0x004,0x05c,0x0b4,0x10c,0x164,0x1bc,0x214,0x26c,0x2c4,0x31c,0x374,0x3cc,0x424,0x47c,0x4d4,0x52c,0x584,0x5dc,0x634,0x68c,0x6e4,0x73c,0x794,0x7ec,0x844,0x89c,0x038,0x090,0x0e8,0x140,0x198,0x1f0,0x248,0x2a0,0x2f8,0x350,0x3a8,0x400,0x458,0x4b0,0x508 },\r
-       { 0x811,0x869,0x005,0x05d,0x0b5,0x10d,0x165,0x1bd,0x215,0x26d,0x2c5,0x31d,0x375,0x3cd,0x425,0x47d,0x4d5,0x52d,0x585,0x5dd,0x635,0x68d,0x6e5,0x73d,0x795,0x7ed,0x845,0x89d,0x039,0x091,0x0e9,0x141,0x199,0x1f1,0x249,0x2a1,0x2f9,0x351,0x3a9,0x401,0x459,0x4b1,0x509 },\r
-       { 0x866,0x002,0x05a,0x0b2,0x10a,0x162,0x1ba,0x212,0x26a,0x2c2,0x31a,0x372,0x3ca,0x422,0x47a,0x4d2,0x52a,0x582,0x5da,0x632,0x68a,0x6e2,0x73a,0x792,0x7ea,0x842,0x89a,0x036,0x08e,0x0e6,0x13e,0x196,0x1ee,0x246,0x29e,0x2f6,0x34e,0x3a6,0x3fe,0x456,0x4ae,0x506,0x55e },\r
-       { 0x867,0x003,0x05b,0x0b3,0x10b,0x163,0x1bb,0x213,0x26b,0x2c3,0x31b,0x373,0x3cb,0x423,0x47b,0x4d3,0x52b,0x583,0x5db,0x633,0x68b,0x6e3,0x73b,0x793,0x7eb,0x843,0x89b,0x037,0x08f,0x0e7,0x13f,0x197,0x1ef,0x247,0x29f,0x2f7,0x34f,0x3a7,0x3ff,0x457,0x4af,0x507,0x55f }\r
-};\r
-\r
-\r
-//-------------------------------------------------\r
-//  ecc_source_byte - return data from the sector\r
-//  at the given offset, masking anything\r
-//  particular to a mode\r
-//-------------------------------------------------\r
-\r
-static uint8_t ecc_source_byte(const uint8_t *sector, uint32_t offset)\r
-{\r
-       // in mode 2 always treat these as 0 bytes\r
-       return (sector[MODE_OFFSET] == 2 && offset < 4) ? 0x00 : sector[SYNC_OFFSET + SYNC_NUM_BYTES + offset];\r
-}\r
-\r
-/**\r
- * @fn  void ecc_compute_bytes(const uint8_t *sector, const uint16_t *row, int rowlen, uint8_t &val1, uint8_t &val2)\r
- *\r
- * @brief   -------------------------------------------------\r
- *            ecc_compute_bytes - calculate an ECC value (P or Q)\r
- *          -------------------------------------------------.\r
- *\r
- * @param   sector          The sector.\r
- * @param   row             The row.\r
- * @param   rowlen          The rowlen.\r
- * @param [in,out]  val1    The first value.\r
- * @param [in,out]  val2    The second value.\r
- */\r
-\r
-void ecc_compute_bytes(const uint8_t *sector, const uint16_t *row, int rowlen, uint8_t *val1, uint8_t *val2)\r
-{\r
-   int component;\r
-       *val1 = *val2 = 0;\r
-       for (component = 0; component < rowlen; component++)\r
-       {\r
-               *val1 ^= ecc_source_byte(sector, row[component]);\r
-               *val2 ^= ecc_source_byte(sector, row[component]);\r
-               *val1 = ecclow[*val1];\r
-       }\r
-       *val1 = ecchigh[ecclow[*val1] ^ *val2];\r
-       *val2 ^= *val1;\r
-}\r
-\r
-/**\r
- * @fn  int ecc_verify(const uint8_t *sector)\r
- *\r
- * @brief   -------------------------------------------------\r
- *            ecc_verify - verify the P and Q ECC codes in a sector\r
- *          -------------------------------------------------.\r
- *\r
- * @param   sector  The sector.\r
- *\r
- * @return  true if it succeeds, false if it fails.\r
- */\r
-\r
-int ecc_verify(const uint8_t *sector)\r
-{\r
-   int byte;\r
-   \r
-       // first verify P bytes\r
-       for (byte = 0; byte < ECC_P_NUM_BYTES; byte++)\r
-       {\r
-               uint8_t val1, val2;\r
-               ecc_compute_bytes(sector, poffsets[byte], ECC_P_COMP, &val1, &val2);\r
-               if (sector[ECC_P_OFFSET + byte] != val1 || sector[ECC_P_OFFSET + ECC_P_NUM_BYTES + byte] != val2)\r
-                       return 0;\r
-       }\r
-\r
-       // then verify Q bytes\r
-       for (byte = 0; byte < ECC_Q_NUM_BYTES; byte++)\r
-       {\r
-               uint8_t val1, val2;\r
-               ecc_compute_bytes(sector, qoffsets[byte], ECC_Q_COMP, &val1, &val2);\r
-               if (sector[ECC_Q_OFFSET + byte] != val1 || sector[ECC_Q_OFFSET + ECC_Q_NUM_BYTES + byte] != val2)\r
-                       return 0;\r
-       }\r
-       return 1;\r
-}\r
-\r
-/**\r
- * @fn  void ecc_generate(uint8_t *sector)\r
- *\r
- * @brief   -------------------------------------------------\r
- *            ecc_generate - generate the P and Q ECC codes for a sector, overwriting any\r
- *            existing codes\r
- *          -------------------------------------------------.\r
- *\r
- * @param [in,out]  sector  If non-null, the sector.\r
- */\r
-\r
-void ecc_generate(uint8_t *sector)\r
-{\r
-   int byte;\r
-       // first verify P bytes\r
-       for (byte = 0; byte < ECC_P_NUM_BYTES; byte++)\r
-               ecc_compute_bytes(sector, poffsets[byte], ECC_P_COMP, &sector[ECC_P_OFFSET + byte], &sector[ECC_P_OFFSET + ECC_P_NUM_BYTES + byte]);\r
-\r
-       // then verify Q bytes\r
-       for (byte = 0; byte < ECC_Q_NUM_BYTES; byte++)\r
-               ecc_compute_bytes(sector, qoffsets[byte], ECC_Q_COMP, &sector[ECC_Q_OFFSET + byte], &sector[ECC_Q_OFFSET + ECC_Q_NUM_BYTES + byte]);\r
-}\r
-\r
-/**\r
- * @fn  void ecc_clear(uint8_t *sector)\r
- *\r
- * @brief   -------------------------------------------------\r
- *            ecc_clear - erase the ECC P and Q cods to 0 within a sector\r
- *          -------------------------------------------------.\r
- *\r
- * @param [in,out]  sector  If non-null, the sector.\r
- */\r
-\r
-void ecc_clear(uint8_t *sector)\r
-{\r
-       memset(&sector[ECC_P_OFFSET], 0, 2 * ECC_P_NUM_BYTES);\r
-       memset(&sector[ECC_Q_OFFSET], 0, 2 * ECC_Q_NUM_BYTES);\r
-}\r
+/* license:BSD-3-Clause
+ * copyright-holders:Aaron Giles
+***************************************************************************
+
+    cdrom.c
+
+    Generic MAME CD-ROM utilties - build IDE and SCSI CD-ROMs on top of this
+
+****************************************************************************
+
+    IMPORTANT:
+    "physical" block addresses are the actual addresses on the emulated CD.
+    "chd" block addresses are the block addresses in the CHD file.
+    Because we pad each track to a 4-frame boundary, these addressing
+    schemes will differ after track 1!
+
+***************************************************************************/
+
+#include <assert.h>
+#include <string.h>
+
+#include "cdrom.h"
+
+/***************************************************************************
+    DEBUGGING
+***************************************************************************/
+
+/** @brief  The verbose. */
+#define VERBOSE (0)
+#if VERBOSE
+
+/**
+ * @def LOG(x) do
+ *
+ * @brief   A macro that defines log.
+ *
+ * @param   x   The void to process.
+ */
+
+#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
+
+/**
+ * @fn  void CLIB_DECL logerror(const char *text, ...) ATTR_PRINTF(1,2);
+ *
+ * @brief   Logerrors the given text.
+ *
+ * @param   text    The text.
+ *
+ * @return  A CLIB_DECL.
+ */
+
+void CLIB_DECL logerror(const char *text, ...) ATTR_PRINTF(1,2);
+#else
+
+/**
+ * @def LOG(x);
+ *
+ * @brief   A macro that defines log.
+ *
+ * @param   x   The void to process.
+ */
+
+#define LOG(x)
+#endif
+
+/***************************************************************************
+    CONSTANTS
+***************************************************************************/
+
+/** @brief  offset within sector. */
+#define SYNC_OFFSET 0x000
+/** @brief  12 bytes. */
+#define SYNC_NUM_BYTES 12
+
+/** @brief  offset within sector. */
+#define MODE_OFFSET 0x00f
+
+/** @brief  offset within sector. */
+#define ECC_P_OFFSET 0x81c
+/** @brief  2 lots of 86. */
+#define ECC_P_NUM_BYTES 86
+/** @brief  24 bytes each. */
+#define ECC_P_COMP 24
+
+/** @brief  The ECC q offset. */
+#define ECC_Q_OFFSET (ECC_P_OFFSET + 2 * ECC_P_NUM_BYTES)
+/** @brief  2 lots of 52. */
+#define ECC_Q_NUM_BYTES 52
+/** @brief  43 bytes each. */
+#define ECC_Q_COMP 43
+
+/**
+ * @brief   -------------------------------------------------
+ *            ECC lookup tables pre-calculated tables for ECC data calcs
+ *          -------------------------------------------------.
+ */
+
+static const uint8_t ecclow[256] =
+{
+       0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
+       0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e,
+       0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e,
+       0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e,
+       0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e,
+       0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe,
+       0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,
+       0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe,
+       0x1d, 0x1f, 0x19, 0x1b, 0x15, 0x17, 0x11, 0x13, 0x0d, 0x0f, 0x09, 0x0b, 0x05, 0x07, 0x01, 0x03,
+       0x3d, 0x3f, 0x39, 0x3b, 0x35, 0x37, 0x31, 0x33, 0x2d, 0x2f, 0x29, 0x2b, 0x25, 0x27, 0x21, 0x23,
+       0x5d, 0x5f, 0x59, 0x5b, 0x55, 0x57, 0x51, 0x53, 0x4d, 0x4f, 0x49, 0x4b, 0x45, 0x47, 0x41, 0x43,
+       0x7d, 0x7f, 0x79, 0x7b, 0x75, 0x77, 0x71, 0x73, 0x6d, 0x6f, 0x69, 0x6b, 0x65, 0x67, 0x61, 0x63,
+       0x9d, 0x9f, 0x99, 0x9b, 0x95, 0x97, 0x91, 0x93, 0x8d, 0x8f, 0x89, 0x8b, 0x85, 0x87, 0x81, 0x83,
+       0xbd, 0xbf, 0xb9, 0xbb, 0xb5, 0xb7, 0xb1, 0xb3, 0xad, 0xaf, 0xa9, 0xab, 0xa5, 0xa7, 0xa1, 0xa3,
+       0xdd, 0xdf, 0xd9, 0xdb, 0xd5, 0xd7, 0xd1, 0xd3, 0xcd, 0xcf, 0xc9, 0xcb, 0xc5, 0xc7, 0xc1, 0xc3,
+       0xfd, 0xff, 0xf9, 0xfb, 0xf5, 0xf7, 0xf1, 0xf3, 0xed, 0xef, 0xe9, 0xeb, 0xe5, 0xe7, 0xe1, 0xe3
+};
+
+/** @brief  The ecchigh[ 256]. */
+static const uint8_t ecchigh[256] =
+{
+       0x00, 0xf4, 0xf5, 0x01, 0xf7, 0x03, 0x02, 0xf6, 0xf3, 0x07, 0x06, 0xf2, 0x04, 0xf0, 0xf1, 0x05,
+       0xfb, 0x0f, 0x0e, 0xfa, 0x0c, 0xf8, 0xf9, 0x0d, 0x08, 0xfc, 0xfd, 0x09, 0xff, 0x0b, 0x0a, 0xfe,
+       0xeb, 0x1f, 0x1e, 0xea, 0x1c, 0xe8, 0xe9, 0x1d, 0x18, 0xec, 0xed, 0x19, 0xef, 0x1b, 0x1a, 0xee,
+       0x10, 0xe4, 0xe5, 0x11, 0xe7, 0x13, 0x12, 0xe6, 0xe3, 0x17, 0x16, 0xe2, 0x14, 0xe0, 0xe1, 0x15,
+       0xcb, 0x3f, 0x3e, 0xca, 0x3c, 0xc8, 0xc9, 0x3d, 0x38, 0xcc, 0xcd, 0x39, 0xcf, 0x3b, 0x3a, 0xce,
+       0x30, 0xc4, 0xc5, 0x31, 0xc7, 0x33, 0x32, 0xc6, 0xc3, 0x37, 0x36, 0xc2, 0x34, 0xc0, 0xc1, 0x35,
+       0x20, 0xd4, 0xd5, 0x21, 0xd7, 0x23, 0x22, 0xd6, 0xd3, 0x27, 0x26, 0xd2, 0x24, 0xd0, 0xd1, 0x25,
+       0xdb, 0x2f, 0x2e, 0xda, 0x2c, 0xd8, 0xd9, 0x2d, 0x28, 0xdc, 0xdd, 0x29, 0xdf, 0x2b, 0x2a, 0xde,
+       0x8b, 0x7f, 0x7e, 0x8a, 0x7c, 0x88, 0x89, 0x7d, 0x78, 0x8c, 0x8d, 0x79, 0x8f, 0x7b, 0x7a, 0x8e,
+       0x70, 0x84, 0x85, 0x71, 0x87, 0x73, 0x72, 0x86, 0x83, 0x77, 0x76, 0x82, 0x74, 0x80, 0x81, 0x75,
+       0x60, 0x94, 0x95, 0x61, 0x97, 0x63, 0x62, 0x96, 0x93, 0x67, 0x66, 0x92, 0x64, 0x90, 0x91, 0x65,
+       0x9b, 0x6f, 0x6e, 0x9a, 0x6c, 0x98, 0x99, 0x6d, 0x68, 0x9c, 0x9d, 0x69, 0x9f, 0x6b, 0x6a, 0x9e,
+       0x40, 0xb4, 0xb5, 0x41, 0xb7, 0x43, 0x42, 0xb6, 0xb3, 0x47, 0x46, 0xb2, 0x44, 0xb0, 0xb1, 0x45,
+       0xbb, 0x4f, 0x4e, 0xba, 0x4c, 0xb8, 0xb9, 0x4d, 0x48, 0xbc, 0xbd, 0x49, 0xbf, 0x4b, 0x4a, 0xbe,
+       0xab, 0x5f, 0x5e, 0xaa, 0x5c, 0xa8, 0xa9, 0x5d, 0x58, 0xac, 0xad, 0x59, 0xaf, 0x5b, 0x5a, 0xae,
+       0x50, 0xa4, 0xa5, 0x51, 0xa7, 0x53, 0x52, 0xa6, 0xa3, 0x57, 0x56, 0xa2, 0x54, 0xa0, 0xa1, 0x55
+};
+
+/**
+ * @brief   -------------------------------------------------
+ *            poffsets - each row represents the addresses used to calculate a byte of the ECC P
+ *            data 86 (*2) ECC P bytes, 24 values represented by each
+ *          -------------------------------------------------.
+ */
+
+static const uint16_t poffsets[ECC_P_NUM_BYTES][ECC_P_COMP] =
+{
+       { 0x000,0x056,0x0ac,0x102,0x158,0x1ae,0x204,0x25a,0x2b0,0x306,0x35c,0x3b2,0x408,0x45e,0x4b4,0x50a,0x560,0x5b6,0x60c,0x662,0x6b8,0x70e,0x764,0x7ba },
+       { 0x001,0x057,0x0ad,0x103,0x159,0x1af,0x205,0x25b,0x2b1,0x307,0x35d,0x3b3,0x409,0x45f,0x4b5,0x50b,0x561,0x5b7,0x60d,0x663,0x6b9,0x70f,0x765,0x7bb },
+       { 0x002,0x058,0x0ae,0x104,0x15a,0x1b0,0x206,0x25c,0x2b2,0x308,0x35e,0x3b4,0x40a,0x460,0x4b6,0x50c,0x562,0x5b8,0x60e,0x664,0x6ba,0x710,0x766,0x7bc },
+       { 0x003,0x059,0x0af,0x105,0x15b,0x1b1,0x207,0x25d,0x2b3,0x309,0x35f,0x3b5,0x40b,0x461,0x4b7,0x50d,0x563,0x5b9,0x60f,0x665,0x6bb,0x711,0x767,0x7bd },
+       { 0x004,0x05a,0x0b0,0x106,0x15c,0x1b2,0x208,0x25e,0x2b4,0x30a,0x360,0x3b6,0x40c,0x462,0x4b8,0x50e,0x564,0x5ba,0x610,0x666,0x6bc,0x712,0x768,0x7be },
+       { 0x005,0x05b,0x0b1,0x107,0x15d,0x1b3,0x209,0x25f,0x2b5,0x30b,0x361,0x3b7,0x40d,0x463,0x4b9,0x50f,0x565,0x5bb,0x611,0x667,0x6bd,0x713,0x769,0x7bf },
+       { 0x006,0x05c,0x0b2,0x108,0x15e,0x1b4,0x20a,0x260,0x2b6,0x30c,0x362,0x3b8,0x40e,0x464,0x4ba,0x510,0x566,0x5bc,0x612,0x668,0x6be,0x714,0x76a,0x7c0 },
+       { 0x007,0x05d,0x0b3,0x109,0x15f,0x1b5,0x20b,0x261,0x2b7,0x30d,0x363,0x3b9,0x40f,0x465,0x4bb,0x511,0x567,0x5bd,0x613,0x669,0x6bf,0x715,0x76b,0x7c1 },
+       { 0x008,0x05e,0x0b4,0x10a,0x160,0x1b6,0x20c,0x262,0x2b8,0x30e,0x364,0x3ba,0x410,0x466,0x4bc,0x512,0x568,0x5be,0x614,0x66a,0x6c0,0x716,0x76c,0x7c2 },
+       { 0x009,0x05f,0x0b5,0x10b,0x161,0x1b7,0x20d,0x263,0x2b9,0x30f,0x365,0x3bb,0x411,0x467,0x4bd,0x513,0x569,0x5bf,0x615,0x66b,0x6c1,0x717,0x76d,0x7c3 },
+       { 0x00a,0x060,0x0b6,0x10c,0x162,0x1b8,0x20e,0x264,0x2ba,0x310,0x366,0x3bc,0x412,0x468,0x4be,0x514,0x56a,0x5c0,0x616,0x66c,0x6c2,0x718,0x76e,0x7c4 },
+       { 0x00b,0x061,0x0b7,0x10d,0x163,0x1b9,0x20f,0x265,0x2bb,0x311,0x367,0x3bd,0x413,0x469,0x4bf,0x515,0x56b,0x5c1,0x617,0x66d,0x6c3,0x719,0x76f,0x7c5 },
+       { 0x00c,0x062,0x0b8,0x10e,0x164,0x1ba,0x210,0x266,0x2bc,0x312,0x368,0x3be,0x414,0x46a,0x4c0,0x516,0x56c,0x5c2,0x618,0x66e,0x6c4,0x71a,0x770,0x7c6 },
+       { 0x00d,0x063,0x0b9,0x10f,0x165,0x1bb,0x211,0x267,0x2bd,0x313,0x369,0x3bf,0x415,0x46b,0x4c1,0x517,0x56d,0x5c3,0x619,0x66f,0x6c5,0x71b,0x771,0x7c7 },
+       { 0x00e,0x064,0x0ba,0x110,0x166,0x1bc,0x212,0x268,0x2be,0x314,0x36a,0x3c0,0x416,0x46c,0x4c2,0x518,0x56e,0x5c4,0x61a,0x670,0x6c6,0x71c,0x772,0x7c8 },
+       { 0x00f,0x065,0x0bb,0x111,0x167,0x1bd,0x213,0x269,0x2bf,0x315,0x36b,0x3c1,0x417,0x46d,0x4c3,0x519,0x56f,0x5c5,0x61b,0x671,0x6c7,0x71d,0x773,0x7c9 },
+       { 0x010,0x066,0x0bc,0x112,0x168,0x1be,0x214,0x26a,0x2c0,0x316,0x36c,0x3c2,0x418,0x46e,0x4c4,0x51a,0x570,0x5c6,0x61c,0x672,0x6c8,0x71e,0x774,0x7ca },
+       { 0x011,0x067,0x0bd,0x113,0x169,0x1bf,0x215,0x26b,0x2c1,0x317,0x36d,0x3c3,0x419,0x46f,0x4c5,0x51b,0x571,0x5c7,0x61d,0x673,0x6c9,0x71f,0x775,0x7cb },
+       { 0x012,0x068,0x0be,0x114,0x16a,0x1c0,0x216,0x26c,0x2c2,0x318,0x36e,0x3c4,0x41a,0x470,0x4c6,0x51c,0x572,0x5c8,0x61e,0x674,0x6ca,0x720,0x776,0x7cc },
+       { 0x013,0x069,0x0bf,0x115,0x16b,0x1c1,0x217,0x26d,0x2c3,0x319,0x36f,0x3c5,0x41b,0x471,0x4c7,0x51d,0x573,0x5c9,0x61f,0x675,0x6cb,0x721,0x777,0x7cd },
+       { 0x014,0x06a,0x0c0,0x116,0x16c,0x1c2,0x218,0x26e,0x2c4,0x31a,0x370,0x3c6,0x41c,0x472,0x4c8,0x51e,0x574,0x5ca,0x620,0x676,0x6cc,0x722,0x778,0x7ce },
+       { 0x015,0x06b,0x0c1,0x117,0x16d,0x1c3,0x219,0x26f,0x2c5,0x31b,0x371,0x3c7,0x41d,0x473,0x4c9,0x51f,0x575,0x5cb,0x621,0x677,0x6cd,0x723,0x779,0x7cf },
+       { 0x016,0x06c,0x0c2,0x118,0x16e,0x1c4,0x21a,0x270,0x2c6,0x31c,0x372,0x3c8,0x41e,0x474,0x4ca,0x520,0x576,0x5cc,0x622,0x678,0x6ce,0x724,0x77a,0x7d0 },
+       { 0x017,0x06d,0x0c3,0x119,0x16f,0x1c5,0x21b,0x271,0x2c7,0x31d,0x373,0x3c9,0x41f,0x475,0x4cb,0x521,0x577,0x5cd,0x623,0x679,0x6cf,0x725,0x77b,0x7d1 },
+       { 0x018,0x06e,0x0c4,0x11a,0x170,0x1c6,0x21c,0x272,0x2c8,0x31e,0x374,0x3ca,0x420,0x476,0x4cc,0x522,0x578,0x5ce,0x624,0x67a,0x6d0,0x726,0x77c,0x7d2 },
+       { 0x019,0x06f,0x0c5,0x11b,0x171,0x1c7,0x21d,0x273,0x2c9,0x31f,0x375,0x3cb,0x421,0x477,0x4cd,0x523,0x579,0x5cf,0x625,0x67b,0x6d1,0x727,0x77d,0x7d3 },
+       { 0x01a,0x070,0x0c6,0x11c,0x172,0x1c8,0x21e,0x274,0x2ca,0x320,0x376,0x3cc,0x422,0x478,0x4ce,0x524,0x57a,0x5d0,0x626,0x67c,0x6d2,0x728,0x77e,0x7d4 },
+       { 0x01b,0x071,0x0c7,0x11d,0x173,0x1c9,0x21f,0x275,0x2cb,0x321,0x377,0x3cd,0x423,0x479,0x4cf,0x525,0x57b,0x5d1,0x627,0x67d,0x6d3,0x729,0x77f,0x7d5 },
+       { 0x01c,0x072,0x0c8,0x11e,0x174,0x1ca,0x220,0x276,0x2cc,0x322,0x378,0x3ce,0x424,0x47a,0x4d0,0x526,0x57c,0x5d2,0x628,0x67e,0x6d4,0x72a,0x780,0x7d6 },
+       { 0x01d,0x073,0x0c9,0x11f,0x175,0x1cb,0x221,0x277,0x2cd,0x323,0x379,0x3cf,0x425,0x47b,0x4d1,0x527,0x57d,0x5d3,0x629,0x67f,0x6d5,0x72b,0x781,0x7d7 },
+       { 0x01e,0x074,0x0ca,0x120,0x176,0x1cc,0x222,0x278,0x2ce,0x324,0x37a,0x3d0,0x426,0x47c,0x4d2,0x528,0x57e,0x5d4,0x62a,0x680,0x6d6,0x72c,0x782,0x7d8 },
+       { 0x01f,0x075,0x0cb,0x121,0x177,0x1cd,0x223,0x279,0x2cf,0x325,0x37b,0x3d1,0x427,0x47d,0x4d3,0x529,0x57f,0x5d5,0x62b,0x681,0x6d7,0x72d,0x783,0x7d9 },
+       { 0x020,0x076,0x0cc,0x122,0x178,0x1ce,0x224,0x27a,0x2d0,0x326,0x37c,0x3d2,0x428,0x47e,0x4d4,0x52a,0x580,0x5d6,0x62c,0x682,0x6d8,0x72e,0x784,0x7da },
+       { 0x021,0x077,0x0cd,0x123,0x179,0x1cf,0x225,0x27b,0x2d1,0x327,0x37d,0x3d3,0x429,0x47f,0x4d5,0x52b,0x581,0x5d7,0x62d,0x683,0x6d9,0x72f,0x785,0x7db },
+       { 0x022,0x078,0x0ce,0x124,0x17a,0x1d0,0x226,0x27c,0x2d2,0x328,0x37e,0x3d4,0x42a,0x480,0x4d6,0x52c,0x582,0x5d8,0x62e,0x684,0x6da,0x730,0x786,0x7dc },
+       { 0x023,0x079,0x0cf,0x125,0x17b,0x1d1,0x227,0x27d,0x2d3,0x329,0x37f,0x3d5,0x42b,0x481,0x4d7,0x52d,0x583,0x5d9,0x62f,0x685,0x6db,0x731,0x787,0x7dd },
+       { 0x024,0x07a,0x0d0,0x126,0x17c,0x1d2,0x228,0x27e,0x2d4,0x32a,0x380,0x3d6,0x42c,0x482,0x4d8,0x52e,0x584,0x5da,0x630,0x686,0x6dc,0x732,0x788,0x7de },
+       { 0x025,0x07b,0x0d1,0x127,0x17d,0x1d3,0x229,0x27f,0x2d5,0x32b,0x381,0x3d7,0x42d,0x483,0x4d9,0x52f,0x585,0x5db,0x631,0x687,0x6dd,0x733,0x789,0x7df },
+       { 0x026,0x07c,0x0d2,0x128,0x17e,0x1d4,0x22a,0x280,0x2d6,0x32c,0x382,0x3d8,0x42e,0x484,0x4da,0x530,0x586,0x5dc,0x632,0x688,0x6de,0x734,0x78a,0x7e0 },
+       { 0x027,0x07d,0x0d3,0x129,0x17f,0x1d5,0x22b,0x281,0x2d7,0x32d,0x383,0x3d9,0x42f,0x485,0x4db,0x531,0x587,0x5dd,0x633,0x689,0x6df,0x735,0x78b,0x7e1 },
+       { 0x028,0x07e,0x0d4,0x12a,0x180,0x1d6,0x22c,0x282,0x2d8,0x32e,0x384,0x3da,0x430,0x486,0x4dc,0x532,0x588,0x5de,0x634,0x68a,0x6e0,0x736,0x78c,0x7e2 },
+       { 0x029,0x07f,0x0d5,0x12b,0x181,0x1d7,0x22d,0x283,0x2d9,0x32f,0x385,0x3db,0x431,0x487,0x4dd,0x533,0x589,0x5df,0x635,0x68b,0x6e1,0x737,0x78d,0x7e3 },
+       { 0x02a,0x080,0x0d6,0x12c,0x182,0x1d8,0x22e,0x284,0x2da,0x330,0x386,0x3dc,0x432,0x488,0x4de,0x534,0x58a,0x5e0,0x636,0x68c,0x6e2,0x738,0x78e,0x7e4 },
+       { 0x02b,0x081,0x0d7,0x12d,0x183,0x1d9,0x22f,0x285,0x2db,0x331,0x387,0x3dd,0x433,0x489,0x4df,0x535,0x58b,0x5e1,0x637,0x68d,0x6e3,0x739,0x78f,0x7e5 },
+       { 0x02c,0x082,0x0d8,0x12e,0x184,0x1da,0x230,0x286,0x2dc,0x332,0x388,0x3de,0x434,0x48a,0x4e0,0x536,0x58c,0x5e2,0x638,0x68e,0x6e4,0x73a,0x790,0x7e6 },
+       { 0x02d,0x083,0x0d9,0x12f,0x185,0x1db,0x231,0x287,0x2dd,0x333,0x389,0x3df,0x435,0x48b,0x4e1,0x537,0x58d,0x5e3,0x639,0x68f,0x6e5,0x73b,0x791,0x7e7 },
+       { 0x02e,0x084,0x0da,0x130,0x186,0x1dc,0x232,0x288,0x2de,0x334,0x38a,0x3e0,0x436,0x48c,0x4e2,0x538,0x58e,0x5e4,0x63a,0x690,0x6e6,0x73c,0x792,0x7e8 },
+       { 0x02f,0x085,0x0db,0x131,0x187,0x1dd,0x233,0x289,0x2df,0x335,0x38b,0x3e1,0x437,0x48d,0x4e3,0x539,0x58f,0x5e5,0x63b,0x691,0x6e7,0x73d,0x793,0x7e9 },
+       { 0x030,0x086,0x0dc,0x132,0x188,0x1de,0x234,0x28a,0x2e0,0x336,0x38c,0x3e2,0x438,0x48e,0x4e4,0x53a,0x590,0x5e6,0x63c,0x692,0x6e8,0x73e,0x794,0x7ea },
+       { 0x031,0x087,0x0dd,0x133,0x189,0x1df,0x235,0x28b,0x2e1,0x337,0x38d,0x3e3,0x439,0x48f,0x4e5,0x53b,0x591,0x5e7,0x63d,0x693,0x6e9,0x73f,0x795,0x7eb },
+       { 0x032,0x088,0x0de,0x134,0x18a,0x1e0,0x236,0x28c,0x2e2,0x338,0x38e,0x3e4,0x43a,0x490,0x4e6,0x53c,0x592,0x5e8,0x63e,0x694,0x6ea,0x740,0x796,0x7ec },
+       { 0x033,0x089,0x0df,0x135,0x18b,0x1e1,0x237,0x28d,0x2e3,0x339,0x38f,0x3e5,0x43b,0x491,0x4e7,0x53d,0x593,0x5e9,0x63f,0x695,0x6eb,0x741,0x797,0x7ed },
+       { 0x034,0x08a,0x0e0,0x136,0x18c,0x1e2,0x238,0x28e,0x2e4,0x33a,0x390,0x3e6,0x43c,0x492,0x4e8,0x53e,0x594,0x5ea,0x640,0x696,0x6ec,0x742,0x798,0x7ee },
+       { 0x035,0x08b,0x0e1,0x137,0x18d,0x1e3,0x239,0x28f,0x2e5,0x33b,0x391,0x3e7,0x43d,0x493,0x4e9,0x53f,0x595,0x5eb,0x641,0x697,0x6ed,0x743,0x799,0x7ef },
+       { 0x036,0x08c,0x0e2,0x138,0x18e,0x1e4,0x23a,0x290,0x2e6,0x33c,0x392,0x3e8,0x43e,0x494,0x4ea,0x540,0x596,0x5ec,0x642,0x698,0x6ee,0x744,0x79a,0x7f0 },
+       { 0x037,0x08d,0x0e3,0x139,0x18f,0x1e5,0x23b,0x291,0x2e7,0x33d,0x393,0x3e9,0x43f,0x495,0x4eb,0x541,0x597,0x5ed,0x643,0x699,0x6ef,0x745,0x79b,0x7f1 },
+       { 0x038,0x08e,0x0e4,0x13a,0x190,0x1e6,0x23c,0x292,0x2e8,0x33e,0x394,0x3ea,0x440,0x496,0x4ec,0x542,0x598,0x5ee,0x644,0x69a,0x6f0,0x746,0x79c,0x7f2 },
+       { 0x039,0x08f,0x0e5,0x13b,0x191,0x1e7,0x23d,0x293,0x2e9,0x33f,0x395,0x3eb,0x441,0x497,0x4ed,0x543,0x599,0x5ef,0x645,0x69b,0x6f1,0x747,0x79d,0x7f3 },
+       { 0x03a,0x090,0x0e6,0x13c,0x192,0x1e8,0x23e,0x294,0x2ea,0x340,0x396,0x3ec,0x442,0x498,0x4ee,0x544,0x59a,0x5f0,0x646,0x69c,0x6f2,0x748,0x79e,0x7f4 },
+       { 0x03b,0x091,0x0e7,0x13d,0x193,0x1e9,0x23f,0x295,0x2eb,0x341,0x397,0x3ed,0x443,0x499,0x4ef,0x545,0x59b,0x5f1,0x647,0x69d,0x6f3,0x749,0x79f,0x7f5 },
+       { 0x03c,0x092,0x0e8,0x13e,0x194,0x1ea,0x240,0x296,0x2ec,0x342,0x398,0x3ee,0x444,0x49a,0x4f0,0x546,0x59c,0x5f2,0x648,0x69e,0x6f4,0x74a,0x7a0,0x7f6 },
+       { 0x03d,0x093,0x0e9,0x13f,0x195,0x1eb,0x241,0x297,0x2ed,0x343,0x399,0x3ef,0x445,0x49b,0x4f1,0x547,0x59d,0x5f3,0x649,0x69f,0x6f5,0x74b,0x7a1,0x7f7 },
+       { 0x03e,0x094,0x0ea,0x140,0x196,0x1ec,0x242,0x298,0x2ee,0x344,0x39a,0x3f0,0x446,0x49c,0x4f2,0x548,0x59e,0x5f4,0x64a,0x6a0,0x6f6,0x74c,0x7a2,0x7f8 },
+       { 0x03f,0x095,0x0eb,0x141,0x197,0x1ed,0x243,0x299,0x2ef,0x345,0x39b,0x3f1,0x447,0x49d,0x4f3,0x549,0x59f,0x5f5,0x64b,0x6a1,0x6f7,0x74d,0x7a3,0x7f9 },
+       { 0x040,0x096,0x0ec,0x142,0x198,0x1ee,0x244,0x29a,0x2f0,0x346,0x39c,0x3f2,0x448,0x49e,0x4f4,0x54a,0x5a0,0x5f6,0x64c,0x6a2,0x6f8,0x74e,0x7a4,0x7fa },
+       { 0x041,0x097,0x0ed,0x143,0x199,0x1ef,0x245,0x29b,0x2f1,0x347,0x39d,0x3f3,0x449,0x49f,0x4f5,0x54b,0x5a1,0x5f7,0x64d,0x6a3,0x6f9,0x74f,0x7a5,0x7fb },
+       { 0x042,0x098,0x0ee,0x144,0x19a,0x1f0,0x246,0x29c,0x2f2,0x348,0x39e,0x3f4,0x44a,0x4a0,0x4f6,0x54c,0x5a2,0x5f8,0x64e,0x6a4,0x6fa,0x750,0x7a6,0x7fc },
+       { 0x043,0x099,0x0ef,0x145,0x19b,0x1f1,0x247,0x29d,0x2f3,0x349,0x39f,0x3f5,0x44b,0x4a1,0x4f7,0x54d,0x5a3,0x5f9,0x64f,0x6a5,0x6fb,0x751,0x7a7,0x7fd },
+       { 0x044,0x09a,0x0f0,0x146,0x19c,0x1f2,0x248,0x29e,0x2f4,0x34a,0x3a0,0x3f6,0x44c,0x4a2,0x4f8,0x54e,0x5a4,0x5fa,0x650,0x6a6,0x6fc,0x752,0x7a8,0x7fe },
+       { 0x045,0x09b,0x0f1,0x147,0x19d,0x1f3,0x249,0x29f,0x2f5,0x34b,0x3a1,0x3f7,0x44d,0x4a3,0x4f9,0x54f,0x5a5,0x5fb,0x651,0x6a7,0x6fd,0x753,0x7a9,0x7ff },
+       { 0x046,0x09c,0x0f2,0x148,0x19e,0x1f4,0x24a,0x2a0,0x2f6,0x34c,0x3a2,0x3f8,0x44e,0x4a4,0x4fa,0x550,0x5a6,0x5fc,0x652,0x6a8,0x6fe,0x754,0x7aa,0x800 },
+       { 0x047,0x09d,0x0f3,0x149,0x19f,0x1f5,0x24b,0x2a1,0x2f7,0x34d,0x3a3,0x3f9,0x44f,0x4a5,0x4fb,0x551,0x5a7,0x5fd,0x653,0x6a9,0x6ff,0x755,0x7ab,0x801 },
+       { 0x048,0x09e,0x0f4,0x14a,0x1a0,0x1f6,0x24c,0x2a2,0x2f8,0x34e,0x3a4,0x3fa,0x450,0x4a6,0x4fc,0x552,0x5a8,0x5fe,0x654,0x6aa,0x700,0x756,0x7ac,0x802 },
+       { 0x049,0x09f,0x0f5,0x14b,0x1a1,0x1f7,0x24d,0x2a3,0x2f9,0x34f,0x3a5,0x3fb,0x451,0x4a7,0x4fd,0x553,0x5a9,0x5ff,0x655,0x6ab,0x701,0x757,0x7ad,0x803 },
+       { 0x04a,0x0a0,0x0f6,0x14c,0x1a2,0x1f8,0x24e,0x2a4,0x2fa,0x350,0x3a6,0x3fc,0x452,0x4a8,0x4fe,0x554,0x5aa,0x600,0x656,0x6ac,0x702,0x758,0x7ae,0x804 },
+       { 0x04b,0x0a1,0x0f7,0x14d,0x1a3,0x1f9,0x24f,0x2a5,0x2fb,0x351,0x3a7,0x3fd,0x453,0x4a9,0x4ff,0x555,0x5ab,0x601,0x657,0x6ad,0x703,0x759,0x7af,0x805 },
+       { 0x04c,0x0a2,0x0f8,0x14e,0x1a4,0x1fa,0x250,0x2a6,0x2fc,0x352,0x3a8,0x3fe,0x454,0x4aa,0x500,0x556,0x5ac,0x602,0x658,0x6ae,0x704,0x75a,0x7b0,0x806 },
+       { 0x04d,0x0a3,0x0f9,0x14f,0x1a5,0x1fb,0x251,0x2a7,0x2fd,0x353,0x3a9,0x3ff,0x455,0x4ab,0x501,0x557,0x5ad,0x603,0x659,0x6af,0x705,0x75b,0x7b1,0x807 },
+       { 0x04e,0x0a4,0x0fa,0x150,0x1a6,0x1fc,0x252,0x2a8,0x2fe,0x354,0x3aa,0x400,0x456,0x4ac,0x502,0x558,0x5ae,0x604,0x65a,0x6b0,0x706,0x75c,0x7b2,0x808 },
+       { 0x04f,0x0a5,0x0fb,0x151,0x1a7,0x1fd,0x253,0x2a9,0x2ff,0x355,0x3ab,0x401,0x457,0x4ad,0x503,0x559,0x5af,0x605,0x65b,0x6b1,0x707,0x75d,0x7b3,0x809 },
+       { 0x050,0x0a6,0x0fc,0x152,0x1a8,0x1fe,0x254,0x2aa,0x300,0x356,0x3ac,0x402,0x458,0x4ae,0x504,0x55a,0x5b0,0x606,0x65c,0x6b2,0x708,0x75e,0x7b4,0x80a },
+       { 0x051,0x0a7,0x0fd,0x153,0x1a9,0x1ff,0x255,0x2ab,0x301,0x357,0x3ad,0x403,0x459,0x4af,0x505,0x55b,0x5b1,0x607,0x65d,0x6b3,0x709,0x75f,0x7b5,0x80b },
+       { 0x052,0x0a8,0x0fe,0x154,0x1aa,0x200,0x256,0x2ac,0x302,0x358,0x3ae,0x404,0x45a,0x4b0,0x506,0x55c,0x5b2,0x608,0x65e,0x6b4,0x70a,0x760,0x7b6,0x80c },
+       { 0x053,0x0a9,0x0ff,0x155,0x1ab,0x201,0x257,0x2ad,0x303,0x359,0x3af,0x405,0x45b,0x4b1,0x507,0x55d,0x5b3,0x609,0x65f,0x6b5,0x70b,0x761,0x7b7,0x80d },
+       { 0x054,0x0aa,0x100,0x156,0x1ac,0x202,0x258,0x2ae,0x304,0x35a,0x3b0,0x406,0x45c,0x4b2,0x508,0x55e,0x5b4,0x60a,0x660,0x6b6,0x70c,0x762,0x7b8,0x80e },
+       { 0x055,0x0ab,0x101,0x157,0x1ad,0x203,0x259,0x2af,0x305,0x35b,0x3b1,0x407,0x45d,0x4b3,0x509,0x55f,0x5b5,0x60b,0x661,0x6b7,0x70d,0x763,0x7b9,0x80f }
+};
+
+/**
+ * @brief   -------------------------------------------------
+ *            qoffsets - each row represents the addresses used to calculate a byte of the ECC Q
+ *            data 52 (*2) ECC Q bytes, 43 values represented by each
+ *          -------------------------------------------------.
+ */
+
+static const uint16_t qoffsets[ECC_Q_NUM_BYTES][ECC_Q_COMP] =
+{
+       { 0x000,0x058,0x0b0,0x108,0x160,0x1b8,0x210,0x268,0x2c0,0x318,0x370,0x3c8,0x420,0x478,0x4d0,0x528,0x580,0x5d8,0x630,0x688,0x6e0,0x738,0x790,0x7e8,0x840,0x898,0x034,0x08c,0x0e4,0x13c,0x194,0x1ec,0x244,0x29c,0x2f4,0x34c,0x3a4,0x3fc,0x454,0x4ac,0x504,0x55c,0x5b4 },
+       { 0x001,0x059,0x0b1,0x109,0x161,0x1b9,0x211,0x269,0x2c1,0x319,0x371,0x3c9,0x421,0x479,0x4d1,0x529,0x581,0x5d9,0x631,0x689,0x6e1,0x739,0x791,0x7e9,0x841,0x899,0x035,0x08d,0x0e5,0x13d,0x195,0x1ed,0x245,0x29d,0x2f5,0x34d,0x3a5,0x3fd,0x455,0x4ad,0x505,0x55d,0x5b5 },
+       { 0x056,0x0ae,0x106,0x15e,0x1b6,0x20e,0x266,0x2be,0x316,0x36e,0x3c6,0x41e,0x476,0x4ce,0x526,0x57e,0x5d6,0x62e,0x686,0x6de,0x736,0x78e,0x7e6,0x83e,0x896,0x032,0x08a,0x0e2,0x13a,0x192,0x1ea,0x242,0x29a,0x2f2,0x34a,0x3a2,0x3fa,0x452,0x4aa,0x502,0x55a,0x5b2,0x60a },
+       { 0x057,0x0af,0x107,0x15f,0x1b7,0x20f,0x267,0x2bf,0x317,0x36f,0x3c7,0x41f,0x477,0x4cf,0x527,0x57f,0x5d7,0x62f,0x687,0x6df,0x737,0x78f,0x7e7,0x83f,0x897,0x033,0x08b,0x0e3,0x13b,0x193,0x1eb,0x243,0x29b,0x2f3,0x34b,0x3a3,0x3fb,0x453,0x4ab,0x503,0x55b,0x5b3,0x60b },
+       { 0x0ac,0x104,0x15c,0x1b4,0x20c,0x264,0x2bc,0x314,0x36c,0x3c4,0x41c,0x474,0x4cc,0x524,0x57c,0x5d4,0x62c,0x684,0x6dc,0x734,0x78c,0x7e4,0x83c,0x894,0x030,0x088,0x0e0,0x138,0x190,0x1e8,0x240,0x298,0x2f0,0x348,0x3a0,0x3f8,0x450,0x4a8,0x500,0x558,0x5b0,0x608,0x660 },
+       { 0x0ad,0x105,0x15d,0x1b5,0x20d,0x265,0x2bd,0x315,0x36d,0x3c5,0x41d,0x475,0x4cd,0x525,0x57d,0x5d5,0x62d,0x685,0x6dd,0x735,0x78d,0x7e5,0x83d,0x895,0x031,0x089,0x0e1,0x139,0x191,0x1e9,0x241,0x299,0x2f1,0x349,0x3a1,0x3f9,0x451,0x4a9,0x501,0x559,0x5b1,0x609,0x661 },
+       { 0x102,0x15a,0x1b2,0x20a,0x262,0x2ba,0x312,0x36a,0x3c2,0x41a,0x472,0x4ca,0x522,0x57a,0x5d2,0x62a,0x682,0x6da,0x732,0x78a,0x7e2,0x83a,0x892,0x02e,0x086,0x0de,0x136,0x18e,0x1e6,0x23e,0x296,0x2ee,0x346,0x39e,0x3f6,0x44e,0x4a6,0x4fe,0x556,0x5ae,0x606,0x65e,0x6b6 },
+       { 0x103,0x15b,0x1b3,0x20b,0x263,0x2bb,0x313,0x36b,0x3c3,0x41b,0x473,0x4cb,0x523,0x57b,0x5d3,0x62b,0x683,0x6db,0x733,0x78b,0x7e3,0x83b,0x893,0x02f,0x087,0x0df,0x137,0x18f,0x1e7,0x23f,0x297,0x2ef,0x347,0x39f,0x3f7,0x44f,0x4a7,0x4ff,0x557,0x5af,0x607,0x65f,0x6b7 },
+       { 0x158,0x1b0,0x208,0x260,0x2b8,0x310,0x368,0x3c0,0x418,0x470,0x4c8,0x520,0x578,0x5d0,0x628,0x680,0x6d8,0x730,0x788,0x7e0,0x838,0x890,0x02c,0x084,0x0dc,0x134,0x18c,0x1e4,0x23c,0x294,0x2ec,0x344,0x39c,0x3f4,0x44c,0x4a4,0x4fc,0x554,0x5ac,0x604,0x65c,0x6b4,0x70c },
+       { 0x159,0x1b1,0x209,0x261,0x2b9,0x311,0x369,0x3c1,0x419,0x471,0x4c9,0x521,0x579,0x5d1,0x629,0x681,0x6d9,0x731,0x789,0x7e1,0x839,0x891,0x02d,0x085,0x0dd,0x135,0x18d,0x1e5,0x23d,0x295,0x2ed,0x345,0x39d,0x3f5,0x44d,0x4a5,0x4fd,0x555,0x5ad,0x605,0x65d,0x6b5,0x70d },
+       { 0x1ae,0x206,0x25e,0x2b6,0x30e,0x366,0x3be,0x416,0x46e,0x4c6,0x51e,0x576,0x5ce,0x626,0x67e,0x6d6,0x72e,0x786,0x7de,0x836,0x88e,0x02a,0x082,0x0da,0x132,0x18a,0x1e2,0x23a,0x292,0x2ea,0x342,0x39a,0x3f2,0x44a,0x4a2,0x4fa,0x552,0x5aa,0x602,0x65a,0x6b2,0x70a,0x762 },
+       { 0x1af,0x207,0x25f,0x2b7,0x30f,0x367,0x3bf,0x417,0x46f,0x4c7,0x51f,0x577,0x5cf,0x627,0x67f,0x6d7,0x72f,0x787,0x7df,0x837,0x88f,0x02b,0x083,0x0db,0x133,0x18b,0x1e3,0x23b,0x293,0x2eb,0x343,0x39b,0x3f3,0x44b,0x4a3,0x4fb,0x553,0x5ab,0x603,0x65b,0x6b3,0x70b,0x763 },
+       { 0x204,0x25c,0x2b4,0x30c,0x364,0x3bc,0x414,0x46c,0x4c4,0x51c,0x574,0x5cc,0x624,0x67c,0x6d4,0x72c,0x784,0x7dc,0x834,0x88c,0x028,0x080,0x0d8,0x130,0x188,0x1e0,0x238,0x290,0x2e8,0x340,0x398,0x3f0,0x448,0x4a0,0x4f8,0x550,0x5a8,0x600,0x658,0x6b0,0x708,0x760,0x7b8 },
+       { 0x205,0x25d,0x2b5,0x30d,0x365,0x3bd,0x415,0x46d,0x4c5,0x51d,0x575,0x5cd,0x625,0x67d,0x6d5,0x72d,0x785,0x7dd,0x835,0x88d,0x029,0x081,0x0d9,0x131,0x189,0x1e1,0x239,0x291,0x2e9,0x341,0x399,0x3f1,0x449,0x4a1,0x4f9,0x551,0x5a9,0x601,0x659,0x6b1,0x709,0x761,0x7b9 },
+       { 0x25a,0x2b2,0x30a,0x362,0x3ba,0x412,0x46a,0x4c2,0x51a,0x572,0x5ca,0x622,0x67a,0x6d2,0x72a,0x782,0x7da,0x832,0x88a,0x026,0x07e,0x0d6,0x12e,0x186,0x1de,0x236,0x28e,0x2e6,0x33e,0x396,0x3ee,0x446,0x49e,0x4f6,0x54e,0x5a6,0x5fe,0x656,0x6ae,0x706,0x75e,0x7b6,0x80e },
+       { 0x25b,0x2b3,0x30b,0x363,0x3bb,0x413,0x46b,0x4c3,0x51b,0x573,0x5cb,0x623,0x67b,0x6d3,0x72b,0x783,0x7db,0x833,0x88b,0x027,0x07f,0x0d7,0x12f,0x187,0x1df,0x237,0x28f,0x2e7,0x33f,0x397,0x3ef,0x447,0x49f,0x4f7,0x54f,0x5a7,0x5ff,0x657,0x6af,0x707,0x75f,0x7b7,0x80f },
+       { 0x2b0,0x308,0x360,0x3b8,0x410,0x468,0x4c0,0x518,0x570,0x5c8,0x620,0x678,0x6d0,0x728,0x780,0x7d8,0x830,0x888,0x024,0x07c,0x0d4,0x12c,0x184,0x1dc,0x234,0x28c,0x2e4,0x33c,0x394,0x3ec,0x444,0x49c,0x4f4,0x54c,0x5a4,0x5fc,0x654,0x6ac,0x704,0x75c,0x7b4,0x80c,0x864 },
+       { 0x2b1,0x309,0x361,0x3b9,0x411,0x469,0x4c1,0x519,0x571,0x5c9,0x621,0x679,0x6d1,0x729,0x781,0x7d9,0x831,0x889,0x025,0x07d,0x0d5,0x12d,0x185,0x1dd,0x235,0x28d,0x2e5,0x33d,0x395,0x3ed,0x445,0x49d,0x4f5,0x54d,0x5a5,0x5fd,0x655,0x6ad,0x705,0x75d,0x7b5,0x80d,0x865 },
+       { 0x306,0x35e,0x3b6,0x40e,0x466,0x4be,0x516,0x56e,0x5c6,0x61e,0x676,0x6ce,0x726,0x77e,0x7d6,0x82e,0x886,0x022,0x07a,0x0d2,0x12a,0x182,0x1da,0x232,0x28a,0x2e2,0x33a,0x392,0x3ea,0x442,0x49a,0x4f2,0x54a,0x5a2,0x5fa,0x652,0x6aa,0x702,0x75a,0x7b2,0x80a,0x862,0x8ba },
+       { 0x307,0x35f,0x3b7,0x40f,0x467,0x4bf,0x517,0x56f,0x5c7,0x61f,0x677,0x6cf,0x727,0x77f,0x7d7,0x82f,0x887,0x023,0x07b,0x0d3,0x12b,0x183,0x1db,0x233,0x28b,0x2e3,0x33b,0x393,0x3eb,0x443,0x49b,0x4f3,0x54b,0x5a3,0x5fb,0x653,0x6ab,0x703,0x75b,0x7b3,0x80b,0x863,0x8bb },
+       { 0x35c,0x3b4,0x40c,0x464,0x4bc,0x514,0x56c,0x5c4,0x61c,0x674,0x6cc,0x724,0x77c,0x7d4,0x82c,0x884,0x020,0x078,0x0d0,0x128,0x180,0x1d8,0x230,0x288,0x2e0,0x338,0x390,0x3e8,0x440,0x498,0x4f0,0x548,0x5a0,0x5f8,0x650,0x6a8,0x700,0x758,0x7b0,0x808,0x860,0x8b8,0x054 },
+       { 0x35d,0x3b5,0x40d,0x465,0x4bd,0x515,0x56d,0x5c5,0x61d,0x675,0x6cd,0x725,0x77d,0x7d5,0x82d,0x885,0x021,0x079,0x0d1,0x129,0x181,0x1d9,0x231,0x289,0x2e1,0x339,0x391,0x3e9,0x441,0x499,0x4f1,0x549,0x5a1,0x5f9,0x651,0x6a9,0x701,0x759,0x7b1,0x809,0x861,0x8b9,0x055 },
+       { 0x3b2,0x40a,0x462,0x4ba,0x512,0x56a,0x5c2,0x61a,0x672,0x6ca,0x722,0x77a,0x7d2,0x82a,0x882,0x01e,0x076,0x0ce,0x126,0x17e,0x1d6,0x22e,0x286,0x2de,0x336,0x38e,0x3e6,0x43e,0x496,0x4ee,0x546,0x59e,0x5f6,0x64e,0x6a6,0x6fe,0x756,0x7ae,0x806,0x85e,0x8b6,0x052,0x0aa },
+       { 0x3b3,0x40b,0x463,0x4bb,0x513,0x56b,0x5c3,0x61b,0x673,0x6cb,0x723,0x77b,0x7d3,0x82b,0x883,0x01f,0x077,0x0cf,0x127,0x17f,0x1d7,0x22f,0x287,0x2df,0x337,0x38f,0x3e7,0x43f,0x497,0x4ef,0x547,0x59f,0x5f7,0x64f,0x6a7,0x6ff,0x757,0x7af,0x807,0x85f,0x8b7,0x053,0x0ab },
+       { 0x408,0x460,0x4b8,0x510,0x568,0x5c0,0x618,0x670,0x6c8,0x720,0x778,0x7d0,0x828,0x880,0x01c,0x074,0x0cc,0x124,0x17c,0x1d4,0x22c,0x284,0x2dc,0x334,0x38c,0x3e4,0x43c,0x494,0x4ec,0x544,0x59c,0x5f4,0x64c,0x6a4,0x6fc,0x754,0x7ac,0x804,0x85c,0x8b4,0x050,0x0a8,0x100 },
+       { 0x409,0x461,0x4b9,0x511,0x569,0x5c1,0x619,0x671,0x6c9,0x721,0x779,0x7d1,0x829,0x881,0x01d,0x075,0x0cd,0x125,0x17d,0x1d5,0x22d,0x285,0x2dd,0x335,0x38d,0x3e5,0x43d,0x495,0x4ed,0x545,0x59d,0x5f5,0x64d,0x6a5,0x6fd,0x755,0x7ad,0x805,0x85d,0x8b5,0x051,0x0a9,0x101 },
+       { 0x45e,0x4b6,0x50e,0x566,0x5be,0x616,0x66e,0x6c6,0x71e,0x776,0x7ce,0x826,0x87e,0x01a,0x072,0x0ca,0x122,0x17a,0x1d2,0x22a,0x282,0x2da,0x332,0x38a,0x3e2,0x43a,0x492,0x4ea,0x542,0x59a,0x5f2,0x64a,0x6a2,0x6fa,0x752,0x7aa,0x802,0x85a,0x8b2,0x04e,0x0a6,0x0fe,0x156 },
+       { 0x45f,0x4b7,0x50f,0x567,0x5bf,0x617,0x66f,0x6c7,0x71f,0x777,0x7cf,0x827,0x87f,0x01b,0x073,0x0cb,0x123,0x17b,0x1d3,0x22b,0x283,0x2db,0x333,0x38b,0x3e3,0x43b,0x493,0x4eb,0x543,0x59b,0x5f3,0x64b,0x6a3,0x6fb,0x753,0x7ab,0x803,0x85b,0x8b3,0x04f,0x0a7,0x0ff,0x157 },
+       { 0x4b4,0x50c,0x564,0x5bc,0x614,0x66c,0x6c4,0x71c,0x774,0x7cc,0x824,0x87c,0x018,0x070,0x0c8,0x120,0x178,0x1d0,0x228,0x280,0x2d8,0x330,0x388,0x3e0,0x438,0x490,0x4e8,0x540,0x598,0x5f0,0x648,0x6a0,0x6f8,0x750,0x7a8,0x800,0x858,0x8b0,0x04c,0x0a4,0x0fc,0x154,0x1ac },
+       { 0x4b5,0x50d,0x565,0x5bd,0x615,0x66d,0x6c5,0x71d,0x775,0x7cd,0x825,0x87d,0x019,0x071,0x0c9,0x121,0x179,0x1d1,0x229,0x281,0x2d9,0x331,0x389,0x3e1,0x439,0x491,0x4e9,0x541,0x599,0x5f1,0x649,0x6a1,0x6f9,0x751,0x7a9,0x801,0x859,0x8b1,0x04d,0x0a5,0x0fd,0x155,0x1ad },
+       { 0x50a,0x562,0x5ba,0x612,0x66a,0x6c2,0x71a,0x772,0x7ca,0x822,0x87a,0x016,0x06e,0x0c6,0x11e,0x176,0x1ce,0x226,0x27e,0x2d6,0x32e,0x386,0x3de,0x436,0x48e,0x4e6,0x53e,0x596,0x5ee,0x646,0x69e,0x6f6,0x74e,0x7a6,0x7fe,0x856,0x8ae,0x04a,0x0a2,0x0fa,0x152,0x1aa,0x202 },
+       { 0x50b,0x563,0x5bb,0x613,0x66b,0x6c3,0x71b,0x773,0x7cb,0x823,0x87b,0x017,0x06f,0x0c7,0x11f,0x177,0x1cf,0x227,0x27f,0x2d7,0x32f,0x387,0x3df,0x437,0x48f,0x4e7,0x53f,0x597,0x5ef,0x647,0x69f,0x6f7,0x74f,0x7a7,0x7ff,0x857,0x8af,0x04b,0x0a3,0x0fb,0x153,0x1ab,0x203 },
+       { 0x560,0x5b8,0x610,0x668,0x6c0,0x718,0x770,0x7c8,0x820,0x878,0x014,0x06c,0x0c4,0x11c,0x174,0x1cc,0x224,0x27c,0x2d4,0x32c,0x384,0x3dc,0x434,0x48c,0x4e4,0x53c,0x594,0x5ec,0x644,0x69c,0x6f4,0x74c,0x7a4,0x7fc,0x854,0x8ac,0x048,0x0a0,0x0f8,0x150,0x1a8,0x200,0x258 },
+       { 0x561,0x5b9,0x611,0x669,0x6c1,0x719,0x771,0x7c9,0x821,0x879,0x015,0x06d,0x0c5,0x11d,0x175,0x1cd,0x225,0x27d,0x2d5,0x32d,0x385,0x3dd,0x435,0x48d,0x4e5,0x53d,0x595,0x5ed,0x645,0x69d,0x6f5,0x74d,0x7a5,0x7fd,0x855,0x8ad,0x049,0x0a1,0x0f9,0x151,0x1a9,0x201,0x259 },
+       { 0x5b6,0x60e,0x666,0x6be,0x716,0x76e,0x7c6,0x81e,0x876,0x012,0x06a,0x0c2,0x11a,0x172,0x1ca,0x222,0x27a,0x2d2,0x32a,0x382,0x3da,0x432,0x48a,0x4e2,0x53a,0x592,0x5ea,0x642,0x69a,0x6f2,0x74a,0x7a2,0x7fa,0x852,0x8aa,0x046,0x09e,0x0f6,0x14e,0x1a6,0x1fe,0x256,0x2ae },
+       { 0x5b7,0x60f,0x667,0x6bf,0x717,0x76f,0x7c7,0x81f,0x877,0x013,0x06b,0x0c3,0x11b,0x173,0x1cb,0x223,0x27b,0x2d3,0x32b,0x383,0x3db,0x433,0x48b,0x4e3,0x53b,0x593,0x5eb,0x643,0x69b,0x6f3,0x74b,0x7a3,0x7fb,0x853,0x8ab,0x047,0x09f,0x0f7,0x14f,0x1a7,0x1ff,0x257,0x2af },
+       { 0x60c,0x664,0x6bc,0x714,0x76c,0x7c4,0x81c,0x874,0x010,0x068,0x0c0,0x118,0x170,0x1c8,0x220,0x278,0x2d0,0x328,0x380,0x3d8,0x430,0x488,0x4e0,0x538,0x590,0x5e8,0x640,0x698,0x6f0,0x748,0x7a0,0x7f8,0x850,0x8a8,0x044,0x09c,0x0f4,0x14c,0x1a4,0x1fc,0x254,0x2ac,0x304 },
+       { 0x60d,0x665,0x6bd,0x715,0x76d,0x7c5,0x81d,0x875,0x011,0x069,0x0c1,0x119,0x171,0x1c9,0x221,0x279,0x2d1,0x329,0x381,0x3d9,0x431,0x489,0x4e1,0x539,0x591,0x5e9,0x641,0x699,0x6f1,0x749,0x7a1,0x7f9,0x851,0x8a9,0x045,0x09d,0x0f5,0x14d,0x1a5,0x1fd,0x255,0x2ad,0x305 },
+       { 0x662,0x6ba,0x712,0x76a,0x7c2,0x81a,0x872,0x00e,0x066,0x0be,0x116,0x16e,0x1c6,0x21e,0x276,0x2ce,0x326,0x37e,0x3d6,0x42e,0x486,0x4de,0x536,0x58e,0x5e6,0x63e,0x696,0x6ee,0x746,0x79e,0x7f6,0x84e,0x8a6,0x042,0x09a,0x0f2,0x14a,0x1a2,0x1fa,0x252,0x2aa,0x302,0x35a },
+       { 0x663,0x6bb,0x713,0x76b,0x7c3,0x81b,0x873,0x00f,0x067,0x0bf,0x117,0x16f,0x1c7,0x21f,0x277,0x2cf,0x327,0x37f,0x3d7,0x42f,0x487,0x4df,0x537,0x58f,0x5e7,0x63f,0x697,0x6ef,0x747,0x79f,0x7f7,0x84f,0x8a7,0x043,0x09b,0x0f3,0x14b,0x1a3,0x1fb,0x253,0x2ab,0x303,0x35b },
+       { 0x6b8,0x710,0x768,0x7c0,0x818,0x870,0x00c,0x064,0x0bc,0x114,0x16c,0x1c4,0x21c,0x274,0x2cc,0x324,0x37c,0x3d4,0x42c,0x484,0x4dc,0x534,0x58c,0x5e4,0x63c,0x694,0x6ec,0x744,0x79c,0x7f4,0x84c,0x8a4,0x040,0x098,0x0f0,0x148,0x1a0,0x1f8,0x250,0x2a8,0x300,0x358,0x3b0 },
+       { 0x6b9,0x711,0x769,0x7c1,0x819,0x871,0x00d,0x065,0x0bd,0x115,0x16d,0x1c5,0x21d,0x275,0x2cd,0x325,0x37d,0x3d5,0x42d,0x485,0x4dd,0x535,0x58d,0x5e5,0x63d,0x695,0x6ed,0x745,0x79d,0x7f5,0x84d,0x8a5,0x041,0x099,0x0f1,0x149,0x1a1,0x1f9,0x251,0x2a9,0x301,0x359,0x3b1 },
+       { 0x70e,0x766,0x7be,0x816,0x86e,0x00a,0x062,0x0ba,0x112,0x16a,0x1c2,0x21a,0x272,0x2ca,0x322,0x37a,0x3d2,0x42a,0x482,0x4da,0x532,0x58a,0x5e2,0x63a,0x692,0x6ea,0x742,0x79a,0x7f2,0x84a,0x8a2,0x03e,0x096,0x0ee,0x146,0x19e,0x1f6,0x24e,0x2a6,0x2fe,0x356,0x3ae,0x406 },
+       { 0x70f,0x767,0x7bf,0x817,0x86f,0x00b,0x063,0x0bb,0x113,0x16b,0x1c3,0x21b,0x273,0x2cb,0x323,0x37b,0x3d3,0x42b,0x483,0x4db,0x533,0x58b,0x5e3,0x63b,0x693,0x6eb,0x743,0x79b,0x7f3,0x84b,0x8a3,0x03f,0x097,0x0ef,0x147,0x19f,0x1f7,0x24f,0x2a7,0x2ff,0x357,0x3af,0x407 },
+       { 0x764,0x7bc,0x814,0x86c,0x008,0x060,0x0b8,0x110,0x168,0x1c0,0x218,0x270,0x2c8,0x320,0x378,0x3d0,0x428,0x480,0x4d8,0x530,0x588,0x5e0,0x638,0x690,0x6e8,0x740,0x798,0x7f0,0x848,0x8a0,0x03c,0x094,0x0ec,0x144,0x19c,0x1f4,0x24c,0x2a4,0x2fc,0x354,0x3ac,0x404,0x45c },
+       { 0x765,0x7bd,0x815,0x86d,0x009,0x061,0x0b9,0x111,0x169,0x1c1,0x219,0x271,0x2c9,0x321,0x379,0x3d1,0x429,0x481,0x4d9,0x531,0x589,0x5e1,0x639,0x691,0x6e9,0x741,0x799,0x7f1,0x849,0x8a1,0x03d,0x095,0x0ed,0x145,0x19d,0x1f5,0x24d,0x2a5,0x2fd,0x355,0x3ad,0x405,0x45d },
+       { 0x7ba,0x812,0x86a,0x006,0x05e,0x0b6,0x10e,0x166,0x1be,0x216,0x26e,0x2c6,0x31e,0x376,0x3ce,0x426,0x47e,0x4d6,0x52e,0x586,0x5de,0x636,0x68e,0x6e6,0x73e,0x796,0x7ee,0x846,0x89e,0x03a,0x092,0x0ea,0x142,0x19a,0x1f2,0x24a,0x2a2,0x2fa,0x352,0x3aa,0x402,0x45a,0x4b2 },
+       { 0x7bb,0x813,0x86b,0x007,0x05f,0x0b7,0x10f,0x167,0x1bf,0x217,0x26f,0x2c7,0x31f,0x377,0x3cf,0x427,0x47f,0x4d7,0x52f,0x587,0x5df,0x637,0x68f,0x6e7,0x73f,0x797,0x7ef,0x847,0x89f,0x03b,0x093,0x0eb,0x143,0x19b,0x1f3,0x24b,0x2a3,0x2fb,0x353,0x3ab,0x403,0x45b,0x4b3 },
+       { 0x810,0x868,0x004,0x05c,0x0b4,0x10c,0x164,0x1bc,0x214,0x26c,0x2c4,0x31c,0x374,0x3cc,0x424,0x47c,0x4d4,0x52c,0x584,0x5dc,0x634,0x68c,0x6e4,0x73c,0x794,0x7ec,0x844,0x89c,0x038,0x090,0x0e8,0x140,0x198,0x1f0,0x248,0x2a0,0x2f8,0x350,0x3a8,0x400,0x458,0x4b0,0x508 },
+       { 0x811,0x869,0x005,0x05d,0x0b5,0x10d,0x165,0x1bd,0x215,0x26d,0x2c5,0x31d,0x375,0x3cd,0x425,0x47d,0x4d5,0x52d,0x585,0x5dd,0x635,0x68d,0x6e5,0x73d,0x795,0x7ed,0x845,0x89d,0x039,0x091,0x0e9,0x141,0x199,0x1f1,0x249,0x2a1,0x2f9,0x351,0x3a9,0x401,0x459,0x4b1,0x509 },
+       { 0x866,0x002,0x05a,0x0b2,0x10a,0x162,0x1ba,0x212,0x26a,0x2c2,0x31a,0x372,0x3ca,0x422,0x47a,0x4d2,0x52a,0x582,0x5da,0x632,0x68a,0x6e2,0x73a,0x792,0x7ea,0x842,0x89a,0x036,0x08e,0x0e6,0x13e,0x196,0x1ee,0x246,0x29e,0x2f6,0x34e,0x3a6,0x3fe,0x456,0x4ae,0x506,0x55e },
+       { 0x867,0x003,0x05b,0x0b3,0x10b,0x163,0x1bb,0x213,0x26b,0x2c3,0x31b,0x373,0x3cb,0x423,0x47b,0x4d3,0x52b,0x583,0x5db,0x633,0x68b,0x6e3,0x73b,0x793,0x7eb,0x843,0x89b,0x037,0x08f,0x0e7,0x13f,0x197,0x1ef,0x247,0x29f,0x2f7,0x34f,0x3a7,0x3ff,0x457,0x4af,0x507,0x55f }
+};
+
+/*-------------------------------------------------
+ *  ecc_source_byte - return data from the sector
+ *  at the given offset, masking anything
+ *  particular to a mode
+ *-------------------------------------------------
+ */
+
+static inline uint8_t ecc_source_byte(const uint8_t *sector, uint32_t offset)
+{
+       /* in mode 2 always treat these as 0 bytes */
+       return (sector[MODE_OFFSET] == 2 && offset < 4) ? 0x00 : sector[SYNC_OFFSET + SYNC_NUM_BYTES + offset];
+}
+
+/**
+ * @fn  void ecc_compute_bytes(const uint8_t *sector, const uint16_t *row, int rowlen, uint8_t &val1, uint8_t &val2)
+ *
+ * @brief   -------------------------------------------------
+ *            ecc_compute_bytes - calculate an ECC value (P or Q)
+ *          -------------------------------------------------.
+ *
+ * @param   sector          The sector.
+ * @param   row             The row.
+ * @param   rowlen          The rowlen.
+ * @param [in,out]  val1    The first value.
+ * @param [in,out]  val2    The second value.
+ */
+
+void ecc_compute_bytes(const uint8_t *sector, const uint16_t *row, int rowlen, uint8_t *val1, uint8_t *val2)
+{
+       int component;
+       *val1 = *val2 = 0;
+       for (component = 0; component < rowlen; component++)
+       {
+               *val1 ^= ecc_source_byte(sector, row[component]);
+               *val2 ^= ecc_source_byte(sector, row[component]);
+               *val1 = ecclow[*val1];
+       }
+       *val1 = ecchigh[ecclow[*val1] ^ *val2];
+       *val2 ^= *val1;
+}
+
+/**
+ * @fn  int ecc_verify(const uint8_t *sector)
+ *
+ * @brief   -------------------------------------------------
+ *            ecc_verify - verify the P and Q ECC codes in a sector
+ *          -------------------------------------------------.
+ *
+ * @param   sector  The sector.
+ *
+ * @return  true if it succeeds, false if it fails.
+ */
+
+int ecc_verify(const uint8_t *sector)
+{
+       int byte;
+       /* first verify P bytes */
+       for (byte = 0; byte < ECC_P_NUM_BYTES; byte++)
+       {
+               uint8_t val1, val2;
+               ecc_compute_bytes(sector, poffsets[byte], ECC_P_COMP, &val1, &val2);
+               if (sector[ECC_P_OFFSET + byte] != val1 || sector[ECC_P_OFFSET + ECC_P_NUM_BYTES + byte] != val2)
+                       return 0;
+       }
+
+       /* then verify Q bytes */
+       for (byte = 0; byte < ECC_Q_NUM_BYTES; byte++)
+       {
+               uint8_t val1, val2;
+               ecc_compute_bytes(sector, qoffsets[byte], ECC_Q_COMP, &val1, &val2);
+               if (sector[ECC_Q_OFFSET + byte] != val1 || sector[ECC_Q_OFFSET + ECC_Q_NUM_BYTES + byte] != val2)
+                       return 0;
+       }
+       return 1;
+}
+
+/**
+ * @fn  void ecc_generate(uint8_t *sector)
+ *
+ * @brief   -------------------------------------------------
+ *            ecc_generate - generate the P and Q ECC codes for a sector, overwriting any
+ *            existing codes
+ *          -------------------------------------------------.
+ *
+ * @param [in,out]  sector  If non-null, the sector.
+ */
+
+void ecc_generate(uint8_t *sector)
+{
+       int byte;
+       /* first verify P bytes */
+       for (byte = 0; byte < ECC_P_NUM_BYTES; byte++)
+               ecc_compute_bytes(sector, poffsets[byte], ECC_P_COMP, &sector[ECC_P_OFFSET + byte], &sector[ECC_P_OFFSET + ECC_P_NUM_BYTES + byte]);
+
+       /* then verify Q bytes */
+       for (byte = 0; byte < ECC_Q_NUM_BYTES; byte++)
+               ecc_compute_bytes(sector, qoffsets[byte], ECC_Q_COMP, &sector[ECC_Q_OFFSET + byte], &sector[ECC_Q_OFFSET + ECC_Q_NUM_BYTES + byte]);
+}
+
+/**
+ * @fn  void ecc_clear(uint8_t *sector)
+ *
+ * @brief   -------------------------------------------------
+ *            ecc_clear - erase the ECC P and Q cods to 0 within a sector
+ *          -------------------------------------------------.
+ *
+ * @param [in,out]  sector  If non-null, the sector.
+ */
+
+void ecc_clear(uint8_t *sector)
+{
+       memset(&sector[ECC_P_OFFSET], 0, 2 * ECC_P_NUM_BYTES);
+       memset(&sector[ECC_Q_OFFSET], 0, 2 * ECC_Q_NUM_BYTES);
+}
index 8a3341c..65aa182 100644 (file)
-// license:BSD-3-Clause\r
-// copyright-holders:Aaron Giles\r
-/***************************************************************************\r
-\r
-    cdrom.h\r
-\r
-    Generic MAME cd-rom implementation\r
-\r
-***************************************************************************/\r
-\r
-#pragma once\r
-\r
-#ifndef __CDROM_H__\r
-#define __CDROM_H__\r
-\r
-#include <stdint.h>\r
-\r
-\r
-/***************************************************************************\r
-    CONSTANTS\r
-***************************************************************************/\r
-\r
-// tracks are padded to a multiple of this many frames\r
-extern const uint32_t CD_TRACK_PADDING;\r
-\r
-#define CD_MAX_TRACKS           (99)    /* AFAIK the theoretical limit */\r
-#define CD_MAX_SECTOR_DATA      (2352)\r
-#define CD_MAX_SUBCODE_DATA     (96)\r
-\r
-#define CD_FRAME_SIZE           (CD_MAX_SECTOR_DATA + CD_MAX_SUBCODE_DATA)\r
-#define CD_FRAMES_PER_HUNK      (8)\r
-\r
-#define CD_METADATA_WORDS       (1+(CD_MAX_TRACKS * 6))\r
-\r
-enum\r
-{\r
-       CD_TRACK_MODE1 = 0,         /* mode 1 2048 bytes/sector */\r
-       CD_TRACK_MODE1_RAW,         /* mode 1 2352 bytes/sector */\r
-       CD_TRACK_MODE2,             /* mode 2 2336 bytes/sector */\r
-       CD_TRACK_MODE2_FORM1,       /* mode 2 2048 bytes/sector */\r
-       CD_TRACK_MODE2_FORM2,       /* mode 2 2324 bytes/sector */\r
-       CD_TRACK_MODE2_FORM_MIX,    /* mode 2 2336 bytes/sector */\r
-       CD_TRACK_MODE2_RAW,         /* mode 2 2352 bytes / sector */\r
-       CD_TRACK_AUDIO,         /* redbook audio track 2352 bytes/sector (588 samples) */\r
-\r
-       CD_TRACK_RAW_DONTCARE       /* special flag for cdrom_read_data: just return me whatever is there */\r
-};\r
-\r
-enum\r
-{\r
-       CD_SUB_NORMAL = 0,          /* "cooked" 96 bytes per sector */\r
-       CD_SUB_RAW,                 /* raw uninterleaved 96 bytes per sector */\r
-       CD_SUB_NONE                 /* no subcode data stored */\r
-};\r
-\r
-#define CD_FLAG_GDROM   0x00000001  // disc is a GD-ROM, all tracks should be stored with GD-ROM metadata\r
-#define CD_FLAG_GDROMLE 0x00000002  // legacy GD-ROM, with little-endian CDDA data\r
-\r
-/***************************************************************************\r
-    FUNCTION PROTOTYPES\r
-***************************************************************************/\r
-\r
-// ECC utilities\r
-int ecc_verify(const uint8_t *sector);\r
-void ecc_generate(uint8_t *sector);\r
-void ecc_clear(uint8_t *sector);\r
-\r
-\r
-\r
-/***************************************************************************\r
-    INLINE FUNCTIONS\r
-***************************************************************************/\r
-\r
-static inline uint32_t msf_to_lba(uint32_t msf)\r
-{\r
-       return ( ((msf&0x00ff0000)>>16) * 60 * 75) + (((msf&0x0000ff00)>>8) * 75) + ((msf&0x000000ff)>>0);\r
-}\r
-\r
-static inline uint32_t lba_to_msf(uint32_t lba)\r
-{\r
-       uint8_t m, s, f;\r
-\r
-       m = lba / (60 * 75);\r
-       lba -= m * (60 * 75);\r
-       s = lba / 75;\r
-       f = lba % 75;\r
-\r
-       return ((m / 10) << 20) | ((m % 10) << 16) |\r
-                       ((s / 10) << 12) | ((s % 10) <<  8) |\r
-                       ((f / 10) <<  4) | ((f % 10) <<  0);\r
-}\r
-\r
-// segacd needs it like this.. investigate\r
-// Angelo also says PCE tracks often start playing at the\r
-// wrong address.. related?\r
-static inline uint32_t lba_to_msf_alt(int lba)\r
-{\r
-       uint32_t ret = 0;\r
-\r
-       ret |= ((lba / (60 * 75))&0xff)<<16;\r
-       ret |= (((lba / 75) % 60)&0xff)<<8;\r
-       ret |= ((lba % 75)&0xff)<<0;\r
-\r
-       return ret;\r
-}\r
-\r
-#endif  // __CDROM_H__\r
+/* license:BSD-3-Clause
+ * copyright-holders:Aaron Giles
+***************************************************************************
+
+    cdrom.h
+
+    Generic MAME cd-rom implementation
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __CDROM_H__
+#define __CDROM_H__
+
+#include <stdint.h>
+
+
+/***************************************************************************
+    CONSTANTS
+***************************************************************************/
+
+/* tracks are padded to a multiple of this many frames */
+extern const uint32_t CD_TRACK_PADDING;
+
+#define CD_MAX_TRACKS           (99)    /* AFAIK the theoretical limit */
+#define CD_MAX_SECTOR_DATA      (2352)
+#define CD_MAX_SUBCODE_DATA     (96)
+
+#define CD_FRAME_SIZE           (CD_MAX_SECTOR_DATA + CD_MAX_SUBCODE_DATA)
+#define CD_FRAMES_PER_HUNK      (8)
+
+#define CD_METADATA_WORDS       (1+(CD_MAX_TRACKS * 6))
+
+enum
+{
+       CD_TRACK_MODE1 = 0,         /* mode 1 2048 bytes/sector */
+       CD_TRACK_MODE1_RAW,         /* mode 1 2352 bytes/sector */
+       CD_TRACK_MODE2,             /* mode 2 2336 bytes/sector */
+       CD_TRACK_MODE2_FORM1,       /* mode 2 2048 bytes/sector */
+       CD_TRACK_MODE2_FORM2,       /* mode 2 2324 bytes/sector */
+       CD_TRACK_MODE2_FORM_MIX,    /* mode 2 2336 bytes/sector */
+       CD_TRACK_MODE2_RAW,         /* mode 2 2352 bytes / sector */
+       CD_TRACK_AUDIO,         /* redbook audio track 2352 bytes/sector (588 samples) */
+
+       CD_TRACK_RAW_DONTCARE       /* special flag for cdrom_read_data: just return me whatever is there */
+};
+
+enum
+{
+       CD_SUB_NORMAL = 0,          /* "cooked" 96 bytes per sector */
+       CD_SUB_RAW,                 /* raw uninterleaved 96 bytes per sector */
+       CD_SUB_NONE                 /* no subcode data stored */
+};
+
+#define CD_FLAG_GDROM   0x00000001  /* disc is a GD-ROM, all tracks should be stored with GD-ROM metadata */
+#define CD_FLAG_GDROMLE 0x00000002  /* legacy GD-ROM, with little-endian CDDA data */
+
+/***************************************************************************
+    FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* ECC utilities */
+int ecc_verify(const uint8_t *sector);
+void ecc_generate(uint8_t *sector);
+void ecc_clear(uint8_t *sector);
+
+
+
+/***************************************************************************
+    INLINE FUNCTIONS
+***************************************************************************/
+
+static inline uint32_t msf_to_lba(uint32_t msf)
+{
+       return ( ((msf&0x00ff0000)>>16) * 60 * 75) + (((msf&0x0000ff00)>>8) * 75) + ((msf&0x000000ff)>>0);
+}
+
+static inline uint32_t lba_to_msf(uint32_t lba)
+{
+       uint8_t m, s, f;
+
+       m = lba / (60 * 75);
+       lba -= m * (60 * 75);
+       s = lba / 75;
+       f = lba % 75;
+
+       return ((m / 10) << 20) | ((m % 10) << 16) |
+                       ((s / 10) << 12) | ((s % 10) <<  8) |
+                       ((f / 10) <<  4) | ((f % 10) <<  0);
+}
+
+/**
+ * segacd needs it like this.. investigate
+ * Angelo also says PCE tracks often start playing at the
+ * wrong address.. related?
+ **/
+static inline uint32_t lba_to_msf_alt(int lba)
+{
+       uint32_t ret = 0;
+
+       ret |= ((lba / (60 * 75))&0xff)<<16;
+       ret |= (((lba / 75) % 60)&0xff)<<8;
+       ret |= ((lba % 75)&0xff)<<0;
+
+       return ret;
+}
+
+#endif  /* __CDROM_H__ */
index bf6d342..096ba9e 100644 (file)
     POSSIBILITY OF SUCH DAMAGE.
 
 ***************************************************************************/
-#define DONT_SET_BYTE
-typedef unsigned char Byte;
 
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
 #include "chd.h"
 #include "cdrom.h"
-#include "huffman.h"
 #include "flac.h"
-
-#include "md5.h"
-#include "sha1.h"
+#include "huffman.h"
 #include "LzmaEnc.h"
 #include "LzmaDec.h"
-
-#include <string.h>
-#include <zlib.h>
-
-#include <time.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#include "../deps/crypto/md5.h"
+#include "md5.h"
+#include "sha1.h"
+#include "zlib.h"
 
 #define TRUE 1
 #define FALSE 0
@@ -67,16 +60,12 @@ typedef unsigned char Byte;
 
 #define SHA1_DIGEST_SIZE 20
 
-#define CHD_MAKE_TAG(a,b,c,d)       (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
-
 /***************************************************************************
     DEBUGGING
 ***************************************************************************/
 
 #define PRINTF_MAX_HUNK                                (0)
 
-
-
 /***************************************************************************
     CONSTANTS
 ***************************************************************************/
@@ -101,63 +90,60 @@ typedef unsigned char Byte;
 
 static const uint8_t s_cd_sync_header[12] = { 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00 };
 
-// V3-V4 entry types
+/* V3-V4 entry types */
 enum
 {
-       V34_MAP_ENTRY_TYPE_INVALID = 0,             // invalid type
-       V34_MAP_ENTRY_TYPE_COMPRESSED = 1,          // standard compression
-       V34_MAP_ENTRY_TYPE_UNCOMPRESSED = 2,        // uncompressed data
-       V34_MAP_ENTRY_TYPE_MINI = 3,                // mini: use offset as raw data
-       V34_MAP_ENTRY_TYPE_SELF_HUNK = 4,           // same as another hunk in this file
-       V34_MAP_ENTRY_TYPE_PARENT_HUNK = 5,         // same as a hunk in the parent file
-       V34_MAP_ENTRY_TYPE_2ND_COMPRESSED = 6       // compressed with secondary algorithm (usually FLAC CDDA)
+       V34_MAP_ENTRY_TYPE_INVALID = 0,             /* invalid type */
+       V34_MAP_ENTRY_TYPE_COMPRESSED = 1,          /* standard compression */
+       V34_MAP_ENTRY_TYPE_UNCOMPRESSED = 2,        /* uncompressed data */
+       V34_MAP_ENTRY_TYPE_MINI = 3,                /* mini: use offset as raw data */
+       V34_MAP_ENTRY_TYPE_SELF_HUNK = 4,           /* same as another hunk in this file */
+       V34_MAP_ENTRY_TYPE_PARENT_HUNK = 5,         /* same as a hunk in the parent file */
+       V34_MAP_ENTRY_TYPE_2ND_COMPRESSED = 6       /* compressed with secondary algorithm (usually FLAC CDDA) */
 };
 
-// V5 compression types
+/* V5 compression types */
 enum
 {
-       ///< codec #0
-       // these types are live when running
+       /* codec #0
+        * these types are live when running */
        COMPRESSION_TYPE_0 = 0,
-       ///< codec #1
+       /* codec #1 */
        COMPRESSION_TYPE_1 = 1,
-       ///< codec #2
+       /* codec #2 */
        COMPRESSION_TYPE_2 = 2,
-       ///< codec #3
+       /* codec #3 */
        COMPRESSION_TYPE_3 = 3,
-       ///< no compression; implicit length = hunkbytes
+       /* no compression; implicit length = hunkbytes */
        COMPRESSION_NONE = 4,
-       ///< same as another block in this chd
+       /* same as another block in this chd */
        COMPRESSION_SELF = 5,
-       ///< same as a hunk's worth of units in the parent chd
+       /* same as a hunk's worth of units in the parent chd */
        COMPRESSION_PARENT = 6,
 
-       ///< start of small RLE run (4-bit length)
-       // these additional pseudo-types are used for compressed encodings:
+       /* start of small RLE run (4-bit length)
+        * these additional pseudo-types are used for compressed encodings: */
        COMPRESSION_RLE_SMALL,
-       ///< start of large RLE run (8-bit length)
+       /* start of large RLE run (8-bit length) */
        COMPRESSION_RLE_LARGE,
-       ///< same as the last COMPRESSION_SELF block
+       /* same as the last COMPRESSION_SELF block */
        COMPRESSION_SELF_0,
-       ///< same as the last COMPRESSION_SELF block + 1
+       /* same as the last COMPRESSION_SELF block + 1 */
        COMPRESSION_SELF_1,
-       ///< same block in the parent
+       /* same block in the parent */
        COMPRESSION_PARENT_SELF,
-       ///< same as the last COMPRESSION_PARENT block
+       /* same as the last COMPRESSION_PARENT block */
        COMPRESSION_PARENT_0,
-       ///< same as the last COMPRESSION_PARENT block + 1
+       /* same as the last COMPRESSION_PARENT block + 1 */
        COMPRESSION_PARENT_1
 };
 
-
 /***************************************************************************
     MACROS
 ***************************************************************************/
 
 #define EARLY_EXIT(x)                          do { (void)(x); goto cleanup; } while (0)
 
-
-
 /***************************************************************************
     TYPE DEFINITIONS
 ***************************************************************************/
@@ -175,7 +161,6 @@ struct _codec_interface
        chd_error       (*config)(void *codec, int param, void *config); /* configure */
 };
 
-
 /* a single map entry */
 typedef struct _map_entry map_entry;
 struct _map_entry
@@ -186,7 +171,6 @@ struct _map_entry
        UINT8                                   flags;                  /* misc flags */
 };
 
-
 /* simple linked-list of hunks used for our CRC map */
 typedef struct _crcmap_entry crcmap_entry;
 struct _crcmap_entry
@@ -195,7 +179,6 @@ struct _crcmap_entry
        crcmap_entry *                  next;                   /* next entry in list */
 };
 
-
 /* a single metadata entry */
 typedef struct _metadata_entry metadata_entry;
 struct _metadata_entry
@@ -236,7 +219,7 @@ struct _lzma_allocator
 };
 
 typedef struct _lzma_codec_data lzma_codec_data;
-struct _lzma_codec_data 
+struct _lzma_codec_data
 {
        CLzmaDec                decoder;
        lzma_allocator  allocator;
@@ -245,7 +228,7 @@ struct _lzma_codec_data
 /* codec-private data for the CDZL codec */
 typedef struct _cdzl_codec_data cdzl_codec_data;
 struct _cdzl_codec_data {
-       // internal state
+       /* internal state */
        zlib_codec_data         base_decompressor;
        zlib_codec_data         subcode_decompressor;
        uint8_t*                        buffer;
@@ -254,7 +237,7 @@ struct _cdzl_codec_data {
 /* codec-private data for the CDLZ codec */
 typedef struct _cdlz_codec_data cdlz_codec_data;
 struct _cdlz_codec_data {
-       // internal state
+       /* internal state */
        lzma_codec_data         base_decompressor;
        zlib_codec_data         subcode_decompressor;
        uint8_t*                        buffer;
@@ -263,7 +246,7 @@ struct _cdlz_codec_data {
 /* codec-private data for the CDFL codec */
 typedef struct _cdfl_codec_data cdfl_codec_data;
 struct _cdfl_codec_data {
-       // internal state
+       /* internal state */
        int             swap_endian;
        flac_decoder    decoder;
        z_stream        inflater;
@@ -317,10 +300,9 @@ struct _chd_file
        UINT32                                  async_hunknum;  /* hunk index for asynchronous operations */
        void *                                  async_buffer;   /* buffer pointer for asynchronous operations */
 
-       UINT8 *                                 file_cache; /* cache of underlying file */
+       UINT8 *                                 file_cache;             /* cache of underlying file */
 };
 
-
 /* a single metadata hash entry */
 typedef struct _metadata_hash metadata_hash;
 struct _metadata_hash
@@ -329,8 +311,6 @@ struct _metadata_hash
        UINT8                                   sha1[CHD_SHA1_BYTES]; /* hash */
 };
 
-
-
 /***************************************************************************
     GLOBAL VARIABLES
 ***************************************************************************/
@@ -338,16 +318,13 @@ struct _metadata_hash
 static const UINT8 nullmd5[CHD_MD5_BYTES] = { 0 };
 static const UINT8 nullsha1[CHD_SHA1_BYTES] = { 0 };
 
-
-
 /***************************************************************************
     PROTOTYPES
 ***************************************************************************/
 
 /* internal header operations */
 static chd_error header_validate(const chd_header *header);
-static chd_error header_read(core_file *file, chd_header *header);
-
+static chd_error header_read(chd_file *chd, chd_header *header);
 
 /* internal hunk read/write */
 static chd_error hunk_read_into_cache(chd_file *chd, UINT32 hunknum);
@@ -359,7 +336,6 @@ static chd_error map_read(chd_file *chd);
 /* metadata management */
 static chd_error metadata_find_entry(chd_file *chd, UINT32 metatag, UINT32 metaindex, metadata_entry *metaentry);
 
-
 /* zlib compression codec */
 static chd_error zlib_codec_init(void *codec, uint32_t hunkbytes);
 static void zlib_codec_free(void *codec);
@@ -387,75 +363,76 @@ static chd_error cdfl_codec_init(void* codec, uint32_t hunkbytes);
 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);
 
-//**************************************************************************
-//  LZMA ALLOCATOR HELPER
-//**************************************************************************
+/***************************************************************************
+ *  LZMA ALLOCATOR HELPER
+ ***************************************************************************
+ */
 
 void *lzma_fast_alloc(void *p, size_t size);
 void lzma_fast_free(void *p, void *address);
 
-//-------------------------------------------------
-//  lzma_allocator_init
-//-------------------------------------------------
+/*-------------------------------------------------
+ *  lzma_allocator_init
+ *-------------------------------------------------
+ */
 
 void lzma_allocator_init(void* p)
 {
        lzma_allocator *codec = (lzma_allocator *)(p);
 
-       // reset pointer list
+       /* reset pointer list */
        memset(codec->allocptr, 0, sizeof(codec->allocptr));
        codec->Alloc = lzma_fast_alloc;
        codec->Free = lzma_fast_free;
 }
 
-//-------------------------------------------------
-//  lzma_allocator_free
-//-------------------------------------------------
+/*-------------------------------------------------
+ *  lzma_allocator_free
+ *-------------------------------------------------
+ */
 
 void lzma_allocator_free(void* p )
 {
-   int i;
        lzma_allocator *codec = (lzma_allocator *)(p);
 
-       // free our memory
-       for (i = 0 ; i < MAX_LZMA_ALLOCS ; i++)
+       /* free our memory */
+       for (int i = 0 ; i < MAX_LZMA_ALLOCS ; i++)
        {
                if (codec->allocptr[i] != NULL)
                        free(codec->allocptr[i]);
        }
 }
 
-//-------------------------------------------------
-//  lzma_fast_alloc - fast malloc for lzma, which
-//  allocates and frees memory frequently
-//-------------------------------------------------
+/*-------------------------------------------------
+ *  lzma_fast_alloc - fast malloc for lzma, which
+ *  allocates and frees memory frequently
+ *-------------------------------------------------
+ */
 
 void *lzma_fast_alloc(void *p, size_t size)
 {
-   int scan;
-   uint32_t *addr        = NULL;
        lzma_allocator *codec = (lzma_allocator *)(p);
 
-       // compute the size, rounding to the nearest 1k
+       /* compute the size, rounding to the nearest 1k */
        size = (size + 0x3ff) & ~0x3ff;
 
-       // reuse a hunk if we can
-       for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++)
+       /* reuse a hunk if we can */
+       for (int scan = 0; scan < MAX_LZMA_ALLOCS; scan++)
        {
                uint32_t *ptr = codec->allocptr[scan];
                if (ptr != NULL && size == *ptr)
                {
-                       // set the low bit of the size so we don't match next time
+                       /* set the low bit of the size so we don't match next time */
                        *ptr |= 1;
                        return ptr + 1;
                }
        }
 
-       // alloc a new one and put it into the list
-       addr = (uint32_t *)malloc(sizeof(uint8_t) * (size + sizeof(uint32_t)));
+       /* alloc a new one and put it into the list */
+       uint32_t *addr = (uint32_t *)malloc(sizeof(uint8_t) * size + sizeof(uintptr_t));
        if (addr==NULL)
                return NULL;
-       for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++)
+       for (int scan = 0; scan < MAX_LZMA_ALLOCS; scan++)
        {
                if (codec->allocptr[scan] == NULL)
                {
@@ -464,76 +441,70 @@ void *lzma_fast_alloc(void *p, size_t size)
                }
        }
 
-       // set the low bit of the size so we don't match next time
+       /* set the low bit of the size so we don't match next time */
        *addr = size | 1;
-       return addr + 1;
+       return addr + (sizeof(uint32_t) == sizeof(uintptr_t) ? 1 : 2);
 }
 
-
-//-------------------------------------------------
-//  lzma_fast_free - fast free for lzma, which
-//  allocates and frees memory frequently
-//-------------------------------------------------
+/*-------------------------------------------------
+ *  lzma_fast_free - fast free for lzma, which
+ *  allocates and frees memory frequently
+ *-------------------------------------------------
+ */
 
 void lzma_fast_free(void *p, void *address)
 {
-   int scan;
-   uint32_t *ptr;
-   lzma_allocator *codec;
        if (address == NULL)
                return;
 
-       codec = (lzma_allocator *)(p);
+       lzma_allocator *codec = (lzma_allocator *)(p);
 
-       // find the hunk
-       ptr = (uint32_t *)(address) - 1;
-       for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++)
+       /* find the hunk */
+       uint32_t *ptr = (uint32_t *)(address) - 1;
+       for (int scan = 0; scan < MAX_LZMA_ALLOCS; scan++)
        {
                if (ptr == codec->allocptr[scan])
                {
-                       // clear the low bit of the size to allow matches
+                       /* clear the low bit of the size to allow matches */
                        *ptr &= ~1;
                        return;
                }
        }
 }
 
-//**************************************************************************
-//  LZMA DECOMPRESSOR
-//**************************************************************************
-
+/***************************************************************************
+ *  LZMA DECOMPRESSOR
+ ***************************************************************************
+ */
 
-//-------------------------------------------------
-//  lzma_codec_init - constructor
-//-------------------------------------------------
+/*-------------------------------------------------
+ *  lzma_codec_init - constructor
+ *-------------------------------------------------
+ */
 
 chd_error lzma_codec_init(void* codec, uint32_t hunkbytes)
 {
-   CLzmaEncHandle enc;
-       CLzmaEncProps encoder_props;
-       Byte decoder_props[LZMA_PROPS_SIZE];
-   SizeT props_size;
-   lzma_allocator* alloc;
        lzma_codec_data* lzma_codec = (lzma_codec_data*) codec;
 
-       // construct the decoder
+       /* construct the decoder */
        LzmaDec_Construct(&lzma_codec->decoder);
 
-       // FIXME: this code is written in a way that makes it impossible to safely upgrade the LZMA SDK
-       // This code assumes that the current version of the encoder imposes the same requirements on the
-       // decoder as the encoder used to produce the file.  This is not necessarily true.  The format
-       // needs to be changed so the encoder properties are written to the file.
+       /* FIXME: this code is written in a way that makes it impossible to safely upgrade the LZMA SDK
+        * This code assumes that the current version of the encoder imposes the same requirements on the
+        * decoder as the encoder used to produce the file.  This is not necessarily true.  The format
+        * needs to be changed so the encoder properties are written to the file.
 
-       // configure the properties like the compressor did
+        * configure the properties like the compressor did */
+       CLzmaEncProps encoder_props;
        LzmaEncProps_Init(&encoder_props);
        encoder_props.level = 9;
        encoder_props.reduceSize = hunkbytes;
        LzmaEncProps_Normalize(&encoder_props);
 
-       // convert to decoder properties
-       alloc = &lzma_codec->allocator;
+       /* convert to decoder properties */
+       lzma_allocator* alloc = &lzma_codec->allocator;
        lzma_allocator_init(alloc);
-       enc = LzmaEnc_Create((ISzAlloc*)alloc);
+       CLzmaEncHandle enc = LzmaEnc_Create((ISzAlloc*)alloc);
        if (!enc)
                return CHDERR_DECOMPRESSION_ERROR;
        if (LzmaEnc_SetProps(enc, &encoder_props) != SZ_OK)
@@ -541,7 +512,8 @@ chd_error lzma_codec_init(void* codec, uint32_t hunkbytes)
                LzmaEnc_Destroy(enc, (ISzAlloc*)&alloc, (ISzAlloc*)&alloc);
                return CHDERR_DECOMPRESSION_ERROR;
        }
-       props_size = sizeof(decoder_props);
+       Byte decoder_props[LZMA_PROPS_SIZE];
+       SizeT props_size = sizeof(decoder_props);
        if (LzmaEnc_WriteProperties(enc, decoder_props, &props_size) != SZ_OK)
        {
                LzmaEnc_Destroy(enc, (ISzAlloc*)alloc, (ISzAlloc*)alloc);
@@ -549,60 +521,59 @@ chd_error lzma_codec_init(void* codec, uint32_t hunkbytes)
        }
        LzmaEnc_Destroy(enc, (ISzAlloc*)alloc, (ISzAlloc*)alloc);
 
-       // do memory allocations
+       /* do memory allocations */
        if (LzmaDec_Allocate(&lzma_codec->decoder, decoder_props, LZMA_PROPS_SIZE, (ISzAlloc*)alloc) != SZ_OK)
                return CHDERR_DECOMPRESSION_ERROR;
-       
-       // Okay
+
+       /* Okay */
        return CHDERR_NONE;
 }
 
-
-//-------------------------------------------------
-//  lzma_codec_free
-//-------------------------------------------------
+/*-------------------------------------------------
+ *  lzma_codec_free
+ *-------------------------------------------------
+ */
 
 void lzma_codec_free(void* codec)
 {
        lzma_codec_data* lzma_codec = (lzma_codec_data*) codec;
 
-       // free memory
+       /* free memory */
        LzmaDec_Free(&lzma_codec->decoder, (ISzAlloc*)&lzma_codec->allocator);
+       lzma_allocator_free(&lzma_codec->allocator);
 }
 
-
-//-------------------------------------------------
-//  decompress - decompress data using the LZMA
-//  codec
-//-------------------------------------------------
+/*-------------------------------------------------
+ *  decompress - decompress data using the LZMA
+ *  codec
+ *-------------------------------------------------
+ */
 
 chd_error lzma_codec_decompress(void* codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
 {
-       ELzmaStatus status;
-   SRes res;
-   SizeT consumedlen, decodedlen;
-       // initialize
+       /* initialize */
        lzma_codec_data* lzma_codec = (lzma_codec_data*) codec;
        LzmaDec_Init(&lzma_codec->decoder);
 
-       // decode
-       consumedlen = complen;
-       decodedlen = destlen;
-       res = LzmaDec_DecodeToBuf(&lzma_codec->decoder, dest, &decodedlen, src, &consumedlen, LZMA_FINISH_END, &status);
+       /* decode */
+       SizeT consumedlen = complen;
+       SizeT decodedlen = destlen;
+       ELzmaStatus status;
+       SRes res = LzmaDec_DecodeToBuf(&lzma_codec->decoder, dest, &decodedlen, src, &consumedlen, LZMA_FINISH_END, &status);
        if ((res != SZ_OK && res != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) || consumedlen != complen || decodedlen != destlen)
                return CHDERR_DECOMPRESSION_ERROR;
        return CHDERR_NONE;
 }
 
-// cdlz
+/* cdlz */
 chd_error cdlz_codec_init(void* codec, uint32_t hunkbytes)
 {
        cdlz_codec_data* cdlz = (cdlz_codec_data*) codec;
 
-       // allocate buffer
+       /* allocate buffer */
        cdlz->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes);
-       
-       // make sure the CHD's hunk size is an even multiple of the frame size
+
+       /* make sure the CHD's hunk size is an even multiple of the frame size */
        lzma_codec_init(&cdlz->base_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA);
        zlib_codec_init(&cdlz->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SUBCODE_DATA);
 
@@ -614,39 +585,40 @@ chd_error cdlz_codec_init(void* codec, uint32_t hunkbytes)
 
 void cdlz_codec_free(void* codec)
 {
-       // TODO
+       cdlz_codec_data* cdlz = (cdlz_codec_data*) codec;
+       free(cdlz->buffer);
+       lzma_codec_free(&cdlz->base_decompressor);
+       zlib_codec_free(&cdlz->subcode_decompressor);
 }
 
 chd_error cdlz_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
 {
-   uint32_t framenum;
+       uint8_t *sector;
        cdlz_codec_data* cdlz = (cdlz_codec_data*)codec;
 
-       // determine header bytes
+       /* 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
+       /* 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
+       /* reset and decode */
        lzma_codec_decompress(&cdlz->base_decompressor, &src[header_bytes], complen_base, &cdlz->buffer[0], frames * CD_MAX_SECTOR_DATA);
        zlib_codec_decompress(&cdlz->subcode_decompressor, &src[header_bytes + complen_base], complen - complen_base - header_bytes, &cdlz->buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA);
 
-       // reassemble the data
-       for (framenum = 0; framenum < frames; framenum++)
+       /* reassemble the data */
+       for (uint32_t framenum = 0; framenum < frames; framenum++)
        {
-      uint8_t *sector;
-
                memcpy(&dest[framenum * CD_FRAME_SIZE], &cdlz->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA);
                memcpy(&dest[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], &cdlz->buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], CD_MAX_SUBCODE_DATA);
 
-               // reconstitute the ECC data and sync header
-               sector = &dest[framenum * CD_FRAME_SIZE];
+               /* 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));
@@ -656,14 +628,13 @@ chd_error cdlz_codec_decompress(void *codec, const uint8_t *src, uint32_t comple
        return CHDERR_NONE;
 }
 
-
-// cdzl
+/* cdzl */
 
 chd_error cdzl_codec_init(void *codec, uint32_t hunkbytes)
 {
        cdzl_codec_data* cdzl = (cdzl_codec_data*)codec;
 
-       // make sure the CHD's hunk size is an even multiple of the frame size
+       /* make sure the CHD's hunk size is an even multiple of the frame size */
        zlib_codec_init(&cdzl->base_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA);
        zlib_codec_init(&cdzl->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SUBCODE_DATA);
 
@@ -676,38 +647,40 @@ chd_error cdzl_codec_init(void *codec, uint32_t hunkbytes)
 
 void cdzl_codec_free(void *codec)
 {
-       // TODO
+       cdzl_codec_data* cdzl = (cdzl_codec_data*)codec;
+       zlib_codec_free(&cdzl->base_decompressor);
+       zlib_codec_free(&cdzl->subcode_decompressor);
+       free(cdzl->buffer);
 }
 
 chd_error cdzl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
 {
-   uint32_t framenum;
+       uint8_t *sector;
        cdzl_codec_data* cdzl = (cdzl_codec_data*)codec;
-       
-       // determine header bytes
+
+       /* 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
+       /* 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
+       /* reset and decode */
        zlib_codec_decompress(&cdzl->base_decompressor, &src[header_bytes], complen_base, &cdzl->buffer[0], frames * CD_MAX_SECTOR_DATA);
        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);
 
-       // reassemble the data
-       for (framenum = 0; framenum < frames; framenum++)
+       /* reassemble the data */
+       for (uint32_t framenum = 0; framenum < frames; framenum++)
        {
-      uint8_t *sector;
                memcpy(&dest[framenum * CD_FRAME_SIZE], &cdzl->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA);
                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);
 
-               // reconstitute the ECC data and sync header
-               sector = &dest[framenum * CD_FRAME_SIZE];
+               /* 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));
@@ -717,20 +690,20 @@ chd_error cdzl_codec_decompress(void *codec, const uint8_t *src, uint32_t comple
        return CHDERR_NONE;
 }
 
-//**************************************************************************
-//  CD FLAC DECOMPRESSOR
-//**************************************************************************
-
-
+/***************************************************************************
+ *  CD FLAC DECOMPRESSOR
+ ***************************************************************************
+ */
 
-//------------------------------------------------------
-//  cdfl_codec_blocksize - return the optimal block size
-//------------------------------------------------------
+/*------------------------------------------------------
+ *  cdfl_codec_blocksize - return the optimal block size
+ *------------------------------------------------------
+ */
 
 static uint32_t cdfl_codec_blocksize(uint32_t bytes)
 {
-       // determine FLAC block size, which must be 16-65535
-       // clamp to 2k since that's supposed to be the sweet spot
+       /* determine FLAC block size, which must be 16-65535
+        * clamp to 2k since that's supposed to be the sweet spot */
        uint32_t hunkbytes = bytes / 4;
        while (hunkbytes > 2048)
                hunkbytes /= 2;
@@ -739,83 +712,83 @@ static uint32_t cdfl_codec_blocksize(uint32_t bytes)
 
 chd_error cdfl_codec_init(void *codec, uint32_t hunkbytes)
 {
-   int zerr;
-       uint16_t native_endian = 0;
        cdfl_codec_data *cdfl = (cdfl_codec_data*)codec;
 
        cdfl->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes);
 
-       // make sure the CHD's hunk size is an even multiple of the frame size
+       /* make sure the CHD's hunk size is an even multiple of the frame size */
        if (hunkbytes % CD_FRAME_SIZE != 0)
                return CHDERR_CODEC_ERROR;
 
-       // determine whether we want native or swapped samples
+       /* determine whether we want native or swapped samples */
+       uint16_t native_endian = 0;
        *(uint8_t *)(&native_endian) = 1;
        cdfl->swap_endian = (native_endian & 1);
 
-       // init the inflater
-       cdfl->inflater.next_in = (Bytef *)cdfl; // bogus, but that's ok
+       /* init the inflater */
+       cdfl->inflater.next_in = (Bytef *)cdfl; /* bogus, but that's ok */
        cdfl->inflater.avail_in = 0;
-    //cdfl->allocator.install(cdfl->inflater);
+#if 0
+       cdfl->allocator.install(cdfl->inflater);
+#endif
        cdfl->inflater.zalloc = zlib_fast_alloc;
        cdfl->inflater.zfree = zlib_fast_free;
        cdfl->inflater.opaque = &cdfl->allocator;
-       zerr = inflateInit2(&cdfl->inflater, -MAX_WBITS);
+       int zerr = inflateInit2(&cdfl->inflater, -MAX_WBITS);
 
-       // convert errors
+       /* convert errors */
        if (zerr == Z_MEM_ERROR)
                return CHDERR_OUT_OF_MEMORY;
        else if (zerr != Z_OK)
                return CHDERR_CODEC_ERROR;
 
-       // init flac decoder
+       /* flac decoder init */
        flac_decoder_init(&cdfl->decoder);
-
        return CHDERR_NONE;
 }
 
 void cdfl_codec_free(void *codec)
 {
        cdfl_codec_data *cdfl = (cdfl_codec_data*)codec;
+       free(cdfl->buffer);
        inflateEnd(&cdfl->inflater);
+       flac_decoder_free(&cdfl->decoder);
 }
 
 chd_error cdfl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
 {
-   int zerr;
-   uint8_t *buffer;
-   uint32_t framenum, offset;
        cdfl_codec_data *cdfl = (cdfl_codec_data*)codec;
 
-       // reset and decode
+       /* reset and decode */
        uint32_t frames = destlen / CD_FRAME_SIZE;
+
        if (!flac_decoder_reset(&cdfl->decoder, 44100, 2, cdfl_codec_blocksize(frames * CD_MAX_SECTOR_DATA), src, complen))
                return CHDERR_DECOMPRESSION_ERROR;
-       buffer = &cdfl->buffer[0];
+       uint8_t *buffer = &cdfl->buffer[0];
        if (!flac_decoder_decode_interleaved(&cdfl->decoder, (int16_t *)(buffer), frames * CD_MAX_SECTOR_DATA/4, cdfl->swap_endian))
                return CHDERR_DECOMPRESSION_ERROR;
 
-       // inflate the subcode data
-       offset = flac_decoder_finish(&cdfl->decoder);
+       /* inflate the subcode data */
+       uint32_t offset = flac_decoder_finish(&cdfl->decoder);
        cdfl->inflater.next_in = (Bytef *)(src + offset);
        cdfl->inflater.avail_in = complen - offset;
        cdfl->inflater.total_in = 0;
        cdfl->inflater.next_out = &cdfl->buffer[frames * CD_MAX_SECTOR_DATA];
        cdfl->inflater.avail_out = frames * CD_MAX_SUBCODE_DATA;
        cdfl->inflater.total_out = 0;
-       zerr = inflateReset(&cdfl->inflater);
+       int zerr = inflateReset(&cdfl->inflater);
        if (zerr != Z_OK)
                return CHDERR_DECOMPRESSION_ERROR;
 
-       // do it
+       /* do it */
        zerr = inflate(&cdfl->inflater, Z_FINISH);
        if (zerr != Z_STREAM_END)
                return CHDERR_DECOMPRESSION_ERROR;
        if (cdfl->inflater.total_out != frames * CD_MAX_SUBCODE_DATA)
                return CHDERR_DECOMPRESSION_ERROR;
 
-       // reassemble the data
-       for (framenum = 0; framenum < frames; framenum++)
+       /* reassemble the data */
+       for (uint32_t framenum = 0; framenum < frames; framenum++)
        {
                memcpy(&dest[framenum * CD_FRAME_SIZE], &cdfl->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA);
                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);
@@ -827,13 +800,6 @@ chd_error cdfl_codec_decompress(void *codec, const uint8_t *src, uint32_t comple
     CODEC INTERFACES
 ***************************************************************************/
 
-#define CHD_MAKE_TAG(a,b,c,d)       (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
-
-// general codecs with CD frontend
-#define CHD_CODEC_CD_ZLIB CHD_MAKE_TAG('c','d','z','l')
-#define CHD_CODEC_CD_LZMA CHD_MAKE_TAG('c','d','l','z')
-#define CHD_CODEC_CD_FLAC CHD_MAKE_TAG('c','d','f','l')
-
 static const codec_interface codec_interfaces[] =
 {
        /* "none" or no compression */
@@ -869,6 +835,17 @@ static const codec_interface codec_interfaces[] =
                NULL
        },
 
+       /* V5 zlib compression */
+       {
+               CHD_CODEC_ZLIB,
+               "zlib (Deflate)",
+               FALSE,
+               zlib_codec_init,
+               zlib_codec_free,
+               zlib_codec_decompress,
+               NULL
+       },
+
        /* V5 CD zlib compression */
        {
                CHD_CODEC_CD_ZLIB,
@@ -878,7 +855,7 @@ static const codec_interface codec_interfaces[] =
                cdzl_codec_free,
                cdzl_codec_decompress,
                NULL
-       },      
+       },
 
        /* V5 CD lzma compression */
        {
@@ -889,7 +866,7 @@ static const codec_interface codec_interfaces[] =
                cdlz_codec_free,
                cdlz_codec_decompress,
                NULL
-       },              
+       },
 
        /* V5 CD flac compression */
        {
@@ -900,7 +877,7 @@ static const codec_interface codec_interfaces[] =
                cdfl_codec_free,
                cdfl_codec_decompress,
                NULL
-       },              
+       },
 };
 
 /***************************************************************************
@@ -918,7 +895,6 @@ static inline UINT64 get_bigendian_uint64(const UINT8 *base)
                        ((UINT64)base[4] << 24) | ((UINT64)base[5] << 16) | ((UINT64)base[6] << 8) | (UINT64)base[7];
 }
 
-
 /*-------------------------------------------------
     put_bigendian_uint64 - write a UINT64 to
     the data stream in bigendian order
@@ -954,7 +930,7 @@ static inline UINT64 get_bigendian_uint48(const UINT8 *base)
 
 static inline void put_bigendian_uint48(UINT8 *base, UINT64 value)
 {
-       value &= 0xffffffffffff; 
+       value &= 0xffffffffffff;
        base[0] = value >> 40;
        base[1] = value >> 32;
        base[2] = value >> 24;
@@ -972,27 +948,25 @@ static inline UINT32 get_bigendian_uint32(const UINT8 *base)
        return (base[0] << 24) | (base[1] << 16) | (base[2] << 8) | base[3];
 }
 
-
 /*-------------------------------------------------
     put_bigendian_uint32 - write a UINT32 to
     the data stream in bigendian order
 -------------------------------------------------*/
 
-static inline void put_bigendian_uint24(UINT8 *base, UINT32 value)
+static inline void put_bigendian_uint32(UINT8 *base, UINT32 value)
 {
-       value &= 0xffffff;
-       base[0] = value >> 16;
-       base[1] = value >> 8;
-       base[2] = value;
+       base[0] = value >> 24;
+       base[1] = value >> 16;
+       base[2] = value >> 8;
+       base[3] = value;
 }
 
-
 /*-------------------------------------------------
     put_bigendian_uint24 - write a UINT24 to
     the data stream in bigendian order
 -------------------------------------------------*/
 
-static inline void put_bigendian_uint32(UINT8 *base, UINT32 value)
+static inline void put_bigendian_uint24(UINT8 *base, UINT32 value)
 {
        value &= 0xffffff;
        base[0] = value >> 16;
@@ -1020,7 +994,6 @@ static inline UINT16 get_bigendian_uint16(const UINT8 *base)
        return (base[0] << 8) | base[1];
 }
 
-
 /*-------------------------------------------------
     put_bigendian_uint16 - write a UINT16 to
     the data stream in bigendian order
@@ -1032,7 +1005,6 @@ static inline void put_bigendian_uint16(UINT8 *base, UINT16 value)
        base[1] = value;
 }
 
-
 /*-------------------------------------------------
     map_extract - extract a single map
     entry from the datastream
@@ -1046,7 +1018,6 @@ static inline void map_extract(const UINT8 *base, map_entry *entry)
        entry->flags = base[15];
 }
 
-
 /*-------------------------------------------------
     map_assemble - write a single map
     entry to the datastream
@@ -1069,7 +1040,6 @@ static inline int map_size_v5(chd_header* header)
        return header->hunkcount * header->mapentrybytes;
 }
 
-
 /*-------------------------------------------------
     crc16 - calculate CRC16 (from hashing.cpp)
 -------------------------------------------------*/
@@ -1115,65 +1085,62 @@ uint16_t crc16(const void *data, uint32_t length)
 
        const uint8_t *src = (uint8_t*)data;
 
-       // fetch the current value into a local and rip through the source data
+       /* fetch the current value into a local and rip through the source data */
        while (length-- != 0)
                crc = (crc << 8) ^ s_table[(crc >> 8) ^ *src++];
        return crc;
 }
 
+/*-------------------------------------------------
+       compressed - test if CHD file is compressed
++-------------------------------------------------*/
+
+static inline int compressed(chd_header* header) {
+       return header->compression[0] != CHD_CODEC_NONE;
+}
+
 /*-------------------------------------------------
        decompress_v5_map - decompress the v5 map
 -------------------------------------------------*/
 
 static chd_error decompress_v5_map(chd_file* chd, chd_header* header)
 {
-   int hunknum;
-       uint8_t lastcomp = 0;
-       int repcount = 0;
-       uint32_t last_self = 0;
-       uint64_t last_parent = 0;
-   struct bitstream* bitbuf;
-   uint32_t mapbytes;
-   uint64_t firstoffs;
-   uint16_t mapcrc;
-   uint8_t lengthbits;
-   uint8_t selfbits;
-   uint8_t parentbits;
-   uint8_t *compressed;
-       uint8_t rawbuf[16];
-   struct huffman_decoder* decoder;
-   enum huffman_error err;
-   uint64_t curoffset;
+       int rawmapsize = map_size_v5(header);
 
-       if (header->mapoffset == 0)
+       if (!compressed(header))
        {
-               //memset(header->rawmap, 0xff,map_size_v5(header));
-               return CHDERR_READ_ERROR;
+               header->rawmap = (uint8_t*)malloc(rawmapsize);
+               core_fseek(chd->file, header->mapoffset, SEEK_SET);
+               core_fread(chd->file, header->rawmap, rawmapsize);
+               return CHDERR_NONE;
        }
 
-       // read the reader
+       /* read the reader */
+       uint8_t rawbuf[16];
        core_fseek(chd->file, header->mapoffset, SEEK_SET);
        core_fread(chd->file, rawbuf, sizeof(rawbuf));
-       mapbytes = get_bigendian_uint32(&rawbuf[0]);
-       firstoffs = get_bigendian_uint48(&rawbuf[4]);
-       mapcrc = get_bigendian_uint16(&rawbuf[10]);
-       lengthbits = rawbuf[12];
-       selfbits = rawbuf[13];
-       parentbits = rawbuf[14];
-
-       // now read the map
-       compressed = (uint8_t*)malloc(sizeof(uint8_t) * mapbytes);
+       uint32_t const mapbytes = get_bigendian_uint32(&rawbuf[0]);
+       uint64_t const firstoffs = get_bigendian_uint48(&rawbuf[4]);
+       uint16_t const mapcrc = get_bigendian_uint16(&rawbuf[10]);
+       uint8_t const lengthbits = rawbuf[12];
+       uint8_t const selfbits = rawbuf[13];
+       uint8_t const parentbits = rawbuf[14];
+
+       /* now read the map */
+       uint8_t* compressed = (uint8_t*)malloc(sizeof(uint8_t) * mapbytes);
        core_fseek(chd->file, header->mapoffset + 16, SEEK_SET);
        core_fread(chd->file, compressed, mapbytes);
-       bitbuf = create_bitstream(compressed, sizeof(uint8_t) * mapbytes);
-       header->rawmap = (uint8_t*)malloc(sizeof(uint8_t) * map_size_v5(header));
+       struct bitstream* bitbuf = create_bitstream(compressed, sizeof(uint8_t) * mapbytes);
+       header->rawmap = (uint8_t*)malloc(rawmapsize);
 
-       // first decode the compression types
-       decoder = create_huffman_decoder(16, 8);
-       err = huffman_import_tree_rle(decoder, bitbuf);
+       /* first decode the compression types */
+       struct huffman_decoder* decoder = create_huffman_decoder(16, 8);
+       enum huffman_error err = huffman_import_tree_rle(decoder, bitbuf);
        if (err != HUFFERR_NONE)
                return CHDERR_DECOMPRESSION_ERROR;
-       for (hunknum = 0; hunknum < header->hunkcount; hunknum++)
+       uint8_t lastcomp = 0;
+       int repcount = 0;
+       for (int hunknum = 0; hunknum < header->hunkcount; hunknum++)
        {
                uint8_t *rawmap = header->rawmap + (hunknum * 12);
                if (repcount > 0)
@@ -1190,9 +1157,11 @@ static chd_error decompress_v5_map(chd_file* chd, chd_header* header)
                }
        }
 
-       // then iterate through the hunks and extract the needed data
-       curoffset = firstoffs;
-       for (hunknum = 0; hunknum < header->hunkcount; hunknum++)
+       /* then iterate through the hunks and extract the needed data */
+       uint64_t curoffset = firstoffs;
+       uint32_t last_self = 0;
+       uint64_t last_parent = 0;
+       for (int hunknum = 0; hunknum < header->hunkcount; hunknum++)
        {
                uint8_t *rawmap = header->rawmap + (hunknum * 12);
                uint64_t offset = curoffset;
@@ -1200,7 +1169,7 @@ static chd_error decompress_v5_map(chd_file* chd, chd_header* header)
                uint16_t crc = 0;
                switch (rawmap[0])
                {
-                       // base types
+                       /* base types */
                        case COMPRESSION_TYPE_0:
                        case COMPRESSION_TYPE_1:
                        case COMPRESSION_TYPE_2:
@@ -1223,7 +1192,7 @@ static chd_error decompress_v5_map(chd_file* chd, chd_header* header)
                                last_parent = offset;
                                break;
 
-                       // pseudo-types; convert into base types
+                       /* pseudo-types; convert into base types */
                        case COMPRESSION_SELF_1:
                                last_self++;
                        case COMPRESSION_SELF_0:
@@ -1243,17 +1212,23 @@ static chd_error decompress_v5_map(chd_file* chd, chd_header* header)
                                offset = last_parent;
                                break;
                }
-               // UINT24 length
+               /* UINT24 length */
                put_bigendian_uint24(&rawmap[1], length);
 
-               // UINT48 offset
+               /* UINT48 offset */
                put_bigendian_uint48(&rawmap[4], offset);
 
-               // crc16
+               /* crc16 */
                put_bigendian_uint16(&rawmap[10], crc);
        }
 
-       // verify the final CRC
+       free(compressed);
+       free(bitbuf);
+       free(decoder->lookup);
+       free(decoder->huffnode);
+       free(decoder);
+
+       /* verify the final CRC */
        if (crc16(&header->rawmap[0], header->hunkcount * 12) != mapcrc)
                return CHDERR_DECOMPRESSION_ERROR;
 
@@ -1278,12 +1253,10 @@ static inline void map_extract_old(const UINT8 *base, map_entry *entry, UINT32 h
 #endif
 }
 
-
 /***************************************************************************
     CHD FILE MANAGEMENT
 ***************************************************************************/
 
-
 /*-------------------------------------------------
     chd_open_file - open a CHD file for access
 -------------------------------------------------*/
@@ -1303,16 +1276,16 @@ chd_error chd_open_file(core_file *file, int mode, chd_file *parent, chd_file **
                EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);
 
        /* allocate memory for the final result */
-       newchd = (chd_file *)malloc(sizeof(chd_file));
+       newchd = (chd_file *)malloc(sizeof(**chd));
        if (newchd == NULL)
                EARLY_EXIT(err = CHDERR_OUT_OF_MEMORY);
-       memset(newchd, 0, sizeof(chd_file));
+       memset(newchd, 0, sizeof(*newchd));
        newchd->cookie = COOKIE_VALUE;
        newchd->parent = parent;
        newchd->file = file;
 
        /* now attempt to read the header */
-       err = header_read(newchd->file, &newchd->header);
+       err = header_read(newchd, &newchd->header);
        if (err != CHDERR_NONE)
                EARLY_EXIT(err);
 
@@ -1353,13 +1326,14 @@ chd_error chd_open_file(core_file *file, int mode, chd_file *parent, chd_file **
        if (newchd->header.version < 5)
        {
                err = map_read(newchd);
-               if (err != CHDERR_NONE)
-                       EARLY_EXIT(err);
        }
-       else 
+       else
        {
                err = decompress_v5_map(newchd, &(newchd->header));
        }
+       if (err != CHDERR_NONE)
+               EARLY_EXIT(err);
+
 
        /* allocate and init the hunk cache */
        newchd->cache = (UINT8 *)malloc(newchd->header.hunkbytes);
@@ -1378,66 +1352,75 @@ chd_error chd_open_file(core_file *file, int mode, chd_file *parent, chd_file **
        if (newchd->header.version < 5)
        {
                for (intfnum = 0; intfnum < ARRAY_LENGTH(codec_interfaces); intfnum++)
+               {
                        if (codec_interfaces[intfnum].compression == newchd->header.compression[0])
                        {
                                newchd->codecintf[0] = &codec_interfaces[intfnum];
                                break;
                        }
+               }
+
                if (intfnum == ARRAY_LENGTH(codec_interfaces))
                        EARLY_EXIT(err = CHDERR_UNSUPPORTED_FORMAT);
 
                /* initialize the codec */
                if (newchd->codecintf[0]->init != NULL)
+               {
                        err = (*newchd->codecintf[0]->init)(&newchd->zlib_codec_data, newchd->header.hunkbytes);
+                       if (err != CHDERR_NONE)
+                               EARLY_EXIT(err);
+               }
        }
        else
        {
-      int decompnum;
-
-               // verify the compression types and initialize the codecs
-               for (decompnum = 0; decompnum < ARRAY_LENGTH(newchd->header.compression); decompnum++)
+               /* verify the compression types and initialize the codecs */
+               for (int decompnum = 0; decompnum < ARRAY_LENGTH(newchd->header.compression); decompnum++)
                {
-         int i;
-                       for (i = 0 ; i < ARRAY_LENGTH(codec_interfaces) ; i++)
+                       for (int i = 0 ; i < ARRAY_LENGTH(codec_interfaces) ; i++)
                        {
                                if (codec_interfaces[i].compression == newchd->header.compression[decompnum])
                                {
                                        newchd->codecintf[decompnum] = &codec_interfaces[i];
-                                       if (newchd->codecintf[decompnum] == NULL && newchd->header.compression[decompnum] != 0)
-                                               err = CHDERR_UNSUPPORTED_FORMAT;
-
-                                       /* initialize the codec */
-                                       if (newchd->codecintf[decompnum]->init != NULL) 
-                                       {
-                                               void* codec = NULL;
-                                               switch (newchd->header.compression[decompnum])
-                                               {
-                                                       case CHD_CODEC_CD_ZLIB:
-                                                               codec = &newchd->cdzl_codec_data;
-                                                               break;
-
-                                                       case CHD_CODEC_CD_LZMA:
-                                                               codec = &newchd->cdlz_codec_data;
-                                                               break;
-
-                                                       case CHD_CODEC_CD_FLAC:
-                                                               codec = &newchd->cdfl_codec_data;
-                                                               break;
-                                               }
-                                               if (codec != NULL)
-                                               {
-                                                       err = (*newchd->codecintf[decompnum]->init)(codec, newchd->header.hunkbytes);
-                                               }
-                                       }
+                                       break;
                                }
                        }
+
+                       if (newchd->codecintf[decompnum] == NULL && newchd->header.compression[decompnum] != 0)
+                               EARLY_EXIT(err = CHDERR_UNSUPPORTED_FORMAT);
+
+                       /* initialize the codec */
+                       if (newchd->codecintf[decompnum]->init != NULL)
+                       {
+                               void* codec = NULL;
+                               switch (newchd->header.compression[decompnum])
+                               {
+                                       case CHD_CODEC_ZLIB:
+                                               codec = &newchd->zlib_codec_data;
+                                               break;
+
+                                       case CHD_CODEC_CD_ZLIB:
+                                               codec = &newchd->cdzl_codec_data;
+                                               break;
+
+                                       case CHD_CODEC_CD_LZMA:
+                                               codec = &newchd->cdlz_codec_data;
+                                               break;
+
+                                       case CHD_CODEC_CD_FLAC:
+                                               codec = &newchd->cdfl_codec_data;
+                                               break;
+                               }
+
+                               if (codec == NULL)
+                                       EARLY_EXIT(err = CHDERR_UNSUPPORTED_FORMAT);
+
+                               err = (*newchd->codecintf[decompnum]->init)(codec, newchd->header.hunkbytes);
+                               if (err != CHDERR_NONE)
+                                       EARLY_EXIT(err);
+                       }
                }
        }
 
-       // HACK
-       //if (err != CHDERR_NONE)
-       //      EARLY_EXIT(err);
-
        /* all done */
        *chd = newchd;
        return CHDERR_NONE;
@@ -1448,6 +1431,37 @@ cleanup:
        return err;
 }
 
+/*-------------------------------------------------
+    chd_precache - precache underlying file in
+    memory
+-------------------------------------------------*/
+
+chd_error chd_precache(chd_file *chd)
+{
+       ssize_t size, count;
+
+       if (chd->file_cache == NULL)
+       {
+               core_fseek(chd->file, 0, SEEK_END);
+               size = core_ftell(chd->file);
+               if (size <= 0)
+                       return CHDERR_INVALID_DATA;
+               chd->file_cache = malloc(size);
+               if (chd->file_cache == NULL)
+                       return CHDERR_OUT_OF_MEMORY;
+               core_fseek(chd->file, 0, SEEK_SET);
+               count = core_fread(chd->file, chd->file_cache, size);
+               if (count != size)
+               {
+                       free(chd->file_cache);
+                       chd->file_cache = NULL;
+                       return CHDERR_READ_ERROR;
+               }
+       }
+
+       return CHDERR_NONE;
+}
+
 /*-------------------------------------------------
     chd_open - open a CHD file by
     filename
@@ -1492,32 +1506,6 @@ cleanup:
        return err;
 }
 
-chd_error chd_precache(chd_file *chd)
-{
-       ssize_t size, count;
-
-       if (chd->file_cache == NULL)
-       {
-               core_fseek(chd->file, 0, SEEK_END);
-               size = core_ftell(chd->file);
-               if (size <= 0)
-                       return CHDERR_INVALID_DATA;
-               chd->file_cache = malloc(size);
-               if (chd->file_cache == NULL)
-                       return CHDERR_OUT_OF_MEMORY;
-               core_fseek(chd->file, 0, SEEK_SET);
-               count = core_fread(chd->file, chd->file_cache, size);
-               if (count != size)
-               {
-                       free(chd->file_cache);
-                       chd->file_cache = NULL;
-                       return CHDERR_READ_ERROR;
-               }
-       }
-
-       return CHDERR_NONE;
-}
-
 /*-------------------------------------------------
     chd_close - close a CHD file for access
 -------------------------------------------------*/
@@ -1531,22 +1519,29 @@ void chd_close(chd_file *chd)
        /* deinit the codec */
        if (chd->header.version < 5)
        {
-       if (chd->codecintf[0] != NULL && chd->codecintf[0]->free != NULL)
-               (*chd->codecintf[0]->free)(&chd->zlib_codec_data);
+               if (chd->codecintf[0] != NULL && chd->codecintf[0]->free != NULL)
+                       (*chd->codecintf[0]->free)(&chd->zlib_codec_data);
        }
        else
        {
-      int i;
-               // Free the codecs
-               for (i = 0 ; i < 4 ; i++)
+               /* Free the codecs */
+               for (int i = 0 ; i < ARRAY_LENGTH(chd->codecintf); i++)
                {
                        void* codec = NULL;
+
+                       if (chd->codecintf[i] == NULL)
+                               continue;
+
                        switch (chd->codecintf[i]->compression)
                        {
                                case CHD_CODEC_CD_LZMA:
                                        codec = &chd->cdlz_codec_data;
                                        break;
 
+                               case CHD_CODEC_ZLIB:
+                                       codec = &chd->zlib_codec_data;
+                                       break;
+
                                case CHD_CODEC_CD_ZLIB:
                                        codec = &chd->cdzl_codec_data;
                                        break;
@@ -1554,14 +1549,15 @@ void chd_close(chd_file *chd)
                                case CHD_CODEC_CD_FLAC:
                                        codec = &chd->cdfl_codec_data;
                                        break;
-                       }               
+                       }
+
                        if (codec)
                        {
                                (*chd->codecintf[i]->free)(codec);
                        }
                }
 
-               // Free the raw map
+               /* Free the raw map */
                if (chd->header.rawmap != NULL)
                        free(chd->header.rawmap);
        }
@@ -1601,7 +1597,6 @@ void chd_close(chd_file *chd)
        free(chd);
 }
 
-
 /*-------------------------------------------------
     chd_core_file - return the associated
     core_file
@@ -1612,7 +1607,6 @@ core_file *chd_core_file(chd_file *chd)
        return chd->file;
 }
 
-
 /*-------------------------------------------------
     chd_error_string - return an error string for
     the given CHD error
@@ -1654,8 +1648,6 @@ const char *chd_error_string(chd_error err)
        }
 }
 
-
-
 /***************************************************************************
     CHD HEADER MANAGEMENT
 ***************************************************************************/
@@ -1674,8 +1666,6 @@ const chd_header *chd_get_header(chd_file *chd)
        return &chd->header;
 }
 
-
-
 /***************************************************************************
     CORE DATA READ/WRITE
 ***************************************************************************/
@@ -1699,10 +1689,6 @@ chd_error chd_read(chd_file *chd, UINT32 hunknum, void *buffer)
        return hunk_read_into_memory(chd, hunknum, (UINT8 *)buffer);
 }
 
-
-
-
-
 /***************************************************************************
     METADATA MANAGEMENT
 ***************************************************************************/
@@ -1762,8 +1748,6 @@ chd_error chd_get_metadata(chd_file *chd, UINT32 searchtag, UINT32 searchindex,
        return CHDERR_NONE;
 }
 
-
-
 /***************************************************************************
     CODEC INTERFACES
 ***************************************************************************/
@@ -1775,11 +1759,9 @@ chd_error chd_get_metadata(chd_file *chd, UINT32 searchtag, UINT32 searchindex,
 
 chd_error chd_codec_config(chd_file *chd, int param, void *config)
 {
-
        return CHDERR_INVALID_PARAMETER;
 }
 
-
 /*-------------------------------------------------
     chd_get_codec_name - get the name of a
     particular codec
@@ -1790,7 +1772,6 @@ const char *chd_get_codec_name(UINT32 codec)
        return "Unknown";
 }
 
-
 /***************************************************************************
     INTERNAL HEADER OPERATIONS
 ***************************************************************************/
@@ -1803,11 +1784,11 @@ const char *chd_get_codec_name(UINT32 codec)
 static chd_error header_validate(const chd_header *header)
 {
        int intfnum;
-  
+
        /* require a valid version */
        if (header->version == 0 || header->version > CHD_HEADER_VERSION)
                return CHDERR_UNSUPPORTED_VERSION;
-  
+
        /* require a valid length */
        if ((header->version == 1 && header->length != CHD_V1_HEADER_SIZE) ||
                (header->version == 2 && header->length != CHD_V2_HEADER_SIZE) ||
@@ -1815,7 +1796,7 @@ static chd_error header_validate(const chd_header *header)
                (header->version == 4 && header->length != CHD_V4_HEADER_SIZE) ||
                (header->version == 5 && header->length != CHD_V5_HEADER_SIZE))
                return CHDERR_INVALID_PARAMETER;
-  
+
        /* Do not validate v5 header */
        if (header->version <= 4)
        {
@@ -1859,13 +1840,38 @@ static chd_error header_validate(const chd_header *header)
        return CHDERR_NONE;
 }
 
+/*-------------------------------------------------
+    header_guess_unitbytes - for older CHD formats,
+    guess at the bytes/unit based on metadata
+-------------------------------------------------*/
+
+static UINT32 header_guess_unitbytes(chd_file *chd)
+{
+       /* look for hard disk metadata; if found, then the unit size == sector size */
+       char metadata[512];
+       int i0, i1, i2, i3;
+       if (chd_get_metadata(chd, HARD_DISK_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE &&
+               sscanf(metadata, HARD_DISK_METADATA_FORMAT, &i0, &i1, &i2, &i3) == 4)
+               return i3;
+
+       /* look for CD-ROM metadata; if found, then the unit size == CD frame size */
+       if (chd_get_metadata(chd, CDROM_OLD_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE ||
+               chd_get_metadata(chd, CDROM_TRACK_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE ||
+               chd_get_metadata(chd, CDROM_TRACK_METADATA2_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE ||
+               chd_get_metadata(chd, GDROM_OLD_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE ||
+               chd_get_metadata(chd, GDROM_TRACK_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE)
+               return CD_FRAME_SIZE;
+
+       /* otherwise, just map 1:1 with the hunk size */
+       return chd->header.hunkbytes;
+}
 
 /*-------------------------------------------------
     header_read - read a CHD header into the
     internal data structure
 -------------------------------------------------*/
 
-static chd_error header_read(core_file *file, chd_header *header)
+static chd_error header_read(chd_file *chd, chd_header *header)
 {
        UINT8 rawheader[CHD_MAX_HEADER_SIZE];
        UINT32 count;
@@ -1875,12 +1881,12 @@ static chd_error header_read(core_file *file, chd_header *header)
                return CHDERR_INVALID_PARAMETER;
 
        /* punt if invalid file */
-       if (file == NULL)
+       if (chd->file == NULL)
                return CHDERR_INVALID_FILE;
 
        /* seek and read */
-       core_fseek(file, 0, SEEK_SET);
-       count = core_fread(file, rawheader, sizeof(rawheader));
+       core_fseek(chd->file, 0, SEEK_SET);
+       count = core_fread(chd->file, rawheader, sizeof(rawheader));
        if (count != sizeof(rawheader))
                return CHDERR_READ_ERROR;
 
@@ -1903,12 +1909,15 @@ static chd_error header_read(core_file *file, chd_header *header)
                (header->version == 3 && header->length != CHD_V3_HEADER_SIZE) ||
                (header->version == 4 && header->length != CHD_V4_HEADER_SIZE) ||
                (header->version == 5 && header->length != CHD_V5_HEADER_SIZE))
-               
+
                return CHDERR_INVALID_DATA;
 
        /* extract the common data */
        header->flags           = get_bigendian_uint32(&rawheader[16]);
        header->compression[0]  = get_bigendian_uint32(&rawheader[20]);
+       header->compression[1]  = CHD_CODEC_NONE;
+       header->compression[2]  = CHD_CODEC_NONE;
+       header->compression[3]  = CHD_CODEC_NONE;
 
        /* extract the V1/V2-specific data */
        if (header->version < 3)
@@ -1923,6 +1932,8 @@ static chd_error header_read(core_file *file, chd_header *header)
                memcpy(header->parentmd5, &rawheader[60], CHD_MD5_BYTES);
                header->logicalbytes = (UINT64)header->obsolete_cylinders * (UINT64)header->obsolete_heads * (UINT64)header->obsolete_sectors * (UINT64)seclen;
                header->hunkbytes = seclen * header->obsolete_hunksize;
+               header->unitbytes          = header_guess_unitbytes(chd);
+               header->unitcount          = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes;
                header->metaoffset = 0;
        }
 
@@ -1935,6 +1946,8 @@ static chd_error header_read(core_file *file, chd_header *header)
                memcpy(header->md5, &rawheader[44], CHD_MD5_BYTES);
                memcpy(header->parentmd5, &rawheader[60], CHD_MD5_BYTES);
                header->hunkbytes    = get_bigendian_uint32(&rawheader[76]);
+               header->unitbytes    = header_guess_unitbytes(chd);
+               header->unitcount    = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes;
                memcpy(header->sha1, &rawheader[80], CHD_SHA1_BYTES);
                memcpy(header->parentsha1, &rawheader[100], CHD_SHA1_BYTES);
        }
@@ -1946,6 +1959,8 @@ static chd_error header_read(core_file *file, chd_header *header)
                header->logicalbytes = get_bigendian_uint64(&rawheader[28]);
                header->metaoffset   = get_bigendian_uint64(&rawheader[36]);
                header->hunkbytes    = get_bigendian_uint32(&rawheader[44]);
+               header->unitbytes    = header_guess_unitbytes(chd);
+               header->unitcount    = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes;
                memcpy(header->sha1, &rawheader[48], CHD_SHA1_BYTES);
                memcpy(header->parentsha1, &rawheader[68], CHD_SHA1_BYTES);
                memcpy(header->rawsha1, &rawheader[88], CHD_SHA1_BYTES);
@@ -1955,30 +1970,30 @@ static chd_error header_read(core_file *file, chd_header *header)
        else if (header->version == 5)
        {
                /* TODO */
-               header->compression[0]  = get_bigendian_uint32(&rawheader[16]);
-               header->compression[1]  = get_bigendian_uint32(&rawheader[20]);
-               header->compression[2]  = get_bigendian_uint32(&rawheader[24]);
-               header->compression[3]  = get_bigendian_uint32(&rawheader[28]);
-               header->logicalbytes    = get_bigendian_uint64(&rawheader[32]);
-               header->mapoffset       = get_bigendian_uint64(&rawheader[40]);
-               header->metaoffset      = get_bigendian_uint64(&rawheader[48]);
-               header->hunkbytes       = get_bigendian_uint32(&rawheader[56]);
-               header->hunkcount               = (header->logicalbytes + header->hunkbytes - 1) / header->hunkbytes;
-               header->unitbytes       = get_bigendian_uint32(&rawheader[60]);
-               header->unitcount       = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes;
+               header->compression[0]  = get_bigendian_uint32(&rawheader[16]);
+               header->compression[1]  = get_bigendian_uint32(&rawheader[20]);
+               header->compression[2]  = get_bigendian_uint32(&rawheader[24]);
+               header->compression[3]  = get_bigendian_uint32(&rawheader[28]);
+               header->logicalbytes    = get_bigendian_uint64(&rawheader[32]);
+               header->mapoffset       = get_bigendian_uint64(&rawheader[40]);
+               header->metaoffset      = get_bigendian_uint64(&rawheader[48]);
+               header->hunkbytes       = get_bigendian_uint32(&rawheader[56]);
+               header->hunkcount       = (header->logicalbytes + header->hunkbytes - 1) / header->hunkbytes;
+               header->unitbytes       = get_bigendian_uint32(&rawheader[60]);
+               header->unitcount       = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes;
                memcpy(header->sha1, &rawheader[84], CHD_SHA1_BYTES);
                memcpy(header->parentsha1, &rawheader[104], CHD_SHA1_BYTES);
                memcpy(header->rawsha1, &rawheader[64], CHD_SHA1_BYTES);
 
-               // determine properties of map entries
-               header->mapentrybytes = 12; //TODO compressed() ? 12 : 4;
+               /* determine properties of map entries */
+               header->mapentrybytes = compressed(header) ? 12 : 4;
 
-               // hack
+               /* hack */
                header->totalhunks              = header->hunkcount;
        }
 
        /* Unknown version */
-       else 
+       else
        {
                /* TODO */
        }
@@ -1987,41 +2002,16 @@ static chd_error header_read(core_file *file, chd_header *header)
        return CHDERR_NONE;
 }
 
-
 /***************************************************************************
     INTERNAL HUNK READ/WRITE
 ***************************************************************************/
 
 /*-------------------------------------------------
-    hunk_read_into_cache - read a hunk into
-    the CHD's hunk cache
+    hunk_read_compressed - read a compressed
+    hunk
 -------------------------------------------------*/
 
-static chd_error hunk_read_into_cache(chd_file *chd, UINT32 hunknum)
-{
-       chd_error err;
-
-       /* track the max */
-       if (hunknum > chd->maxhunk)
-               chd->maxhunk = hunknum;
-
-       /* if we're already in the cache, we're done */
-       if (chd->cachehunk == hunknum)
-               return CHDERR_NONE;
-       chd->cachehunk = ~0;
-
-       /* otherwise, read the data */
-       err = hunk_read_into_memory(chd, hunknum, chd->cache);
-       if (err != CHDERR_NONE)
-               return err;
-
-       /* mark the hunk successfully cached in */
-       chd->cachehunk = hunknum;
-       return CHDERR_NONE;
-}
-
-
-static UINT8* read_compressed(chd_file *chd, UINT64 offset, size_t size)
+static UINT8* hunk_read_compressed(chd_file *chd, UINT64 offset, size_t size)
 {
        ssize_t bytes;
        if (chd->file_cache != NULL)
@@ -2038,7 +2028,12 @@ static UINT8* read_compressed(chd_file *chd, UINT64 offset, size_t size)
        }
 }
 
-static chd_error read_uncompressed(chd_file *chd, UINT64 offset, size_t size, UINT8 *dest)
+/*-------------------------------------------------
+    hunk_read_uncompressed - read an uncompressed
+    hunk
+-------------------------------------------------*/
+
+static chd_error hunk_read_uncompressed(chd_file *chd, UINT64 offset, size_t size, UINT8 *dest)
 {
        ssize_t bytes;
        if (chd->file_cache != NULL)
@@ -2055,6 +2050,34 @@ static chd_error read_uncompressed(chd_file *chd, UINT64 offset, size_t size, UI
        return CHDERR_NONE;
 }
 
+/*-------------------------------------------------
+    hunk_read_into_cache - read a hunk into
+    the CHD's hunk cache
+-------------------------------------------------*/
+
+static chd_error hunk_read_into_cache(chd_file *chd, UINT32 hunknum)
+{
+       chd_error err;
+
+       /* track the max */
+       if (hunknum > chd->maxhunk)
+               chd->maxhunk = hunknum;
+
+       /* if we're already in the cache, we're done */
+       if (chd->cachehunk == hunknum)
+               return CHDERR_NONE;
+       chd->cachehunk = ~0;
+
+       /* otherwise, read the data */
+       err = hunk_read_into_memory(chd, hunknum, chd->cache);
+       if (err != CHDERR_NONE)
+               return err;
+
+       /* mark the hunk successfully cached in */
+       chd->cachehunk = hunknum;
+       return CHDERR_NONE;
+}
+
 /*-------------------------------------------------
     hunk_read_into_memory - read a hunk into
     memory at the given location
@@ -2064,7 +2087,7 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des
 {
        chd_error err;
 
-       // punt if no file
+       /* punt if no file */
        if (chd->file == NULL)
                return CHDERR_INVALID_FILE;
 
@@ -2076,31 +2099,31 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des
        {
                map_entry *entry = &chd->map[hunknum];
                UINT32 bytes;
+               UINT8* compressed_bytes;
 
                /* switch off the entry type */
                switch (entry->flags & MAP_ENTRY_FLAG_TYPE_MASK)
                {
                        /* compressed data */
                        case V34_MAP_ENTRY_TYPE_COMPRESSED:
-            {
-               void* codec;
-              UINT8 *bytes = read_compressed(chd, entry->offset, entry->length);
-              if (bytes == NULL)
-                      return CHDERR_READ_ERROR;
-
-               /* now decompress using the codec */
-               err   = CHDERR_NONE;
-               codec = &chd->zlib_codec_data;
-               if (chd->codecintf[0]->decompress != NULL)
-                  err = (*chd->codecintf[0]->decompress)(codec, bytes, entry->length, dest, chd->header.hunkbytes);
-               if (err != CHDERR_NONE)
-                  return err;
-            }
+
+                               /* 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;
+                               void* codec = &chd->zlib_codec_data;
+                               if (chd->codecintf[0]->decompress != NULL)
+                                       err = (*chd->codecintf[0]->decompress)(codec, compressed_bytes, entry->length, dest, chd->header.hunkbytes);
+                               if (err != CHDERR_NONE)
+                                       return err;
                                break;
 
                        /* uncompressed data */
                        case V34_MAP_ENTRY_TYPE_UNCOMPRESSED:
-                               err = read_uncompressed(chd, entry->offset, chd->header.hunkbytes, dest);
+                               err = hunk_read_uncompressed(chd, entry->offset, chd->header.hunkbytes, dest);
                                if (err != CHDERR_NONE)
                                        return err;
                                break;
@@ -2129,43 +2152,45 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des
        }
        else
        {
-
-               // get a pointer to the map entry
+               /* get a pointer to the map entry */
                uint64_t blockoffs;
                uint32_t blocklen;
                uint16_t blockcrc;
-      void* codec = NULL;
                uint8_t *rawmap = &chd->header.rawmap[chd->header.mapentrybytes * hunknum];
-               UINT8 *bytes;
+               UINT8* compressed_bytes;
 
-               // uncompressed case
-               /* TODO
-               if (!compressed())
+               /* uncompressed case */
+               if (!compressed(&chd->header))
                {
-                       blockoffs = uint64_t(be_read(rawmap, 4)) * uint64_t(m_hunkbytes);
-                       if (blockoffs != 0)
-                               file_read(blockoffs, dest, m_hunkbytes);
+                       blockoffs = (uint64_t)get_bigendian_uint32(rawmap) * (uint64_t)chd->header.hunkbytes;
+                       if (blockoffs != 0) {
+                               core_fseek(chd->file, blockoffs, SEEK_SET);
+                               core_fread(chd->file, dest, chd->header.hunkbytes);
+                       /* TODO
                        else if (m_parent_missing)
-                               throw CHDERR_REQUIRES_PARENT;
-                       else if (m_parent != nullptr)
-                               m_parent->read_hunk(hunknum, dest);
-                       else
-                               memset(dest, 0, m_hunkbytes);
-                       return CHDERR_NONE;
-               }*/
+                               throw CHDERR_REQUIRES_PARENT; */
+                       } else if (chd->parent) {
+                               err = hunk_read_into_memory(chd->parent, hunknum, dest);
+                               if (err != CHDERR_NONE)
+                                       return err;
+                       } else {
+                               memset(dest, 0, chd->header.hunkbytes);
+                       }
+               }
 
-               // compressed case
+               /* compressed case */
                blocklen = get_bigendian_uint24(&rawmap[1]);
                blockoffs = get_bigendian_uint48(&rawmap[4]);
                blockcrc = get_bigendian_uint16(&rawmap[10]);
+               void* codec = NULL;
                switch (rawmap[0])
                {
                        case COMPRESSION_TYPE_0:
                        case COMPRESSION_TYPE_1:
                        case COMPRESSION_TYPE_2:
                        case COMPRESSION_TYPE_3:
-                               bytes = read_compressed(chd, blockoffs, blocklen);
-                               if (bytes == NULL)
+                               compressed_bytes = hunk_read_compressed(chd, blockoffs, blocklen);
+                               if (compressed_bytes == NULL)
                                        return CHDERR_READ_ERROR;
                                switch (chd->codecintf[rawmap[0]]->compression)
                                {
@@ -2173,6 +2198,10 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des
                                                codec = &chd->cdlz_codec_data;
                                                break;
 
+                                       case CHD_CODEC_ZLIB:
+                                               codec = &chd->zlib_codec_data;
+                                               break;
+
                                        case CHD_CODEC_CD_ZLIB:
                                                codec = &chd->cdzl_codec_data;
                                                break;
@@ -2183,13 +2212,13 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des
                                }
                                if (codec==NULL)
                                        return CHDERR_DECOMPRESSION_ERROR;
-                               chd->codecintf[rawmap[0]]->decompress(codec, bytes, blocklen, dest, chd->header.hunkbytes);
+                               chd->codecintf[rawmap[0]]->decompress(codec, compressed_bytes, blocklen, dest, chd->header.hunkbytes);
                                if (dest != NULL && crc16(dest, chd->header.hunkbytes) != blockcrc)
                                        return CHDERR_DECOMPRESSION_ERROR;
                                return CHDERR_NONE;
 
                        case COMPRESSION_NONE:
-                               err = read_uncompressed(chd, blockoffs, blocklen, dest);
+                               err = hunk_read_uncompressed(chd, blockoffs, blocklen, dest);
                                if (err != CHDERR_NONE)
                                        return err;
                                if (crc16(dest, chd->header.hunkbytes) != blockcrc)
@@ -2200,20 +2229,21 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des
                                return hunk_read_into_memory(chd, blockoffs, dest);
 
                        case COMPRESSION_PARENT:
-                               // TODO
-                               //if (m_parent_missing)
-                               //      return CHDERR_REQUIRES_PARENT;
-                               //return m_parent->read_bytes(uint64_t(blockoffs) * uint64_t(m_parent->unit_bytes()), dest, m_hunkbytes);
+#if 0
+                               /* TODO */
+                               if (m_parent_missing)
+                                       return CHDERR_REQUIRES_PARENT;
+                               return m_parent->read_bytes(uint64_t(blockoffs) * uint64_t(m_parent->unit_bytes()), dest, m_hunkbytes);
+#endif
                                return CHDERR_DECOMPRESSION_ERROR;
                }
                return CHDERR_NONE;
        }
 
-       // We should not reach this code
+       /* We should not reach this code */
        return CHDERR_DECOMPRESSION_ERROR;
 }
 
-
 /***************************************************************************
     INTERNAL MAP ACCESS
 ***************************************************************************/
@@ -2299,9 +2329,6 @@ cleanup:
        return err;
 }
 
-
-
-
 /***************************************************************************
     INTERNAL METADATA ACCESS
 ***************************************************************************/
@@ -2351,8 +2378,6 @@ static chd_error metadata_find_entry(chd_file *chd, UINT32 metatag, UINT32 metai
        return CHDERR_METADATA_NOT_FOUND;
 }
 
-
-
 /***************************************************************************
     ZLIB COMPRESSION CODEC
 ***************************************************************************/
@@ -2393,7 +2418,6 @@ static chd_error zlib_codec_init(void *codec, uint32_t hunkbytes)
        return err;
 }
 
-
 /*-------------------------------------------------
     zlib_codec_free - free data for the ZLIB
     codec
@@ -2407,19 +2431,17 @@ static void zlib_codec_free(void *codec)
        if (data != NULL)
        {
                int i;
-      zlib_allocator alloc;
 
                inflateEnd(&data->inflater);
 
                /* free our fast memory */
-               alloc = data->allocator;
+               zlib_allocator alloc = data->allocator;
                for (i = 0; i < MAX_ZLIB_ALLOCS; i++)
                        if (alloc.allocptr[i])
                                free(alloc.allocptr[i]);
        }
 }
 
-
 /*-------------------------------------------------
     zlib_codec_decompress - decomrpess data using
     the ZLIB codec
@@ -2449,7 +2471,6 @@ static chd_error zlib_codec_decompress(void *codec, const uint8_t *src, uint32_t
        return CHDERR_NONE;
 }
 
-
 /*-------------------------------------------------
     zlib_fast_alloc - fast malloc for ZLIB, which
     allocates and frees memory frequently
@@ -2477,7 +2498,7 @@ static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size)
        }
 
        /* alloc a new one */
-       ptr = (UINT32 *)malloc(size + sizeof(UINT32));
+       ptr = (UINT32 *)malloc(size + sizeof(uintptr_t));
        if (!ptr)
                return NULL;
 
@@ -2491,10 +2512,9 @@ static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size)
 
        /* set the low bit of the size so we don't match next time */
        *ptr = size | 1;
-       return ptr + 1;
+       return ptr + (sizeof(uint32_t) == sizeof(uintptr_t) ? 1 : 2);
 }
 
-
 /*-------------------------------------------------
     zlib_fast_free - fast free for ZLIB, which
     allocates and frees memory frequently
@@ -2503,7 +2523,7 @@ static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size)
 static void zlib_fast_free(voidpf opaque, voidpf address)
 {
        zlib_allocator *alloc = (zlib_allocator *)opaque;
-       UINT32 *ptr = (UINT32 *)address - 1;
+       UINT32 *ptr = (UINT32 *)address - (sizeof(uint32_t) == sizeof(uintptr_t) ? 1 : 2);
        int i;
 
        /* find the hunk */
index 37aeab4..444a0d8 100644 (file)
@@ -194,12 +194,21 @@ extern "C" {
 #define CHDFLAGS_IS_WRITEABLE          0x00000002
 #define CHDFLAGS_UNDEFINED                     0xfffffffc
 
+#define CHD_MAKE_TAG(a,b,c,d)       (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
+
 /* compression types */
 #define CHDCOMPRESSION_NONE                    0
 #define CHDCOMPRESSION_ZLIB                    1
 #define CHDCOMPRESSION_ZLIB_PLUS       2
 #define CHDCOMPRESSION_AV                      3
 
+#define CHD_CODEC_NONE 0
+#define CHD_CODEC_ZLIB                         CHD_MAKE_TAG('z','l','i','b')
+/* general codecs with CD frontend */
+#define CHD_CODEC_CD_ZLIB                      CHD_MAKE_TAG('c','d','z','l')
+#define CHD_CODEC_CD_LZMA                      CHD_MAKE_TAG('c','d','l','z')
+#define CHD_CODEC_CD_FLAC                      CHD_MAKE_TAG('c','d','f','l')
+
 /* A/V codec configuration parameters */
 #define AV_CODEC_COMPRESS_CONFIG       1
 #define AV_CODEC_DECOMPRESS_CONFIG     2
@@ -212,33 +221,34 @@ extern "C" {
 #define CHD_MDFLAGS_CHECKSUM           0x01            /* indicates data is checksummed */
 
 /* standard hard disk metadata */
-#define HARD_DISK_METADATA_TAG         0x47444444      /* 'GDDD' */
+#define HARD_DISK_METADATA_TAG         CHD_MAKE_TAG('G','D','D','D')
 #define HARD_DISK_METADATA_FORMAT      "CYLS:%d,HEADS:%d,SECS:%d,BPS:%d"
 
 /* hard disk identify information */
-#define HARD_DISK_IDENT_METADATA_TAG 0x49444e54 /* 'IDNT' */
+#define HARD_DISK_IDENT_METADATA_TAG CHD_MAKE_TAG('I','D','N','T')
 
 /* hard disk key information */
-#define HARD_DISK_KEY_METADATA_TAG     0x4b455920  /* 'KEY '  */
+#define HARD_DISK_KEY_METADATA_TAG     CHD_MAKE_TAG('K','E','Y',' ')
 
 /* pcmcia CIS information */
-#define PCMCIA_CIS_METADATA_TAG                0x43495320  /* 'CIS '  */
+#define PCMCIA_CIS_METADATA_TAG                CHD_MAKE_TAG('C','I','S',' ')
 
 /* standard CD-ROM metadata */
-#define CDROM_OLD_METADATA_TAG         0x43484344      /* 'CHCD' */
-#define CDROM_TRACK_METADATA_TAG       0x43485452      /* 'CHTR' */
+#define CDROM_OLD_METADATA_TAG         CHD_MAKE_TAG('C','H','C','D')
+#define CDROM_TRACK_METADATA_TAG       CHD_MAKE_TAG('C','H','T','R')
 #define CDROM_TRACK_METADATA_FORMAT    "TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d"
-#define CDROM_TRACK_METADATA2_TAG      0x43485432      /* 'CHT2' */
+#define CDROM_TRACK_METADATA2_TAG      CHD_MAKE_TAG('C','H','T','2')
 #define CDROM_TRACK_METADATA2_FORMAT   "TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d PREGAP:%d PGTYPE:%s PGSUB:%s POSTGAP:%d"
-#define GDROM_TRACK_METADATA_TAG       0x43484744      /* 'CHTD' */
+#define GDROM_OLD_METADATA_TAG         CHD_MAKE_TAG('C','H','G','T')
+#define GDROM_TRACK_METADATA_TAG       CHD_MAKE_TAG('C', 'H', 'G', 'D')
 #define GDROM_TRACK_METADATA_FORMAT    "TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d PAD:%d PREGAP:%d PGTYPE:%s PGSUB:%s POSTGAP:%d"
 
 /* standard A/V metadata */
-#define AV_METADATA_TAG                                0x41564156      /* 'AVAV' */
+#define AV_METADATA_TAG                                CHD_MAKE_TAG('A','V','A','V')
 #define AV_METADATA_FORMAT                     "FPS:%d.%06d WIDTH:%d HEIGHT:%d INTERLACED:%d CHANNELS:%d SAMPLERATE:%d"
 
 /* A/V laserdisc frame metadata */
-#define AV_LD_METADATA_TAG                     0x41564C44      /* 'AVLD' */
+#define AV_LD_METADATA_TAG                     CHD_MAKE_TAG('A','V','L','D')
 
 /* CHD open values */
 #define CHD_OPEN_READ                          1
@@ -305,14 +315,14 @@ struct _chd_header
        UINT8           parentmd5[CHD_MD5_BYTES];       /* overall MD5 checksum of parent */
        UINT8           sha1[CHD_SHA1_BYTES];           /* overall SHA1 checksum */
        UINT8           rawsha1[CHD_SHA1_BYTES];        /* SHA1 checksum of raw data */
-       UINT8           parentsha1[CHD_SHA1_BYTES];     /* overall SHA1 checksum of parent */   
+       UINT8           parentsha1[CHD_SHA1_BYTES];     /* overall SHA1 checksum of parent */
        UINT32          unitbytes;                                      /* TODO V5 */
-       UINT64          unitcount;                                      /* TODO V5 */   
+       UINT64          unitcount;                                      /* TODO V5 */
     UINT32      hunkcount;                  /* TODO V5 */
 
-    // map information
-    UINT32      mapentrybytes;              // length of each entry in a map (V5)
-    UINT8*      rawmap;                     // raw map data
+    /* map information */
+    UINT32      mapentrybytes;              /* length of each entry in a map (V5) */
+    UINT8*      rawmap;                     /* raw map data */
 
        UINT32          obsolete_cylinders;                     /* obsolete field -- do not use! */
        UINT32          obsolete_sectors;                       /* obsolete field -- do not use! */
@@ -341,10 +351,10 @@ struct _chd_verify_result
 /* ----- CHD file management ----- */
 
 /* create a new CHD file fitting the given description */
-// chd_error chd_create(const char *filename, UINT64 logicalbytes, UINT32 hunkbytes, UINT32 compression, chd_file *parent);
+/* chd_error chd_create(const char *filename, UINT64 logicalbytes, UINT32 hunkbytes, UINT32 compression, chd_file *parent); */
 
 /* same as chd_create(), but accepts an already-opened core_file object */
-// chd_error chd_create_file(core_file *file, UINT64 logicalbytes, UINT32 hunkbytes, UINT32 compression, chd_file *parent);
+/* chd_error chd_create_file(core_file *file, UINT64 logicalbytes, UINT32 hunkbytes, UINT32 compression, chd_file *parent); */
 
 /* open an existing CHD file */
 chd_error chd_open(const char *filename, int mode, chd_file *parent, chd_file **chd);
index 6264bea..5aecc14 100644 (file)
@@ -4,10 +4,6 @@
 #include <stdint.h>
 #include <stdio.h>
 
-#ifdef __LIBRETRO__
-#include <streams/file_stream_transforms.h>
-#endif
-
 #define ARRAY_LENGTH(x) (sizeof(x)/sizeof(x[0]))
 
 typedef uint64_t UINT64;
@@ -26,15 +22,13 @@ typedef int8_t INT8;
 #define core_fread(fc, buff, len) fread(buff, 1, len, fc)
 #define core_fclose fclose
 #define core_ftell ftell
-
-static size_t core_fsize(core_file* f)
+static size_t core_fsize(core_file *f)
 {
-   size_t rv;
-   size_t p = ftell(f);
-   fseek(f, 0, SEEK_END);
-   rv = ftell(f);
-   fseek(f, p, SEEK_SET);
-   return rv;
+    long p = ftell(f);
+    fseek(f, 0, SEEK_END);
+    long rv = ftell(f);
+    fseek(f, p, SEEK_SET);
+    return rv;
 }
 
 #endif
index 29844b6..8e31ed6 100644 (file)
-// license:BSD-3-Clause\r
-// copyright-holders:Aaron Giles\r
-/***************************************************************************\r
-\r
-    flac.c\r
-\r
-    FLAC compression wrappers\r
-\r
-***************************************************************************/\r
-\r
-#include <assert.h>\r
-#include <string.h>\r
-#include "flac.h"\r
-\r
-//**************************************************************************\r
-//  FLAC DECODER\r
-//**************************************************************************\r
-\r
-static FLAC__StreamDecoderReadStatus flac_decoder_read_callback_static(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data);\r
-FLAC__StreamDecoderReadStatus flac_decoder_read_callback(void* client_data, FLAC__byte buffer[], size_t *bytes);\r
-static void flac_decoder_metadata_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data);\r
-static FLAC__StreamDecoderTellStatus flac_decoder_tell_callback_static(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data);\r
-static FLAC__StreamDecoderWriteStatus flac_decoder_write_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);\r
-FLAC__StreamDecoderWriteStatus flac_decoder_write_callback(void* client_data, const FLAC__Frame *frame, const FLAC__int32 * const buffer[]);\r
-static void flac_decoder_error_callback_static(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);\r
-\r
-// getters (valid after reset)\r
-static uint32_t sample_rate(flac_decoder *decoder)  { return decoder->sample_rate; }\r
-static uint8_t channels(flac_decoder *decoder)  { return decoder->channels; }\r
-static uint8_t bits_per_sample(flac_decoder *decoder) { return decoder->bits_per_sample; }\r
-static uint32_t total_samples(flac_decoder *decoder)  { return FLAC__stream_decoder_get_total_samples(decoder->decoder); }\r
-static FLAC__StreamDecoderState state(flac_decoder *decoder) { return FLAC__stream_decoder_get_state(decoder->decoder); }\r
-static const char *state_string(flac_decoder *decoder) { return FLAC__stream_decoder_get_resolved_state_string(decoder->decoder); }\r
-\r
-//-------------------------------------------------\r
-//  flac_decoder - constructor\r
-//-------------------------------------------------\r
-\r
-void flac_decoder_init(flac_decoder *decoder)\r
-{\r
-       decoder->decoder = FLAC__stream_decoder_new();\r
-       decoder->sample_rate = 0;\r
-       decoder->channels = 0;\r
-       decoder->bits_per_sample = 0;\r
-       decoder->compressed_offset = 0;\r
-       decoder->compressed_start = NULL;\r
-       decoder->compressed_length = 0;\r
-       decoder->compressed2_start = NULL;\r
-       decoder->compressed2_length = 0;\r
-       decoder->uncompressed_offset = 0;\r
-       decoder->uncompressed_length = 0;\r
-       decoder->uncompressed_swap = 0;\r
-}\r
-\r
-//-------------------------------------------------\r
-//  flac_decoder - destructor\r
-//-------------------------------------------------\r
-\r
-void flac_decoder_free(flac_decoder* decoder)\r
-{\r
-       if ((decoder != NULL) && (decoder->decoder != NULL))\r
-               FLAC__stream_decoder_delete(decoder->decoder);\r
-}\r
-\r
-\r
-//-------------------------------------------------\r
-//  reset - reset state with the original\r
-//  parameters\r
-//-------------------------------------------------\r
-\r
-static int flac_decoder_internal_reset(flac_decoder* decoder)\r
-{\r
-       decoder->compressed_offset = 0;\r
-       if (FLAC__stream_decoder_init_stream(decoder->decoder,\r
-                               &flac_decoder_read_callback_static,\r
-                               NULL,\r
-                               &flac_decoder_tell_callback_static,\r
-                               NULL,\r
-                               NULL,\r
-                               &flac_decoder_write_callback_static,\r
-                               &flac_decoder_metadata_callback_static,\r
-                               &flac_decoder_error_callback_static, decoder) != FLAC__STREAM_DECODER_INIT_STATUS_OK)\r
-               return 0;\r
-       return FLAC__stream_decoder_process_until_end_of_metadata(decoder->decoder);\r
-}\r
-\r
-\r
-\r
-//-------------------------------------------------\r
-//  reset - reset state with new memory parameters\r
-//  and a custom-generated header\r
-//-------------------------------------------------\r
-\r
-int flac_decoder_reset(flac_decoder* decoder, uint32_t sample_rate, uint8_t num_channels, uint32_t block_size, const void *buffer, uint32_t length)\r
-{\r
-       // modify the template header with our parameters\r
-       static const uint8_t s_header_template[0x2a] =\r
-       {\r
-               0x66, 0x4C, 0x61, 0x43,                         // +00: 'fLaC' stream header\r
-               0x80,                                           // +04: metadata block type 0 (STREAMINFO),\r
-                                                                                                               //      flagged as last block\r
-               0x00, 0x00, 0x22,                               // +05: metadata block length = 0x22\r
-               0x00, 0x00,                                     // +08: minimum block size\r
-               0x00, 0x00,                                     // +0A: maximum block size\r
-               0x00, 0x00, 0x00,                               // +0C: minimum frame size (0 == unknown)\r
-               0x00, 0x00, 0x00,                               // +0F: maximum frame size (0 == unknown)\r
-               0x0A, 0xC4, 0x42, 0xF0, 0x00, 0x00, 0x00, 0x00, // +12: sample rate (0x0ac44 == 44100),\r
-                                                                                                               //      numchannels (2), sample bits (16),\r
-                                                                                                               //      samples in stream (0 == unknown)\r
-               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // +1A: MD5 signature (0 == none)\r
-               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  //\r
-                                                                                                               // +2A: start of stream data\r
-       };\r
-       memcpy(decoder->custom_header, s_header_template, sizeof(s_header_template));\r
-       decoder->custom_header[0x08] = decoder->custom_header[0x0a] = block_size >> 8;\r
-       decoder->custom_header[0x09] = decoder->custom_header[0x0b] = block_size & 0xff;\r
-       decoder->custom_header[0x12] = sample_rate >> 12;\r
-       decoder->custom_header[0x13] = sample_rate >> 4;\r
-       decoder->custom_header[0x14] = (sample_rate << 4) | ((num_channels - 1) << 1);\r
-\r
-       // configure the header ahead of the provided buffer\r
-       decoder->compressed_start = (const FLAC__byte *)(decoder->custom_header);\r
-       decoder->compressed_length = sizeof(decoder->custom_header);\r
-       decoder->compressed2_start = (const FLAC__byte *)(buffer);\r
-       decoder->compressed2_length = length;\r
-       return flac_decoder_internal_reset(decoder);\r
-}\r
-\r
-\r
-//-------------------------------------------------\r
-//  decode_interleaved - decode to an interleaved\r
-//  sound stream\r
-//-------------------------------------------------\r
-\r
-int flac_decoder_decode_interleaved(flac_decoder* decoder, int16_t *samples, uint32_t num_samples, int swap_endian)\r
-{\r
-       // configure the uncompressed buffer\r
-       memset(decoder->uncompressed_start, 0, sizeof(decoder->uncompressed_start));\r
-       decoder->uncompressed_start[0] = samples;\r
-       decoder->uncompressed_offset = 0;\r
-       decoder->uncompressed_length = num_samples;\r
-       decoder->uncompressed_swap = swap_endian;\r
-\r
-       // loop until we get everything we want\r
-       while (decoder->uncompressed_offset < decoder->uncompressed_length)\r
-               if (!FLAC__stream_decoder_process_single(decoder->decoder))\r
-                       return 0;\r
-       return 1;\r
-}\r
-\r
-\r
-/*\r
-//-------------------------------------------------\r
-//  decode - decode to an multiple independent\r
-//  data streams\r
-//-------------------------------------------------\r
-\r
-bool flac_decoder::decode(int16_t **samples, uint32_t num_samples, bool swap_endian)\r
-{\r
-       // make sure we don't have too many channels\r
-       int chans = channels();\r
-       if (chans > ARRAY_LENGTH(m_uncompressed_start))\r
-               return false;\r
-\r
-       // configure the uncompressed buffer\r
-       memset(m_uncompressed_start, 0, sizeof(m_uncompressed_start));\r
-       for (int curchan = 0; curchan < chans; curchan++)\r
-               m_uncompressed_start[curchan] = samples[curchan];\r
-       m_uncompressed_offset = 0;\r
-       m_uncompressed_length = num_samples;\r
-       m_uncompressed_swap = swap_endian;\r
-\r
-       // loop until we get everything we want\r
-       while (m_uncompressed_offset < m_uncompressed_length)\r
-               if (!FLAC__stream_decoder_process_single(m_decoder))\r
-                       return false;\r
-       return true;\r
-}\r
-*/\r
-\r
-//-------------------------------------------------\r
-//  finish - finish up the decode\r
-//-------------------------------------------------\r
-\r
-uint32_t flac_decoder_finish(flac_decoder* decoder)\r
-{\r
-       // get the final decoding position and move forward\r
-       FLAC__uint64 position = 0;\r
-       FLAC__stream_decoder_get_decode_position(decoder->decoder, &position);\r
-       FLAC__stream_decoder_finish(decoder->decoder);\r
-\r
-       // adjust position if we provided the header\r
-       if (position == 0)\r
-               return 0;\r
-       if (decoder->compressed_start == (const FLAC__byte *)(decoder->custom_header))\r
-               position -= decoder->compressed_length;\r
-       return position;\r
-}\r
-\r
-\r
-//-------------------------------------------------\r
-//  read_callback - handle reads from the input\r
-//  stream\r
-//-------------------------------------------------\r
-\r
-#define MIN(x, y) ((x) < (y) ? (x) : (y))\r
-\r
-FLAC__StreamDecoderReadStatus flac_decoder_read_callback_static(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)\r
-{\r
-       return flac_decoder_read_callback(client_data, buffer, bytes);\r
-}\r
-\r
-FLAC__StreamDecoderReadStatus flac_decoder_read_callback(void* client_data, FLAC__byte buffer[], size_t *bytes)\r
-{\r
-       flac_decoder* decoder = (flac_decoder*)client_data;\r
-\r
-       uint32_t expected = *bytes;\r
-\r
-       // copy from primary buffer first\r
-       uint32_t outputpos = 0;\r
-       if (outputpos < *bytes && decoder->compressed_offset < decoder->compressed_length)\r
-       {\r
-               uint32_t bytes_to_copy = MIN(*bytes - outputpos, decoder->compressed_length - decoder->compressed_offset);\r
-               memcpy(&buffer[outputpos], decoder->compressed_start + decoder->compressed_offset, bytes_to_copy);\r
-               outputpos += bytes_to_copy;\r
-               decoder->compressed_offset += bytes_to_copy;\r
-       }\r
-\r
-       // once we're out of that, copy from the secondary buffer\r
-       if (outputpos < *bytes && decoder->compressed_offset < decoder->compressed_length + decoder->compressed2_length)\r
-       {\r
-               uint32_t bytes_to_copy = MIN(*bytes - outputpos, decoder->compressed2_length - (decoder->compressed_offset - decoder->compressed_length));\r
-               memcpy(&buffer[outputpos], decoder->compressed2_start + decoder->compressed_offset - decoder->compressed_length, bytes_to_copy);\r
-               outputpos += bytes_to_copy;\r
-               decoder->compressed_offset += bytes_to_copy;\r
-       }\r
-       *bytes = outputpos;\r
-\r
-       // return based on whether we ran out of data\r
-       return (*bytes < expected) ? FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM : FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;\r
-}\r
-\r
-\r
-//-------------------------------------------------\r
-//  metadata_callback - handle STREAMINFO metadata\r
-//-------------------------------------------------\r
-\r
-void flac_decoder_metadata_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)\r
-{\r
-   flac_decoder *fldecoder;\r
-       // ignore all but STREAMINFO metadata\r
-       if (metadata->type != FLAC__METADATA_TYPE_STREAMINFO)\r
-               return;\r
-\r
-       // parse out the data we care about\r
-       fldecoder = (flac_decoder *)(client_data);\r
-       fldecoder->sample_rate = metadata->data.stream_info.sample_rate;\r
-       fldecoder->bits_per_sample = metadata->data.stream_info.bits_per_sample;\r
-       fldecoder->channels = metadata->data.stream_info.channels;\r
-}\r
-\r
-\r
-//-------------------------------------------------\r
-//  tell_callback - handle requests to find out\r
-//  where in the input stream we are\r
-//-------------------------------------------------\r
-\r
-FLAC__StreamDecoderTellStatus flac_decoder_tell_callback_static(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data)\r
-{\r
-       *absolute_byte_offset = ((flac_decoder *)client_data)->compressed_offset;\r
-       return FLAC__STREAM_DECODER_TELL_STATUS_OK;\r
-}\r
-\r
-\r
-//-------------------------------------------------\r
-//  write_callback - handle writes to the output\r
-//  stream\r
-//-------------------------------------------------\r
-\r
-FLAC__StreamDecoderWriteStatus flac_decoder_write_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)\r
-{\r
-       return flac_decoder_write_callback(client_data, frame, buffer);\r
-}\r
-\r
-FLAC__StreamDecoderWriteStatus flac_decoder_write_callback(void *client_data, const FLAC__Frame *frame, const FLAC__int32 * const buffer[])\r
-{\r
-   int shift, blocksize;\r
-       flac_decoder * decoder = (flac_decoder *)client_data;\r
-\r
-       assert(frame->header.channels == channels(decoder));\r
-\r
-       // interleaved case\r
-       shift = decoder->uncompressed_swap ? 8 : 0;\r
-       blocksize = frame->header.blocksize;\r
-\r
-       if (decoder->uncompressed_start[1] == NULL)\r
-       {\r
-      int sampnum, chan;\r
-               int16_t *dest = decoder->uncompressed_start[0] + decoder->uncompressed_offset * frame->header.channels;\r
-               for (sampnum = 0; sampnum < blocksize && decoder->uncompressed_offset < decoder->uncompressed_length; sampnum++, decoder->uncompressed_offset++)\r
-                       for (chan = 0; chan < frame->header.channels; chan++)\r
-                               *dest++ = (int16_t)((((uint16_t)buffer[chan][sampnum]) << shift) | (((uint16_t)buffer[chan][sampnum]) >> shift));\r
-       }\r
-\r
-       // non-interleaved case\r
-       else\r
-       {\r
-      int sampnum, chan;\r
-               for (sampnum = 0; sampnum < blocksize && decoder->uncompressed_offset < decoder->uncompressed_length; sampnum++, decoder->uncompressed_offset++)\r
-                       for (chan = 0; chan < frame->header.channels; chan++)\r
-                               if (decoder->uncompressed_start[chan] != NULL)\r
-                                       decoder->uncompressed_start[chan][decoder->uncompressed_offset] = (int16_t) ( (((uint16_t)(buffer[chan][sampnum])) << shift) | ( ((uint16_t)(buffer[chan][sampnum])) >> shift) );\r
-       }\r
-       return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;\r
-}\r
-\r
-/**\r
- * @fn  void flac_decoder::error_callback_static(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)\r
- *\r
- * @brief   -------------------------------------------------\r
- *            error_callback - handle errors (ignore them)\r
- *          -------------------------------------------------.\r
- *\r
- * @param   decoder             The decoder.\r
- * @param   status              The status.\r
- * @param [in,out]  client_data If non-null, information describing the client.\r
- */\r
-\r
-void flac_decoder_error_callback_static(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)\r
-{\r
-}\r
+/* license:BSD-3-Clause
+ * copyright-holders:Aaron Giles
+***************************************************************************
+
+    flac.c
+
+    FLAC compression wrappers
+
+***************************************************************************/
+
+#include <assert.h>
+#include <string.h>
+#include "flac.h"
+
+/***************************************************************************
+ *  FLAC DECODER
+ ***************************************************************************
+ */
+
+static FLAC__StreamDecoderReadStatus flac_decoder_read_callback_static(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data);
+FLAC__StreamDecoderReadStatus flac_decoder_read_callback(void* client_data, FLAC__byte buffer[], size_t *bytes);
+static void flac_decoder_metadata_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data);
+static FLAC__StreamDecoderTellStatus flac_decoder_tell_callback_static(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
+static FLAC__StreamDecoderWriteStatus flac_decoder_write_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
+FLAC__StreamDecoderWriteStatus flac_decoder_write_callback(void* client_data, const FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
+static void flac_decoder_error_callback_static(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
+
+/* getters (valid after reset) */
+static uint32_t sample_rate(flac_decoder *decoder)  { return decoder->sample_rate; }
+static uint8_t channels(flac_decoder *decoder)  { return decoder->channels; }
+static uint8_t bits_per_sample(flac_decoder *decoder) { return decoder->bits_per_sample; }
+static uint32_t total_samples(flac_decoder *decoder)  { return FLAC__stream_decoder_get_total_samples(decoder->decoder); }
+static FLAC__StreamDecoderState state(flac_decoder *decoder) { return FLAC__stream_decoder_get_state(decoder->decoder); }
+static const char *state_string(flac_decoder *decoder) { return FLAC__stream_decoder_get_resolved_state_string(decoder->decoder); }
+
+/*-------------------------------------------------
+ *  flac_decoder - constructor
+ *-------------------------------------------------
+ */
+
+void flac_decoder_init(flac_decoder *decoder)
+{
+       decoder->decoder = FLAC__stream_decoder_new();
+       decoder->sample_rate = 0;
+       decoder->channels = 0;
+       decoder->bits_per_sample = 0;
+       decoder->compressed_offset = 0;
+       decoder->compressed_start = NULL;
+       decoder->compressed_length = 0;
+       decoder->compressed2_start = NULL;
+       decoder->compressed2_length = 0;
+       decoder->uncompressed_offset = 0;
+       decoder->uncompressed_length = 0;
+       decoder->uncompressed_swap = 0;
+}
+
+/*-------------------------------------------------
+ *  flac_decoder - destructor
+ *-------------------------------------------------
+ */
+
+void flac_decoder_free(flac_decoder* decoder)
+{
+       if ((decoder != NULL) && (decoder->decoder != NULL))
+               FLAC__stream_decoder_delete(decoder->decoder);
+}
+
+/*-------------------------------------------------
+ *  reset - reset state with the original
+ *  parameters
+ *-------------------------------------------------
+ */
+
+static int flac_decoder_internal_reset(flac_decoder* decoder)
+{
+       decoder->compressed_offset = 0;
+       if (FLAC__stream_decoder_init_stream(decoder->decoder,
+                               &flac_decoder_read_callback_static,
+                               NULL,
+                               &flac_decoder_tell_callback_static,
+                               NULL,
+                               NULL,
+                               &flac_decoder_write_callback_static,
+                               &flac_decoder_metadata_callback_static,
+                               &flac_decoder_error_callback_static, decoder) != FLAC__STREAM_DECODER_INIT_STATUS_OK)
+               return 0;
+       return FLAC__stream_decoder_process_until_end_of_metadata(decoder->decoder);
+}
+
+/*-------------------------------------------------
+ *  reset - reset state with new memory parameters
+ *  and a custom-generated header
+ *-------------------------------------------------
+ */
+
+int flac_decoder_reset(flac_decoder* decoder, uint32_t sample_rate, uint8_t num_channels, uint32_t block_size, const void *buffer, uint32_t length)
+{
+       /* modify the template header with our parameters */
+       static const uint8_t s_header_template[0x2a] =
+       {
+               0x66, 0x4C, 0x61, 0x43,                         /* +00: 'fLaC' stream header */
+               0x80,                                           /* +04: metadata block type 0 (STREAMINFO), */
+                                                               /*      flagged as last block */
+               0x00, 0x00, 0x22,                               /* +05: metadata block length = 0x22 */
+               0x00, 0x00,                                     /* +08: minimum block size */
+               0x00, 0x00,                                     /* +0A: maximum block size */
+               0x00, 0x00, 0x00,                               /* +0C: minimum frame size (0 == unknown) */
+               0x00, 0x00, 0x00,                               /* +0F: maximum frame size (0 == unknown) */
+               0x0A, 0xC4, 0x42, 0xF0, 0x00, 0x00, 0x00, 0x00, /* +12: sample rate (0x0ac44 == 44100), */
+                                                               /*      numchannels (2), sample bits (16), */
+                                                               /*      samples in stream (0 == unknown) */
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* +1A: MD5 signature (0 == none) */
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  /* +2A: start of stream data */
+       };
+       memcpy(decoder->custom_header, s_header_template, sizeof(s_header_template));
+       decoder->custom_header[0x08] = decoder->custom_header[0x0a] = block_size >> 8;
+       decoder->custom_header[0x09] = decoder->custom_header[0x0b] = block_size & 0xff;
+       decoder->custom_header[0x12] = sample_rate >> 12;
+       decoder->custom_header[0x13] = sample_rate >> 4;
+       decoder->custom_header[0x14] = (sample_rate << 4) | ((num_channels - 1) << 1);
+
+       /* configure the header ahead of the provided buffer */
+       decoder->compressed_start = (const FLAC__byte *)(decoder->custom_header);
+       decoder->compressed_length = sizeof(decoder->custom_header);
+       decoder->compressed2_start = (const FLAC__byte *)(buffer);
+       decoder->compressed2_length = length;
+       return flac_decoder_internal_reset(decoder);
+}
+
+/*-------------------------------------------------
+ *  decode_interleaved - decode to an interleaved
+ *  sound stream
+ *-------------------------------------------------
+ */
+
+int flac_decoder_decode_interleaved(flac_decoder* decoder, int16_t *samples, uint32_t num_samples, int swap_endian)
+{
+       /* configure the uncompressed buffer */
+       memset(decoder->uncompressed_start, 0, sizeof(decoder->uncompressed_start));
+       decoder->uncompressed_start[0] = samples;
+       decoder->uncompressed_offset = 0;
+       decoder->uncompressed_length = num_samples;
+       decoder->uncompressed_swap = swap_endian;
+
+       /* loop until we get everything we want */
+       while (decoder->uncompressed_offset < decoder->uncompressed_length)
+               if (!FLAC__stream_decoder_process_single(decoder->decoder))
+                       return 0;
+       return 1;
+}
+
+#if 0
+/*-------------------------------------------------
+ *  decode - decode to an multiple independent
+ *  data streams
+ *-------------------------------------------------
+ */
+
+bool flac_decoder::decode(int16_t **samples, uint32_t num_samples, bool swap_endian)
+{
+       /* make sure we don't have too many channels */
+       int chans = channels();
+       if (chans > ARRAY_LENGTH(m_uncompressed_start))
+               return false;
+
+       /* configure the uncompressed buffer */
+       memset(m_uncompressed_start, 0, sizeof(m_uncompressed_start));
+       for (int curchan = 0; curchan < chans; curchan++)
+               m_uncompressed_start[curchan] = samples[curchan];
+       m_uncompressed_offset = 0;
+       m_uncompressed_length = num_samples;
+       m_uncompressed_swap = swap_endian;
+
+       /* loop until we get everything we want */
+       while (m_uncompressed_offset < m_uncompressed_length)
+               if (!FLAC__stream_decoder_process_single(m_decoder))
+                       return false;
+       return true;
+}
+#endif
+
+/*-------------------------------------------------
+ *  finish - finish up the decode
+ *-------------------------------------------------
+ */
+
+uint32_t flac_decoder_finish(flac_decoder* decoder)
+{
+       /* get the final decoding position and move forward */
+       FLAC__uint64 position = 0;
+       FLAC__stream_decoder_get_decode_position(decoder->decoder, &position);
+       FLAC__stream_decoder_finish(decoder->decoder);
+
+       /* adjust position if we provided the header */
+       if (position == 0)
+               return 0;
+       if (decoder->compressed_start == (const FLAC__byte *)(decoder->custom_header))
+               position -= decoder->compressed_length;
+       return position;
+}
+
+/*-------------------------------------------------
+ *  read_callback - handle reads from the input
+ *  stream
+ *-------------------------------------------------
+ */
+
+#define MIN(x, y) ((x) < (y) ? (x) : (y))
+
+FLAC__StreamDecoderReadStatus flac_decoder_read_callback_static(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+{
+       return flac_decoder_read_callback(client_data, buffer, bytes);
+}
+
+FLAC__StreamDecoderReadStatus flac_decoder_read_callback(void* client_data, FLAC__byte buffer[], size_t *bytes)
+{
+       flac_decoder* decoder = (flac_decoder*)client_data;
+
+       uint32_t expected = *bytes;
+
+       /* copy from primary buffer first */
+       uint32_t outputpos = 0;
+       if (outputpos < *bytes && decoder->compressed_offset < decoder->compressed_length)
+       {
+               uint32_t bytes_to_copy = MIN(*bytes - outputpos, decoder->compressed_length - decoder->compressed_offset);
+               memcpy(&buffer[outputpos], decoder->compressed_start + decoder->compressed_offset, bytes_to_copy);
+               outputpos += bytes_to_copy;
+               decoder->compressed_offset += bytes_to_copy;
+       }
+
+       /* once we're out of that, copy from the secondary buffer */
+       if (outputpos < *bytes && decoder->compressed_offset < decoder->compressed_length + decoder->compressed2_length)
+       {
+               uint32_t bytes_to_copy = MIN(*bytes - outputpos, decoder->compressed2_length - (decoder->compressed_offset - decoder->compressed_length));
+               memcpy(&buffer[outputpos], decoder->compressed2_start + decoder->compressed_offset - decoder->compressed_length, bytes_to_copy);
+               outputpos += bytes_to_copy;
+               decoder->compressed_offset += bytes_to_copy;
+       }
+       *bytes = outputpos;
+
+       /* return based on whether we ran out of data */
+       return (*bytes < expected) ? FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM : FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+}
+
+/*-------------------------------------------------
+ *  metadata_callback - handle STREAMINFO metadata
+ *-------------------------------------------------
+ */
+
+void flac_decoder_metadata_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+       flac_decoder *fldecoder;
+       /* ignore all but STREAMINFO metadata */
+       if (metadata->type != FLAC__METADATA_TYPE_STREAMINFO)
+               return;
+
+       /* parse out the data we care about */
+       fldecoder = (flac_decoder *)(client_data);
+       fldecoder->sample_rate = metadata->data.stream_info.sample_rate;
+       fldecoder->bits_per_sample = metadata->data.stream_info.bits_per_sample;
+       fldecoder->channels = metadata->data.stream_info.channels;
+}
+
+/*-------------------------------------------------
+ *  tell_callback - handle requests to find out
+ *  where in the input stream we are
+ *-------------------------------------------------
+ */
+
+FLAC__StreamDecoderTellStatus flac_decoder_tell_callback_static(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
+{
+       *absolute_byte_offset = ((flac_decoder *)client_data)->compressed_offset;
+       return FLAC__STREAM_DECODER_TELL_STATUS_OK;
+}
+
+/*-------------------------------------------------
+ *  write_callback - handle writes to the output
+ *  stream
+ *-------------------------------------------------
+ */
+
+FLAC__StreamDecoderWriteStatus flac_decoder_write_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+       return flac_decoder_write_callback(client_data, frame, buffer);
+}
+
+FLAC__StreamDecoderWriteStatus flac_decoder_write_callback(void *client_data, const FLAC__Frame *frame, const FLAC__int32 * const buffer[])
+{
+       int sampnum, chan;
+       int shift, blocksize;
+       flac_decoder * decoder = (flac_decoder *)client_data;
+
+       assert(frame->header.channels == channels(decoder));
+
+       /* interleaved case */
+       shift = decoder->uncompressed_swap ? 8 : 0;
+       blocksize = frame->header.blocksize;
+       if (decoder->uncompressed_start[1] == NULL)
+       {
+               int16_t *dest = decoder->uncompressed_start[0] + decoder->uncompressed_offset * frame->header.channels;
+               for (sampnum = 0; sampnum < blocksize && decoder->uncompressed_offset < decoder->uncompressed_length; sampnum++, decoder->uncompressed_offset++)
+                       for (chan = 0; chan < frame->header.channels; chan++)
+                               *dest++ = (int16_t)((((uint16_t)buffer[chan][sampnum]) << shift) | (((uint16_t)buffer[chan][sampnum]) >> shift));
+       }
+
+       /* non-interleaved case */
+       else
+       {
+               for (sampnum = 0; sampnum < blocksize && decoder->uncompressed_offset < decoder->uncompressed_length; sampnum++, decoder->uncompressed_offset++)
+                       for (chan = 0; chan < frame->header.channels; chan++)
+                               if (decoder->uncompressed_start[chan] != NULL)
+                                       decoder->uncompressed_start[chan][decoder->uncompressed_offset] = (int16_t) ( (((uint16_t)(buffer[chan][sampnum])) << shift) | ( ((uint16_t)(buffer[chan][sampnum])) >> shift) );
+       }
+       return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+/**
+ * @fn  void flac_decoder::error_callback_static(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+ *
+ * @brief   -------------------------------------------------
+ *            error_callback - handle errors (ignore them)
+ *          -------------------------------------------------.
+ *
+ * @param   decoder             The decoder.
+ * @param   status              The status.
+ * @param [in,out]  client_data If non-null, information describing the client.
+ */
+
+void flac_decoder_error_callback_static(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+}
index 23e91a9..6cf011f 100644 (file)
@@ -1,50 +1,51 @@
-// license:BSD-3-Clause\r
-// copyright-holders:Aaron Giles\r
-/***************************************************************************\r
-\r
-    flac.h\r
-\r
-    FLAC compression wrappers\r
-\r
-***************************************************************************/\r
-\r
-#pragma once\r
-\r
-#ifndef __FLAC_H__\r
-#define __FLAC_H__\r
-\r
-#include <stdint.h>\r
-#include "FLAC/all.h"\r
-\r
-//**************************************************************************\r
-//  TYPE DEFINITIONS\r
-//**************************************************************************\r
-\r
-typedef struct _flac_decoder flac_decoder;\r
-struct _flac_decoder {\r
-               // output state\r
-       FLAC__StreamDecoder*    decoder;                                // actual encoder\r
-       uint32_t                sample_rate;                    // decoded sample rate\r
-       uint8_t                 channels;                               // decoded number of channels\r
-       uint8_t                 bits_per_sample;                // decoded bits per sample\r
-       uint32_t                compressed_offset;              // current offset in compressed data\r
-       const FLAC__byte *      compressed_start;               // start of compressed data\r
-       uint32_t                compressed_length;              // length of compressed data\r
-       const FLAC__byte *      compressed2_start;              // start of compressed data\r
-       uint32_t                compressed2_length;             // length of compressed data\r
-       int16_t *               uncompressed_start[8];  // pointer to start of uncompressed data (up to 8 streams)\r
-       uint32_t                uncompressed_offset;    // current position in uncompressed data\r
-       uint32_t                uncompressed_length;    // length of uncompressed data\r
-       int                     uncompressed_swap;              // swap uncompressed sample data\r
-       uint8_t                 custom_header[0x2a];    // custom header\r
-};\r
-\r
-// ======================> flac_decoder\r
-\r
-void           flac_decoder_init(flac_decoder* decoder);\r
-void           flac_decoder_free(flac_decoder* decoder);\r
-int            flac_decoder_reset(flac_decoder* decoder, uint32_t sample_rate, uint8_t num_channels, uint32_t block_size, const void *buffer, uint32_t length);\r
-int            flac_decoder_decode_interleaved(flac_decoder* decoder, int16_t *samples, uint32_t num_samples, int swap_endian);\r
-uint32_t       flac_decoder_finish(flac_decoder* decoder);\r
-\r
-#endif // __FLAC_H__\r
+/* license:BSD-3-Clause
+ * copyright-holders:Aaron Giles
+ ***************************************************************************
+
+    flac.h
+
+    FLAC compression wrappers
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __FLAC_H__
+#define __FLAC_H__
+
+#include <stdint.h>
+#include <FLAC/all.h>
+
+/***************************************************************************
+ *  TYPE DEFINITIONS
+ ***************************************************************************
+ */
+
+typedef struct _flac_decoder flac_decoder;
+struct _flac_decoder {
+               /* output state */
+       FLAC__StreamDecoder*    decoder;                                /* actual encoder */
+       uint32_t                sample_rate;                    /* decoded sample rate */
+       uint8_t                 channels;                               /* decoded number of channels */
+       uint8_t                 bits_per_sample;                /* decoded bits per sample */
+       uint32_t                compressed_offset;              /* current offset in compressed data */
+       const FLAC__byte *      compressed_start;               /* start of compressed data */
+       uint32_t                compressed_length;              /* length of compressed data */
+       const FLAC__byte *      compressed2_start;              /* start of compressed data */
+       uint32_t                compressed2_length;             /* length of compressed data */
+       int16_t *               uncompressed_start[8];  /* pointer to start of uncompressed data (up to 8 streams) */
+       uint32_t                uncompressed_offset;    /* current position in uncompressed data */
+       uint32_t                uncompressed_length;    /* length of uncompressed data */
+       int                     uncompressed_swap;              /* swap uncompressed sample data */
+       uint8_t                 custom_header[0x2a];    /* custom header */
+};
+
+/* ======================> flac_decoder */
+
+void           flac_decoder_init(flac_decoder* decoder);
+void           flac_decoder_free(flac_decoder* decoder);
+int            flac_decoder_reset(flac_decoder* decoder, uint32_t sample_rate, uint8_t num_channels, uint32_t block_size, const void *buffer, uint32_t length);
+int            flac_decoder_decode_interleaved(flac_decoder* decoder, int16_t *samples, uint32_t num_samples, int swap_endian);
+uint32_t       flac_decoder_finish(flac_decoder* decoder);
+
+#endif /* __FLAC_H__ */
index d67ec19..f48210e 100644 (file)
-// license:BSD-3-Clause\r
-// copyright-holders:Aaron Giles\r
-/***************************************************************************\r
-\r
-    huffman.c\r
-\r
-    Static Huffman compression and decompression helpers.\r
-\r
-****************************************************************************\r
-\r
-    Maximum codelength is officially (alphabetsize - 1). This would be 255 bits\r
-    (since we use 1 byte values). However, it is also dependent upon the number\r
-    of samples used, as follows:\r
-\r
-         2 bits -> 3..4 samples\r
-         3 bits -> 5..7 samples\r
-         4 bits -> 8..12 samples\r
-         5 bits -> 13..20 samples\r
-         6 bits -> 21..33 samples\r
-         7 bits -> 34..54 samples\r
-         8 bits -> 55..88 samples\r
-         9 bits -> 89..143 samples\r
-        10 bits -> 144..232 samples\r
-        11 bits -> 233..376 samples\r
-        12 bits -> 377..609 samples\r
-        13 bits -> 610..986 samples\r
-        14 bits -> 987..1596 samples\r
-        15 bits -> 1597..2583 samples\r
-        16 bits -> 2584..4180 samples   -> note that a 4k data size guarantees codelength <= 16 bits\r
-        17 bits -> 4181..6764 samples\r
-        18 bits -> 6765..10945 samples\r
-        19 bits -> 10946..17710 samples\r
-        20 bits -> 17711..28656 samples\r
-        21 bits -> 28657..46367 samples\r
-        22 bits -> 46368..75024 samples\r
-        23 bits -> 75025..121392 samples\r
-        24 bits -> 121393..196417 samples\r
-        25 bits -> 196418..317810 samples\r
-        26 bits -> 317811..514228 samples\r
-        27 bits -> 514229..832039 samples\r
-        28 bits -> 832040..1346268 samples\r
-        29 bits -> 1346269..2178308 samples\r
-        30 bits -> 2178309..3524577 samples\r
-        31 bits -> 3524578..5702886 samples\r
-        32 bits -> 5702887..9227464 samples\r
-\r
-    Looking at it differently, here is where powers of 2 fall into these buckets:\r
-\r
-          256 samples -> 11 bits max\r
-          512 samples -> 12 bits max\r
-           1k samples -> 14 bits max\r
-           2k samples -> 15 bits max\r
-           4k samples -> 16 bits max\r
-           8k samples -> 18 bits max\r
-          16k samples -> 19 bits max\r
-          32k samples -> 21 bits max\r
-          64k samples -> 22 bits max\r
-         128k samples -> 24 bits max\r
-         256k samples -> 25 bits max\r
-         512k samples -> 27 bits max\r
-           1M samples -> 28 bits max\r
-           2M samples -> 29 bits max\r
-           4M samples -> 31 bits max\r
-           8M samples -> 32 bits max\r
-\r
-****************************************************************************\r
-\r
-    Delta-RLE encoding works as follows:\r
-\r
-    Starting value is assumed to be 0. All data is encoded as a delta\r
-    from the previous value, such that final[i] = final[i - 1] + delta.\r
-    Long runs of 0s are RLE-encoded as follows:\r
-\r
-        0x100 = repeat count of 8\r
-        0x101 = repeat count of 9\r
-        0x102 = repeat count of 10\r
-        0x103 = repeat count of 11\r
-        0x104 = repeat count of 12\r
-        0x105 = repeat count of 13\r
-        0x106 = repeat count of 14\r
-        0x107 = repeat count of 15\r
-        0x108 = repeat count of 16\r
-        0x109 = repeat count of 32\r
-        0x10a = repeat count of 64\r
-        0x10b = repeat count of 128\r
-        0x10c = repeat count of 256\r
-        0x10d = repeat count of 512\r
-        0x10e = repeat count of 1024\r
-        0x10f = repeat count of 2048\r
-\r
-    Note that repeat counts are reset at the end of a row, so if a 0 run\r
-    extends to the end of a row, a large repeat count may be used.\r
-\r
-    The reason for starting the run counts at 8 is that 0 is expected to\r
-    be the most common symbol, and is typically encoded in 1 or 2 bits.\r
-\r
-***************************************************************************/\r
-\r
-#include <stdlib.h>\r
-#include <assert.h>\r
-#include <stdio.h>\r
-#include <string.h>\r
-\r
-#include "huffman.h"\r
-\r
-#define MAX(x,y) ((x) > (y) ? (x) : (y))\r
-\r
-//**************************************************************************\r
-//  MACROS\r
-//**************************************************************************\r
-\r
-#define MAKE_LOOKUP(code,bits)  (((code) << 5) | ((bits) & 0x1f))\r
-\r
-\r
-//**************************************************************************\r
-//  IMPLEMENTATION\r
-//**************************************************************************\r
-\r
-//-------------------------------------------------\r
-//  huffman_context_base - create an encoding/\r
-//  decoding context\r
-//-------------------------------------------------\r
-\r
-struct huffman_decoder* create_huffman_decoder(int numcodes, int maxbits)\r
-{\r
-   struct huffman_decoder* decoder;\r
-\r
-       /* limit to 24 bits */\r
-       if (maxbits > 24)\r
-               return NULL;\r
-\r
-       decoder = (struct huffman_decoder*)malloc(sizeof(struct huffman_decoder));\r
-       decoder->numcodes = numcodes;\r
-       decoder->maxbits = maxbits;\r
-       decoder->lookup = (lookup_value*)malloc(sizeof(lookup_value) * (1 << maxbits));\r
-       decoder->huffnode = (struct node_t*)malloc(sizeof(struct node_t) * numcodes);\r
-       decoder->datahisto = NULL;\r
-       decoder->prevdata = 0;\r
-       decoder->rleremaining = 0;\r
-       return decoder;\r
-}\r
-\r
-//-------------------------------------------------\r
-//  decode_one - decode a single code from the\r
-//  huffman stream\r
-//-------------------------------------------------\r
-\r
-uint32_t huffman_decode_one(struct huffman_decoder* decoder, struct bitstream* bitbuf)\r
-{\r
-       /* peek ahead to get maxbits worth of data */\r
-       uint32_t bits = bitstream_peek(bitbuf, decoder->maxbits);\r
-\r
-       /* look it up, then remove the actual number of bits for this code */\r
-       lookup_value lookup = decoder->lookup[bits];\r
-       bitstream_remove(bitbuf, lookup & 0x1f);\r
-\r
-       /* return the value */\r
-       return lookup >> 5;\r
-}\r
-\r
-//-------------------------------------------------\r
-//  import_tree_rle - import an RLE-encoded\r
-//  huffman tree from a source data stream\r
-//-------------------------------------------------\r
-\r
-enum huffman_error huffman_import_tree_rle(struct huffman_decoder* decoder, struct bitstream* bitbuf)\r
-{\r
-   enum huffman_error error;\r
-       int curnode;\r
-       // bits per entry depends on the maxbits\r
-       int numbits;\r
-       if (decoder->maxbits >= 16)\r
-               numbits = 5;\r
-       else if (decoder->maxbits >= 8)\r
-               numbits = 4;\r
-       else\r
-               numbits = 3;\r
-\r
-       // loop until we read all the nodes\r
-       for (curnode = 0; curnode < decoder->numcodes; )\r
-       {\r
-               // a non-one value is just raw\r
-               int nodebits = bitstream_read(bitbuf, numbits);\r
-               if (nodebits != 1)\r
-                       decoder->huffnode[curnode++].numbits = nodebits;\r
-\r
-               // a one value is an escape code\r
-               else\r
-               {\r
-                       // a double 1 is just a single 1\r
-                       nodebits = bitstream_read(bitbuf, numbits);\r
-                       if (nodebits == 1)\r
-                               decoder->huffnode[curnode++].numbits = nodebits;\r
-\r
-                       // otherwise, we need one for value for the repeat count\r
-                       else\r
-                       {\r
-                               int repcount = bitstream_read(bitbuf, numbits) + 3;\r
-                               while (repcount--)\r
-                                       decoder->huffnode[curnode++].numbits = nodebits;\r
-                       }\r
-               }\r
-       }\r
-\r
-       // make sure we ended up with the right number\r
-       if (curnode != decoder->numcodes)\r
-               return HUFFERR_INVALID_DATA;\r
-\r
-       // assign canonical codes for all nodes based on their code lengths\r
-       error = huffman_assign_canonical_codes(decoder);\r
-       if (error != HUFFERR_NONE)\r
-               return error;\r
-\r
-       // build the lookup table\r
-       huffman_build_lookup_table(decoder);\r
-\r
-       // determine final input length and report errors\r
-       return bitstream_overflow(bitbuf) ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;\r
-}\r
-\r
-\r
-//-------------------------------------------------\r
-//  import_tree_huffman - import a huffman-encoded\r
-//  huffman tree from a source data stream\r
-//-------------------------------------------------\r
-\r
-enum huffman_error huffman_import_tree_huffman(struct huffman_decoder* decoder, struct bitstream* bitbuf)\r
-{\r
-   int index;\r
-   int start;\r
-       int count = 0;\r
-       uint8_t rlefullbits = 0;\r
-       int last = 0;\r
-       int curcode;\r
-   enum huffman_error error;\r
-   uint32_t temp;\r
-       // start by parsing the lengths for the small tree\r
-       struct huffman_decoder* smallhuff = create_huffman_decoder(24, 6);\r
-\r
-       smallhuff->huffnode[0].numbits = bitstream_read(bitbuf, 3);\r
-       start = bitstream_read(bitbuf, 3) + 1;\r
-\r
-       for (index = 1; index < 24; index++)\r
-       {\r
-               if (index < start || count == 7)\r
-                       smallhuff->huffnode[index].numbits = 0;\r
-               else\r
-               {\r
-                       count = bitstream_read(bitbuf, 3);\r
-                       smallhuff->huffnode[index].numbits = (count == 7) ? 0 : count;\r
-               }\r
-       }\r
-\r
-       // then regenerate the tree\r
-       error = huffman_assign_canonical_codes(smallhuff);\r
-       if (error != HUFFERR_NONE)\r
-               return error;\r
-       huffman_build_lookup_table(smallhuff);\r
-\r
-       // determine the maximum length of an RLE count\r
-       temp = decoder->numcodes - 9;\r
-       while (temp != 0)\r
-               temp >>= 1, rlefullbits++;\r
-\r
-       // now process the rest of the data\r
-       for (curcode = 0; curcode < decoder->numcodes; )\r
-       {\r
-               int value = huffman_decode_one(smallhuff, bitbuf);\r
-               if (value != 0)\r
-                       decoder->huffnode[curcode++].numbits = last = value - 1;\r
-               else\r
-               {\r
-                       int count = bitstream_read(bitbuf, 3) + 2;\r
-                       if (count == 7+2)\r
-                               count += bitstream_read(bitbuf, rlefullbits);\r
-                       for ( ; count != 0 && curcode < decoder->numcodes; count--)\r
-                               decoder->huffnode[curcode++].numbits = last;\r
-               }\r
-       }\r
-\r
-       // make sure we ended up with the right number\r
-       if (curcode != decoder->numcodes)\r
-               return HUFFERR_INVALID_DATA;\r
-\r
-       // assign canonical codes for all nodes based on their code lengths\r
-       error = huffman_assign_canonical_codes(decoder);\r
-       if (error != HUFFERR_NONE)\r
-               return error;\r
-\r
-       // build the lookup table\r
-       huffman_build_lookup_table(decoder);\r
-\r
-       // determine final input length and report errors\r
-       return bitstream_overflow(bitbuf) ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;\r
-}\r
-\r
-\r
-//-------------------------------------------------\r
-//  compute_tree_from_histo - common backend for\r
-//  computing a tree based on the data histogram\r
-//-------------------------------------------------\r
-\r
-enum huffman_error huffman_compute_tree_from_histo(struct huffman_decoder* decoder)\r
-{\r
-   int i;\r
-   uint32_t upperweight;\r
-       uint32_t lowerweight = 0;\r
-       // compute the number of data items in the histogram\r
-       uint32_t sdatacount = 0;\r
-       for (i = 0; i < decoder->numcodes; i++)\r
-               sdatacount += decoder->datahisto[i];\r
-\r
-       // binary search to achieve the optimum encoding\r
-       upperweight = sdatacount * 2;\r
-       while (1)\r
-       {\r
-               // build a tree using the current weight\r
-               uint32_t curweight = (upperweight + lowerweight) / 2;\r
-               int curmaxbits = huffman_build_tree(decoder, sdatacount, curweight);\r
-\r
-               // apply binary search here\r
-               if (curmaxbits <= decoder->maxbits)\r
-               {\r
-                       lowerweight = curweight;\r
-\r
-                       // early out if it worked with the raw weights, or if we're done searching\r
-                       if (curweight == sdatacount || (upperweight - lowerweight) <= 1)\r
-                               break;\r
-               }\r
-               else\r
-                       upperweight = curweight;\r
-       }\r
-\r
-       // assign canonical codes for all nodes based on their code lengths\r
-       return huffman_assign_canonical_codes(decoder);\r
-}\r
-\r
-\r
-\r
-//**************************************************************************\r
-//  INTERNAL FUNCTIONS\r
-//**************************************************************************\r
-\r
-//-------------------------------------------------\r
-//  tree_node_compare - compare two tree nodes\r
-//  by weight\r
-//-------------------------------------------------\r
-\r
-static int huffman_tree_node_compare(const void *item1, const void *item2)\r
-{\r
-       const struct node_t *node1 = *(const struct node_t **)item1;\r
-       const struct node_t *node2 = *(const struct node_t **)item2;\r
-       if (node2->weight != node1->weight)\r
-               return node2->weight - node1->weight;\r
-       if (node2->bits - node1->bits == 0)\r
-               fprintf(stderr, "identical node sort keys, should not happen!\n");\r
-       return (int)node1->bits - (int)node2->bits;\r
-}\r
-\r
-\r
-//-------------------------------------------------\r
-//  build_tree - build a huffman tree based on the\r
-//  data distribution\r
-//-------------------------------------------------\r
-\r
-int huffman_build_tree(struct huffman_decoder* decoder, uint32_t totaldata, uint32_t totalweight)\r
-{\r
-   int curcode;\r
-   int nextalloc;\r
-       int maxbits = 0;\r
-       // make a list of all non-zero nodes\r
-       struct node_t** list = (struct node_t**)malloc(sizeof(struct node_t*) * decoder->numcodes * 2);\r
-       int listitems = 0;\r
-       memset(decoder->huffnode, 0, decoder->numcodes * sizeof(decoder->huffnode[0]));\r
-       for (curcode = 0; curcode < decoder->numcodes; curcode++)\r
-               if (decoder->datahisto[curcode] != 0)\r
-               {\r
-                       list[listitems++] = &decoder->huffnode[curcode];\r
-                       decoder->huffnode[curcode].count = decoder->datahisto[curcode];\r
-                       decoder->huffnode[curcode].bits = curcode;\r
-\r
-                       // scale the weight by the current effective length, ensuring we don't go to 0\r
-                       decoder->huffnode[curcode].weight = ((uint64_t)decoder->datahisto[curcode]) * ((uint64_t)totalweight) / ((uint64_t)totaldata);\r
-                       if (decoder->huffnode[curcode].weight == 0)\r
-                               decoder->huffnode[curcode].weight = 1;\r
-               }\r
-/*\r
-        fprintf(stderr, "Pre-sort:\n");\r
-        for (int i = 0; i < listitems; i++) {\r
-            fprintf(stderr, "weight: %d code: %d\n", list[i]->m_weight, list[i]->m_bits);\r
-        }\r
-*/\r
-       // sort the list by weight, largest weight first\r
-       qsort(&list[0], listitems, sizeof(list[0]), huffman_tree_node_compare);\r
-/*\r
-        fprintf(stderr, "Post-sort:\n");\r
-        for (int i = 0; i < listitems; i++) {\r
-            fprintf(stderr, "weight: %d code: %d\n", list[i]->m_weight, list[i]->m_bits);\r
-        }\r
-        fprintf(stderr, "===================\n");\r
-*/\r
-       // now build the tree\r
-       nextalloc = decoder->numcodes;\r
-\r
-       while (listitems > 1)\r
-       {\r
-               int curitem;\r
-               // remove lowest two items\r
-               struct node_t* node1 = &(*list[--listitems]);\r
-               struct node_t* node0 = &(*list[--listitems]);\r
-\r
-               // create new node\r
-               struct node_t* newnode = &decoder->huffnode[nextalloc++];\r
-               newnode->parent = NULL;\r
-               node0->parent = node1->parent = newnode;\r
-               newnode->weight = node0->weight + node1->weight;\r
-\r
-               // insert into list at appropriate location\r
-               for (curitem = 0; curitem < listitems; curitem++)\r
-                       if (newnode->weight > list[curitem]->weight)\r
-                       {\r
-                               memmove(&list[curitem+1], &list[curitem], (listitems - curitem) * sizeof(list[0]));\r
-                               break;\r
-                       }\r
-               list[curitem] = newnode;\r
-               listitems++;\r
-       }\r
-\r
-       // compute the number of bits in each code, and fill in another histogram\r
-       for (curcode = 0; curcode < decoder->numcodes; curcode++)\r
-       {\r
-               struct node_t* node = &decoder->huffnode[curcode];\r
-               node->numbits = 0;\r
-               node->bits = 0;\r
-\r
-               // if we have a non-zero weight, compute the number of bits\r
-               if (node->weight > 0)\r
-               {\r
-         struct node_t *curnode;\r
-                       // determine the number of bits for this node\r
-                       for (curnode = node; curnode->parent != NULL; curnode = curnode->parent)\r
-                               node->numbits++;\r
-                       if (node->numbits == 0)\r
-                               node->numbits = 1;\r
-\r
-                       // keep track of the max\r
-                       maxbits = MAX(maxbits, ((int)node->numbits));\r
-               }\r
-       }\r
-       return maxbits;\r
-}\r
-\r
-\r
-//-------------------------------------------------\r
-//  assign_canonical_codes - assign canonical codes\r
-//  to all the nodes based on the number of bits\r
-//  in each\r
-//-------------------------------------------------\r
-\r
-enum huffman_error huffman_assign_canonical_codes(struct huffman_decoder* decoder)\r
-{\r
-   int curcode, codelen;\r
-       uint32_t curstart = 0;\r
-\r
-       // build up a histogram of bit lengths\r
-       uint32_t bithisto[33] = { 0 };\r
-       for (curcode = 0; curcode < decoder->numcodes; curcode++)\r
-       {\r
-               struct node_t* node = &decoder->huffnode[curcode];\r
-               if (node->numbits > decoder->maxbits)\r
-                       return HUFFERR_INTERNAL_INCONSISTENCY;\r
-               if (node->numbits <= 32)\r
-                       bithisto[node->numbits]++;\r
-       }\r
-\r
-       // for each code length, determine the starting code number\r
-       for (codelen = 32; codelen > 0; codelen--)\r
-       {\r
-               uint32_t nextstart = (curstart + bithisto[codelen]) >> 1;\r
-               if (codelen != 1 && nextstart * 2 != (curstart + bithisto[codelen]))\r
-                       return HUFFERR_INTERNAL_INCONSISTENCY;\r
-               bithisto[codelen] = curstart;\r
-               curstart = nextstart;\r
-       }\r
-\r
-       // now assign canonical codes\r
-       for (curcode = 0; curcode < decoder->numcodes; curcode++)\r
-       {\r
-               struct node_t* node = &decoder->huffnode[curcode];\r
-               if (node->numbits > 0)\r
-                       node->bits = bithisto[node->numbits]++;\r
-       }\r
-       return HUFFERR_NONE;\r
-}\r
-\r
-\r
-//-------------------------------------------------\r
-//  build_lookup_table - build a lookup table for\r
-//  fast decoding\r
-//-------------------------------------------------\r
-\r
-void huffman_build_lookup_table(struct huffman_decoder* decoder)\r
-{\r
-   int curcode;\r
-       // iterate over all codes\r
-       for (curcode = 0; curcode < decoder->numcodes; curcode++)\r
-       {\r
-               // process all nodes which have non-zero bits\r
-               struct node_t* node = &decoder->huffnode[curcode];\r
-               if (node->numbits > 0)\r
-               {\r
-         int shift;\r
-         lookup_value *dest;\r
-         lookup_value *destend;\r
-\r
-                       // set up the entry\r
-                       lookup_value value = MAKE_LOOKUP(curcode, node->numbits);\r
-\r
-                       // fill all matching entries\r
-                       shift   = decoder->maxbits - node->numbits;\r
-                       dest    = &decoder->lookup[node->bits << shift];\r
-                       destend = &decoder->lookup[((node->bits + 1) << shift) - 1];\r
-\r
-                       while (dest <= destend)\r
-                               *dest++ = value;\r
-               }\r
-       }\r
-}\r
+/* license:BSD-3-Clause
+ * copyright-holders:Aaron Giles
+****************************************************************************
+
+    huffman.c
+
+    Static Huffman compression and decompression helpers.
+
+****************************************************************************
+
+    Maximum codelength is officially (alphabetsize - 1). This would be 255 bits
+    (since we use 1 byte values). However, it is also dependent upon the number
+    of samples used, as follows:
+
+         2 bits -> 3..4 samples
+         3 bits -> 5..7 samples
+         4 bits -> 8..12 samples
+         5 bits -> 13..20 samples
+         6 bits -> 21..33 samples
+         7 bits -> 34..54 samples
+         8 bits -> 55..88 samples
+         9 bits -> 89..143 samples
+        10 bits -> 144..232 samples
+        11 bits -> 233..376 samples
+        12 bits -> 377..609 samples
+        13 bits -> 610..986 samples
+        14 bits -> 987..1596 samples
+        15 bits -> 1597..2583 samples
+        16 bits -> 2584..4180 samples   -> note that a 4k data size guarantees codelength <= 16 bits
+        17 bits -> 4181..6764 samples
+        18 bits -> 6765..10945 samples
+        19 bits -> 10946..17710 samples
+        20 bits -> 17711..28656 samples
+        21 bits -> 28657..46367 samples
+        22 bits -> 46368..75024 samples
+        23 bits -> 75025..121392 samples
+        24 bits -> 121393..196417 samples
+        25 bits -> 196418..317810 samples
+        26 bits -> 317811..514228 samples
+        27 bits -> 514229..832039 samples
+        28 bits -> 832040..1346268 samples
+        29 bits -> 1346269..2178308 samples
+        30 bits -> 2178309..3524577 samples
+        31 bits -> 3524578..5702886 samples
+        32 bits -> 5702887..9227464 samples
+
+    Looking at it differently, here is where powers of 2 fall into these buckets:
+
+          256 samples -> 11 bits max
+          512 samples -> 12 bits max
+           1k samples -> 14 bits max
+           2k samples -> 15 bits max
+           4k samples -> 16 bits max
+           8k samples -> 18 bits max
+          16k samples -> 19 bits max
+          32k samples -> 21 bits max
+          64k samples -> 22 bits max
+         128k samples -> 24 bits max
+         256k samples -> 25 bits max
+         512k samples -> 27 bits max
+           1M samples -> 28 bits max
+           2M samples -> 29 bits max
+           4M samples -> 31 bits max
+           8M samples -> 32 bits max
+
+****************************************************************************
+
+    Delta-RLE encoding works as follows:
+
+    Starting value is assumed to be 0. All data is encoded as a delta
+    from the previous value, such that final[i] = final[i - 1] + delta.
+    Long runs of 0s are RLE-encoded as follows:
+
+        0x100 = repeat count of 8
+        0x101 = repeat count of 9
+        0x102 = repeat count of 10
+        0x103 = repeat count of 11
+        0x104 = repeat count of 12
+        0x105 = repeat count of 13
+        0x106 = repeat count of 14
+        0x107 = repeat count of 15
+        0x108 = repeat count of 16
+        0x109 = repeat count of 32
+        0x10a = repeat count of 64
+        0x10b = repeat count of 128
+        0x10c = repeat count of 256
+        0x10d = repeat count of 512
+        0x10e = repeat count of 1024
+        0x10f = repeat count of 2048
+
+    Note that repeat counts are reset at the end of a row, so if a 0 run
+    extends to the end of a row, a large repeat count may be used.
+
+    The reason for starting the run counts at 8 is that 0 is expected to
+    be the most common symbol, and is typically encoded in 1 or 2 bits.
+
+***************************************************************************/
+
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "huffman.h"
+
+#define MAX(x,y) ((x) > (y) ? (x) : (y))
+
+/***************************************************************************
+ *  MACROS
+ ***************************************************************************
+ */
+
+#define MAKE_LOOKUP(code,bits)  (((code) << 5) | ((bits) & 0x1f))
+
+/***************************************************************************
+ *  IMPLEMENTATION
+ ***************************************************************************
+ */
+
+/*-------------------------------------------------
+ *  huffman_context_base - create an encoding/
+ *  decoding context
+ *-------------------------------------------------
+ */
+
+struct huffman_decoder* create_huffman_decoder(int numcodes, int maxbits)
+{
+       /* limit to 24 bits */
+       if (maxbits > 24)
+               return NULL;
+
+       struct huffman_decoder* decoder = (struct huffman_decoder*)malloc(sizeof(struct huffman_decoder));
+       decoder->numcodes = numcodes;
+       decoder->maxbits = maxbits;
+       decoder->lookup = (lookup_value*)malloc(sizeof(lookup_value) * (1 << maxbits));
+       decoder->huffnode = (struct node_t*)malloc(sizeof(struct node_t) * numcodes);
+       decoder->datahisto = NULL;
+       decoder->prevdata = 0;
+       decoder->rleremaining = 0;
+       return decoder;
+}
+
+/*-------------------------------------------------
+ *  decode_one - decode a single code from the
+ *  huffman stream
+ *-------------------------------------------------
+ */
+
+uint32_t huffman_decode_one(struct huffman_decoder* decoder, struct bitstream* bitbuf)
+{
+       /* peek ahead to get maxbits worth of data */
+       uint32_t bits = bitstream_peek(bitbuf, decoder->maxbits);
+
+       /* look it up, then remove the actual number of bits for this code */
+       lookup_value lookup = decoder->lookup[bits];
+       bitstream_remove(bitbuf, lookup & 0x1f);
+
+       /* return the value */
+       return lookup >> 5;
+}
+
+/*-------------------------------------------------
+ *  import_tree_rle - import an RLE-encoded
+ *  huffman tree from a source data stream
+ *-------------------------------------------------
+ */
+
+enum huffman_error huffman_import_tree_rle(struct huffman_decoder* decoder, struct bitstream* bitbuf)
+{
+       /* bits per entry depends on the maxbits */
+       int numbits;
+       if (decoder->maxbits >= 16)
+               numbits = 5;
+       else if (decoder->maxbits >= 8)
+               numbits = 4;
+       else
+               numbits = 3;
+
+       /* loop until we read all the nodes */
+       int curnode;
+       for (curnode = 0; curnode < decoder->numcodes; )
+       {
+               /* a non-one value is just raw */
+               int nodebits = bitstream_read(bitbuf, numbits);
+               if (nodebits != 1)
+                       decoder->huffnode[curnode++].numbits = nodebits;
+
+               /* a one value is an escape code */
+               else
+               {
+                       /* a double 1 is just a single 1 */
+                       nodebits = bitstream_read(bitbuf, numbits);
+                       if (nodebits == 1)
+                               decoder->huffnode[curnode++].numbits = nodebits;
+
+                       /* otherwise, we need one for value for the repeat count */
+                       else
+                       {
+                               int repcount = bitstream_read(bitbuf, numbits) + 3;
+                               while (repcount--)
+                                       decoder->huffnode[curnode++].numbits = nodebits;
+                       }
+               }
+       }
+
+       /* make sure we ended up with the right number */
+       if (curnode != decoder->numcodes)
+               return HUFFERR_INVALID_DATA;
+
+       /* assign canonical codes for all nodes based on their code lengths */
+       enum huffman_error error = huffman_assign_canonical_codes(decoder);
+       if (error != HUFFERR_NONE)
+               return error;
+
+       /* build the lookup table */
+       huffman_build_lookup_table(decoder);
+
+       /* determine final input length and report errors */
+       return bitstream_overflow(bitbuf) ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ *  import_tree_huffman - import a huffman-encoded
+ *  huffman tree from a source data stream
+ *-------------------------------------------------
+ */
+
+enum huffman_error huffman_import_tree_huffman(struct huffman_decoder* decoder, struct bitstream* bitbuf)
+{
+       /* start by parsing the lengths for the small tree */
+       struct huffman_decoder* smallhuff = create_huffman_decoder(24, 6);
+       smallhuff->huffnode[0].numbits = bitstream_read(bitbuf, 3);
+       int start = bitstream_read(bitbuf, 3) + 1;
+       int count = 0;
+       for (int index = 1; index < 24; index++)
+       {
+               if (index < start || count == 7)
+                       smallhuff->huffnode[index].numbits = 0;
+               else
+               {
+                       count = bitstream_read(bitbuf, 3);
+                       smallhuff->huffnode[index].numbits = (count == 7) ? 0 : count;
+               }
+       }
+
+       /* then regenerate the tree */
+       enum huffman_error error = huffman_assign_canonical_codes(smallhuff);
+       if (error != HUFFERR_NONE)
+               return error;
+       huffman_build_lookup_table(smallhuff);
+
+       /* determine the maximum length of an RLE count */
+       uint32_t temp = decoder->numcodes - 9;
+       uint8_t rlefullbits = 0;
+       while (temp != 0)
+               temp >>= 1, rlefullbits++;
+
+       /* now process the rest of the data */
+       int last = 0;
+       int curcode;
+       for (curcode = 0; curcode < decoder->numcodes; )
+       {
+               int value = huffman_decode_one(smallhuff, bitbuf);
+               if (value != 0)
+                       decoder->huffnode[curcode++].numbits = last = value - 1;
+               else
+               {
+                       int count = bitstream_read(bitbuf, 3) + 2;
+                       if (count == 7+2)
+                               count += bitstream_read(bitbuf, rlefullbits);
+                       for ( ; count != 0 && curcode < decoder->numcodes; count--)
+                               decoder->huffnode[curcode++].numbits = last;
+               }
+       }
+
+       /* make sure we ended up with the right number */
+       if (curcode != decoder->numcodes)
+               return HUFFERR_INVALID_DATA;
+
+       /* assign canonical codes for all nodes based on their code lengths */
+       error = huffman_assign_canonical_codes(decoder);
+       if (error != HUFFERR_NONE)
+               return error;
+
+       /* build the lookup table */
+       huffman_build_lookup_table(decoder);
+
+       /* determine final input length and report errors */
+       return bitstream_overflow(bitbuf) ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
+}
+
+/*-------------------------------------------------
+ *  compute_tree_from_histo - common backend for
+ *  computing a tree based on the data histogram
+ *-------------------------------------------------
+ */
+
+enum huffman_error huffman_compute_tree_from_histo(struct huffman_decoder* decoder)
+{
+       /* compute the number of data items in the histogram */
+       uint32_t sdatacount = 0;
+       for (int i = 0; i < decoder->numcodes; i++)
+               sdatacount += decoder->datahisto[i];
+
+       /* binary search to achieve the optimum encoding */
+       uint32_t lowerweight = 0;
+       uint32_t upperweight = sdatacount * 2;
+       while (1)
+       {
+               /* build a tree using the current weight */
+               uint32_t curweight = (upperweight + lowerweight) / 2;
+               int curmaxbits = huffman_build_tree(decoder, sdatacount, curweight);
+
+               /* apply binary search here */
+               if (curmaxbits <= decoder->maxbits)
+               {
+                       lowerweight = curweight;
+
+                       /* early out if it worked with the raw weights, or if we're done searching */
+                       if (curweight == sdatacount || (upperweight - lowerweight) <= 1)
+                               break;
+               }
+               else
+                       upperweight = curweight;
+       }
+
+       /* assign canonical codes for all nodes based on their code lengths */
+       return huffman_assign_canonical_codes(decoder);
+}
+
+/***************************************************************************
+ *  INTERNAL FUNCTIONS
+ ***************************************************************************
+ */
+
+/*-------------------------------------------------
+ *  tree_node_compare - compare two tree nodes
+ *  by weight
+ *-------------------------------------------------
+ */
+
+static int huffman_tree_node_compare(const void *item1, const void *item2)
+{
+       const struct node_t *node1 = *(const struct node_t **)item1;
+       const struct node_t *node2 = *(const struct node_t **)item2;
+       if (node2->weight != node1->weight)
+               return node2->weight - node1->weight;
+       if (node2->bits - node1->bits == 0)
+               fprintf(stderr, "identical node sort keys, should not happen!\n");
+       return (int)node1->bits - (int)node2->bits;
+}
+
+/*-------------------------------------------------
+ *  build_tree - build a huffman tree based on the
+ *  data distribution
+ *-------------------------------------------------
+ */
+
+int huffman_build_tree(struct huffman_decoder* decoder, uint32_t totaldata, uint32_t totalweight)
+{
+       /* make a list of all non-zero nodes */
+       struct node_t** list = (struct node_t**)malloc(sizeof(struct node_t*) * decoder->numcodes * 2);
+       int listitems = 0;
+       memset(decoder->huffnode, 0, decoder->numcodes * sizeof(decoder->huffnode[0]));
+       for (int curcode = 0; curcode < decoder->numcodes; curcode++)
+               if (decoder->datahisto[curcode] != 0)
+               {
+                       list[listitems++] = &decoder->huffnode[curcode];
+                       decoder->huffnode[curcode].count = decoder->datahisto[curcode];
+                       decoder->huffnode[curcode].bits = curcode;
+
+                       /* scale the weight by the current effective length, ensuring we don't go to 0 */
+                       decoder->huffnode[curcode].weight = ((uint64_t)decoder->datahisto[curcode]) * ((uint64_t)totalweight) / ((uint64_t)totaldata);
+                       if (decoder->huffnode[curcode].weight == 0)
+                               decoder->huffnode[curcode].weight = 1;
+               }
+
+#if 0
+        fprintf(stderr, "Pre-sort:\n");
+        for (int i = 0; i < listitems; i++) {
+            fprintf(stderr, "weight: %d code: %d\n", list[i]->m_weight, list[i]->m_bits);
+        }
+#endif
+
+       /* sort the list by weight, largest weight first */
+       qsort(&list[0], listitems, sizeof(list[0]), huffman_tree_node_compare);
+
+#if 0
+        fprintf(stderr, "Post-sort:\n");
+        for (int i = 0; i < listitems; i++) {
+            fprintf(stderr, "weight: %d code: %d\n", list[i]->m_weight, list[i]->m_bits);
+        }
+        fprintf(stderr, "===================\n");
+#endif
+
+       /* now build the tree */
+       int nextalloc = decoder->numcodes;
+       while (listitems > 1)
+       {
+               /* remove lowest two items */
+               struct node_t* node1 = &(*list[--listitems]);
+               struct node_t* node0 = &(*list[--listitems]);
+
+               /* create new node */
+               struct node_t* newnode = &decoder->huffnode[nextalloc++];
+               newnode->parent = NULL;
+               node0->parent = node1->parent = newnode;
+               newnode->weight = node0->weight + node1->weight;
+
+               /* insert into list at appropriate location */
+               int curitem;
+               for (curitem = 0; curitem < listitems; curitem++)
+                       if (newnode->weight > list[curitem]->weight)
+                       {
+                               memmove(&list[curitem+1], &list[curitem], (listitems - curitem) * sizeof(list[0]));
+                               break;
+                       }
+               list[curitem] = newnode;
+               listitems++;
+       }
+
+       /* compute the number of bits in each code, and fill in another histogram */
+       int maxbits = 0;
+       for (int curcode = 0; curcode < decoder->numcodes; curcode++)
+       {
+               struct node_t* node = &decoder->huffnode[curcode];
+               node->numbits = 0;
+               node->bits = 0;
+
+               /* if we have a non-zero weight, compute the number of bits */
+               if (node->weight > 0)
+               {
+                       /* determine the number of bits for this node */
+                       for (struct node_t *curnode = node; curnode->parent != NULL; curnode = curnode->parent)
+                               node->numbits++;
+                       if (node->numbits == 0)
+                               node->numbits = 1;
+
+                       /* keep track of the max */
+                       maxbits = MAX(maxbits, ((int)node->numbits));
+               }
+       }
+       return maxbits;
+}
+
+/*-------------------------------------------------
+ *  assign_canonical_codes - assign canonical codes
+ *  to all the nodes based on the number of bits
+ *  in each
+ *-------------------------------------------------
+ */
+
+enum huffman_error huffman_assign_canonical_codes(struct huffman_decoder* decoder)
+{
+       /* build up a histogram of bit lengths */
+       uint32_t bithisto[33] = { 0 };
+       for (int curcode = 0; curcode < decoder->numcodes; curcode++)
+       {
+               struct node_t* node = &decoder->huffnode[curcode];
+               if (node->numbits > decoder->maxbits)
+                       return HUFFERR_INTERNAL_INCONSISTENCY;
+               if (node->numbits <= 32)
+                       bithisto[node->numbits]++;
+       }
+
+       /* for each code length, determine the starting code number */
+       uint32_t curstart = 0;
+       for (int codelen = 32; codelen > 0; codelen--)
+       {
+               uint32_t nextstart = (curstart + bithisto[codelen]) >> 1;
+               if (codelen != 1 && nextstart * 2 != (curstart + bithisto[codelen]))
+                       return HUFFERR_INTERNAL_INCONSISTENCY;
+               bithisto[codelen] = curstart;
+               curstart = nextstart;
+       }
+
+       /* now assign canonical codes */
+       for (int curcode = 0; curcode < decoder->numcodes; curcode++)
+       {
+               struct node_t* node = &decoder->huffnode[curcode];
+               if (node->numbits > 0)
+                       node->bits = bithisto[node->numbits]++;
+       }
+       return HUFFERR_NONE;
+}
+
+/*-------------------------------------------------
+ *  build_lookup_table - build a lookup table for
+ *  fast decoding
+ *-------------------------------------------------
+ */
+
+void huffman_build_lookup_table(struct huffman_decoder* decoder)
+{
+       /* iterate over all codes */
+       for (int curcode = 0; curcode < decoder->numcodes; curcode++)
+       {
+               /* process all nodes which have non-zero bits */
+               struct node_t* node = &decoder->huffnode[curcode];
+               if (node->numbits > 0)
+               {
+                       /* set up the entry */
+                       lookup_value value = MAKE_LOOKUP(curcode, node->numbits);
+
+                       /* fill all matching entries */
+                       int shift = decoder->maxbits - node->numbits;
+                       lookup_value *dest = &decoder->lookup[node->bits << shift];
+                       lookup_value *destend = &decoder->lookup[((node->bits + 1) << shift) - 1];
+                       while (dest <= destend)
+                               *dest++ = value;
+               }
+       }
+}
index 71de399..8bcc45a 100644 (file)
@@ -1,87 +1,89 @@
-// license:BSD-3-Clause\r
-// copyright-holders:Aaron Giles\r
-/***************************************************************************\r
-\r
-    huffman.h\r
-\r
-    Static Huffman compression and decompression helpers.\r
-\r
-***************************************************************************/\r
-\r
-#pragma once\r
-\r
-#ifndef __HUFFMAN_H__\r
-#define __HUFFMAN_H__\r
-\r
-#include "bitstream.h"\r
-\r
-\r
-//**************************************************************************\r
-//  CONSTANTS\r
-//**************************************************************************\r
-\r
-enum huffman_error\r
-{\r
-       HUFFERR_NONE = 0,\r
-       HUFFERR_TOO_MANY_BITS,\r
-       HUFFERR_INVALID_DATA,\r
-       HUFFERR_INPUT_BUFFER_TOO_SMALL,\r
-       HUFFERR_OUTPUT_BUFFER_TOO_SMALL,\r
-       HUFFERR_INTERNAL_INCONSISTENCY,\r
-       HUFFERR_TOO_MANY_CONTEXTS\r
-};\r
-\r
-\r
-\r
-//**************************************************************************\r
-//  TYPE DEFINITIONS\r
-//**************************************************************************\r
-\r
-typedef uint16_t lookup_value;\r
-\r
-// a node in the huffman tree\r
-struct node_t\r
-{\r
-       struct node_t*          parent;         // pointer to parent node\r
-       uint32_t                        count;          // number of hits on this node\r
-       uint32_t                        weight;         // assigned weight of this node\r
-       uint32_t                        bits;           // bits used to encode the node\r
-       uint8_t                         numbits;        // number of bits needed for this node\r
-};\r
-\r
-// ======================> huffman_context_base\r
-\r
-// context class for decoding\r
-struct huffman_decoder\r
-{\r
-       // internal state\r
-       uint32_t                        numcodes;             // number of total codes being processed\r
-       uint8_t                         maxbits;              // maximum bits per code\r
-       uint8_t                         prevdata;             // value of the previous data (for delta-RLE encoding)\r
-       int                     rleremaining;         // number of RLE bytes remaining (for delta-RLE encoding)\r
-       lookup_value *          lookup;               // pointer to the lookup table\r
-       struct node_t *     huffnode;             // array of nodes\r
-       uint32_t *              datahisto;            // histogram of data values\r
-\r
-       // array versions of the info we need\r
-       //node_t*                       huffnode_array; //[_NumCodes];\r
-       //lookup_value* lookup_array; //[1 << _MaxBits];        \r
-};\r
-\r
-// ======================> huffman_decoder\r
-\r
-struct huffman_decoder* create_huffman_decoder(int numcodes, int maxbits);\r
-\r
-// single item operations\r
-uint32_t huffman_decode_one(struct huffman_decoder* decoder, struct bitstream* bitbuf);\r
-\r
-enum huffman_error huffman_import_tree_rle(struct huffman_decoder* decoder, struct bitstream* bitbuf);\r
-enum huffman_error huffman_import_tree_huffman(struct huffman_decoder* decoder, struct bitstream* bitbuf);\r
-\r
-int huffman_build_tree(struct huffman_decoder* decoder, uint32_t totaldata, uint32_t totalweight);\r
-enum huffman_error huffman_assign_canonical_codes(struct huffman_decoder* decoder);\r
-enum huffman_error huffman_compute_tree_from_histo(struct huffman_decoder* decoder);\r
-\r
-void huffman_build_lookup_table(struct huffman_decoder* decoder);\r
-\r
-#endif\r
+/* license:BSD-3-Clause
+ * copyright-holders:Aaron Giles
+ ***************************************************************************
+
+    huffman.h
+
+    Static Huffman compression and decompression helpers.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __HUFFMAN_H__
+#define __HUFFMAN_H__
+
+#include "bitstream.h"
+
+
+/***************************************************************************
+ *  CONSTANTS
+ ***************************************************************************
+ */
+
+enum huffman_error
+{
+       HUFFERR_NONE = 0,
+       HUFFERR_TOO_MANY_BITS,
+       HUFFERR_INVALID_DATA,
+       HUFFERR_INPUT_BUFFER_TOO_SMALL,
+       HUFFERR_OUTPUT_BUFFER_TOO_SMALL,
+       HUFFERR_INTERNAL_INCONSISTENCY,
+       HUFFERR_TOO_MANY_CONTEXTS
+};
+
+/***************************************************************************
+ *  TYPE DEFINITIONS
+ ***************************************************************************
+ */
+
+typedef uint16_t lookup_value;
+
+/* a node in the huffman tree */
+struct node_t
+{
+       struct node_t*          parent;         /* pointer to parent node */
+       uint32_t                        count;          /* number of hits on this node */
+       uint32_t                        weight;         /* assigned weight of this node */
+       uint32_t                        bits;           /* bits used to encode the node */
+       uint8_t                         numbits;        /* number of bits needed for this node */
+};
+
+/* ======================> huffman_context_base */
+
+/* context class for decoding */
+struct huffman_decoder
+{
+       /* internal state */
+       uint32_t                        numcodes;             /* number of total codes being processed */
+       uint8_t                         maxbits;           /* maximum bits per code */
+       uint8_t                         prevdata;             /* value of the previous data (for delta-RLE encoding) */
+       int                     rleremaining;         /* number of RLE bytes remaining (for delta-RLE encoding) */
+       lookup_value *          lookup;               /* pointer to the lookup table */
+       struct node_t *     huffnode;             /* array of nodes */
+       uint32_t *              datahisto;            /* histogram of data values */
+
+       /* array versions of the info we need */
+#if 0
+       node_t*                 huffnode_array; /* [_NumCodes]; */
+       lookup_value*   lookup_array; /* [1 << _MaxBits]; */
+#endif
+};
+
+/* ======================> huffman_decoder */
+
+struct huffman_decoder* create_huffman_decoder(int numcodes, int maxbits);
+
+/* single item operations */
+uint32_t huffman_decode_one(struct huffman_decoder* decoder, struct bitstream* bitbuf);
+
+enum huffman_error huffman_import_tree_rle(struct huffman_decoder* decoder, struct bitstream* bitbuf);
+enum huffman_error huffman_import_tree_huffman(struct huffman_decoder* decoder, struct bitstream* bitbuf);
+
+int huffman_build_tree(struct huffman_decoder* decoder, uint32_t totaldata, uint32_t totalweight);
+enum huffman_error huffman_assign_canonical_codes(struct huffman_decoder* decoder);
+enum huffman_error huffman_compute_tree_from_histo(struct huffman_decoder* decoder);
+
+void huffman_build_lookup_table(struct huffman_decoder* decoder);
+
+#endif