OPENMPT_NAMESPACE_BEGIN PNG::Bitmap *PNG::ReadPNG(FileReader &file) //----------------------------------------- { file.Rewind(); if(!file.ReadMagic("\211PNG\r\n\032\n")) { return nullptr; } uint32_t width = 0; uint32_t height = 0; uint8_t bitDepth; uint8_t colorType; uint8_t compressionMethod; uint8_t filterMethod; uint8_t interlaceMethod; std::vector<uint8_t> dataIn; std::vector<Pixel> palette; while(file.AreBytesLeft()) { uint32_t chunkLength = file.ReadUint32BE(); char magic[4]; file.ReadArray(magic); FileReader chunk = file.ReadChunk(chunkLength); file.Skip(4); // CRC32 if(!memcmp(magic, "IHDR", 4)) { // Image header width = chunk.ReadUint32BE(); height = chunk.ReadUint32BE(); bitDepth = chunk.ReadUint8(); colorType = chunk.ReadUint8(); compressionMethod = chunk.ReadUint8(); filterMethod = chunk.ReadUint8(); interlaceMethod = chunk.ReadUint8(); ASSERT(!filterMethod && !interlaceMethod); } else if(!memcmp(magic, "IDAT", 4)) { // Data block(s) z_stream strm; strm.zalloc = Z_NULL; strm.zfree = Z_NULL; strm.opaque = Z_NULL; strm.avail_in = static_cast<uInt>(chunk.GetLength()); strm.next_in = (Bytef *)(chunk.GetRawData()); if(inflateInit2(&strm, 15) != Z_OK) { break; } int retVal; do { dataIn.resize(dataIn.size() + 4096); strm.avail_out = 4096; strm.next_out = (Bytef *)&dataIn[dataIn.size() - 4096]; retVal = inflate(&strm, Z_NO_FLUSH); } while(retVal == Z_OK); inflateEnd(&strm); } else if(!memcmp(magic, "PLTE", 4)) { // Palette for <= 8-bit images palette.resize(256); size_t numEntries = std::min<size_t>(256u, chunk.GetLength() / 3u); for(size_t i = 0; i < numEntries; i++) { uint8_t p[3]; chunk.ReadArray(p); palette[i] = Pixel(p[0], p[1], p[2], 255); } } } // LUT for translating the color type into a number of color samples const uint32_t sampleTable[] = { 1, // 0: Grayscale 0, 3, // 2: RGB 1, // 3: Palette bitmap 2, // 4: Grayscale + Alpha 0, 4 // 6: RGBA }; const uint32_t bitsPerPixel = colorType < CountOf(sampleTable) ? sampleTable[colorType] * bitDepth : 0; if(!width || !height || !bitsPerPixel || (colorType != 2 && colorType != 3 && colorType != 6) || bitDepth != 8 // Only RGB(A) and 8-bit palette PNGs for now. || compressionMethod || interlaceMethod || (colorType == 3 && palette.empty()) || dataIn.size() < (bitsPerPixel * width * height) / 8 + height) // Enough data present? { return nullptr; } Bitmap *bitmap = new (std::nothrow) Bitmap(width, height); Pixel *pixelOut = bitmap->GetPixels(); uint32_t x = 0, y = 0; size_t offset = 0; while(y < height) { if(x == 0) { filterMethod = dataIn[offset++]; ASSERT(!filterMethod); } if(colorType == 6) { // RGBA pixelOut->r = dataIn[offset++]; pixelOut->g = dataIn[offset++]; pixelOut->b = dataIn[offset++]; pixelOut->a = dataIn[offset++]; } else if(colorType == 2) { // RGB pixelOut->r = dataIn[offset++]; pixelOut->g = dataIn[offset++]; pixelOut->b = dataIn[offset++]; pixelOut->a = 255; } else if(colorType == 3) { // Palette *pixelOut = palette[dataIn[offset++]]; } pixelOut++; x++; if(x == width) { y++; x = 0; } } return bitmap; }
OPENMPT_NAMESPACE_BEGIN #if MPT_COMPILER_GCC #if MPT_GCC_AT_LEAST(4,6,0) #pragma GCC diagnostic push #endif #pragma GCC diagnostic ignored "-Wswitch" #elif MPT_COMPILER_CLANG #pragma clang diagnostic push #if MPT_CLANG_AT_LEAST(3,3,0) #pragma clang diagnostic ignored "-Wswitch" #else #pragma clang diagnostic ignored "-Wswitch-enum" #endif #endif // Read a sample from memory size_t SampleIO::ReadSample(ModSample &sample, FileReader &file) const //-------------------------------------------------------------------- { if(sample.nLength < 1 || !file.IsValid()) { return 0; } LimitMax(sample.nLength, MAX_SAMPLE_LENGTH); const char * const sourceBuf = file.GetRawData(); const FileReader::off_t fileSize = file.BytesLeft(), filePosition = file.GetPosition(); FileReader::off_t bytesRead = 0; // Amount of memory that has been read from file sample.uFlags.set(CHN_16BIT, GetBitDepth() >= 16); sample.uFlags.set(CHN_STEREO, GetChannelFormat() != mono); size_t sampleSize = sample.AllocateSample(); // Target sample size in bytes if(sampleSize == 0) { sample.nLength = 0; return 0; } ASSERT(sampleSize >= sample.GetSampleSizeInBytes()); ////////////////////////////////////////////////////// // 8-Bit / Mono / PCM if(GetBitDepth() == 8 && GetChannelFormat() == mono) { switch(GetEncoding()) { case signedPCM: // 8-Bit / Mono / Signed / PCM bytesRead = CopyMonoSample<SC::DecodeInt8>(sample, sourceBuf, fileSize); break; case unsignedPCM: // 8-Bit / Mono / Unsigned / PCM bytesRead = CopyMonoSample<SC::DecodeUint8>(sample, sourceBuf, fileSize); break; case deltaPCM: // 8-Bit / Mono / Delta / PCM case MT2: bytesRead = CopyMonoSample<SC::DecodeInt8Delta>(sample, sourceBuf, fileSize); break; case PCM7to8: // 7 Bit stored as 8-Bit with highest bit unused / Mono / Signed / PCM bytesRead = CopyMonoSample<SC::DecodeInt7>(sample, sourceBuf, fileSize); break; } } ////////////////////////////////////////////////////// // 8-Bit / Stereo Split / PCM else if(GetBitDepth() == 8 && GetChannelFormat() == stereoSplit) { switch(GetEncoding()) { case signedPCM: // 8-Bit / Stereo Split / Signed / PCM bytesRead = CopyStereoSplitSample<SC::DecodeInt8>(sample, sourceBuf, fileSize); break; case unsignedPCM: // 8-Bit / Stereo Split / Unsigned / PCM bytesRead = CopyStereoSplitSample<SC::DecodeUint8>(sample, sourceBuf, fileSize); break; case deltaPCM: // 8-Bit / Stereo Split / Delta / PCM case MT2: bytesRead = CopyStereoSplitSample<SC::DecodeInt8Delta>(sample, sourceBuf, fileSize); break; } } ////////////////////////////////////////////////////// // 8-Bit / Stereo Interleaved / PCM else if(GetBitDepth() == 8 && GetChannelFormat() == stereoInterleaved) { switch(GetEncoding()) { case signedPCM: // 8-Bit / Stereo Interleaved / Signed / PCM bytesRead = CopyStereoInterleavedSample<SC::DecodeInt8>(sample, sourceBuf, fileSize); break; case unsignedPCM: // 8-Bit / Stereo Interleaved / Unsigned / PCM bytesRead = CopyStereoInterleavedSample<SC::DecodeUint8>(sample, sourceBuf, fileSize); break; case deltaPCM: // 8-Bit / Stereo Interleaved / Delta / PCM bytesRead = CopyStereoInterleavedSample<SC::DecodeInt8Delta>(sample, sourceBuf, fileSize); break; } } ////////////////////////////////////////////////////// // 16-Bit / Mono / Little Endian / PCM else if(GetBitDepth() == 16 && GetChannelFormat() == mono && GetEndianness() == littleEndian) { switch(GetEncoding()) { case signedPCM: // 16-Bit / Stereo Interleaved / Signed / PCM bytesRead = CopyMonoSample<SC::DecodeInt16<0, littleEndian16> >(sample, sourceBuf, fileSize); break; case unsignedPCM: // 16-Bit / Stereo Interleaved / Unsigned / PCM bytesRead = CopyMonoSample<SC::DecodeInt16<0x8000u, littleEndian16> >(sample, sourceBuf, fileSize); break; case deltaPCM: // 16-Bit / Stereo Interleaved / Delta / PCM case MT2: bytesRead = CopyMonoSample<SC::DecodeInt16Delta<littleEndian16> >(sample, sourceBuf, fileSize); break; } } ////////////////////////////////////////////////////// // 16-Bit / Mono / Big Endian / PCM else if(GetBitDepth() == 16 && GetChannelFormat() == mono && GetEndianness() == bigEndian) { switch(GetEncoding()) { case signedPCM: // 16-Bit / Mono / Signed / PCM bytesRead = CopyMonoSample<SC::DecodeInt16<0, bigEndian16> >(sample, sourceBuf, fileSize); break; case unsignedPCM: // 16-Bit / Mono / Unsigned / PCM bytesRead = CopyMonoSample<SC::DecodeInt16<0x8000u, bigEndian16> >(sample, sourceBuf, fileSize); break; case deltaPCM: // 16-Bit / Mono / Delta / PCM bytesRead = CopyMonoSample<SC::DecodeInt16Delta<bigEndian16> >(sample, sourceBuf, fileSize); break; } } ////////////////////////////////////////////////////// // 16-Bit / Stereo Split / Little Endian / PCM else if(GetBitDepth() == 16 && GetChannelFormat() == stereoSplit && GetEndianness() == littleEndian) { switch(GetEncoding()) { case signedPCM: // 16-Bit / Stereo Split / Signed / PCM bytesRead = CopyStereoSplitSample<SC::DecodeInt16<0, littleEndian16> >(sample, sourceBuf, fileSize); break; case unsignedPCM: // 16-Bit / Stereo Split / Unsigned / PCM bytesRead = CopyStereoSplitSample<SC::DecodeInt16<0x8000u, littleEndian16> >(sample, sourceBuf, fileSize); break; case deltaPCM: // 16-Bit / Stereo Split / Delta / PCM case MT2: bytesRead = CopyStereoSplitSample<SC::DecodeInt16Delta<littleEndian16> >(sample, sourceBuf, fileSize); break; } } ////////////////////////////////////////////////////// // 16-Bit / Stereo Split / Big Endian / PCM else if(GetBitDepth() == 16 && GetChannelFormat() == stereoSplit && GetEndianness() == bigEndian) { switch(GetEncoding()) { case signedPCM: // 16-Bit / Stereo Split / Signed / PCM bytesRead = CopyStereoSplitSample<SC::DecodeInt16<0, bigEndian16> >(sample, sourceBuf, fileSize); break; case unsignedPCM: // 16-Bit / Stereo Split / Unsigned / PCM bytesRead = CopyStereoSplitSample<SC::DecodeInt16<0x8000u, bigEndian16> >(sample, sourceBuf, fileSize); break; case deltaPCM: // 16-Bit / Stereo Split / Delta / PCM bytesRead = CopyStereoSplitSample<SC::DecodeInt16Delta<bigEndian16> >(sample, sourceBuf, fileSize); break; } } ////////////////////////////////////////////////////// // 16-Bit / Stereo Interleaved / Little Endian / PCM else if(GetBitDepth() == 16 && GetChannelFormat() == stereoInterleaved && GetEndianness() == littleEndian) { switch(GetEncoding()) { case signedPCM: // 16-Bit / Stereo Interleaved / Signed / PCM bytesRead = CopyStereoInterleavedSample<SC::DecodeInt16<0, littleEndian16> >(sample, sourceBuf, fileSize); break; case unsignedPCM: // 16-Bit / Stereo Interleaved / Unsigned / PCM bytesRead = CopyStereoInterleavedSample<SC::DecodeInt16<0x8000u, littleEndian16> >(sample, sourceBuf, fileSize); break; case deltaPCM: // 16-Bit / Stereo Interleaved / Delta / PCM bytesRead = CopyStereoInterleavedSample<SC::DecodeInt16Delta<littleEndian16> >(sample, sourceBuf, fileSize); break; } } ////////////////////////////////////////////////////// // 16-Bit / Stereo Interleaved / Big Endian / PCM else if(GetBitDepth() == 16 && GetChannelFormat() == stereoInterleaved && GetEndianness() == bigEndian) { switch(GetEncoding()) { case signedPCM: // 16-Bit / Stereo Interleaved / Signed / PCM bytesRead = CopyStereoInterleavedSample<SC::DecodeInt16<0, bigEndian16> >(sample, sourceBuf, fileSize); break; case unsignedPCM: // 16-Bit / Stereo Interleaved / Unsigned / PCM bytesRead = CopyStereoInterleavedSample<SC::DecodeInt16<0x8000u, bigEndian16> >(sample, sourceBuf, fileSize); break; case deltaPCM: // 16-Bit / Stereo Interleaved / Delta / PCM bytesRead = CopyStereoInterleavedSample<SC::DecodeInt16Delta<bigEndian16> >(sample, sourceBuf, fileSize); break; } } ////////////////////////////////////////////////////// // 24-Bit / Signed / Mono / PCM else if(GetBitDepth() == 24 && GetChannelFormat() == mono && GetEncoding() == signedPCM) { if(GetEndianness() == littleEndian) { bytesRead = CopyMonoSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt24<0, littleEndian24> > >(sample, sourceBuf, fileSize); } else { bytesRead = CopyMonoSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt24<0, bigEndian24> > >(sample, sourceBuf, fileSize); } } ////////////////////////////////////////////////////// // 24-Bit / Signed / Stereo Interleaved / PCM else if(GetBitDepth() == 24 && GetChannelFormat() == stereoInterleaved && GetEncoding() == signedPCM) { if(GetEndianness() == littleEndian) { bytesRead = CopyStereoInterleavedSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt24<0, littleEndian24> > >(sample, sourceBuf, fileSize); } else { bytesRead = CopyStereoInterleavedSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt24<0, bigEndian24> > >(sample, sourceBuf, fileSize); } } ////////////////////////////////////////////////////// // 32-Bit / Signed / Mono / PCM else if(GetBitDepth() == 32 && GetChannelFormat() == mono && GetEncoding() == signedPCM) { if(GetEndianness() == littleEndian) { bytesRead = CopyMonoSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt32<0, littleEndian32> > >(sample, sourceBuf, fileSize); } else { bytesRead = CopyMonoSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt32<0, bigEndian32> > >(sample, sourceBuf, fileSize); } } ////////////////////////////////////////////////////// // 32-Bit / Signed / Stereo Interleaved / PCM else if(GetBitDepth() == 32 && GetChannelFormat() == stereoInterleaved && GetEncoding() == signedPCM) { if(GetEndianness() == littleEndian) { bytesRead = CopyStereoInterleavedSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt32<0, littleEndian32> > >(sample, sourceBuf, fileSize); } else { bytesRead = CopyStereoInterleavedSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt32<0, bigEndian32> > >(sample, sourceBuf, fileSize); } } ////////////////////////////////////////////////////// // 32-Bit / Float / Mono / PCM else if(GetBitDepth() == 32 && GetChannelFormat() == mono && GetEncoding() == floatPCM) { if(GetEndianness() == littleEndian) { bytesRead = CopyMonoSample<SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeFloat32<littleEndian32> > >(sample, sourceBuf, fileSize); } else { bytesRead = CopyMonoSample<SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeFloat32<bigEndian32> > >(sample, sourceBuf, fileSize); } } ////////////////////////////////////////////////////// // 32-Bit / Float / Stereo Interleaved / PCM else if(GetBitDepth() == 32 && GetChannelFormat() == stereoInterleaved && GetEncoding() == floatPCM) { if(GetEndianness() == littleEndian) { bytesRead = CopyStereoInterleavedSample<SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeFloat32<littleEndian32> > >(sample, sourceBuf, fileSize); } else { bytesRead = CopyStereoInterleavedSample<SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeFloat32<bigEndian32> > >(sample, sourceBuf, fileSize); } } ////////////////////////////////////////////////////// // 24-Bit / Signed / Mono, Stereo Interleaved / PCM else if(GetBitDepth() == 24 && (GetChannelFormat() == mono || GetChannelFormat() == stereoInterleaved) && GetEncoding() == signedPCMnormalize) { // Normalize to 16-Bit uint32 srcPeak = uint32(1)<<31; if(GetEndianness() == littleEndian) { bytesRead = CopyAndNormalizeSample<SC::NormalizationChain<SC::Convert<int16, int32>, SC::DecodeInt24<0, littleEndian24> > >(sample, sourceBuf, fileSize, &srcPeak); } else { bytesRead = CopyAndNormalizeSample<SC::NormalizationChain<SC::Convert<int16, int32>, SC::DecodeInt24<0, bigEndian24> > >(sample, sourceBuf, fileSize, &srcPeak); } if(bytesRead) { // Adjust sample volume so we do not affect relative volume of the sample. Normalizing is only done to increase precision. sample.nGlobalVol = static_cast<uint16>(Clamp(Util::muldivr_unsigned(sample.nGlobalVol, srcPeak, uint32(1)<<31), uint32(1), uint32(64))); } } ////////////////////////////////////////////////////// // 32-Bit / Signed / Mono, Stereo Interleaved / PCM else if(GetBitDepth() == 32 && (GetChannelFormat() == mono || GetChannelFormat() == stereoInterleaved) && GetEncoding() == signedPCMnormalize) { // Normalize to 16-Bit uint32 srcPeak = uint32(1)<<31; if(GetEndianness() == littleEndian) { bytesRead = CopyAndNormalizeSample<SC::NormalizationChain<SC::Convert<int16, int32>, SC::DecodeInt32<0, littleEndian32> > >(sample, sourceBuf, fileSize, &srcPeak); } else { bytesRead = CopyAndNormalizeSample<SC::NormalizationChain<SC::Convert<int16, int32>, SC::DecodeInt32<0, bigEndian32> > >(sample, sourceBuf, fileSize, &srcPeak); } if(bytesRead) { // Adjust sample volume so we do not affect relative volume of the sample. Normalizing is only done to increase precision. sample.nGlobalVol = static_cast<uint16>(Clamp(Util::muldivr_unsigned(sample.nGlobalVol, srcPeak, uint32(1)<<31), uint32(1), uint32(64))); } } ////////////////////////////////////////////////////// // 32-Bit / Float / Mono, Stereo Interleaved / PCM else if(GetBitDepth() == 32 && (GetChannelFormat() == mono || GetChannelFormat() == stereoInterleaved) && GetEncoding() == floatPCMnormalize) { // Normalize to 16-Bit float32 srcPeak = 1.0f; if(GetEndianness() == littleEndian) { bytesRead = CopyAndNormalizeSample<SC::NormalizationChain<SC::Convert<int16, float32>, SC::DecodeFloat32<littleEndian32> > >(sample, sourceBuf, fileSize, &srcPeak); } else { bytesRead = CopyAndNormalizeSample<SC::NormalizationChain<SC::Convert<int16, float32>, SC::DecodeFloat32<bigEndian32> > >(sample, sourceBuf, fileSize, &srcPeak); } if(bytesRead) { // Adjust sample volume so we do not affect relative volume of the sample. Normalizing is only done to increase precision. sample.nGlobalVol = Util::Round<uint16>(Clamp(sample.nGlobalVol * srcPeak, 1.0f, 64.0f)); } } ////////////////////////////////////////////////////// // 32-Bit / Float / Mono / PCM / full scale 2^15 else if(GetBitDepth() == 32 && GetChannelFormat() == mono && GetEncoding() == floatPCM15) { if(GetEndianness() == littleEndian) { bytesRead = CopyMonoSample (sample, sourceBuf, fileSize, SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeScaledFloat32<littleEndian32> > (SC::Convert<int16, float32>(), SC::DecodeScaledFloat32<littleEndian32>(1.0f / static_cast<float>(1<<15))) ); } else { bytesRead = CopyMonoSample (sample, sourceBuf, fileSize, SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeScaledFloat32<bigEndian32> > (SC::Convert<int16, float32>(), SC::DecodeScaledFloat32<bigEndian32>(1.0f / static_cast<float>(1<<15))) ); } } ////////////////////////////////////////////////////// // 32-Bit / Float / Stereo Interleaved / PCM / full scale 2^15 else if(GetBitDepth() == 32 && GetChannelFormat() == stereoInterleaved && GetEncoding() == floatPCM15) { if(GetEndianness() == littleEndian) { bytesRead = CopyStereoInterleavedSample (sample, sourceBuf, fileSize, SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeScaledFloat32<littleEndian32> > (SC::Convert<int16, float32>(), SC::DecodeScaledFloat32<littleEndian32>(1.0f / static_cast<float>(1<<15))) ); } else { bytesRead = CopyStereoInterleavedSample (sample, sourceBuf, fileSize, SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeScaledFloat32<bigEndian32> > (SC::Convert<int16, float32>(), SC::DecodeScaledFloat32<bigEndian32>(1.0f / static_cast<float>(1<<15))) ); } } ////////////////////////////////////////////////////// // 32-Bit / Float / Stereo Interleaved / PCM / full scale 2^23 else if(GetBitDepth() == 32 && GetChannelFormat() == mono && GetEncoding() == floatPCM23) { if(GetEndianness() == littleEndian) { bytesRead = CopyMonoSample (sample, sourceBuf, fileSize, SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeScaledFloat32<littleEndian32> > (SC::Convert<int16, float32>(), SC::DecodeScaledFloat32<littleEndian32>(1.0f / static_cast<float>(1<<23))) ); } else { bytesRead = CopyMonoSample (sample, sourceBuf, fileSize, SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeScaledFloat32<bigEndian32> > (SC::Convert<int16, float32>(), SC::DecodeScaledFloat32<bigEndian32>(1.0f / static_cast<float>(1<<23))) ); } } ////////////////////////////////////////////////////// // 32-Bit / Float / Stereo Interleaved / PCM / full scale 2^23 else if(GetBitDepth() == 32 && GetChannelFormat() == stereoInterleaved && GetEncoding() == floatPCM23) { if(GetEndianness() == littleEndian) { bytesRead = CopyStereoInterleavedSample (sample, sourceBuf, fileSize, SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeScaledFloat32<littleEndian32> > (SC::Convert<int16, float32>(), SC::DecodeScaledFloat32<littleEndian32>(1.0f / static_cast<float>(1<<23))) ); } else { bytesRead = CopyStereoInterleavedSample (sample, sourceBuf, fileSize, SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeScaledFloat32<bigEndian32> > (SC::Convert<int16, float32>(), SC::DecodeScaledFloat32<bigEndian32>(1.0f / static_cast<float>(1<<23))) ); } } ////////////////////////////////////////////////////// // Compressed samples if(*this == SampleIO(_8bit, mono, littleEndian, ADPCM)) { // 4-Bit ADPCM data int8 compressionTable[16]; // ADPCM Compression LUT if(file.ReadArray(compressionTable)) { size_t readLength = (sample.nLength + 1) / 2; LimitMax(readLength, file.BytesLeft()); const uint8 *inBuf = reinterpret_cast<const uint8*>(sourceBuf) + sizeof(compressionTable); int8 *outBuf = static_cast<int8 *>(sample.pSample); int8 delta = 0; for(size_t i = readLength; i != 0; i--) { delta += compressionTable[*inBuf & 0x0F]; *(outBuf++) = delta; delta += compressionTable[(*inBuf >> 4) & 0x0F]; *(outBuf++) = delta; inBuf++; } bytesRead = sizeof(compressionTable) + readLength; }