public async Task Extract() { TotalWords = (await mRead(64)).GetValueOrDefault(); FileLength?.Invoke(TotalWords); mMaxHistory = Convert.ToUInt32((await mRead(32)).GetValueOrDefault()); mPresentLength = Convert.ToInt32((await mRead(8)).GetValueOrDefault()); int historyLengthInBits = Log2_WiegleyJ(mMaxHistory - 1) + 1; while (mWordsWritten < TotalWords) { var type = await mRead(1); if (type == null) { throw new EndOfStreamException(); } if (type.Value == 1) { var word = await mRead(8); if (word == null) { throw new EndOfStreamException(); } await mWrite(word.Value, 8); mHistory.AddLast(Convert.ToByte(word.Value)); if (mHistory.Count > mMaxHistory) { mHistory.RemoveFirst(); } mWordsWritten++; WordsWritten?.Invoke(1); } else if (type.Value == 0) { var offset = await mRead(historyLengthInBits); var length = await mRead(mPresentLength); if (offset == null || length == null) { throw new EndOfStreamException(); } if (offset >= mHistory.Count) { throw new ArgumentOutOfRangeException(nameof(offset)); } if (offset < length - 1) { throw new ArgumentOutOfRangeException(nameof(length)); } var pointer = mHistory.Last; for (int i = 0; i < offset.Value; i++) { pointer = pointer.Previous; } for (int i = 0; i < length.Value; i++) { mHistory.AddLast(pointer.Value); await mWrite(pointer.Value, 8); pointer = pointer.Next; if (mHistory.Count > mMaxHistory) { mHistory.RemoveFirst(); } } mWordsWritten += length.Value; WordsWritten?.Invoke(length.Value); } else { throw new ArgumentOutOfRangeException(nameof(type)); } } }
public async Task Decode() { /* --Structure-- * word length : byte * original file length in bytes : long * tree : Bit... * code : Bit... */ //Reading word length, original file length this.wordLength = (byte)await reader.ReadCustomLength(8); long originalFileLength = (long)await reader.ReadCustomLength(64); WordLength?.Invoke(this.wordLength, originalFileLength); if (originalFileLength > 0) { //Parsing tree from bits TreeNode root = await ParseDecodeTreeAsync(); //Creating decode table Dictionary <long?, (long?code, int codeLength)> encodingTable = await CreateEncodingsAsync(root); decimal bytesWritten = 0; decimal wordToBytes = ((decimal)this.wordLength) / 8; while (bytesWritten + wordToBytes <= originalFileLength) { TreeNode branch = root; while (branch.leaf == null) { long?currentBit = await reader.ReadCustomLength(1); branch = currentBit == 1 ? branch.Right : branch.Left; } bytesWritten += wordToBytes; await this.writer.WriteCustomLength((long)branch.leaf, this.wordLength); WordsWritten?.Invoke(1); } TreeNode branch2 = root; var da = (((decimal)originalFileLength) - bytesWritten); var remainder = (8 * (((decimal)originalFileLength) - bytesWritten)); if (remainder > 0) { while (true) { long?currentBit = await reader.ReadCustomLength(1); branch2 = currentBit == 1 ? branch2.Right : branch2.Left; if (branch2.leaf != null) { bytesWritten += wordToBytes; var d = (int)(remainder * this.wordLength); await this.writer.WriteCustomLength((long)(branch2.leaf >> (this.wordLength - (int)remainder)), (int)remainder); WordsWritten?.Invoke(1); break; } } } } //Save //await this.writer.FlushBuffer(); }
public async Task Encode(byte wordLength) { this.wordLength = wordLength; //Calculate word frequencies //------------------------------------------------------------------------- Dictionary <long?, long> frequencies = await CalculateFrequencyAsync(); //Check if empty file if (frequencies.Count > 0) { //Create encoding tree //------------------------------------------------------------------------- //Create sorted list List <KeyValuePair <long?, long> > frequencyList = frequencies.ToList(); frequencyList.Sort((val1, val2) => (val1.Value.CompareTo(val2.Value))); //Creating tree TreeNode root = await CreateEncodeTree(frequencyList); //Create encoding table from tree //------------------------------------------------------------------------- Dictionary <long?, (long?code, int codeLength)> encodingTable = await CreateEncodingsAsync(root); //Encode file //------------------------------------------------------------------------- /* --Structure-- * word length : byte * original file length in bytes : long * tree : Bits... * code : Bits... */ long originalFileLength = reader.GetFileSize(); //Writing await this.writer.WriteCustomLength((long)this.wordLength, sizeof(byte) * 8); await this.writer.WriteCustomLength(originalFileLength, sizeof(long) * 8); //Writing tree await WriteEncodingTreeAsync(root); long?currentWord; long bitsWritten = 0; while ((currentWord = await this.reader.ReadCustomLength(this.wordLength)) != null) { bitsWritten += encodingTable[currentWord].codeLength; await this.writer.WriteCustomLength((long)encodingTable[currentWord].code, encodingTable[currentWord].codeLength); WordsWritten?.Invoke(1); } for (int i = this.wordLength - 1; i > 0; i--) { currentWord = await this.reader.ReadCustomLength(i); if (currentWord != null) { currentWord <<= this.wordLength - i; bitsWritten += encodingTable[currentWord].codeLength; await this.writer.WriteCustomLength((long)encodingTable[currentWord].code, encodingTable[currentWord].codeLength); WordsWritten?.Invoke(1); } } } else { //File is empty //Encode file //------------------------------------------------------------------------- /* --Structure-- * word length : byte * original file length in bytes : long */ //Writing empty file with word length and size of 0 await this.writer.WriteCustomLength((long)this.wordLength, sizeof(byte) * 8); await this.writer.WriteCustomLength(0, sizeof(long) * 8); } //Save //await this.writer.FlushBuffer(); }
public async Task Compress(ulong size) { byte historyLengthInBits = (byte)(Log2_WiegleyJ(mMaxHistory - 1) + 1); byte presentLengthInBits = (byte)(Log2_WiegleyJ((uint)mPresent.Count) + 1); Console.WriteLine($"History length in bits: {historyLengthInBits}; present length in bits: {presentLengthInBits}"); int typeThreshold = (1 + historyLengthInBits + presentLengthInBits) / (1 + sizeof(byte)); // write file size, most significant part first await mWrite(unchecked ((long)size), 64); // write history size (in bytes) await mWrite(mMaxHistory, 32); // write present size (in bits) await mWrite(presentLengthInBits, 8); byte?nextWord; while (mPresent.Count > 0) { int bestPosition = 0; int bestLength = 0; var historyStart = mHistory.Last; int currentPosition = 0; while (historyStart != null) { var present = mPresent.First; var history = historyStart; if (history.Value == present.Value) { int maxPossibleLength = Math.Min(mPresent.Count, currentPosition + 1); int currentLength = 1; history = history.Next; present = present.Next; while (currentLength < maxPossibleLength && history.Value == present.Value) { currentLength++; history = history.Next; present = present.Next; } if (currentLength > bestLength) { bestLength = currentLength; bestPosition = currentPosition; } } currentPosition++; historyStart = historyStart.Previous; } if (bestLength <= typeThreshold) { // couldn't find matching word await mWrite(1, 1); byte word = mPresent.First.Value; mPresent.RemoveFirst(); await mWrite(word, 8); mHistory.AddLast(word); WordsWritten?.Invoke(1); nextWord = await mNextWord(); if (nextWord != null) { mPresent.AddLast(nextWord.Value); } } else { // found a matching word await mWrite(0, 1); await mWrite(bestPosition, historyLengthInBits); await mWrite(bestLength, presentLengthInBits); WordsWritten?.Invoke(bestLength); for (int i = 0; i < bestLength; i++) { byte word = mPresent.First.Value; mPresent.RemoveFirst(); mHistory.AddLast(word); nextWord = await mNextWord(); if (nextWord != null) { mPresent.AddLast(nextWord.Value); } } } while (mHistory.Count > mMaxHistory) { mHistory.RemoveFirst(); } } }