scpsection2.cs
来自「ecg tool kit for medical image retrieval」· CS 代码 · 共 1,006 行 · 第 1/2 页
CS
1,006 行
/***************************************************************************
Copyright 2004-2007, Thoraxcentrum, Erasmus MC, Rotterdam, The Netherlands
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Written by Maarten JB van Ettinger.
****************************************************************************/
using System;
using System.Runtime.InteropServices;
using Communication.IO.Tools;
namespace ECGConversion.SCP
{
/// <summary>
/// Class contains section 2 (HuffmanTables).
/// </summary>
/// <remarks>
/// SCP uses a diffrent way to store codes, then UNIPRO. because I preffer the way UNIPRO
/// stores its codes. I store the SCP codes the same way as UNIPRO, but when I read/write
/// them from/to a buffer I reverse the code. This solution keeps the working of the SCP
/// and UNIPRO decode/encode very simalar, which is always a positive thing.
/// </remarks>
public class SCPSection2 : SCPSection
{
// Defined in SCP.
private static ushort _SectionID = 2;
private static ushort _DefaultTable = 19999;
// currently selected table.
private int _Selected = 0;
// Part of the stored Data Structure.
private ushort _NrTables = 0;
private SCPHuffmanStruct[][] _Tables = 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 * Marshal.SizeOf(typeof(SCPHuffmanStruct)) )) > 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 += Marshal.SizeOf(_Tables[table][loper]);
}
}
}
return 0x0;
}
protected override int _Write(byte[] buffer, int offset)
{
BytesTool.writeBytes(_NrTables, buffer, offset, Marshal.SizeOf(_NrTables), true);
offset += Marshal.SizeOf(_NrTables);
if (_NrTables < _DefaultTable)
{
for (int table=0;table < _NrTables;table++)
{
BytesTool.writeBytes(_Tables[table].Length, buffer, offset, Marshal.SizeOf(_NrTables), true);
offset += Marshal.SizeOf(_NrTables);
for (int loper=0;loper < _Tables[table].Length;loper++)
{
int err = _Tables[table][loper].Write(buffer, offset);
if (err != 0)
{
return err << table;
}
offset += Marshal.SizeOf(_Tables[table][loper]);
}
}
}
return 0x0;
}
protected override void _Empty()
{
_Tables = null;
_NrTables = 0;
}
protected override int _getLength()
{
if (Works())
{
int sum = Marshal.SizeOf(_NrTables);
if (_NrTables != _DefaultTable)
{
for (int table=0;table < _NrTables;table++)
{
sum += Marshal.SizeOf(_NrTables) + (_Tables[table].Length * Marshal.SizeOf(typeof(SCPHuffmanStruct)));
}
}
return ((sum % 2) == 0 ? sum : sum + 1);
}
return 0;
}
public override ushort getSectionID()
{
return _SectionID;
}
public override bool Works()
{
if ((_Tables != null)
&& (_NrTables == _Tables.Length))
{
for (int table=0;table < _Tables.Length;table++)
{
if (_Tables[table] == null)
{
return false;
}
for (int loper=0;loper < _Tables[table].Length;loper++)
{
if (_Tables[table][loper] == null)
{
return false;
}
}
}
return true;
}
else if ((_Tables == null)
&& ((_NrTables == _DefaultTable)
|| (_NrTables == 0)))
{
return true;
}
return false;
}
/// <summary>
/// Function to decode 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>
public short[] Decode(byte[] buffer, int offset, int nrbytes, int length, byte difference)
{
if (Works() || (_NrTables == 0))
{
if (_NrTables == _DefaultTable)
{
return InhouseDecode(buffer, offset, nrbytes, length, difference);
}
else if (_NrTables == 0)
{
return NoDecode(buffer, offset, nrbytes, length, difference);
}
else
{
return HuffmanTableDecode(buffer, offset, nrbytes, length, difference);
}
}
return null;
}
/// <summary>
/// Function to do huffman decode of encoded data. (using SCP default huffmantable)
/// </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>
public static short[] InhouseDecode(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);
int max = 9;
while (((currentBit >> 3) < nrbytes)
&& ((currentTime) < length))
{
int count = 0;
// Read in bits till 0 bit or defined maximum.
for (;(count < max) && ((currentBit >> 3) < nrbytes) && (((buffer[currentBit >> 3] >> (0x7 - (currentBit & 0x7))) & 0x1) != 0);count++, currentBit++);
// Increase current bit one more time
if (count != max)
{
currentBit++;
}
// If it doesn't fit stop
if ((currentBit >> 3) >= nrbytes)
{
break;
}
if (count >= max)
{
// Read in last bit
bool tmp = (((buffer[currentBit >> 3] >> (0x7 - (currentBit & 0x7))) & 0x1) == 0);
currentBit++;
// store starting point of additional bits.
int start = currentBit;
// If last bit 0 read in 8 additional bits else 16 additional bits.
int stop = currentBit + (tmp ? 8 : 16);
// If it doesn't fit return with error
if ((stop >> 3) >= nrbytes)
{
break;
}
// Reading in number of extra bits.
for (count=0;currentBit < stop;currentBit++)
{
count <<= 1;
count |= ((buffer[currentBit >> 3] >> (0x7 - (currentBit & 0x7))) & 0x1);
if ((start == currentBit)
&& (count != 0))
{
count = -1;
}
}
}
else if (count != 0)
{
// If it doesn't fit stop
if ((currentBit >> 3) >= nrbytes)
{
break;
}
// if last bit is one value is negative.
if (((buffer[currentBit >> 3] >> (0x7 - (currentBit & 0x7))) & 0x1) != 0)
{
count = -count;
}
currentBit++;
}
// Decode Differences.
switch (difference)
{
case 0:
leadData[currentTime] = ((short) count);
break;
case 1:
leadData[currentTime] = ((currentTime == 0) ? (short) count : (short) (count + leadData[currentTime - 1]));
break;
case 2:
leadData[currentTime] = ((currentTime < 2) ? (short) count : (short) (count + (leadData[currentTime - 1] << 1) - leadData[currentTime - 2]));
break;
default:
// Undefined difference used exit empty.
return null;
}
// Increment time by one.
currentTime++;
}
return leadData;
}
return null;
}
/// <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;
}
/// <summary>
/// Find next hit in byte array starting at an offset in bits.
/// </summary>
/// <param name="buffer">byte array containing encoded data</param>
/// <param name="offset">position (in bits) to start searching for a hit</param>
/// <returns>Info of hit.</returns>
private SCPHuffmanStruct InterpettingData(byte[] buffer, int offset)
{
if ((_Tables[_Selected] != null)
&& (buffer != null))
{
uint bitBuffer = 0;
int readMax = _Tables[_Selected][_Tables[_Selected].Length-1].prefix;
for (int read=0;read < readMax&&((read + offset) >> 3) < buffer.Length;read++)
{
bitBuffer <<= 1;
bitBuffer |= (uint) ((buffer[(offset + read) >> 3] >> (0x7 - ((offset + read) & 0x7))) & 0x1);
for (int table = 0;table < _Tables[_Selected].Length;table++)
{
if ((bitBuffer == _Tables[_Selected][table].code)
&& ((read + 1) == _Tables[_Selected][table].prefix))
{
return _Tables[_Selected][table];
}
}
}
}
return null;
}
/// <summary>
/// Function to do interpetting of unencoded 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>
public static short[] NoDecode(byte[] buffer, int offset, int nrbytes, int length, byte difference)
{
// Check if input data makes sense.
if ((buffer != null)
&& ((offset + nrbytes) <= buffer.Length)
&& ((length * Marshal.SizeOf(typeof(short))) <= nrbytes))
{
short[] leadData = new short[length];
for (int currentTime=0;currentTime < length;currentTime++)
{
short code = (short) BytesTool.readBytes(buffer, offset, Marshal.SizeOf(typeof(short)), true);
offset += Marshal.SizeOf(typeof(short));
// 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;
}
}
return leadData;
}
return null;
}
/// <summary>
/// Function to encode data.
/// </summary>
/// <param name="data">signal to read from</param>
/// <param name="time">number of samples to use</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>
public byte[] Encode(short[] data, int time, short usedTable, byte difference)
{
if (Works() || _NrTables == 0)
{
if (_NrTables == _DefaultTable)
{
return InhouseEncode(data, time, difference);
}
else if (_NrTables == 0)
{
return NoEncode(data, time, difference);
}
else
{
return HuffmanTableEncode(data, time, usedTable, difference);
}
}
return null;
}
/// <summary>
/// Function to encode signal using the default huffman table (using optimized code).
/// </summary>
/// <param name="data">signal to read from</param>
/// <param name="time">number of samples to use</param>
/// <param name="difference">difference to use durring decoding</param>
/// <returns>byte array containing encoded data</returns>
public static byte[] InhouseEncode(short[] data, int time, byte difference)
{
byte[] ret = null;
// Check if input makes sense
if ((data != null)
&& (time <= data.Length))
{
// Initialize some handy variables
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?