/// <summary> /// Function to find corresponding HuffmanStruct with value. /// </summary> /// <param name="value">value to search</param> /// <returns>corresponding HuffmanStruct</returns> private SCPHuffmanStruct InterpettingData(short value) { // Check if selected Table exists if ((_Tables != null) && (_Tables[_Selected] != null)) { // Search in structs of table. for (int loper = 0; loper < _Tables[_Selected].Length; loper++) { SCPHuffmanStruct h = _Tables[_Selected][loper]; // -1, because it can be positive and negative int extra = (h.entire - h.prefix - 1); // Check if value is equal to struct. if ((h.value == value) && (h.tablemode != 0)) { return(h); } // Check if value fits in special case. else if ((extra > 0) && ((value - h.value) < (0x1 << extra)) && ((value - h.value) >= -(0x1 << extra)) && (h.tablemode != 0)) { return(h); } } } return(null); }
protected override int _Read(byte[] buffer, int offset) { int end = offset - Size + Length; if ((offset + Marshal.SizeOf(_NrTables)) > end) { return(0x1); } _NrTables = (ushort)BytesTool.readBytes(buffer, offset, Marshal.SizeOf(_NrTables), true); offset += Marshal.SizeOf(_NrTables); if (_NrTables < _DefaultTable) { _Tables = new SCPHuffmanStruct[_NrTables][]; for (int table = 0; table < _NrTables; table++) { if ((offset + Marshal.SizeOf(_NrTables)) > end) { _Empty(); return(0x2); } _Tables[table] = new SCPHuffmanStruct[BytesTool.readBytes(buffer, offset, Marshal.SizeOf(_NrTables), true)]; offset += Marshal.SizeOf(_NrTables); if ((offset + (_Tables[table].Length * SCPHuffmanStruct.Size)) > end) { _Empty(); return(0x4); } for (int loper = 0; loper < _Tables[table].Length; loper++) { _Tables[table][loper] = new SCPHuffmanStruct(); int err = _Tables[table][loper].Read(buffer, offset); if (err != 0) { return(err << 3 + table); } offset += SCPHuffmanStruct.Size; } } } return(0x0); }
/// <summary> /// Function to encode signal using the huffman table. /// </summary> /// <param name="data">signal to read from</param> /// <param name="time">number of samples to use</param> /// <param name="quanta">sample distance in signal</param> /// <param name="usedTable">table to use for encoding</param> /// <param name="difference">difference to use durring decoding</param> /// <returns>byte array containing encoded data</returns> private byte[] HuffmanTableEncode(short[] data, int time, short usedTable, byte difference) { byte[] ret = null; // Check if input makes sense if ((data != null) && (time <= data.Length)) { // Initialize some handy variables int currentBit = 0; // Make buffer for worst case. byte[] buffer = null; if ((usedTable >= 0) && (usedTable < _Tables.Length) && (usedTable != _Selected)) { uint code = 0; int len = 0; // get TableSwap position in HuffmanTable. int p = getTableSwap(usedTable); // Check if table swap is possible in this table. if (p >= 0) { // Store needed data from swap HuffmanStruct. code = _Tables[_Selected][p].code; len = _Tables[_Selected][p].entire; // set currently selected table. _Selected = usedTable; } // allocate buffer for worstcase. buffer = new byte[((len + (time * getWorstCase())) >> 3) + 1]; // add table swap. for (len--; len >= 0; len--) { buffer[currentBit >> 3] <<= 1; buffer[currentBit >> 3] |= (byte)((code >> len) & 0x1); currentBit++; } } else { // No tables swap, so only space needed for worst case. buffer = new byte[((time * getWorstCase()) >> 3) + 1]; } // For each sample do encode. for (int currentTime = 0; currentTime < time; currentTime++) { short code = 0; // Encode Differences. switch (difference) { case 0: code = data[currentTime]; break; case 1: code = (short)((currentTime < 1) ? data[currentTime] : data[currentTime] - data[currentTime - 1]); break; case 2: code = (short)((currentTime < 2) ? data[currentTime] : data[currentTime] - (data[currentTime - 1] << 1) + data[currentTime - 2]); break; default: // Undefined difference used exit empty. return(null); } // Call Interpetting data to get an hit. SCPHuffmanStruct h = InterpettingData(code); if (h == null) { // not hit table or data must be wrong. return(null); } // Push in the code. for (int loper = (h.prefix - 1); loper >= 0; loper--) { buffer[currentBit >> 3] <<= 1; buffer[currentBit >> 3] |= (byte)((h.code >> loper) & 0x1); currentBit++; } // Push in the extra code, for special case. uint now = (uint)(code - h.value); for (int loper = (h.entire - h.prefix - 1); loper >= 0; loper--) { buffer[currentBit >> 3] <<= 1; buffer[currentBit >> 3] |= (byte)((code >> loper) & 0x1); currentBit++; } } // Shift end to right position. if ((currentBit & 0x7) != 0x0) { buffer[(currentBit >> 3)] <<= (0x8 - (currentBit & 0x7)); currentBit += (0x8 - (currentBit & 0x7)); } else { // seems to solve a small encoding bug. currentBit += 8; } // Allocate a fitting buffer ret = new byte[(currentBit >> 3)]; // Copy worst case buffer in fitting buffer. for (int loper = 0; loper < ret.Length; loper++) { ret[loper] = buffer[loper]; } } return(ret); }
/// <summary> /// Function to do huffman decode of encoded data. /// </summary> /// <param name="buffer">buffer to read in</param> /// <param name="offset">position to start reading</param> /// <param name="nrbytes">nrbytes of encoded bytes in buffer</param> /// <param name="length">length of signal in samples</param> /// <param name="difference">difference to use durring decoding</param> /// <returns>short array containing decoded data</returns> private short[] HuffmanTableDecode(byte[] buffer, int offset, int nrbytes, int length, byte difference) { // This safes us some calculations. nrbytes += offset; // Check if input data makes sense. if ((buffer != null) && (nrbytes <= buffer.Length)) { // Setting up the variables for decode. short[] leadData = new short[length]; int currentTime = 0; int currentBit = (offset << 3); while (((currentBit >> 3) < nrbytes) && ((currentTime) < length)) { // Search for a hit. SCPHuffmanStruct h = InterpettingData(buffer, currentBit); // Exit if there was no hit. if (h == null) { return(null); } // Check if hit fits. if (((currentBit + h.entire) >> 3) >= nrbytes) { break; } // If table mode is 0 do switch. if (h.tablemode == 0) { _Selected = h.value - 1; continue; } short code = 0; // read extra data behind hit if available. for (int count = 0, start = (currentBit + h.prefix); count < (h.entire - h.prefix); count++) { code <<= 1; code += (short)((buffer[(start + count) >> 3] >> (0x7 - ((start + count) & 0x7))) & 0x1); if ((count == 0) && (code != 0)) { code = -1; } } // add up a the value of the hit. code += h.value; // Decode Differences. switch (difference) { case 0: leadData[currentTime] = code; break; case 1: leadData[currentTime] = ((currentTime == 0) ? code : (short)(code + leadData[currentTime - 1])); break; case 2: leadData[currentTime] = ((currentTime < 2) ? code : (short)(code + (leadData[currentTime - 1] << 1) - leadData[currentTime - 2])); break; default: // Undefined difference used exit empty. return(null); } // Increment current bit currentBit += h.entire; // Increment time by one. currentTime++; } return(leadData); } return(null); }