From: <man...@us...> - 2014-02-04 16:17:35
|
Revision: 3651 http://sourceforge.net/p/modplug/code/3651 Author: manxorist Date: 2014-02-04 16:17:27 +0000 (Tue, 04 Feb 2014) Log Message: ----------- Merged revision(s) 3636-3650 from branches/manx/unpack-cleanup: [Ref] Unpack: Modernize interface (currently does 1 additional copy of unpacked data which will be removed again when the refactoring is finished). ........ [Fix] PP20 unpacker: Make it endian-safe. [Ref] PP20 unpacker: Convert to FileReader and OpenMPT types. ........ [Fix] PP20 unpacker: Add a check back that was missed in r3640. ........ [Ref] XPK unpacker: Convert to FileReader and OpenMPT types. ........ [Fix] MMCMP unpacker: Make it endian-safe. [Fix] MMCMP unpacker: Make on-disk structures PACKED. [Fix] MMCMP unpacker: Remove unaligned memory accesses. [Fix] MMCMP unpacker: When parsing compressed data fails, actually return false instead of just skipping rest of uncompression and returning garbage uncompressed data. [Ref] MMCMP unpacker: Convert to FileReader and OpenMPT types. ........ [Ref] PP20 unpacker: Remove bogus size checks. [Fix] PP20 unpacker: Do not overrun compressed data buffer and fail decompression in that case. ........ [Ref] Tiny cleanups. ........ [Fix] XPK unpacker: Add proper bounds cheking to all src and dst buffer accesses. Error out on failure. ........ [Ref] XPK unpacker: Remove bogus size checks. ........ [Fix] Add missing include. ........ [Ref] MMCMP unpacker: Remove bogus size checks. [Fix] MMCMP unpacker: Fix off-by-one in bounds check for uncompressed data. [Fix] MMCMP unpacker: Properly validate all other destination buffer position and size values. Error out on failure instead of crashing. ........ [Ref] MMCMP unpacker: Fail if hdrsize in the file header does not match our expectations. ........ Revision Links: -------------- http://sourceforge.net/p/modplug/code/3640 Modified Paths: -------------- trunk/OpenMPT/soundlib/Mmcmp.cpp trunk/OpenMPT/soundlib/Sndfile.cpp Property Changed: ---------------- trunk/OpenMPT/ Index: trunk/OpenMPT =================================================================== --- trunk/OpenMPT 2014-02-04 16:14:11 UTC (rev 3650) +++ trunk/OpenMPT 2014-02-04 16:17:27 UTC (rev 3651) Property changes on: trunk/OpenMPT ___________________________________________________________________ Modified: svn:mergeinfo ## -19,3 +19,4 ## /branches/manx/stdstring-names:2223,2228 /branches/manx/stdstring-song-name:2462-2463 /branches/manx/unarchiver:1887-1888 +/branches/manx/unpack-cleanup:3636-3650 \ No newline at end of property Modified: trunk/OpenMPT/soundlib/Mmcmp.cpp =================================================================== --- trunk/OpenMPT/soundlib/Mmcmp.cpp 2014-02-04 16:14:11 UTC (rev 3650) +++ trunk/OpenMPT/soundlib/Mmcmp.cpp 2014-02-04 16:17:27 UTC (rev 3651) @@ -11,47 +11,105 @@ #include "stdafx.h" #include "Sndfile.h" +#include "FileReader.h" +#include <stdexcept> + + //#define MMCMP_LOG -BOOL XPK_Unpack(LPCBYTE *ppMemFile, LPDWORD pdwMemLength); -BOOL PP20_Unpack(LPCBYTE *ppMemFile, LPDWORD pdwMemLength); +#ifdef NEEDS_PRAGMA_PACK +#pragma pack(push, 1) +#endif -typedef struct MMCMPFILEHEADER +struct PACKED MMCMPFILEHEADER { - DWORD id_ziRC; // "ziRC" - DWORD id_ONia; // "ONia" - WORD hdrsize; -} MMCMPFILEHEADER, *LPMMCMPFILEHEADER; + char id_ziRC[4]; // "ziRC" + char id_ONia[4]; // "ONia" + uint16 hdrsize; + void ConvertEndianness(); +}; -typedef struct MMCMPHEADER +STATIC_ASSERT(sizeof(MMCMPFILEHEADER) == 10); + +struct PACKED MMCMPHEADER { - WORD version; - WORD nblocks; - DWORD filesize; - DWORD blktable; - BYTE glb_comp; - BYTE fmt_comp; -} MMCMPHEADER, *LPMMCMPHEADER; + uint16 version; + uint16 nblocks; + uint32 filesize; + uint32 blktable; + uint8 glb_comp; + uint8 fmt_comp; + void ConvertEndianness(); +}; -typedef struct MMCMPBLOCK +STATIC_ASSERT(sizeof(MMCMPHEADER) == 14); + +struct PACKED MMCMPBLOCK { - DWORD unpk_size; - DWORD pk_size; - DWORD xor_chk; - WORD sub_blk; - WORD flags; - WORD tt_entries; - WORD num_bits; -} MMCMPBLOCK, *LPMMCMPBLOCK; + uint32 unpk_size; + uint32 pk_size; + uint32 xor_chk; + uint16 sub_blk; + uint16 flags; + uint16 tt_entries; + uint16 num_bits; + void ConvertEndianness(); +}; -typedef struct MMCMPSUBBLOCK +STATIC_ASSERT(sizeof(MMCMPBLOCK) == 20); + +struct PACKED MMCMPSUBBLOCK { - DWORD unpk_pos; - DWORD unpk_size; -} MMCMPSUBBLOCK, *LPMMCMPSUBBLOCK; + uint32 unpk_pos; + uint32 unpk_size; + void ConvertEndianness(); +}; +STATIC_ASSERT(sizeof(MMCMPSUBBLOCK) == 8); + +#ifdef NEEDS_PRAGMA_PACK +#pragma pack(pop) +#endif + +void MMCMPFILEHEADER::ConvertEndianness() +//--------------------------------------- +{ + SwapBytesLE(hdrsize); +} + +void MMCMPHEADER::ConvertEndianness() +//----------------------------------- +{ + SwapBytesLE(version); + SwapBytesLE(nblocks); + SwapBytesLE(filesize); + SwapBytesLE(blktable); + SwapBytesLE(glb_comp); + SwapBytesLE(fmt_comp); +} + +void MMCMPBLOCK::ConvertEndianness() +//---------------------------------- +{ + SwapBytesLE(unpk_size); + SwapBytesLE(pk_size); + SwapBytesLE(xor_chk); + SwapBytesLE(sub_blk); + SwapBytesLE(flags); + SwapBytesLE(tt_entries); + SwapBytesLE(num_bits); +} + +void MMCMPSUBBLOCK::ConvertEndianness() +//------------------------------------- +{ + SwapBytesLE(unpk_pos); + SwapBytesLE(unpk_size); +} + + #define MMCMP_COMP 0x0001 #define MMCMP_DELTA 0x0002 #define MMCMP_16BIT 0x0004 @@ -59,21 +117,21 @@ #define MMCMP_ABS16 0x0200 #define MMCMP_ENDIAN 0x0400 -typedef struct MMCMPBITBUFFER +struct MMCMPBITBUFFER { - UINT bitcount; - DWORD bitbuffer; - LPCBYTE pSrc; - LPCBYTE pEnd; + uint32 bitcount; + uint32 bitbuffer; + const uint8 *pSrc; + const uint8 *pEnd; - DWORD GetBits(UINT nBits); -} MMCMPBITBUFFER; + uint32 GetBits(uint32 nBits); +}; -DWORD MMCMPBITBUFFER::GetBits(UINT nBits) -//--------------------------------------- +uint32 MMCMPBITBUFFER::GetBits(uint32 nBits) +//------------------------------------------ { - DWORD d; + uint32 d; if (!nBits) return 0; while (bitcount < 24) { @@ -86,89 +144,115 @@ return d; } -const DWORD MMCMP8BitCommands[8] = +static const uint32 MMCMP8BitCommands[8] = { 0x01, 0x03, 0x07, 0x0F, 0x1E, 0x3C, 0x78, 0xF8 }; -const UINT MMCMP8BitFetch[8] = +static const uint32 MMCMP8BitFetch[8] = { 3, 3, 3, 3, 2, 1, 0, 0 }; -const DWORD MMCMP16BitCommands[16] = +static const uint32 MMCMP16BitCommands[16] = { 0x01, 0x03, 0x07, 0x0F, 0x1E, 0x3C, 0x78, 0xF0, 0x1F0, 0x3F0, 0x7F0, 0xFF0, 0x1FF0, 0x3FF0, 0x7FF0, 0xFFF0 }; -const UINT MMCMP16BitFetch[16] = +static const uint32 MMCMP16BitFetch[16] = { 4, 4, 4, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -BOOL MMCMP_Unpack(LPCBYTE *ppMemFile, LPDWORD pdwMemLength) -//--------------------------------------------------------- +static bool MMCMP_IsDstBlockValid(const std::vector<char> &unpackedData, uint32 pos, uint32 len) +//---------------------------------------------------------------------------------------------- { - DWORD dwMemLength = *pdwMemLength; - LPCBYTE lpMemFile = *ppMemFile; - LPBYTE pBuffer; - LPMMCMPFILEHEADER pmfh = (LPMMCMPFILEHEADER)(lpMemFile); - LPMMCMPHEADER pmmh = (LPMMCMPHEADER)(lpMemFile+10); - LPDWORD pblk_table; - DWORD dwFileSize; + if(pos >= unpackedData.size()) return false; + if(len > unpackedData.size()) return false; + if(len > unpackedData.size() - pos) return false; + return true; +} - if ((XPK_Unpack(ppMemFile, pdwMemLength)) - || (PP20_Unpack(ppMemFile, pdwMemLength))) + +static bool MMCMP_IsDstBlockValid(const std::vector<char> &unpackedData, const MMCMPSUBBLOCK &subblk) +//--------------------------------------------------------------------------------------------------- +{ + return MMCMP_IsDstBlockValid(unpackedData, subblk.unpk_pos, subblk.unpk_size); +} + + +bool UnpackMMCMP(std::vector<char> &unpackedData, FileReader &file) +//----------------------------------------------------------------- +{ + file.Rewind(); + unpackedData.clear(); + + MMCMPFILEHEADER mfh; + if(!file.ReadConvertEndianness(mfh)) return false; + if(std::memcmp(mfh.id_ziRC, "ziRC", 4) != 0) return false; + if(std::memcmp(mfh.id_ONia, "ONia", 4) != 0) return false; + if(mfh.hdrsize != sizeof(MMCMPHEADER)) return false; + MMCMPHEADER mmh; + if(!file.ReadConvertEndianness(mmh)) return false; + if(mmh.nblocks == 0) return false; + if(mmh.filesize == 0) return false; + if(mmh.filesize > 0x80000000) return false; + if(mmh.blktable > file.GetLength()) return false; + if(mmh.blktable + 4 * mmh.nblocks > file.GetLength()) return false; + + unpackedData.resize(mmh.filesize); + + for (uint32 nBlock=0; nBlock<mmh.nblocks; nBlock++) { - return TRUE; - } - if ((dwMemLength < 256) || (!pmfh) || (pmfh->id_ziRC != 0x4352697A) || (pmfh->id_ONia != 0x61694e4f) || (pmfh->hdrsize < 14) - || (!pmmh->nblocks) || (pmmh->filesize < 16) || (pmmh->filesize > 0x8000000) - || (pmmh->blktable >= dwMemLength) || (pmmh->blktable + 4*pmmh->nblocks > dwMemLength)) return FALSE; - dwFileSize = pmmh->filesize; - if ((pBuffer = (LPBYTE)calloc(1, (dwFileSize + 31) & ~15)) == NULL) return FALSE; - pblk_table = (LPDWORD)(lpMemFile+pmmh->blktable); - for (UINT nBlock=0; nBlock<pmmh->nblocks; nBlock++) - { - DWORD dwMemPos = pblk_table[nBlock]; - LPMMCMPBLOCK pblk = (LPMMCMPBLOCK)(lpMemFile+dwMemPos); - LPMMCMPSUBBLOCK psubblk = (LPMMCMPSUBBLOCK)(lpMemFile+dwMemPos+20); + if(!file.Seek(mmh.blktable + 4*nBlock)) return false; + if(!file.CanRead(4)) return false; + uint32 blkPos = file.ReadUint32LE(); + if(!file.Seek(blkPos)) return false; + MMCMPBLOCK blk; + if(!file.ReadConvertEndianness(blk)) return false; + std::vector<MMCMPSUBBLOCK> subblks(blk.sub_blk); + for(uint32 i=0; i<blk.sub_blk; ++i) + { + if(!file.ReadConvertEndianness(subblks[i])) return false; + } + MMCMPSUBBLOCK *psubblk = blk.sub_blk > 0 ? &(subblks[0]) : nullptr; - if ((dwMemPos + 20 >= dwMemLength) || (dwMemPos + 20 + pblk->sub_blk*8 >= dwMemLength)) break; - dwMemPos += 20 + pblk->sub_blk*8; + if(blkPos + sizeof(MMCMPBLOCK) + blk.sub_blk * sizeof(MMCMPSUBBLOCK) >= file.GetLength()) return false; + uint32 memPos = blkPos + sizeof(MMCMPBLOCK) + blk.sub_blk * sizeof(MMCMPSUBBLOCK); + #ifdef MMCMP_LOG Log("block %d: flags=%04X sub_blocks=%d", nBlock, (UINT)pblk->flags, (UINT)pblk->sub_blk); Log(" pksize=%d unpksize=%d", pblk->pk_size, pblk->unpk_size); Log(" tt_entries=%d num_bits=%d\n", pblk->tt_entries, pblk->num_bits); #endif // Data is not packed - if (!(pblk->flags & MMCMP_COMP)) + if (!(blk.flags & MMCMP_COMP)) { - for (UINT i=0; i<pblk->sub_blk; i++) + for (uint32 i=0; i<blk.sub_blk; i++) { - if ((psubblk->unpk_pos >= dwFileSize) || - (psubblk->unpk_size >= dwFileSize) || - (psubblk->unpk_size > dwFileSize - psubblk->unpk_pos)) break; + if(!MMCMP_IsDstBlockValid(unpackedData, *psubblk)) return false; #ifdef MMCMP_LOG Log(" Unpacked sub-block %d: offset %d, size=%d\n", i, psubblk->unpk_pos, psubblk->unpk_size); #endif - memcpy(pBuffer+psubblk->unpk_pos, lpMemFile+dwMemPos, psubblk->unpk_size); - dwMemPos += psubblk->unpk_size; + if(!file.Seek(memPos)) return false; + if(file.ReadRaw(&(unpackedData[psubblk->unpk_pos]), psubblk->unpk_size) != psubblk->unpk_size) return false; psubblk++; } } else // Data is 16-bit packed - if (pblk->flags & MMCMP_16BIT) + if (blk.flags & MMCMP_16BIT) { MMCMPBITBUFFER bb; - uint16 *pDest = (uint16 *)(pBuffer + psubblk->unpk_pos); - uint32 dwSize = psubblk->unpk_size >> 1; + uint32 subblk = 0; + if(!MMCMP_IsDstBlockValid(unpackedData, psubblk[subblk])) return false; + char *pDest = &(unpackedData[psubblk[subblk].unpk_pos]); + uint32 dwSize = psubblk[subblk].unpk_size >> 1; uint32 dwPos = 0; - uint32 numbits = pblk->num_bits; - uint32 subblk = 0, oldval = 0; + uint32 numbits = blk.num_bits; + uint32 oldval = 0; #ifdef MMCMP_LOG Log(" 16-bit block: pos=%d size=%d ", psubblk->unpk_pos, psubblk->unpk_size); @@ -178,9 +262,11 @@ #endif bb.bitcount = 0; bb.bitbuffer = 0; - bb.pSrc = lpMemFile+dwMemPos+pblk->tt_entries; - bb.pEnd = lpMemFile+dwMemPos+pblk->pk_size; - while (subblk < pblk->sub_blk) + if(!file.Seek(memPos + blk.tt_entries)) return false; + if(!file.CanRead(blk.pk_size - blk.tt_entries)) return false; + bb.pSrc = reinterpret_cast<const uint8 *>(file.GetRawData()); + bb.pEnd = reinterpret_cast<const uint8 *>(file.GetRawData() - blk.tt_entries + blk.pk_size); + while (subblk < blk.sub_blk) { uint32 newval = 0x10000; uint32 d = bb.GetBits(numbits+1); @@ -210,41 +296,50 @@ if (newval < 0x10000) { newval = (newval & 1) ? (uint32)(-(int32)((newval+1) >> 1)) : (uint32)(newval >> 1); - if (pblk->flags & MMCMP_DELTA) + if (blk.flags & MMCMP_DELTA) { newval += oldval; oldval = newval; } else - if (!(pblk->flags & MMCMP_ABS16)) + if (!(blk.flags & MMCMP_ABS16)) { newval ^= 0x8000; } - pDest[dwPos++] = (uint16)newval; + pDest[dwPos*2 + 0] = (uint8)(((uint16)newval) & 0xff); + pDest[dwPos*2 + 1] = (uint8)(((uint16)newval) >> 8); + dwPos++; } if (dwPos >= dwSize) { subblk++; dwPos = 0; + if(!(subblk < blk.sub_blk)) break; + if(!MMCMP_IsDstBlockValid(unpackedData, psubblk[subblk])) return false; dwSize = psubblk[subblk].unpk_size >> 1; - pDest = (uint16 *)(pBuffer + psubblk[subblk].unpk_pos); + pDest = &(unpackedData[psubblk[subblk].unpk_pos]); } } } else // Data is 8-bit packed { MMCMPBITBUFFER bb; - LPBYTE pDest = pBuffer + psubblk->unpk_pos; - uint32 dwSize = psubblk->unpk_size; + uint32 subblk = 0; + if(!MMCMP_IsDstBlockValid(unpackedData, psubblk[subblk])) return false; + char *pDest = &(unpackedData[psubblk[subblk].unpk_pos]); + uint32 dwSize = psubblk[subblk].unpk_size; uint32 dwPos = 0; - uint32 numbits = pblk->num_bits; - uint32 subblk = 0, oldval = 0; - LPCBYTE ptable = lpMemFile+dwMemPos; + uint32 numbits = blk.num_bits; + uint32 oldval = 0; + if(!file.Seek(memPos)) return false; + const uint8 *ptable = reinterpret_cast<const uint8 *>(file.GetRawData()); bb.bitcount = 0; bb.bitbuffer = 0; - bb.pSrc = lpMemFile+dwMemPos+pblk->tt_entries; - bb.pEnd = lpMemFile+dwMemPos+pblk->pk_size; - while (subblk < pblk->sub_blk) + if(!file.Seek(memPos + blk.tt_entries)) return false; + if(!file.CanRead(blk.pk_size - blk.tt_entries)) return false; + bb.pSrc = reinterpret_cast<const uint8 *>(file.GetRawData()); + bb.pEnd = reinterpret_cast<const uint8 *>(file.GetRawData() - blk.tt_entries + blk.pk_size); + while (subblk < blk.sub_blk) { uint32 newval = 0x100; uint32 d = bb.GetBits(numbits+1); @@ -274,7 +369,7 @@ if (newval < 0x100) { int n = ptable[newval]; - if (pblk->flags & MMCMP_DELTA) + if (blk.flags & MMCMP_DELTA) { n += oldval; oldval = n; @@ -285,15 +380,16 @@ { subblk++; dwPos = 0; + if(!(subblk < blk.sub_blk)) break; + if(!MMCMP_IsDstBlockValid(unpackedData, psubblk[subblk])) return false; dwSize = psubblk[subblk].unpk_size; - pDest = pBuffer + psubblk[subblk].unpk_pos; + pDest = &(unpackedData[psubblk[subblk].unpk_pos]); } } } } - *ppMemFile = pBuffer; - *pdwMemLength = dwFileSize; - return TRUE; + + return true; } @@ -302,19 +398,21 @@ // XPK unpacker // + #ifdef NEEDS_PRAGMA_PACK #pragma pack(push, 1) #endif -typedef struct PACKED _XPKFILEHEADER +struct PACKED XPKFILEHEADER { - DWORD dwXPKF; - DWORD dwSrcLen; - DWORD dwSQSH; - DWORD dwDstLen; - CHAR szName[16]; - DWORD dwReserved; -} XPKFILEHEADER, *PXPKFILEHEADER; + char XPKF[4]; + uint32 SrcLen; + char SQSH[4]; + uint32 DstLen; + char Name[16]; + uint32 Reserved; + void ConvertEndianness(); +}; STATIC_ASSERT(sizeof(XPKFILEHEADER) == 36); @@ -322,14 +420,38 @@ #pragma pack(pop) #endif +void XPKFILEHEADER::ConvertEndianness() +//------------------------------------- +{ + SwapBytesBE(SrcLen); + SwapBytesBE(DstLen); + SwapBytesBE(Reserved); +} -static int bfextu(const BYTE *p,int bo,int bc) + +struct XPK_BufferBounds { - int r; + const uint8 *pSrcBeg; + const uint8 *pSrcEnd; + uint8 *pDstBeg; + uint8 *pDstEnd; +}; + +struct XPK_error : public std::range_error +{ + XPK_error() : std::range_error("invalid XPK data") { } +}; + +static int32 bfextu(const uint8 *p, int32 bo, int32 bc, XPK_BufferBounds &bufs) +//----------------------------------------------------------------------------- +{ + int32 r; p += bo / 8; + if(p < bufs.pSrcBeg || p >= bufs.pSrcEnd) throw XPK_error(); r = *(p++); r <<= 8; + if(p < bufs.pSrcBeg || p >= bufs.pSrcEnd) throw XPK_error(); r |= *(p++); r <<= 8; r |= *p; @@ -340,13 +462,16 @@ return r; } -static int bfexts(const BYTE *p,int bo,int bc) +static int32 bfexts(const uint8 *p, int32 bo, int32 bc, XPK_BufferBounds &bufs) +//----------------------------------------------------------------------------- { - int r; + int32 r; p += bo / 8; + if(p < bufs.pSrcBeg || p >= bufs.pSrcEnd) throw XPK_error(); r = *(p++); r <<= 8; + if(p < bufs.pSrcBeg || p >= bufs.pSrcEnd) throw XPK_error(); r |= *(p++); r <<= 8; r |= *p; @@ -357,19 +482,30 @@ } -void XPK_DoUnpack(const BYTE *src, UINT, BYTE *dst, int len) +static bool XPK_DoUnpack(const uint8 *src, uint32 srcLen, uint8 *dst, int32 len) +//------------------------------------------------------------------------------ { - static BYTE xpk_table[] = { 2,3,4,5,6,7,8,0,3,2,4,5,6,7,8,0,4,3,5,2,6,7,8,0,5,4, - 6,2,3,7,8,0,6,5,7,2,3,4,8,0,7,6,8,2,3,4,5,0,8,7,6,2,3,4,5,0 }; - int d0,d1,d2,d3,d4,d5,d6,a2,a5; - int cp, cup1, type; - const BYTE *c; - BYTE *phist; - BYTE *dstmax = dst + len; + if(len <= 0) return false; + static uint8 xpk_table[] = { + 2,3,4,5,6,7,8,0,3,2,4,5,6,7,8,0,4,3,5,2,6,7,8,0,5,4,6,2,3,7,8,0,6,5,7,2,3,4,8,0,7,6,8,2,3,4,5,0,8,7,6,2,3,4,5,0 + }; + int32 d0,d1,d2,d3,d4,d5,d6,a2,a5; + int32 cp, cup1, type; + const uint8 *c; + uint8 *phist = nullptr; + uint8 *dstmax = dst + len; + + XPK_BufferBounds bufs; + bufs.pSrcBeg = src; + bufs.pSrcEnd = src + srcLen; + bufs.pDstBeg = dst; + bufs.pDstEnd = dst + len; c = src; while (len > 0) { + if(&(c[0]) < bufs.pSrcBeg || &(c[0]) >= bufs.pSrcEnd) throw XPK_error(); + if(&(c[7]) < bufs.pSrcBeg || &(c[7]) >= bufs.pSrcEnd) throw XPK_error(); type = c[0]; cp = (c[4]<<8) | (c[5]); // packed cup1 = (c[6]<<8) | (c[7]); // unpacked @@ -379,6 +515,10 @@ if (type == 0) { // RAW chunk + if(c < bufs.pSrcBeg || c >= bufs.pSrcEnd) throw XPK_error(); + if(c + cp > bufs.pSrcEnd) throw XPK_error(); + if(dst < bufs.pDstBeg || dst >= bufs.pDstEnd) throw XPK_error(); + if(dst + cp > bufs.pDstEnd) throw XPK_error(); memcpy(dst,c,cp); dst+=cp; c+=cp; @@ -399,32 +539,33 @@ d0 = d1 = d2 = a2 = 0; d3 = *(src++); - *dst = (BYTE)d3; + if(dst < bufs.pDstBeg || dst >= bufs.pDstEnd) throw XPK_error(); + *dst = (uint8)d3; if (dst < dstmax) dst++; cup1--; while (cup1 > 0) { if (d1 >= 8) goto l6dc; - if (bfextu(src,d0,1)) goto l75a; + if (bfextu(src,d0,1,bufs)) goto l75a; d0 += 1; d5 = 0; d6 = 8; goto l734; l6dc: - if (bfextu(src,d0,1)) goto l726; + if (bfextu(src,d0,1,bufs)) goto l726; d0 += 1; - if (! bfextu(src,d0,1)) goto l75a; + if (! bfextu(src,d0,1,bufs)) goto l75a; d0 += 1; - if (bfextu(src,d0,1)) goto l6f6; + if (bfextu(src,d0,1,bufs)) goto l6f6; d6 = 2; goto l708; l6f6: d0 += 1; - if (!bfextu(src,d0,1)) goto l706; - d6 = bfextu(src,d0,3); + if (!bfextu(src,d0,1,bufs)) goto l706; + d6 = bfextu(src,d0,3,bufs); d0 += 3; goto l70a; @@ -456,10 +597,11 @@ l734: while ((d5 >= 0) && (cup1 > 0)) { - d4 = bfexts(src,d0,d6); + d4 = bfexts(src,d0,d6,bufs); d0 += d6; d3 -= d4; - *dst = (BYTE)d3; + if(dst < bufs.pDstBeg || dst >= bufs.pDstEnd) throw XPK_error(); + *dst = (uint8)d3; if (dst < dstmax) dst++; cup1--; d5--; @@ -472,52 +614,52 @@ d2 -= d6; } } - return; + return true; l75a: d0 += 1; - if (bfextu(src,d0,1)) goto l766; + if (bfextu(src,d0,1,bufs)) goto l766; d4 = 2; goto l79e; l766: d0 += 1; - if (bfextu(src,d0,1)) goto l772; + if (bfextu(src,d0,1,bufs)) goto l772; d4 = 4; goto l79e; l772: d0 += 1; - if (bfextu(src,d0,1)) goto l77e; + if (bfextu(src,d0,1,bufs)) goto l77e; d4 = 6; goto l79e; l77e: d0 += 1; - if (bfextu(src,d0,1)) goto l792; + if (bfextu(src,d0,1,bufs)) goto l792; d0 += 1; - d6 = bfextu(src,d0,3); + d6 = bfextu(src,d0,3,bufs); d0 += 3; d6 += 8; goto l7a8; l792: d0 += 1; - d6 = bfextu(src,d0,5); + d6 = bfextu(src,d0,5,bufs); d0 += 5; d4 = 16; goto l7a6; l79e: d0 += 1; - d6 = bfextu(src,d0,1); + d6 = bfextu(src,d0,1,bufs); d0 += 1; l7a6: d6 += d4; l7a8: - if (bfextu(src,d0,1)) goto l7c4; + if (bfextu(src,d0,1,bufs)) goto l7c4; d0 += 1; - if (bfextu(src,d0,1)) goto l7bc; + if (bfextu(src,d0,1,bufs)) goto l7bc; d5 = 8; a5 = 0; goto l7ca; @@ -532,7 +674,7 @@ a5 = -0x100; l7ca: d0 += 1; - d4 = bfextu(src,d0,d5); + d4 = bfextu(src,d0,d5,bufs); d0 += d5; d6 -= 3; if (d6 >= 0) @@ -546,8 +688,10 @@ while ((d6 >= 0) && (cup1 > 0)) { + if(phist < bufs.pDstBeg || phist >= bufs.pDstEnd) throw XPK_error(); d3 = *phist++; - *dst = (BYTE)d3; + if(dst < bufs.pDstBeg || dst >= bufs.pDstEnd) throw XPK_error(); + *dst = (uint8)d3; if (dst < dstmax) dst++; cup1--; d6--; @@ -556,27 +700,34 @@ } -BOOL XPK_Unpack(LPCBYTE *ppMemFile, LPDWORD pdwMemLength) +bool UnpackXPK(std::vector<char> &unpackedData, FileReader &file) +//--------------------------------------------------------------- { - DWORD dwMemLength = *pdwMemLength; - LPCBYTE lpMemFile = *ppMemFile; - PXPKFILEHEADER pxfh = (PXPKFILEHEADER)lpMemFile; - DWORD dwSrcLen, dwDstLen; - LPBYTE pBuffer; + file.Rewind(); + unpackedData.clear(); - if ((!pxfh) || (dwMemLength < 256) - || (pxfh->dwXPKF != MULTICHAR4_LE_MSVC('F','K','P','X')) || (pxfh->dwSQSH != MULTICHAR4_LE_MSVC('H','S','Q','S'))) return FALSE; - dwSrcLen = BigEndian(pxfh->dwSrcLen); - dwDstLen = BigEndian(pxfh->dwDstLen); - if ((dwSrcLen+8 > dwMemLength) || (dwSrcLen < 256) || (dwDstLen < 256)) return FALSE; + XPKFILEHEADER header; + if(!file.ReadConvertEndianness(header)) return false; + if(std::memcmp(header.XPKF, "XPKF", 4) != 0) return false; + if(std::memcmp(header.SQSH, "SQSH", 4) != 0) return false; + if(header.SrcLen == 0) return false; + if(header.DstLen == 0) return false; + if(!file.CanRead(header.SrcLen + 8 - sizeof(XPKFILEHEADER))) return false; + #ifdef MMCMP_LOG - Log("XPK detected (SrcLen=%d DstLen=%d) filesize=%d\n", dwSrcLen, dwDstLen, dwMemLength); + Log("XPK detected (SrcLen=%d DstLen=%d) filesize=%d\n", header.SrcLen, header.DstLen, file.GetLength()); #endif - if ((pBuffer = (LPBYTE)calloc(1, (dwDstLen + 31) & ~15)) == NULL) return FALSE; - XPK_DoUnpack(lpMemFile+sizeof(XPKFILEHEADER), dwSrcLen+8-sizeof(XPKFILEHEADER), pBuffer, dwDstLen); - *ppMemFile = pBuffer; - *pdwMemLength = dwDstLen; - return TRUE; + unpackedData.resize(header.DstLen); + bool result = false; + try + { + result = XPK_DoUnpack(reinterpret_cast<const uint8 *>(file.GetRawData()), header.SrcLen + 8 - sizeof(XPKFILEHEADER), reinterpret_cast<uint8 *>(&(unpackedData[0])), header.DstLen); + } catch(XPK_error&) + { + return false; + } + + return result; } @@ -585,22 +736,27 @@ // PowerPack PP20 Unpacker // -typedef struct _PPBITBUFFER + +static const uint32 PP20_PACKED_SIZE_MIN = 8; + + +struct PPBITBUFFER { - UINT bitcount; - ULONG bitbuffer; - LPCBYTE pStart; - LPCBYTE pSrc; + uint32 bitcount; + uint32 bitbuffer; + const uint8 *pStart; + const uint8 *pSrc; - ULONG GetBits(UINT n); -} PPBITBUFFER; + uint32 GetBits(uint32 n); +}; -ULONG PPBITBUFFER::GetBits(UINT n) +uint32 PPBITBUFFER::GetBits(uint32 n) +//----------------------------------- { - ULONG result = 0; + uint32 result = 0; - for (UINT i=0; i<n; i++) + for (uint32 i=0; i<n; i++) { if (!bitcount) { @@ -616,10 +772,11 @@ } -void PP20_DoUnpack(const BYTE *pSrc, UINT nSrcLen, BYTE *pDst, UINT nDstLen) +static bool PP20_DoUnpack(const uint8 *pSrc, uint32 nSrcLen, uint8 *pDst, uint32 nDstLen) +//--------------------------------------------------------------------------------------- { PPBITBUFFER BitBuffer; - ULONG nBytesLeft; + uint32 nBytesLeft; BitBuffer.pStart = pSrc; BitBuffer.pSrc = pSrc + nSrcLen - 4; @@ -631,29 +788,30 @@ { if (!BitBuffer.GetBits(1)) { - UINT n = 1; + uint32 n = 1; while (n < nBytesLeft) { - UINT code = BitBuffer.GetBits(2); + uint32 code = BitBuffer.GetBits(2); n += code; if (code != 3) break; } - for (UINT i=0; i<n; i++) + for (uint32 i=0; i<n; i++) { - pDst[--nBytesLeft] = (BYTE)BitBuffer.GetBits(8); + pDst[--nBytesLeft] = (uint8)BitBuffer.GetBits(8); } if (!nBytesLeft) break; } { - UINT n = BitBuffer.GetBits(2)+1; - UINT nbits = pSrc[n-1]; - UINT nofs; + uint32 n = BitBuffer.GetBits(2)+1; + if(n < 1 || n-1 >= nSrcLen) return false; + uint32 nbits = pSrc[n-1]; + uint32 nofs; if (n==4) { nofs = BitBuffer.GetBits( (BitBuffer.GetBits(1)) ? nbits : 7 ); while (n < nBytesLeft) { - UINT code = BitBuffer.GetBits(3); + uint32 code = BitBuffer.GetBits(3); n += code; if (code != 7) break; } @@ -661,35 +819,35 @@ { nofs = BitBuffer.GetBits(nbits); } - for (UINT i=0; i<=n; i++) + for (uint32 i=0; i<=n; i++) { pDst[nBytesLeft-1] = (nBytesLeft+nofs < nDstLen) ? pDst[nBytesLeft+nofs] : 0; if (!--nBytesLeft) break; } } } + return true; } -BOOL PP20_Unpack(LPCBYTE *ppMemFile, LPDWORD pdwMemLength) +bool UnpackPP20(std::vector<char> &unpackedData, FileReader &file) +//---------------------------------------------------------------- { - DWORD dwMemLength = *pdwMemLength; - LPCBYTE lpMemFile = *ppMemFile; - DWORD dwDstLen; - LPBYTE pBuffer; + file.Rewind(); + unpackedData.clear(); - if ((!lpMemFile) || (dwMemLength < 256) || (*(DWORD *)lpMemFile != MULTICHAR4_LE_MSVC('0','2','P','P'))) return FALSE; - dwDstLen = (lpMemFile[dwMemLength-4]<<16) | (lpMemFile[dwMemLength-3]<<8) | (lpMemFile[dwMemLength-2]); - //Log("PP20 detected: Packed length=%d, Unpacked length=%d\n", dwMemLength, dwDstLen); - if ((dwDstLen < 512) || (dwDstLen > 0x400000) || (dwDstLen > 16*dwMemLength)) return FALSE; - if ((pBuffer = (LPBYTE)calloc(1, (dwDstLen + 31) & ~15)) == NULL) return FALSE; - PP20_DoUnpack(lpMemFile+4, dwMemLength-4, pBuffer, dwDstLen); - *ppMemFile = pBuffer; - *pdwMemLength = dwDstLen; - return TRUE; + if(!file.CanRead(PP20_PACKED_SIZE_MIN)) return false; + if(!file.ReadMagic("PP20")) return false; + file.Seek(file.GetLength() - 4); + uint32 dstLen = 0; + dstLen |= file.ReadUint8() << 16; + dstLen |= file.ReadUint8() << 8; + dstLen |= file.ReadUint8() << 0; + if(dstLen == 0) return false; + unpackedData.resize(dstLen); + file.Seek(4); + bool result = PP20_DoUnpack(reinterpret_cast<const uint8 *>(file.GetRawData()), file.GetLength() - 4, reinterpret_cast<uint8 *>(&(unpackedData[0])), dstLen); + + return result; } - - - - Modified: trunk/OpenMPT/soundlib/Sndfile.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.cpp 2014-02-04 16:14:11 UTC (rev 3650) +++ trunk/OpenMPT/soundlib/Sndfile.cpp 2014-02-04 16:17:27 UTC (rev 3651) @@ -30,9 +30,12 @@ #include "../unarchiver/unarchiver.h" #endif // NO_ARCHIVE_SUPPORT -extern BOOL MMCMP_Unpack(LPCBYTE *ppMemFile, LPDWORD pdwMemLength); +bool UnpackXPK(std::vector<char> &unpackedData, FileReader &file); +bool UnpackPP20(std::vector<char> &unpackedData, FileReader &file); +bool UnpackMMCMP(std::vector<char> &unpackedData, FileReader &file); + // -> CODE#0027 // -> DESC="per-instrument volume ramping setup (refered as attack)" @@ -758,10 +761,16 @@ } #endif - BOOL bMMCmp = MMCMP_Unpack(&lpStream, &dwMemLength); - if(bMMCmp) + bool packed = false; + std::vector<char> unpackedData; + if(!packed && UnpackXPK(unpackedData, file)) packed = true; + if(!packed && UnpackPP20(unpackedData, file)) packed = true; + if(!packed && UnpackMMCMP(unpackedData, file)) packed = true; + if(packed) { - file = FileReader(lpStream, dwMemLength); + file = FileReader(&(unpackedData[0]), unpackedData.size()); + lpStream = (LPCBYTE)file.GetRawData(); + dwMemLength = file.GetLength(); } if(!ReadXM(file, loadFlags) @@ -824,12 +833,6 @@ } #endif - if(bMMCmp) - { - free((void*)lpStream); - lpStream = NULL; - } - } else { // New song This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |