// TODO: This would be more efficient as a member of the other class // ie avoid the recursion public LinkedNode Insert(LinkedNode other) { // 'Next' should have a lower weight // we should return the lower weight if (other.Weight <= this.Weight) { // insert before if (this.Next != null) { this.Next.Prev = other; other.Next = this.Next; } this.Next = other; other.Prev = this; return other; } else { if (this.Prev == null) { // Insert after other.Prev = null; this.Prev = other; other.Next = this; } else { this.Prev.Insert(other); } } return this; }
private static LinkedNode BuildList(byte[] primeData) { LinkedNode root; root = new LinkedNode(256, 1); root = root.Insert(new LinkedNode(257, 1)); for (int i = 0; i < primeData.Length; i++) { if (primeData[i] != 0) { root = root.Insert(new LinkedNode(i, primeData[i])); } } return(root); }
private static LinkedNode Decode(BitStream input, LinkedNode head) { LinkedNode node = head; while (node.Child0 != null) { int bit = input.ReadBits(1); if (bit == -1) { throw new Exception("Unexpected end of file"); } node = bit == 0 ? node.Child0 : node.Child1; } return(node); }
public static MemoryStream Decompress(Stream data) { int comptype = data.ReadByte(); if (comptype == 0) { throw new NotImplementedException("Compression type 0 is not currently supported"); } LinkedNode tail = BuildList(sPrime[comptype]); LinkedNode head = BuildTree(tail); MemoryStream outputstream = new MemoryStream(); BitStream bitstream = new BitStream(data); int decoded; do { LinkedNode node = Decode(bitstream, head); decoded = node.DecompressedValue; switch (decoded) { case 256: break; case 257: int newvalue = bitstream.ReadBits(8); outputstream.WriteByte((byte)newvalue); tail = InsertNode(tail, newvalue); break; default: outputstream.WriteByte((byte)decoded); break; } } while (decoded != 256); outputstream.Seek(0, SeekOrigin.Begin); return(outputstream); }
private static LinkedNode BuildTree(LinkedNode tail) { LinkedNode current = tail; while (current != null) { LinkedNode child0 = current; LinkedNode child1 = current.Prev; if (child1 == null) { break; } LinkedNode parent = new LinkedNode(0, child0.Weight + child1.Weight); parent.Child0 = child0; child0.Parent = parent; child1.Parent = parent; current.Insert(parent); current = current.Prev.Prev; } return(current); }
// This increases the weight of the new node and its antecendants // and adjusts the tree if needed private static void AdjustTree(LinkedNode newNode) { LinkedNode current = newNode; while (current != null) { current.Weight++; LinkedNode insertpoint; LinkedNode prev; // Go backwards thru the list looking for the insertion point insertpoint = current; while (true) { prev = insertpoint.Prev; if (prev == null) { break; } if (prev.Weight >= current.Weight) { break; } insertpoint = prev; } // No insertion point found if (insertpoint == current) { current = current.Parent; continue; } // The following code basicly swaps insertpoint with current // remove insert point if (insertpoint.Prev != null) { insertpoint.Prev.Next = insertpoint.Next; } insertpoint.Next.Prev = insertpoint.Prev; // Insert insertpoint after current insertpoint.Next = current.Next; insertpoint.Prev = current; if (current.Next != null) { current.Next.Prev = insertpoint; } current.Next = insertpoint; // remove current current.Prev.Next = current.Next; current.Next.Prev = current.Prev; // insert current after prev LinkedNode temp = prev.Next; current.Next = temp; current.Prev = prev; temp.Prev = current; prev.Next = current; // Set up parent/child links LinkedNode currentparent = current.Parent; LinkedNode insertparent = insertpoint.Parent; if (currentparent.Child0 == current) { currentparent.Child0 = insertpoint; } if (currentparent != insertparent && insertparent.Child0 == insertpoint) { insertparent.Child0 = current; } current.Parent = insertparent; insertpoint.Parent = currentparent; current = current.Parent; } }
private static LinkedNode InsertNode(LinkedNode tail, int decomp) { LinkedNode parent = tail; LinkedNode result = tail.Prev; // This will be the new tail after the tree is updated LinkedNode temp = new LinkedNode(parent.DecompressedValue, parent.Weight); temp.Parent = parent; LinkedNode newnode = new LinkedNode(decomp, 0); newnode.Parent = parent; parent.Child0 = newnode; tail.Next = temp; temp.Prev = tail; newnode.Prev = temp; temp.Next = newnode; AdjustTree(newnode); // TODO: For compression type 0, AdjustTree should be called // once for every value written and only once here AdjustTree(newnode); return result; }
private static LinkedNode Decode(BitStream input, LinkedNode head) { LinkedNode node = head; while (node.Child0 != null) { int bit = input.ReadBits(1); if (bit == -1) { throw new Exception("Unexpected end of file"); } node = bit == 0 ? node.Child0 : node.Child1; } return node; }
private static LinkedNode BuildTree(LinkedNode tail) { LinkedNode current = tail; while (current != null) { LinkedNode child0 = current; LinkedNode child1 = current.Prev; if (child1 == null) { break; } LinkedNode parent = new LinkedNode(0, child0.Weight + child1.Weight); parent.Child0 = child0; child0.Parent = parent; child1.Parent = parent; current.Insert(parent); current = current.Prev.Prev; } return current; }
private static LinkedNode BuildList(byte[] primeData) { LinkedNode root; root = new LinkedNode(256, 1); root = root.Insert(new LinkedNode(257, 1)); for (int i = 0; i < primeData.Length; i++) { if (primeData[i] != 0) { root = root.Insert(new LinkedNode(i, primeData[i])); } } return root; }