private bool MermaidProcessLzRuns(int mode, byte *source, byte *sourceEnd, byte *destination, int destinationSize, long offset, byte *destinationEnd, MermaidLzTable *lz) { int iteration = 0; byte *destinationStart = destination - offset; int savedDist = -8; byte *sourceCurrent = null; for (iteration = 0; iteration != 2; iteration++) { int destinationSizeCurrent = destinationSize; destinationSizeCurrent = destinationSizeCurrent > 0x10000 ? 0x10000 : destinationSizeCurrent; if (iteration == 0) { lz->Offset32Stream = lz->Offset32Stream1; lz->Offset32StreamEnd = lz->Offset32Stream1 + lz->Offset32Stream1Size * 4; lz->CmdStreamEnd = lz->CmdStream + lz->CmdStream2Offsets; } else { lz->Offset32Stream = lz->Offset32Stream2; lz->Offset32StreamEnd = lz->Offset32Stream2 + lz->Offset32Stream2Size * 4; lz->CmdStreamEnd = lz->CmdStream + lz->CmdStream2OffsetsEnd; lz->CmdStream += lz->CmdStream2Offsets; } if (mode == 0) { throw new NotImplementedException($"MermaidProcessLzRuns: Mode 0 not implemented currently"); } else { sourceCurrent = MermaidMode1(destination, destinationSizeCurrent, destinationEnd, destinationStart, sourceEnd, lz, &savedDist, (offset == 0) && (iteration == 0) ? 8 : 0); } destination += destinationSizeCurrent; destinationSize -= destinationSizeCurrent; if (destinationSize == 0) { break; } } if (sourceCurrent != sourceEnd) { throw new DecoderException($"MermaidProcessLzRuns: Failed to read decompress source bytes"); } return(true); }
private byte *MermaidMode1(byte *destination, int destinationSize, byte *destinationEndPtr, byte *destinationStart, byte *sourceEnd, MermaidLzTable *lz, int *savedDist, int startOff) { byte * destinationEnd = destination + destinationSize; byte * cmdStream = lz->CmdStream; byte * cmdStreamEnd = lz->CmdStreamEnd; byte * lengthStream = lz->LengthStream; byte * litStream = lz->LitStream; byte * litStreamEnd = lz->LitStreamEnd; ushort *off16Stream = lz->Offset16Stream; ushort *off16StreamEnd = lz->Offset16StreamEnd; uint * off32Stream = lz->Offset32Stream; uint * off32StreamEnd = lz->Offset32StreamEnd; int recentOffs = *savedDist; byte * match; int length; byte * destinationBegin = destination; destination += startOff; long test = cmdStreamEnd - cmdStream; while (cmdStream < cmdStreamEnd) { uint flag = *cmdStream++; if (flag >= 24) { uint newDist = *off16Stream; uint useDistance = (flag >> 7) - 1; uint litLen = (uint)(flag & 7); Util.Copy64(destination, litStream); destination += litLen; litStream += litLen; recentOffs ^= (int)(useDistance & (uint)(recentOffs ^ -newDist)); off16Stream = (ushort *)((byte *)off16Stream + (useDistance & 2)); match = destination + recentOffs; Util.Copy64(destination, match); Util.Copy64(destination + 8, match + 8); destination += (flag >> 3) & 0xF; } else if (flag > 2) { length = (int)(flag + 5); if (off32Stream == off32StreamEnd) { throw new DecoderException($"MermaidMode1: off32Stream == off32StreamEnd"); } match = destinationBegin - *off32Stream++; recentOffs = (int)(match - destination); if (destinationEnd - destination < length) { throw new DecoderException($"MermaidMode1: destinationEnd - destination < length"); } Util.Copy64(destination, match); Util.Copy64(destination + 8, match + 8); Util.Copy64(destination + 16, match + 16); Util.Copy64(destination + 24, match + 24); destination += length; } else if (flag == 0) { if (sourceEnd - lengthStream == 0) { throw new DecoderException($"MermaidMode1: Not enough source bytes remaining. Have {sourceEnd - lengthStream}"); } length = *lengthStream; if (length > 251) { if (sourceEnd - lengthStream < 3) { throw new DecoderException($"MermaidMode1: Not enough source bytes remaining. Have {sourceEnd - lengthStream}. Need 3"); } length += *(ushort *)(lengthStream + 1) * 4; lengthStream += 2; } lengthStream += 1; length += 64; if (destinationEnd - destination < length || litStreamEnd - litStream < length) { throw new DecoderException($"MermaidMode1: destinationEnd - destination < length || litStreamEnd - litStream < length"); } do { Util.Copy64(destination, litStream); Util.Copy64(destination + 8, litStream + 8); destination += 16; litStream += 16; length -= 16; } while (length > 0); destination += length; litStream += length; } else if (flag == 1) { if (sourceEnd - lengthStream == 0) { throw new DecoderException($"MermaidMode1: Not enough source bytes remaining. Have {sourceEnd - lengthStream}"); } length = *lengthStream; if (length > 251) { if (sourceEnd - lengthStream < 3) { throw new DecoderException($"MermaidMode1: Not enough source bytes remaining. Have {sourceEnd - lengthStream}. Need 3"); } length += *(ushort *)(lengthStream + 1) * 4; lengthStream += 2; } lengthStream += 1; length += 91; if (off16Stream == off16StreamEnd) { throw new DecoderException($"MermaidMode1: off16Stream == off16StreamEnd"); } match = destination - *off16Stream++; recentOffs = (int)(match - destination); do { Util.Copy64(destination, match); Util.Copy64(destination + 8, match + 8); destination += 16; match += 16; length -= 16; } while (length > 0); destination += length; } else { if (sourceEnd - lengthStream == 0) { throw new DecoderException($"MermaidMode1: sourceEnd - lengthStream == 0"); } length = *lengthStream; if (length > 251) { if (sourceEnd - lengthStream < 3) { throw new DecoderException($"MermaidMode1: Not enough source bytes remaining. Have {sourceEnd - lengthStream}. Need 3"); } length += *(ushort *)(lengthStream + 1) * 4; lengthStream += 2; } lengthStream += 1; length += 29; if (off32Stream == off32StreamEnd) { throw new DecoderException($"MermaidMode1: off32Stream == off32StreamEnd"); } match = destinationBegin - *off32Stream++; recentOffs = (int)(match - destination); do { Util.Copy64(destination, match); Util.Copy64(destination + 8, match + 8); destination += 16; match += 16; length -= 16; } while (length > 0); destination += length; } } length = (int)(destinationEnd - destination); if (length >= 8) { do { Util.Copy64(destination, litStream); destination += 8; litStream += 8; length -= 8; } while (length >= 8); } if (length > 0) { do { *destination++ = *litStream++; } while (--length > 0); } *savedDist = recentOffs; lz->LengthStream = lengthStream; lz->Offset16Stream = off16Stream; lz->LitStream = litStream; return(lengthStream); }
private bool MermaidReadLzTable(int mode, byte *source, byte *sourceEnd, byte *destination, int destinationSize, long offset, byte *scratch, byte *scratchEnd, MermaidLzTable *lz) { byte *scratchOut; int decodeCount; int numBytes; uint temp; uint offset32Size2; uint offset32Size1; if (mode > 1) { return(false); } if (sourceEnd - source < 10) { return(false); } if (offset == 0) { Util.Copy64(destination, source); destination += 8; source += 8; } //Decode lit stream scratchOut = scratch; numBytes = DecodeBytes(&scratchOut, source, sourceEnd, &decodeCount, (uint)Math.Min(scratchEnd - scratch, destinationSize), false, scratch, scratchEnd); source += numBytes; lz->LitStream = scratchOut; lz->LitStreamEnd = scratchOut + decodeCount; scratch += decodeCount; //Decode flag stream scratchOut = scratch; numBytes = DecodeBytes(&scratchOut, source, sourceEnd, &decodeCount, (uint)Math.Min(scratchEnd - scratch, destinationSize), false, scratch, scratchEnd); source += numBytes; lz->CmdStream = scratchOut; lz->CmdStreamEnd = scratchOut + decodeCount; scratch += decodeCount; lz->CmdStream2OffsetsEnd = (uint)decodeCount; if (destinationSize <= 0x10000) { lz->CmdStream2Offsets = (uint)decodeCount; } else { if (sourceEnd - source < 2) { throw new DecoderException($"MermaidReadLzTable: Too few bytes ({sourceEnd - source}) remaining"); } lz->CmdStream2Offsets = *(ushort *)source; source += 2; if (lz->CmdStream2Offsets > lz->CmdStream2OffsetsEnd) { throw new DecoderException($"MermaidReadLzTable: lz->CmdStream2Offsets ({lz->CmdStream2Offsets}) > lz->CmdStream2OffsetsEnd ({lz->CmdStream2OffsetsEnd})"); } } if (sourceEnd - source < 2) { throw new DecoderException($"MermaidReadLzTable: Too few bytes ({sourceEnd - source}) remaining"); } int off16Count = *(ushort *)source; if (off16Count == 0xFFFF) { byte *offset16Low; byte *offset16High; int offset16LowCount; int offset16HighCount; source += 2; offset16High = scratch; numBytes = DecodeBytes(&offset16High, source, sourceEnd, &offset16HighCount, (uint)Math.Min(scratchEnd - scratch, destinationSize >> 1), false, scratch, scratchEnd); source += numBytes; scratch += offset16HighCount; offset16Low = scratch; numBytes = DecodeBytes(&offset16Low, source, sourceEnd, &offset16LowCount, (uint)Math.Min(scratchEnd - scratch, destinationSize >> 1), false, scratch, scratchEnd); source += numBytes; scratch += offset16LowCount; if (offset16LowCount != offset16HighCount) { throw new DecoderException($"MermaidReadLzTable: offset16LowCount ({offset16LowCount}) != offset16HighCount ({offset16HighCount})"); } scratch = Util.AlignPointer(scratch, 2); lz->Offset16Stream = (ushort *)scratch; if (scratch + offset16LowCount * 2 > scratchEnd) { throw new DecoderException($"MermaidReadLzTable: scratch + offset16LowCount * 2 > scratchEnd"); } scratch += offset16LowCount * 2; lz->Offset16StreamEnd = (ushort *)scratch; MermaidCombineOffset16(lz->Offset16Stream, offset16LowCount, offset16Low, offset16High); } else { lz->Offset16Stream = (ushort *)(source + 2); source += 2 + off16Count * 2; lz->Offset16StreamEnd = (ushort *)source; } if (sourceEnd - source < 3) { throw new DecoderException($"MermaidReadLzTable: Too few bytes ({sourceEnd - source}) remaining"); } temp = (uint)(source[0] | source[1] << 8 | source[2] << 16); source += 3; if (temp != 0) { offset32Size1 = temp >> 12; offset32Size2 = temp & 0xFFF; if (offset32Size1 == 4095) { if (sourceEnd - source < 2) { throw new DecoderException($"MermaidReadLzTable: Too few bytes ({sourceEnd - source}) remaining"); } offset32Size1 = *(ushort *)source; source += 2; } if (offset32Size2 == 4095) { if (sourceEnd - source < 2) { throw new DecoderException($"MermaidReadLzTable: Too few bytes ({sourceEnd - source}) remaining"); } offset32Size2 = *(ushort *)source; source += 2; } lz->Offset32Stream1Size = offset32Size1; lz->Offset32Stream2Size = offset32Size2; if (scratch + 4 * (offset32Size1 + offset32Size2) + 64 > scratchEnd) { throw new DecoderException($"MermaidReadLzTable: Not enough remaining scratch space"); } scratch = Util.AlignPointer(scratch, 4); lz->Offset32Stream1 = (uint *)scratch; scratch += offset32Size1 * 4; // store dummy bytes after for prefetcher. ((ulong *)scratch)[0] = 0; ((ulong *)scratch)[1] = 0; ((ulong *)scratch)[2] = 0; ((ulong *)scratch)[3] = 0; scratch += 32; lz->Offset32Stream2 = (uint *)scratch; scratch += offset32Size2 * 4; // store dummy bytes after for prefetcher. ((ulong *)scratch)[0] = 0; ((ulong *)scratch)[1] = 0; ((ulong *)scratch)[2] = 0; ((ulong *)scratch)[3] = 0; scratch += 32; numBytes = MermaidDecodeFarOffsets(source, sourceEnd, lz->Offset32Stream1, lz->Offset32Stream1Size, offset); source += numBytes; numBytes = MermaidDecodeFarOffsets(source, sourceEnd, lz->Offset32Stream2, lz->Offset32Stream2Size, offset + 0x10000); source += numBytes; } else { if (scratchEnd - scratch < 32) { throw new DecoderException($"MermaidReadLzTable: Too few bytes ({sourceEnd - source}) remaining"); } lz->Offset32Stream1Size = 0; lz->Offset32Stream2Size = 0; lz->Offset32Stream1 = (uint *)scratch; lz->Offset32Stream2 = (uint *)scratch; // store dummy bytes after for prefetcher. ((ulong *)scratch)[0] = 0; ((ulong *)scratch)[1] = 0; ((ulong *)scratch)[2] = 0; ((ulong *)scratch)[3] = 0; } lz->LengthStream = source; return(true); }