// 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 <= Weight) { // insert before if (Next != null) { Next.Prev = Other; Other.Next = Next; } Next = Other; Other.Prev = this; return Other; } else { if (Prev == null) { // Insert after Other.Prev = null; Prev = Other; Other.Next = this; } else { Prev.Insert(Other); } } return this; }
private static LinkedNode BuildList(byte[] PrimeData) { var 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 MpqParserException("Unexpected end of file"); } node = bit == 0 ? node.Child0 : node.Child1; } return(node); }
public static byte[] 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); return(outputstream.ToArray()); }
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; } }
// 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 prev; // Go backwards thru the list looking for the insertion point LinkedNode 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 BuildTree(LinkedNode Tail) { LinkedNode current = Tail; while(current != null) { LinkedNode child0 = current; LinkedNode child1 = current.Prev; if (child1 == null) break; var 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) { var 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 MpqParserException("Unexpected end of file"); node = bit == 0 ? node.Child0 : node.Child1; } return node; }