⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scp-decode.cpp

📁 BIOSIG is an open source software library for biomedical signal processing. Library works well with
💻 CPP
📖 第 1 页 / 共 5 页
字号:
/*
---------------------------------------------------------------------------
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 + -