📄 scp-decode.cpp
字号:
/*
---------------------------------------------------------------------------
Copyright (C) 2006 Eugenio Cervesato.
Developed at the Associazione per la Ricerca in Cardiologia - Pordenone - Italy,
based on the work of Eugenio Cervesato & Giorgio De Odorico. The original
Copyright and comments follow.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
---------------------------------------------------------------------------
______________________________________________________________________________
scp-decode.cpp This is the "decode" module of the program SCP-AV.
It opens an SCP-ECG v1.0 to v2.0 test file and
extracts all the informations.
Release 2.3 - feb 2006
---------------------------------------------------------------------------
**************************************************************************
************************* original Copyright *****************************
Copyright (C) 2003-2004 Eugenio Cervesato & Giorgio De Odorico.
Developed at the Associazione per la Ricerca in Cardiologia - Pordenone - Italy.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
---------------------------------------------------------------------------
*/
//______________________________________________________________________________
/*
scp-decode.cpp This is the "decode" module of the program SCP-AV.
It opens an SCP-ECG v1.3 or v2.0 test file and
extracts all the informations.
Developed by ING. GIORGIO DE ODORICO (giorgio.deodorico@tiscali.it)
Documentation of the standard comes mainly from:
http://www.centc251.org/TCMeet/doclist/TCdoc02/N02-015-prEN1064.pdf
Internationalization, test, bug fix by Eugenio Cervesato (eugenio.cervesato@aopn.fvg.it)
Release 2.1 - february 2004
*/
// ************************* end of the original Copyright *****************************
// contribution of Michael Breuss <m.breuss@tma-medical.com>. see 'by MB' in the sources
// contribution of Stelios Sfakianakis <ssfak@ics.forth.gr>. see 'by SS' in the sources
// contribution of Federico cantini <cantini@ifc.cnr.it>. see 'by FeC' in the sources
//void remark(char *string);
// by E.C. 13.10.2003 part nedded to compile with gcc (Linux).
// To compile with Borland C++ add the conditional define: WIN32.
// In porting, I nedded to adapt fseek() and write a custom ultoa()
#define TRUE 1
#define FALSE 0
// Insert by FeC
#if defined(__Cygwin__)
#define COMPAT
#include <stdio.h>
void ultoa(unsigned int x, char *s, int base)
{
if (base==10) sprintf(s, "%u", x); // by E.C. 08.02.2006. Only for base=10.
else sprintf(s, "%s", "err"); // uses standard call
}
#elif defined(WIN32)
#define COMPAT
// Insert by SS
#elif defined(__FreeBSD__)
#define COMPAT
#include <sstream>
#include <iomanip>
void ultoa(unsigned int x, char *s, int base)
{
std::ostringstream ss;
ss << std::setbase(base) << x;
strcpy(s, ss.str().c_str());
}
#else
#define COMPAT .__pos
#include <stdio.h>
void ultoa(unsigned int x, char *s, int base)
{
if (base==10) sprintf(s, "%u", x); // by E.C. 08.02.2006. Only for base=10.
else sprintf(s, "%s", "err"); // uses standard call
}
#endif
//______________________________________________________________________________
#include <iostream>
#include <cstring> //strcat, strcpy
#include <cstdio>
using namespace std;
//______________________________________________________________________________
// FILE POINTERS
FILE *in;
#include "../biosig.h"
#include "types.h"
#include "structures.h"
#include "codes.h"
//---------------------------------------------------------------------------
static U_int_L _COUNT_BYTE=1UL; // counter of bytes read
static U_int_L _DIM_FILE; // file length in byte
static const U_int_S _NUM_SECTION=12U; // sections over 11 are not considered
//______________________________________________________________________________
// section 2
U_int_S Input_Bit(U_int_S*,U_int_M&,U_int_M,U_int_S&,bool&);
int_M Input_Bits(U_int_S*,U_int_M&,U_int_M,U_int_S&,U_int_S,bool&);
void decompress(TREE_NODE*,int_M*,U_int_S&,U_int_M&,int_L*,U_int_M,U_int_M&,table_H*,U_int_M*,U_int_M&);
void Tree_Destroy(TREE_NODE*);
TREE_NODE *Tree_Create(TREE_NODE*,U_int_M,table_H*,U_int_M);
void Huffman(int_L*,U_int_M*,U_int_S*,U_int_M&,U_int_M,table_H*,U_int_M*);
void InitHuffman(table_H*); //inizialize default Huffman table
//______________________________________________________________________________
// sections 3, 4, 5 and 6
template<class t1>
void Differences(int_L*,t1,U_int_S);
void Multiply(int_L*,U_int_L,U_int_M);
void Interpolate(int_L*,int_L*,f_lead,lead*,f_Res,Protected_Area*,U_int_L);
void ExecFilter(int_L*,int_L*,U_int_L&,U_int_M);
void DoFilter(int_L*,int_L*,f_Res,f_lead,lead*,Protected_Area*,Subtraction_Zone*);
void DoAdd(int_L*,int_L*,f_Res,int_L*,f_BdR0,Subtraction_Zone*,f_lead,lead*);
void Opt_Filter(int_L*, int_L*, f_Res, f_lead, lead*, Protected_Area*);
//______________________________________________________________________________
// INTERNAL FUNCTIONS
char* ReadString(char*,U_int_M); //read a string
char *FindString(U_int_M); // calculate the length of a string and write it down
int_M Look(alfabetic*,U_int_M,U_int_M,U_int_M); //look at a number in alfabetic and give the position of the array
//______________________________________________________________________________
template<class t1>
void ReadByte(t1&); //read a byte from stream
void Skip(U_int_M); //skip some bytes
//______________________________________________________________________________
U_int_M ReadCRC(); //read first 6 bytes of the file
bool Check_CRC(U_int_M,U_int_L,U_int_L); // CRC check
//______________________________________________________________________________
U_int_L ID_section(U_int_L, int_S &version); //read section ID header
void section_0(pointer_section*, int size_max); //read section 0
void sectionsOptional(pointer_section*,DATA_DECODE&,DATA_RECORD&,DATA_INFO&); //handles optional sections
void Init_S1(DATA_INFO &inf);
void section_1(pointer_section,DATA_INFO&); //read section 1 data
void section_1_0(demographic&); //read tag 0 of section 1
void section_1_1(demographic&); //read tag 1 of section 1
void section_1_2(demographic&); // ... and so on ...
void section_1_3(demographic&);
void section_1_4(demographic&);
void section_1_5(demographic&);
void section_1_6(demographic&);
void section_1_7(demographic&);
void section_1_8(demographic&);
void section_1_9(demographic&);
void section_1_10(clinic&,U_int_M&);
void section_1_11(demographic&);
void section_1_12(demographic&);
void section_1_13(clinic&,U_int_M&);
void section_1_14(descriptive&);
void section_1_15(descriptive&);
void section_1_16(descriptive&);
void section_1_17(descriptive&);
void section_1_18(descriptive&);
void section_1_19(descriptive&);
void section_1_20(clinic&);
void section_1_21(clinic&);
void section_1_22(clinic&);
void section_1_23(descriptive&);
void section_1_24(descriptive&);
void section_1_25(device&);
void section_1_26(device&);
void section_1_27(device&);
void section_1_28(device&);
void section_1_29(device&);
void section_1_30(clinic&,U_int_M&);
void section_1_31(device&);
void section_1_32(clinic&,U_int_M&, int_S version);
void section_1_33(device&);
void section_1_34(device&);
void section_1_35(clinic&,U_int_M&);
void section_1_(); //skip tags of the manufacturer of the section 1
void section_1_255(); //read tag 255 of section 1
void section_2(pointer_section,DATA_DECODE&); //read section 2
void section_3(pointer_section,DATA_DECODE&, int_S version); //read section 3
void section_4(pointer_section,DATA_DECODE&, int_S version); //read section 4
void section_5(pointer_section,DATA_DECODE&,bool); //read section 5
void section_6(pointer_section,DATA_DECODE&,bool); //read section 6
void section_7(pointer_section,DATA_RECORD&, int_S version); //read section 7
void section_8(pointer_section,DATA_INFO&); //read section 8
void section_10(pointer_section,DATA_RECORD&, int_S version); //read section 10
void section_11(pointer_section,DATA_INFO&); //read section 11
//______________________________________________________________________________
void Decode_Data(pointer_section*,DATA_DECODE&,bool&);
//______________________________________________________________________________
void *mymalloc(size_t size) // by E.C. 07.11.2003 this is a workaround for a bug
{ // present somewhere in memory allocation.
// char buff[30]; // this problem should be fixed next!
// ultoa(size, buff, 10); // used for debug purposes, shows the size
// remark(buff);
// void *res=malloc(size*2); // this way each time a doubled memory is requested. And it works!!
void *res=malloc(size);
return res;
}
/* moved by MB
must be declared before first call (otherwise compiler error)
*/
//--------------------------------BYTE & BIT------------------------------------
template<class t1>
void ReadByte(t1 &number)
//read the requested number of bytes and
//convert in decimal, taking into account that the first byte is the LSB.
//the sign of the number is kept
{
U_int_S *num, dim=sizeof(t1);
U_int_S mask=0xFF;
if(dim!=0 && (num=(U_int_S*)mymalloc(dim))==NULL)
{
fprintf(stderr,"Not enough memory"); // no, exit //
exit(2);
}
fread(num,dim,1,in);
number=0;
_COUNT_BYTE+=dim;
while((dim--)>0)
{
number<<=8;
number+=num[dim]&mask;
}
free(num);
}//end ReadByte
// MAIN
int scp_decode(HDRTYPE* hdr, pointer_section *info_sections, DATA_DECODE &info_decoding, DATA_RECORD &info_recording, DATA_INFO &info_textual, bool &add_filter)
{
U_int_M CRC;
U_int_L pos;
// if( (in = fopen(filename, "rb")) ==NULL)
if ( (in = hdr->FILE.FID) ==NULL)
{
fprintf(stdout,"Cannot open the file %s.\n",hdr->FileName);// remark("Cannot open the file.");
// remark(filename);
return FALSE; // by E.C. 15.10.2003 now return FALSE
}
_COUNT_BYTE=1UL;
CRC=ReadCRC();
pos=_COUNT_BYTE;
ReadByte(_DIM_FILE);
// if (CRC != 0xFFFF) Check_CRC(CRC,pos,_DIM_FILE-2U); // by E.C. may 2004 CARDIOLINE 1.0
fseek(in, 0L, SEEK_SET);
//mandatory sections
//remark("before section 0");
section_0(info_sections, _DIM_FILE); // by E.C. may 2004 check file size
//remark("after section 0");
section_1(info_sections[1],info_textual);
//remark("after section 1");
sectionsOptional(info_sections,info_decoding,info_recording,info_textual);
//remark("at end of sections");
// fclose(in);
Decode_Data(info_sections,info_decoding,add_filter);
return TRUE; // by E.C. 15.10.2003 now return TRUE
}
//______________________________________________________________________________
// COMPUTATIONAL FUNCTIONS
//------------------------------STRINGS----------------------------------------
char *ReadString(char *temp_string, U_int_M num)
//read a string from the stream.
//the first extracted byte is written for fist.
//each byte read from the stream is first "transformed" in char.
{
if((temp_string=(char*)mymalloc(sizeof(char)*(num+2)))==NULL) // by E.C. 26.02.2004 one more byte
{
fprintf(stderr,"Not enough memory"); // no, exit //
exit(2);
}
if(!num)
return "";
_COUNT_BYTE+=num;
fread(temp_string,sizeof(char),num,in);
if (temp_string[num-1]!='\0')
temp_string[num]='\0';
return temp_string;
}//end ReadString
int_M Look(alfabetic *code_, U_int_M a, U_int_M b, U_int_M key_)
// look num in code_.number and give the element position
{
U_int_M middle=(a+b)/2U;
if(code_[middle].number==key_)
return middle;
if(a>=b)
return -1;
if(code_[middle].number<key_)
return Look(code_,middle+1,b,key_);
else
return Look(code_,a,middle-1,key_);
}//end Look
char *FindString(U_int_M max)
//read bytes until NULL
{
char *temp_string, c;
U_int_M num=0;
fpos_t filepos;
if(!max)
return "";
fgetpos(in,&filepos);
do
{
c=getc(in);
++num;
}
while(c!='\0' && num<max);
fseek(in,filepos COMPAT,0);
if((temp_string=(char*)mymalloc(sizeof(char)*(num+2)))==NULL) // by E.C. one extra byte nedded
{ // for later str_cat()
fprintf(stderr,"Not enough memory"); // no, exit //
exit(2);
}
if(!num)
return "";
_COUNT_BYTE+=num;
fread(temp_string,sizeof(char),num,in);
if (temp_string[num-1]!='\0')
temp_string[num]='\0';
return temp_string;
}//end FindString
void Skip(U_int_M num)
//skip num bytes from the stream
{
if(num>0U)
fseek(in,num,1U);
_COUNT_BYTE+=num;
}//end Skip
//______________________________________________________________________________
// INITIALIZATION FUNCTIONS
void InitHuffman(table_H *riga)
//build the default Huffman table
{
/*
The table is contructed as stated in the protocol SCP-ECG; each structure in each line.
Columns are:
bit_prefix = number of bits in the prefix
bit_code = number of bits in the code
TMS = table mode
base_value = base value (decoded)
cp = prefix code (in bits)
base_code = decimal value of reversed cp
From the stream I take a bit at a time until I find a correspondent value in the Huffman table.
If:
nbp=nbc the decode value is vb
nbp!=nbc
if m=1 I take nbc-nbp bits next in the stream
if m=0 change to table vb
Remark: Huffman tables stored in the stream contain vb in 2 complemented bytes.
The decimal value of cp is included. Furthermore, always the MSB comes first!
In my Huffman tables I set cp as a decimal value. Infact, I read a group of bits
from the stream and convert them by multipying by 2^pos (where pos is
0 for bit 0, 1 for bit 1 and so on). So I read bits as they are.
DEFAULT HUFFMAN TABLE
nbp nbc m vb cp10 cp
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -