/// <param name="type">0 is YAZ0, 1 is YAY0, anything else is CompressionHeader</param>
        public int Compress(VoidPtr srcAddr, int srcLen, Stream outStream, IProgressTracker progress, int type)
        {
            _pSrc      = (byte *)srcAddr;
            _sourceLen = srcLen;

            int chunkCount = (int)Math.Ceiling((double)srcLen / _threadChunk);

            if (progress != null)
            {
                progress.Begin(0, srcLen, 0);
            }

            _contractions = new List <Contraction> [chunkCount];

            bool YAY0Comp = type == 1;

            if (type == 0)
            {
                YAZ0 header = new YAZ0();
                header._tag           = YAZ0.Tag;
                header._unCompDataLen = (uint)_sourceLen;
                outStream.Write(&header, YAZ0.Size);
            }
            else if (type == 1)
            {
                //Don't write YAY0 header yet.
                //Collect all compression data first
            }
            else
            {
                CompressionHeader header = new CompressionHeader();
                header.Algorithm    = CompressionType.RunLength;
                header.ExpandedSize = (uint)_sourceLen;
                outStream.Write(&header, 4 + (header.LargeSize ? 4 : 0));
            }

            ParallelLoopResult result = Parallel.For(0, chunkCount, FindContractions);

            while (!result.IsCompleted)
            {
                Thread.Sleep(100);
            }

            List <Contraction> fullContractions;
            int  codeBits, current;
            byte codeByte;
            //byte[] temp;
            int lastUpdate = srcLen;

            fullContractions = new List <Contraction>();
            for (int i = 0; i < _contractions.Length; i++)
            {
                fullContractions.AddRange(_contractions[i]);
                _contractions[i].Clear();
                _contractions[i] = null;
            }

            _contractions = null;

            //temp = new byte[3 * 8];
            codeBits = 0;
            codeByte = 0;
            current  = 0;

            List <byte>         tempCounts = new List <byte>();
            List <byte>         tempData   = new List <byte>();
            List <byte>         codes      = new List <byte>();
            List <List <byte> > counts     = new List <List <byte> >();
            List <List <byte> > data       = new List <List <byte> >();

            for (int i = 0; i < srcLen;)
            {
                if (codeBits == 8)
                {
                    codes.Add(codeByte);
                    counts.Add(tempCounts);
                    data.Add(tempData);

                    tempCounts = new List <byte>();
                    tempData   = new List <byte>();

                    codeBits = 0;
                    codeByte = 0;
                }

                if (current < fullContractions.Count && fullContractions[current].Location == i)
                {
                    if (fullContractions[current].Size >= 0x12)
                    {
                        byte
                            b1 = (byte)(fullContractions[current].Offset >> 8),
                            b2 = (byte)(fullContractions[current].Offset & 0xFF);

                        if (YAY0Comp)
                        {
                            tempCounts.Add(b1);
                            tempCounts.Add(b2);
                        }
                        else
                        {
                            tempData.Add(b1);
                            tempData.Add(b2);
                        }
                        tempData.Add((byte)(fullContractions[current].Size - 0x12));
                    }
                    else
                    {
                        byte
                            b1 = (byte)((fullContractions[current].Offset >> 8) | ((fullContractions[current].Size - 2) << 4)),
                            b2 = (byte)(fullContractions[current].Offset & 0xFF);

                        if (YAY0Comp)
                        {
                            tempCounts.Add(b1);
                            tempCounts.Add(b2);
                        }
                        else
                        {
                            tempData.Add(b1);
                            tempData.Add(b2);
                        }
                    }

                    i += fullContractions[current++].Size;

                    while (current < fullContractions.Count && fullContractions[current].Location < i)
                    {
                        current++;
                    }
                }
                else
                {
                    codeByte |= (byte)(1 << (7 - codeBits));
                    tempData.Add(_pSrc[i++]);
                }

                codeBits++;

                if (progress != null)
                {
                    if (i % 0x4000 == 0)
                    {
                        progress.Update(i);
                    }
                }
            }

            codes.Add(codeByte);
            counts.Add(tempCounts);
            data.Add(tempData);

            if (YAY0Comp)
            {
                //Write header
                YAY0 header = new YAY0();
                header._tag           = YAY0.Tag;
                header._unCompDataLen = (uint)_sourceLen;
                uint offset = 0x10 + (uint)codes.Count;
                header._countOffset = offset;
                foreach (List <byte> list in counts)
                {
                    offset += (uint)list.Count;
                }
                header._dataOffset = offset;
                outStream.Write(&header, YAY0.Size);

                //Write codes
                foreach (byte c in codes)
                {
                    outStream.WriteByte(c);
                }

                //Write counts
                foreach (List <byte> list in counts)
                {
                    outStream.Write(list.ToArray(), 0, list.Count);
                }

                //Write data
                foreach (List <byte> list in data)
                {
                    outStream.Write(list.ToArray(), 0, list.Count);
                }
            }
            else
            {
                for (int i = 0; i < codes.Count; i++)
                {
                    //Write code
                    outStream.WriteByte(codes[i]);
                    //Write data
                    outStream.Write(data[i].ToArray(), 0, data[i].Count);
                }
            }

            outStream.Flush();

            if (progress != null)
            {
                progress.Finish();
            }

            return((int)outStream.Length);
        }
Example #2
0
        public int CompressYAZ0(VoidPtr srcAddr, int srcLen, Stream outStream, IProgressTracker progress)
        {
            int  dstLen = 4, bitCount;
            byte control;

            byte *sPtr = (byte *)srcAddr;//, ceil = sPtr + srcLen;
            int   matchLength, matchOffset = 0;

            //Initialize
            Memory.Fill(_First, 0x40000, 0xFF);
            _wIndex = _wLength = 0;

            //Write header
            YAZ0 header = new YAZ0();

            header._tag           = YAZ0.Tag;
            header._unCompDataLen = (uint)srcLen;
            outStream.Write(&header, YAZ0.Size);

            byte[] blockBuffer = new byte[17];
            int    dInd;
            int    lastUpdate = srcLen;
            int    remaining  = srcLen;

            if (progress != null)
            {
                progress.Begin(0, remaining, 0);
            }

            while (remaining > 0)
            {
                dInd = 1;
                for (bitCount = 0, control = 0; (bitCount < 8) && (remaining > 0); bitCount++)
                {
                    control <<= 1;
                    if ((matchLength = FindPattern(sPtr, remaining, ref matchOffset)) != 0)
                    {
                        blockBuffer[dInd++] = (byte)(((matchLength - 3) << 4) | ((matchOffset - 1) >> 8));
                        blockBuffer[dInd++] = (byte)(matchOffset - 1);
                    }
                    else
                    {
                        control            |= 1;
                        matchLength         = 1;
                        blockBuffer[dInd++] = *sPtr;
                    }
                    Consume(sPtr, matchLength, remaining);
                    sPtr      += matchLength;
                    remaining -= matchLength;
                }
                //Left-align bits
                control <<= 8 - bitCount;

                //Write buffer
                blockBuffer[0] = control;
                outStream.Write(blockBuffer, 0, dInd);
                dstLen += dInd;

                if (progress != null)
                {
                    if ((lastUpdate - remaining) > 0x4000)
                    {
                        lastUpdate = remaining;
                        progress.Update(srcLen - remaining);
                    }
                }
            }
            outStream.Flush();

            if (progress != null)
            {
                progress.Finish();
            }

            return(dstLen);
        }