关于CDMA短消息的彩信通知解码原理,网络上找到两篇博客:http://netsin.blog.hexun.com/34791040_d.html;http://blog.lytsing.org/archives/203.html。这里就不加以详细说明,协议格式可以参考TIA-EIA-637-A标准中的4.5.1 Message Identifier和4.5.2 User Data这两部分。MMS-NOTIFICATION的协议格式可以参考wap-209-mmsencapsulation-20020105-a文档。现在主要是利用代码来实现怎么提取彩信通知中的彩信URL。
一、数据类型的统一定义:
/********************************************************************** * 名 称: typedefine.h (通用类型及常量定义) * 功能描述: 一个通用的头文件,实现在不同操作系统下的一些通用类型,常量 * 及一些常量宏的定义 **********************************************************************/ #ifndef _TYPEDEFINE_H_F347AFC389350945 #define _TYPEDEFINE_H_F347AFC389350945 //本文件的类型定义受到如下宏定义的影响: //WIN32 : 编译Windows32环境下的程序 //LINUX : 编译LINUX环境下的程序 //SOLARIS : 编译SALARIS环境下的程序(如果定义了该宏且没有定义_NOCOMPAT_LINUX和LINUX宏,则会自动加上LINUX宏的定义) //_DEBUG : 编译成调试版本的程序 //_DETECT_MEMLEAK : 是否进行内存泄漏检查(应该在有_DEBUG的前提下使用) //_MEMLEAK_CONTENT : 在程序退出显示内存泄漏时,是否显示内存中的内容 //_USE_LOGPROCESS : 是否在程序中使用日志输出处理模块(log_process) //_USE_EXLOG_ASSERT : 如果存在该宏,则表示使用CExLog类的GlobalExLog对象来输出Assert信息. //_UNDEF_UWORD : 存在该宏表示不定义UWORDxxx系统的类型 //_UNDEF_BOOL : 存在该宏表示不定义BOOL类型 //_UNDEF_BYTE : 存在该宏则表示不定义BYTE,WORD,DWORD等类型 //_UNDEF_SIM_TYPE : 存在该宏则表示不定义UC,UI,SI等简单类型 //_UNDEF_STRING : 存在该宏则表示不定义字符串类型(LPCSTR,LPSTR)等 //_INCLUDE_PROGDEF : 如果存在该宏,则将会先包含:"progdef.h",应用程序自己通过定义头文件 //_NOCOMPAT_LINUX : 如果不定义该宏,则默认对SOLARIS环境自动定义LINUX宏.反之,定议该宏,将不会做此处理 //_USE_WINSOCK2 : 对于win32的程序,如果要使用winsock2,则需要定义该宏,否则默认为使用winsock1. //_ENABLE_DEBUG_PRINT: 如果定义该宏,则表示允许打印由DEBUG_PRINT定义输出的调用信息 //_ENABLE_DEBUG_PRINT1:如果定义该宏,则表示允许打印由DEBUG_PRINT1定义输出的调用信息 //_ENABLE_DEBUG_PRINT2:如果定义该宏,则表示允许打印由DEBUG_PRINT2定义输出的调用信息 //_ENABLE_DEBUG_PRINT3:如果定义该宏,则表示允许打印由DEBUG_PRINT3定义输出的调用信息 //_ENABLE_DEBUG_PRINT4:如果定义该宏,则表示允许打印由DEBUG_PRINT4定义输出的调用信息 // : (说明:DEBUG_PRINT,DEBUG_PRINT1,...,DEBUG_PRINT4可能针对不同类型的调试 // 信息的输出,然后由_ENABLE_DEBUG_PRINTn对其进行输出控制) // // (下面的宏应该在需要使用的程序中,单独定义,不建议放在Makefile文件中定义) //_TAKEOVER_NEW_DEL : 接管C++全局的的new和delete操作,用自定义的方法管理动态内存分配,可以防止使用new和 // : delete时产生内存碎片如果要保存调用new操作的代码的位置信息,应该在适当的位置定义 // : "#define new _DEBUG_NEW" //_USE_CLASS_MEM_POOL:标记是否使基于类的内存缓冲分配池(允许重载类的new和delete操作) // :说明:与_TAKEOVER_NEW_DEL不同的是,_TAKEOVER_NEW_DEL是全局的new和delete操作 // :若希望这个类无论在哪里都需要使用内存缓冲池分配内存,则推荐使用此宏. // :(使用_TAKEOVER_NEW_DEL宏可能会造成对在的delete操作不能被调用的情况) #ifdef _INCLUDE_PROGDEF #include "progdef.h" #endif //_INCLUDE_PROGDEF #ifdef SOLARIS #if !defined(_NOCOMPAT_LINUX) && !defined(LINUX) //# 如果没有定义不兼容LINUX的声明,且当前环境没有定义Linux宏,则自动定义该宏 #define LINUX #endif #endif //SOLARIS //************************ 包含头文件 ************************ #ifdef WIN32 //# WIN32: 包含Windows类型定义头文件 #ifdef _USE_WINSOCK2 #include <winsock2.h> #include <mswsock.h> #endif //_USER_WINSOCK2 #include <windows.h> #include <direct.h> #include <time.h> #ifdef _DEBUG //# WIN32调试版,包含调试相关函数的WIN32头文件 #include <crtdbg.h> #pragma warning(disable:4786) //禁止VC编译时出现Debug信息字符太多的告警信息 #endif #elif defined(LINUX) #include <unistd.h> #include <sys/stat.h> #include <sys/types.h> #include <string.h> #include <netinet/in.h> #endif //WIN else LINUX #ifdef SOLARIS #include <strings.h> #include <sys/time.h> #include <signal.h> #include <netinet/in.h> #endif //SOLARIS #ifdef _DETECT_MEMLEAK //# 只有在要求内存泄漏检查时才包含内存泄漏检查函数头文件 #include "memleak_detect.h" #endif //_DETECT_MEMLEAK #include <stdio.h> #include <stdlib.h> #include <ctype.h> //************************* 特殊定义 ************************* #define TYPEDEF typedef #define ENUM enum #define STRUCT struct //*********************** 通用类型定义 *********************** typedef short int int16; typedef unsigned short int uint16; typedef signed char int8; typedef unsigned char uint8; /* #ifdef _Solaris64_ //#Solaris 64位操作系统 typedef int int32; typedef unsigned int uint32; #else //#普通32位操作系统 typedef long int32; typedef unsigned long uint32; #endif //_Solaris64_ */ typedef int int32; typedef unsigned int uint32; #ifdef LINUX typedef long long int int64; typedef unsigned long long int uint64; #elif WIN32 typedef __int64 int64; typedef unsigned __int64 uint64; #endif //WIN32 #ifndef WIN32 //# 只有非WIN32程序才定义以下宏 typedef int INT; typedef unsigned int UINT; typedef long LONG; typedef unsigned long ULONG; typedef char CHAR; typedef unsigned short WCHAR; #ifdef _UNICODE typedef WCHAR TCHAR; #else //_UNICODE typedef CHAR TCHAR; #endif typedef void * PVOID; typedef void * LPVOID; typedef const void * CPVOID; #ifndef _UNDEF_STRING //# 如果没有定义宏_UNDEF_STRING,则定义以下类型 typedef const char * LPCSTR; typedef char * LPSTR; typedef const WCHAR * LPCWSTR; typedef WCHAR * LPWSTR; #endif //_UNDEF_STRING #endif //!WIN32 #ifndef _UNDEF_BYTE //# 如果没有定义宏_UNDEF_BYTE,则定义以下类型 #ifndef _BYTE_DEFINED #define _BYTE_DEFINED typedef unsigned char BYTE; #endif //_BYTE_DEFINED #ifndef _DWORD_DEFINED #define _DWORD_DEFINED #ifdef WIN32 typedef unsigned long DWORD; //保存和Windows的定义一致 #else typedef uint32 DWORD; #endif //WIN32 #endif //_DWORD_DEFINED #ifndef _WORD_DEFINED #define _WORD_DEFINED typedef uint16 WORD; #endif //_WORD_DEFINED typedef BYTE * PBYTE; typedef BYTE * LPBYTE; typedef const BYTE * PCBYTE; typedef const BYTE * LPCBYTE; #endif //_UNDEF_BYTE #ifndef PID typedef uint8 PID; //定义PID类型 #endif //PID #ifndef _UNDEF_SIM_TYPE #ifndef CH #define CH char #define SC signed char #define UC unsigned char #define SI short int #define UI unsigned short int #define SL signed long #define UL unsigned long #define BL UC #endif //CH #endif //_UNDEF_SIM_TYPE #ifndef _UNDEF_UWORD //# 如果没有定义宏_UNDEF_UWORD, 则定义以下类型 typedef uint8 UWORD8; typedef uint16 UWORD16; typedef uint32 UWORD32; typedef int8 WORD8; typedef int16 WORD16; typedef int32 WORD32; #endif //_UNDEF_UWORD #if defined(LINUX) typedef int SOCKET; //定义SOCKET变量类型 #elif defined(WIN32) typedef int socklen_t; #endif //LINUX else WIN32 typedef LPVOID __ITPOSITION; //定义迭代器当前位置的类型(用于枚举各种数据结构对象中的所有元素) #define PRIVATE static //私有函数(只能其所定义的C程序使用的函数)的声明 //*********************** BOOL类型定义 *********************** #if defined(LINUX) && !defined(_UNDEF_BOOL) //# LINUX系统且没有定义宏_UNDEF_BOOL: 才定义BOOL类型 #define BOOL int32 //定义BOOL类型 #define BOOL_DECLARED //typedef DWORD BOOL; //定义BOOL类型 #ifndef TRUE #define TRUE (1) //BOOL:真 #endif //TRUE #ifndef FALSE #define FALSE (0) //BOOL:假 #endif //FALSE #endif //LINUX //*********************** 通用常量定义 *********************** #if defined(WIN32) || defined(SOLARIS) //# WIN32系统: #define MSG_NOSIGNAL (0) #endif //WIN32 #if defined(LINUX) //# LINUX系统: #define INVALID_SOCKET ((SOCKET)-1) //无效的SOCKET句柄 #define SOCKET_ERROR (-1) //SOCKET错误 #define MAX_PATH (260) //文件名最大长度 #endif //LINUX #if defined(SOLARIS) #define INADDR_NONE ((in_addr_t) 0xffffffff) #endif //SOLARIS //************************ 通用宏定义 ************************ //宏:计算一个数组的数组元素的个数 #define __countof(array) (sizeof(array) / sizeof(array[0])) //宏:将一个元素的内容全部用0填充 //参数: elem_ptr - 要被清零的元素指针 //说明: 本宏不需要指明elem_ptr的大小,会自动根据*elem_ptr的类型来决定清零的大小范围 #define ZeroElemPtr(elem_ptr) memset(elem_ptr, 0, sizeof(*elem_ptr)) //宏:将一个元素的内容全部用0填充 //参数: elem - 要被清零的元素(不是指针) //说明: 本宏不需要指明元素elem的大小,会自动计算 #define ZeroElem(elem) memset(&elem, 0, sizeof(elem)) //宏:取指定结构类型的指定字段的偏移量 //参数: type - 指定的结构类型 // item - 指定的字段 #define __OffsetOf(type, item) ((size_t)(&(((type*)0x1000)->item)) - 0x1000) //#宏:取指定结构类型的指定字段的所占内存的大小 //参数: type - 指定的结构类型 // item - 指定的字段 #define __SizeOf(type, item) sizeof(((type*)0x1000)->item) #if defined(WIN32) //# WIN32系统 #define bzero(addr, len) memset(addr, 0, len)//为WIN32定义清零的宏 #define snprintf _snprintf //限制字符个数的sprintf的函数 #define vsnprintf _vsnprintf //限制字符个数的vsprintf函数 #elif defined(LINUX) //# LINUX系统: #define closesocket(x) close((x)) //关闭SOCKET的函数 #define ioctlsocket ioctl #define Sleep(x) sleep(((x) + 500)/1000) //等待函数.x-等待时间(单位:毫秒) #define stricmp(s1, s2) strcasecmp(s1, s2) //忽略大小写比较两个字符串的是否相等 #define strnicmp(s1,s2,n) strncasecmp(s1,s2,(n))//忽略大小写比较两个指定最大长度的字符串的是否相等 #define _mkdir(dir) mkdir(dir, S_IREAD|S_IWRITE|S_IEXEC|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) //创建目录(兼容Windows下的函数) #endif //WIN32 else LINUX //宏:字符串安全拷贝 //参数: // s1 - 保存目标字符串的缓冲区 // s2 - 源字段串的缓冲区 // s1_buf_len - 指示s1缓冲区的总大小(其值必须 > 0) //说明: // 本宏会将s2字段串安全的拷贝到s1的缓冲区,并且为字符串安排字符串结束符'/0' #define strsafecopy(s1, s2, s1_buf_len) {/ strncpy((s1), (s2), (s1_buf_len) - 1); / (s1)[(s1_buf_len) - 1] = 0; / } / //宏:将字符串安全的拷贝到字符数组缓冲区中 //参数: // s1 - 保存目标字符串的字符数组(必须是char xxx[NNN] (NNN>0)的定义的缓冲区,不能是指针或函数的参数) // s2 - 源字符串缓冲区 //说明: // 本宏将s2字段串安全的拷贝到s1的缓冲区中,并自动识别s1的大小,并为字符串安排字符串结点符'/0' #define strsafecopybuffer(s1, s2) strsafecopy(s1, s2, sizeof(s1)) //功能:将双字节数据的高8位和低8位对调 #define SWAP_HIGHLOW_WORD(x) ( (((x) >> 8) & 0xff) | (((x) << 8) & 0xff00) ) #if (__BYTE_ORDER != __BIG_ENDIAN || !defined(__BYTE_ORDER)) //# 如果是低位在前的字节顺序(Intel) //功能:将本主机的字节顺序转换成Intel的字节顺序 #define HOST_TO_INTEL_WORD(x) (x) //功能:将Intel字节顺序转换成本地字节顺序 #define INTEL_TO_HOST_WORD(x) (x) #else //# 如果是高位在前的字节顺序(SUN) //功能:将主机的字节顺序转换成Intel的字节顺序 #define HOST_TO_INTEL_WORD(x) SWAP_HIGHLOW_WORD(x) //功能:将Intel字节顺序转换成本地字节顺序 #define INTEL_TO_HOST_WORD(x) SWAP_HIGHLOW_WORD(x) #endif //LITTLE_ENDIAN //************************ 调试宏定义 ************************ //说明:DEBUG_PRINT,DEBUG_PRINT1,...,DEBUG_PRINT4可用于调试信息的分类显示, // 建议程序统一按如下方式进行分类 // (1) DEBUG_PRINT -- 普通调试信息(也可以充当DEBUG_PRINT1的作用) // (2) DEBUG_PRINT1 -- 程序运行过程控制的一般输出(如:标识程序运行到哪一步了,或变量的值等) // (3) DEBUG_PRINT2 -- 提示/警告信息 // (4) DEBUG_PRINT3 -- 错误信息 // (5) DEBUG_PRINT4 -- 致命错误信息 #ifdef _ENABLE_DEBUG_PRINT //# 允许DEBUG_PRINT宏的输出信息 #define DEBUG_PRINT(args) printf("[%d:0]", __LINE__); printf args #else //_ENABLE_DEBUG_PRINT #define DEBUG_PRINT(args) #endif //_ENABLE_DEBUG_PRINT #ifdef _ENABLE_DEBUG_PRINT1 //# 允许DEBUG_PRINT1宏的输出信息 #define DEBUG_PRINT1(args) printf("[%d:1]", __LINE__); printf args #else //_ENABLE_DEBUG_PRINT1 #define DEBUG_PRINT1(args) #endif //_ENABLE_DEBUG_PRINT1 #ifdef _ENABLE_DEBUG_PRINT2 //# 允许DEBUG_PRINT2宏的输出信息 #define DEBUG_PRINT2(args) printf("[%d:2]", __LINE__); printf args #else //_ENABLE_DEBUG_PRINT2 #define DEBUG_PRINT2(args) #endif //_ENABLE_DEBUG_PRINT2 #ifdef _ENABLE_DEBUG_PRINT3 //# 允许DEBUG_PRINT3宏的输出信息 #define DEBUG_PRINT3(args) printf("[%d:3]", __LINE__); printf args #else //_ENABLE_DEBUG_PRINT3 #define DEBUG_PRINT3(args) #endif //_ENABLE_DEBUG_PRINT3 #ifdef _ENABLE_DEBUG_PRINT4 //# 允许DEBUG_PRINT4宏的输出信息 #define DEBUG_PRINT4(args) printf("[%d:4]", __LINE__); printf args #else //_ENABLE_DEBUG_PRINT4 #define DEBUG_PRINT4(args) #endif //_ENABLE_DEBUG_PRINT4 //************************ 断言宏定义 ************************ #ifdef _USE_LOGPROCESS //# 使用日志处理模块 #include "log_process.h" #endif #if defined(_USE_EXLOG_ASSERT) //# 使用CExLog类的GlobalExLog对象输出ASSERT信息 #ifdef __cplusplus extern "C" void GlobalExLog_WriteLog(int nLogLevel, LPCSTR pszFormat, ...); #else void GlobalExLog_WriteLog(int nLogLevel, LPCSTR pszFormat, ...); #endif #endif //_USE_EXLOG_ASSERT #ifndef ASSERT //# 如果没有ASSERT宏,则定义一个ASSERT宏 #ifdef _DEBUG //# 调试版: //定义ASSERT的宏 #if defined(_USE_LOGPROCESS) //# 使用日志处理模块 //定义基于日志处理模块的ASSERT宏 #ifdef WIN32 //# Win32版本 #define ASSERT(cond) / {/ if (!(cond))/ {/ char szErr[128];/ sprintf(szErr, "<<ASSERT Fail>> in %s at line %d !/n", __FILE__, __LINE__);/ LogWriteLog(LOGLEVEL_OUTPUT, "ASSERT: %s", szErr);/ Sleep(2000);/ perror(szErr);/ _ASSERT(cond);/ }/ } #else //WIN32 //# 非Win32版本 #define ASSERT(cond) / {/ if (!(cond))/ {/ char szErr[128];/ sprintf(szErr, "<<ASSERT Fail>> in %s at line %d !/n", __FILE__, __LINE__);/ LogWriteLog(LOGLEVEL_OUTPUT, "ASSERT: %s", szErr);/ Sleep(2000);/ perror(szErr);/ abort();/ }/ } #endif //WIN32 #elif defined(_USE_EXLOG_ASSERT) && defined(__cplusplus) //#defined(_USE_LOGPROCESS) //# 定义基于CExLog日志输出类的ASSERT宏 #ifdef WIN32 //# Win32版本 #define ASSERT(cond) / {/ if (!(cond))/ {/ char szErr[128];/ sprintf(szErr, "<<ASSERT Fail>> in %s at line %d !/n", __FILE__, __LINE__);/ GlobalExLog_WriteLog(99999, "ASSERT: %s", szErr);/ Sleep(2000);/ perror(szErr);/ _ASSERT(cond);/ }/ } #else //WIN32 //# 非Win32版本 #define ASSERT(cond) / {/ if (!(cond))/ {/ char szErr[128];/ sprintf(szErr, "<<ASSERT Fail>> in %s at line %d !/n", __FILE__, __LINE__);/ GlobalExLog_WriteLog(99999, "ASSERT: %s", szErr);/ Sleep(2000);/ perror(szErr);/ abort();/ }/ } #endif //WIN32 #else //defined(_USE_LOGPROCESS) else defined(_USE_EXLOG_ASSERT) //定义不基于日志处理模块的ASSERT宏 #ifdef WIN32 //# Win32版本 #define ASSERT(cond) / {/ if (!(cond))/ {/ char szErr[128];/ sprintf(szErr, "<<ASSERT Fail>> in %s at line %d !/n", __FILE__, __LINE__);/ perror(szErr);/ _ASSERT(FALSE);/ }/ } #else //WIN32 #define ASSERT(cond) / {/ if (!(cond))/ {/ char szErr[128];/ sprintf(szErr, "<<ASSERT Fail>> in %s at line %d !/n", __FILE__, __LINE__);/ perror(szErr);/ abort();/ }/ } #endif //WIN32 #endif //_USE_LOGPROCESS #else //# 非调试版: //定义空的ASSERT宏 #define ASSERT(cond) #endif //_<mce:script type="text/javascript" src="http://hi.images.csdn.net/js/blog/tiny_mce/themes/advanced/langs/zh.js" mce_src="http://hi.images.csdn.net/js/blog/tiny_mce/themes/advanced/langs/zh.js"></mce:script><mce:script type="text/javascript" src="http://hi.images.csdn.net/js/blog/tiny_mce/plugins/syntaxhl/langs/zh.js" mce_src="http://hi.images.csdn.net/js/blog/tiny_mce/plugins/syntaxhl/langs/zh.js"></mce:script>DEBUG #endif //ASSERT #endif //#ifndef _TYPEDEFINE_H_F347AFC389350945 //** 下面的定义在"#ifndef _TYPEDEFINE_H_F347AFC389350945"的控制范围之外 // 使用独立的办法来防止重复定义,以方便各使用者独立的决定是否接管new和delete ** #if defined(_TAKEOVER_NEW_DEL) && !defined(_NEW_DEL_OPERATOR_DEFINED) #define _NEW_DEL_OPERATOR_DEFINED #include "MemoryBufferPool.h" //# 在定义了"_TAKEOVER_NEW_DEL"宏的情况下重新定义新的new和delete操作 inline static void * operator new(size_t nSize, const char *pszSrcFilename, unsigned nSrcLine) { return GlobalMemAllocManager.Alloc(nSize, pszSrcFilename, nSrcLine); } inline static void * operator new(size_t nSize) { return GlobalMemAllocManager.Alloc(nSize); } inline static void operator delete(void *p, const char *pszSrcFilename, unsigned nSrcLine) { GlobalMemAllocManager.Free(p); } inline static void operator delete[](void *p, const char *pszSrcFilename, unsigned nSrcLine) { GlobalMemAllocManager.Free(p); } inline static void operator delete(void* p) { GlobalMemAllocManager.Free(p); } inline static void operator delete[](void* p) { GlobalMemAllocManager.Free(p); } #ifndef _DEBUG_NEW #define _DEBUG_NEW new(__FILE__, __LINE__) #endif //_DEBUG_NEW #endif //_TAKEOVER_NEW_DEL #if defined(_USE_CLASS_MEM_POOL) #include "MemoryBufferPool.h" #ifndef _DEBUG_NEW #define _DEBUG_NEW new(__FILE__, __LINE__) #endif //_DEBUG_NEW #define DECLARE_CLASS_USE_MEM_POOL / public: / void * operator new(size_t nSize, const char *pszSrcFilename, unsigned nSrcLine) / { / return GlobalMemAllocManager.Alloc(nSize, pszSrcFilename, nSrcLine); / } / void * operator new(size_t nSize) / { / return GlobalMemAllocManager.Alloc(nSize); / } / void operator delete(void *p, const char *pszSrcFilename, unsigned nSrcLine) / { / GlobalMemAllocManager.Free(p); / } / void operator delete[](void *p, const char *pszSrcFilename, unsigned nSrcLine) / { / GlobalMemAllocManager.Free(p); / } / void operator delete(void* p) / { / GlobalMemAllocManager.Free(p); / } / void operator delete[](void* p) / { / GlobalMemAllocManager.Free(p); / } #endif //defined(_USE_MEMORY_BUFFER_POOL)
二、处理缓冲区比特数据流的类
/********************************************************************** * 名 称: CBufferBitDataStream.h (内存比特数据流相关类) * 功能描述: 以BIT为单位在内存中读写数据 **********************************************************************/ #ifndef _MEMBITSTREAM_H_01980A0A9DF09A8E_INCLUDED_ #define _MEMBITSTREAM_H_01980A0A9DF09A8E_INCLUDED_ #include "typedefine.h" //************************** 类定义 ************************** //类名:缓冲区比特数据流 //功能:以比特流的方向向一块内存数据缓冲区中写入数据 class CBufferBitDataStream //: public CBitDataStream { //常量: protected: enum { MAX_TEMPGETBUFFER_SIZE = 64 //临时数据读取缓冲区的大小 }; //属性: protected: BYTE *m_pbBuffer; //目标缓冲区 UINT m_uBufferSize; //目标缓冲区的大小 UINT m_uEndByteIgnoreBit;//标识最后一个字节应该忽略的比特数 UINT m_uGetPos; //当前的字节数据读取位置 BYTE m_pbTempDataBuffer[MAX_TEMPGETBUFFER_SIZE]; //临时数据缓冲区 BYTE *m_pbTempGetBuffer; //临时数据读取缓冲区 UINT m_uTempGetBufferSize; //临时数据读取缓冲区中数据的字节数 UINT m_uTempGetBufferPos; //当前读取到临时缓冲区的第几个字节的位置 UINT m_uTempGetBufferBitPos; //临时缓冲区当前字节已经读取到第几个比特位 UINT m_uTempGetBufferEndByteIgnoreBit;//临时数据读取缓冲中最后一个字节应该忽略的比特数 //操作: public: //功能:构造函数 //参数: // pbBuffer - [out]指向保存比特流的缓冲区的指针 // nBufferSize - [in]缓冲区大小 // byBeginByteIgnore - [in]指示缓冲区的第一个字节的高多少位应该忽略 // byEndByteIgnore - [in]指示缓冲区的最后一个字节的低多少位应该忽略 //说明: // 当缓冲区中的首字节的已经保存了若干位(>0 & < 8)的比特数据时,需要设置 //byBeginByteIgnore > 0,以保证新写入数据时不会覆盖这些数据 CBufferBitDataStream(BYTE *pbBuffer = NULL, UINT nBufferSize = 0, BYTE byBeginByteIgnore = 0, BYTE byEndByteIgnore = 0); //功能:析构函数 ~CBufferBitDataStream(); //功能:重置内存缓冲区 //参数: // pbBuffer - [out]指向保存比特流的缓冲区的指针 // nBufferSize - [in]缓冲区大小 // byBeginByteIgnore - [in]指示缓冲区的第一个字节的高多少位应该忽略 // byEndByteIgnore - [in]指示缓冲区的最后一个字节的低多少位应该忽略 //说明: // 当缓冲区中的首字节的已经保存了若干位(>0 & < 8)的比特数据时,需要设置 //byBeginByteIgnore > 0,以保证新写入数据时不会覆盖这些数据 void ResetBuffer(BYTE *pbBuffer, UINT nBufferSize, BYTE byBeginByteIgnore = 0, BYTE byEndByteIgnore = 0); //功能:判断字节数据流中的数据是否已经完全读取完毕 //参数: // (无) //返回: // 数据字节数据流中的数据已经读取完毕则返回TRUE,否则返回FALSE. BOOL IsGetDataEnd(void); BOOL GetBits(DWORD &rdwData, UINT nNumOfBits, BOOL bOnlyPeek = FALSE); protected: //功能:从字节数据流中获取更多的数据 //参数: // pbBuffer - [out]保存数据源数据的缓冲区 // nBytes - [in]pbBuffer缓冲区的大小 // rnGotBytes - [out]返回实际从数据源中取到多少字节的数据 // rnEndByteIgnoreBits - [out]返回最后一个字节已经忽略多少BIT的数据 //返回: // 如果成功获取数据则返回TRUE,如果处理失败则返回FALSE virtual BOOL GetMoreData(BYTE *pbBuffer, UINT nBytes, UINT &rnGotBytes, UINT &rnEndByteIgnoreBits) { rnGotBytes = 0; rnEndByteIgnoreBits = 0; ASSERT(m_pbBuffer != NULL); if (m_pbBuffer == NULL) { return FALSE; } if (m_uGetPos < m_uBufferSize) { if (m_uGetPos + nBytes <= m_uBufferSize) { //缓冲区中的数据可以全部读取出来 rnGotBytes = nBytes; } else { //缓冲区中的数据已经不足 rnGotBytes = m_uBufferSize - m_uGetPos; } memcpy(pbBuffer, &m_pbBuffer[m_uGetPos], rnGotBytes); m_uGetPos +=rnGotBytes; if (m_uGetPos == m_uBufferSize) { //已经读取到最后一个字节 rnEndByteIgnoreBits = m_uEndByteIgnoreBit; } //读取完毕 return TRUE; } else { //缓冲区中的数据已经全部读取完毕 return FALSE; } } //功能:重置数据读取状态 //参数: // (无) //返回: // (无) //说明: // 本函数应该由派生类在重新准备读取的比特流数据时调用(如:重新Open一个 // 数据文件时). virtual void ResetGet(void) { m_uTempGetBufferSize = 0; m_uTempGetBufferPos = 0; m_uTempGetBufferBitPos = 0; m_uTempGetBufferEndByteIgnoreBit = 0; m_pbTempGetBuffer = m_pbTempDataBuffer; //数据读取缓冲区默认指向内存的临时数据缓冲区中 } }; #endif //_MEMBITSTREAM_H_01980A0A9DF09A8E_INCLUDED_
/********************************************************************** * 名 称: CBufferBitDataStream.h (内存比特数据流相关类) * 功能描述: 以BIT为单位在内存中读写数据 **********************************************************************/ #include "stdafx.h" #include "CBufferBitDataStream.h" //功能:构造函数 //参数: // pbBuffer - [out]指向保存比特流的缓冲区的指针 // nBufferSize - [in]缓冲区大小 // byBeginByteIgnore - [in]指示缓冲区的第一个字节的高多少位应该忽略 // byEndByteIgnore - [in]指示缓冲区的最后一个字节的低多少位应该忽略 //说明: // 当缓冲区中的首字节的已经保存了若干位(>0 & < 8)的比特数据时,需要设置 //byBeginByteIgnore > 0,以保证新写入数据时不会覆盖这些数据 CBufferBitDataStream::CBufferBitDataStream(BYTE *pbBuffer, UINT nBufferSize, BYTE byBeginByteIgnore, BYTE byEndByteIgnore) { ResetBuffer(pbBuffer, nBufferSize, byBeginByteIgnore, byEndByteIgnore); } //功能:析构函数 CBufferBitDataStream::~CBufferBitDataStream() { } //功能:从比特流中取出比特数据 //参数: // rdwData - [out]保存读取到的数据 // nNumOfBits - [in]要取的位数(只能在1~31的范围内) // bOnlyPeek - [in]标识是只是查看数据,而不将读走(下次再读取时还能读取到该数据) //返回: // 若成功读取到数据则返回TRUE, 若缓冲区中没有足够的数据则返回FALSE BOOL CBufferBitDataStream::GetBits(DWORD &rdwData, UINT nNumOfBits, BOOL bOnlyPeek) { ASSERT(nNumOfBits >=1 && nNumOfBits <= 32); if (nNumOfBits < 1 || nNumOfBits > 32) { return FALSE; } UINT &ruGetPos = m_uTempGetBufferPos; //当前读取字节位置 UINT &ruGetBitPos = m_uTempGetBufferBitPos; //当前读取到的比特位置 UINT &ruEndByteIgnore = m_uEndByteIgnoreBit; //最后一字节忽略比特数 //UINT &ruBufferSize = m_uTempGetBufferSize; //缓冲区大小 BYTE *pbBuffer = &m_pbBuffer[ruGetPos]; //缓冲区当前读取位置的指针 if (nNumOfBits + ruGetBitPos > ((m_uBufferSize - ruGetPos) << 3) - ruEndByteIgnore) { //缓冲区中的数据不足 return FALSE; } //取基础字节数据 int nBaseBytes = (nNumOfBits + 7) >> 3; //基础字节数 ASSERT(nBaseBytes >= 1 && nBaseBytes <= 4); static BYTE bFirstMaskTabe[8] = { //首字节俺码表(根据起始BIT不同,需要对首字节进行掩码处理) 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01 }; BYTE byFirstMask = bFirstMaskTabe[ruGetBitPos]; DWORD dwBaseData = 0; //基础数据值 int nShiftRight = 0; //需要右移的比特数 switch (nBaseBytes) { case 1: dwBaseData = pbBuffer[0] & byFirstMask; nShiftRight = 8 - nNumOfBits; break; case 2: dwBaseData = (DWORD(pbBuffer[0] & byFirstMask) << 8) | pbBuffer[1]; nShiftRight = 16 - nNumOfBits; break; case 3: dwBaseData = (DWORD(pbBuffer[0] & byFirstMask) << 16) | (DWORD(pbBuffer[1]) << 8) | pbBuffer[2]; nShiftRight = 24 - nNumOfBits; break; case 4: dwBaseData = (DWORD(pbBuffer[0] & byFirstMask) << 24) | (DWORD(pbBuffer[1]) << 16) | (pbBuffer[2] << 8) | pbBuffer[3]; nShiftRight = 32 - nNumOfBits; break; default: ASSERT(FALSE); break; } //计算需要移动的位数(需要右移的位置 - 需要左移的位数) int nShift = nShiftRight - (int)ruGetBitPos; //取指定BIT数的数据 if (nShift < 0) { //左移 rdwData = (dwBaseData << (-nShift)); } else { //右移 rdwData = (dwBaseData >> nShift); } //计算超过基础数据所需要的比特数 int nMoreBits = ruGetBitPos + nNumOfBits - (nBaseBytes << 3); if (nMoreBits > 0) { //如果所需要的数据超过0,则需要从下一字节中数数据 rdwData |= (pbBuffer[nBaseBytes] >> (8 - nMoreBits)); } if (!bOnlyPeek) { ruGetBitPos += nNumOfBits; ruGetPos += (ruGetBitPos >> 3); ruGetBitPos &= 0x07; } return TRUE; } //功能:判断字节数据流中的数据是否已经完全读取完毕 //参数: // (无) //返回: // 数据字节数据流中的数据已经读取完毕则返回TRUE,否则返回FALSE. BOOL CBufferBitDataStream::IsGetDataEnd(void) { return (m_uGetPos == m_uBufferSize && (m_uTempGetBufferPos + 1 == m_uTempGetBufferSize && m_uTempGetBufferBitPos + m_uEndByteIgnoreBit == 8 || m_uTempGetBufferPos == m_uTempGetBufferSize)); } //功能:重置内存缓冲区 //参数: // pbBuffer - [out]指向保存比特流的缓冲区的指针 // nBufferSize - [in]缓冲区大小 // byBeginByteIgnore - [in]指示缓冲区的第一个字节的高多少位应该忽略 // byEndByteIgnore - [in]指示缓冲区的最后一个字节的低多少位应该忽略 //说明: // 当缓冲区中的首字节的已经保存了若干位(>0 & < 8)的比特数据时,需要设置 //byBeginByteIgnore > 0,以保证新写入数据时不会覆盖这些数据 void CBufferBitDataStream::ResetBuffer(BYTE *pbBuffer, UINT nBufferSize, BYTE byBeginByteIgnore, BYTE byEndByteIgnore) { ResetGet(); m_pbBuffer = pbBuffer; m_uBufferSize = nBufferSize; m_uGetPos = 0; ASSERT(byBeginByteIgnore < 8); if (byBeginByteIgnore < 8) { m_uTempGetBufferBitPos = byBeginByteIgnore; } ASSERT(byEndByteIgnore < 8); if (byEndByteIgnore < 8) { m_uEndByteIgnoreBit = byEndByteIgnore; } //修改基类的临时数据缓冲区,指向用户设置的缓冲区(避免多次读取数据的麻烦) m_pbTempGetBuffer = m_pbBuffer; m_uTempGetBufferSize = m_uBufferSize; }
三、定义Chari部分
/********************************************************************** * 名 称: CDMAChari.h * 功能描述: CDMA短消息Chari结构解码处理 **********************************************************************/ #ifndef _CDMACHARI_H_200803261744_INCLUDED_ #define _CDMACHARI_H_200803261744_INCLUDED_ #include "CBufferBitDataStream.h" class CDMAChariDecoder { // 定义结构类型 public: struct CMMSNotification { UINT uMMSMsgType; BYTE uMMSFrom[100]; UINT uMessageClass; BYTE uTransactionId[350]; UINT uMMSVersion; BYTE bContentLocation[350]; }; // 定义属性 public: UINT m_uMsgType; UINT m_uTotalSegMents; UINT m_uSegmentNumber; UINT m_usourcePort; UINT m_uDestinationPort; CMMSNotification m_mmsNotice; // 定义操作 public: // 构造函数 CDMAChariDecoder(); // 析构函数 ~CDMAChariDecoder(); //功能:对Chari消息进行解码 //参数: // pbBuffer - [in]指向待解码的数据的缓冲区 // uSize - [in]指示待解码的数据的大小(字节数) //返回: // 若解码成功则返回TRUE, 否则返回FALSE; //说明: // 1) 本函数若成功返回,则解码后的结果保存到各"CDMA短消息参数"的成员函数中; BOOL DoDecode(LPCBYTE,UINT,UINT); protected: //功能:从指定的比特数据流中提取指定的比特位的数据 //参数: // bitStream - [in]指示要从哪比特数据流对象中提取数据 // nmOfBits - [in]指示要取多少位的比特数据 //返回: // 返回提取结果 //异常: // throw (int) - 若读取失败将抛出int(-1)异常 DWORD ExtractBits(CBufferBitDataStream &bitStream, UINT numOfBits = 8); }; #endif
/********************************************************************** * 名 称: CDMAChari.h * 功能描述: CDMA短消息Chari结构解码处理 **********************************************************************/ #include "stdafx.h" #include "CDMAChariDecoder.h" // 构造函数 CDMAChariDecoder::CDMAChariDecoder() { } // 析构函数 CDMAChariDecoder::~CDMAChariDecoder() { } //功能:对Chari消息进行解码 //参数: // pbBuffer - [in]指向待解码的数据的缓冲区 // uSize - [in]指示待解码的数据的大小(字节数) //返回: // 若解码成功则返回TRUE, 否则返回FALSE; //说明: // 1) 本函数若成功返回,则解码后的结果保存到各"CDMA短消息参数"的成员函数中; BOOL CDMAChariDecoder::DoDecode(LPCBYTE pbBuffer, UINT uSize,UINT uRealLen) { CBufferBitDataStream cBitStream((LPBYTE)pbBuffer, uSize); try { DWORD tempData;//保存取到无用的临时数据 // 定义偏移量 UINT uPos = 0; UINT uLength = 10; m_uMsgType = (UINT)ExtractBits(cBitStream); m_uTotalSegMents = (UINT)ExtractBits(cBitStream); m_uSegmentNumber = (UINT)ExtractBits(cBitStream); m_usourcePort = (UINT)ExtractBits(cBitStream,16); m_uDestinationPort = (UINT)ExtractBits(cBitStream,16); // 丢弃 cBitStream.GetBits(tempData, 8); // 丢弃 cBitStream.GetBits(tempData, 8); // 获取PDU长度 UINT paramLen = (UINT)ExtractBits(cBitStream); // 丢弃 for(int i=0;i<paramLen;i++) { cBitStream.GetBits(tempData, 8); uLength ++; } //cBitStream.GetBits(tempData, paramLen*8); // BEGIN MMS-Notification while (!cBitStream.IsGetDataEnd() && uLength < uRealLen) { tempData = ExtractBits(cBitStream); uLength ++; switch((BYTE)tempData) { case 0x8C: m_mmsNotice.uMMSMsgType = (UINT)ExtractBits(cBitStream); uLength ++; break; case (0x80+0x18): uPos = 0; while((tempData = (BYTE)ExtractBits(cBitStream)) > 0x00 ) { m_mmsNotice.uTransactionId[uPos++] = (BYTE)tempData; uLength ++; } m_mmsNotice.uTransactionId[uPos++] = 0x00; uLength ++; break; case (0x80+0x0D): m_mmsNotice.uMMSVersion = (UINT)ExtractBits(cBitStream); uLength ++; break; case (0x80+0x03): uPos = 0; while((tempData = (BYTE)ExtractBits(cBitStream)) > 0x00 ) { m_mmsNotice.bContentLocation[uPos++] = (BYTE)tempData; uLength ++; } m_mmsNotice.bContentLocation[uPos++] = 0x00; uLength ++; break; case 0x89: // From长度,丢弃 ExtractBits(cBitStream); uLength ++; tempData = ExtractBits(cBitStream); uLength ++; // 实际接收方地址 if((BYTE)tempData == 0x80) { uPos = 0; while((tempData = (BYTE)ExtractBits(cBitStream)) > 0x00 ) { m_mmsNotice.uMMSFrom[uPos++] = (BYTE)tempData; uLength ++; } m_mmsNotice.uMMSFrom[uPos++] = 0x00; uLength ++; } break; // Message-Class case 0x8A: m_mmsNotice.uMessageClass = (UINT)ExtractBits(cBitStream); uLength ++; break; // MessageSize case 0x8E: uPos = (UINT)ExtractBits(cBitStream); uLength ++; for(int i=0;i<uPos;i++) { ExtractBits(cBitStream); uLength ++; } break; // expiry case 0x88: uPos = (UINT)ExtractBits(cBitStream); uLength ++; for(int i=0;i<uPos;i++) { ExtractBits(cBitStream); uLength ++; } break; default: break; } } //// MMSMsgType //if((BYTE)ExtractBits(cBitStream) == 0x8C) //{ // m_mmsNotice.uMMSMsgType = (UINT)ExtractBits(cBitStream); //} //// TransactionId //if((BYTE)ExtractBits(cBitStream) == (0x80+0x18)) //{ // UINT uPos = 0; // while((tempData = (BYTE)ExtractBits(cBitStream)) > 0x00 ) // { // m_mmsNotice.uTransactionId[uPos++] = (BYTE)tempData; // } // m_mmsNotice.uTransactionId[uPos++] = 0x00; //} //// MMSVersion //if((BYTE)ExtractBits(cBitStream) == (0x80+0x0D)) //{ // m_mmsNotice.uMMSVersion = (UINT)ExtractBits(cBitStream); //} //// ContentLocation //if((BYTE)ExtractBits(cBitStream) == (0x80+0x03)) //{ // UINT uPos = 0; // while((tempData = (BYTE)ExtractBits(cBitStream)) > 0x00 ) // { // m_mmsNotice.bContentLocation[uPos++] = (BYTE)tempData; // } // m_mmsNotice.bContentLocation[uPos++] = 0x00; //} // END MMSVersion return TRUE; } catch (int) { //解码失败 return FALSE; } } //功能:从指定的比特数据流中提取指定的比特位的数据 //参数: // bitStream - [in]指示要从哪比特数据流对象中提取数据 // nmOfBits - [in]指示要取多少位的比特数据 //返回: // 返回提取结果 //异常: // throw (int) - 若读取失败将抛出int(-1)异常 DWORD CDMAChariDecoder::ExtractBits(CBufferBitDataStream &bitStream, UINT numOfBits/* = 8*/) { DWORD data; if (bitStream.GetBits(data, numOfBits)) { return data; } else { //提取失败 throw (-1); } }
四、定义整个消息解码
/********************************************************************** * 名 称: CDMASmsMessageEnDecoder.h * 功能描述: 实现对CDMA短消息承载数据的编码解码处理 **********************************************************************/ #ifndef _CDMASMSMESSAGEENDECODER_H_200803261744_INCLUDED_ #define _CDMASMSMESSAGEENDECODER_H_200803261744_INCLUDED_ #include "CBufferBitDataStream.h" class CCDMASmsMessageDecoder { //常量: public: //** CDMA短消息参数ID ** enum SubParameterId { spiMessageIdentifier = 0x00, //‘00000000’ spiUserData = 0x01, //‘00000001’ }; //** (Message Identifier中的消息类型(MessageType)) ** enum MessageType { mtReserved = 0x00, //‘0000’保留 mtDeliver = 0x01, //‘0001’Deliver (mobile-terminated only) mtSubmit = 0x02, //‘0010’Submit (mobile-originated only) mtCancellation = 0x03, //‘0011’ Cancellation (mobile-originated only) mtDeliveryAcknowledgment = 0x04, //‘0100’ Delivery Acknowledgment (mobile-terminated only) mtUserAcknowledgment = 0x05, //‘0101’ User Acknowledgment (either direction) }; //** 消息编码方式 ** enum MsgEncoding { meOctet = 0x00, //'00000',[8bit],Octet, unspecified,未规范的16进制数 meIS91Extended = 0x01, //'00001',[不确定],IS-91 Extended Protocol Message, me7BitASCII = 0x02, //'00010',[7bit],7-bit ASCII (ANSI X3.4) meIA5 = 0x03, //'00011',[7bit],IA5 (Table 11 of CCITT T.50) meUNICODE = 0x04, //'00100',[16bit],UNICODEi (ISO/IEC 10646-1:1993) meShift_JIS = 0x05, //'00101',[8或16bit],Shift-JIS meKS_C_5601 = 0x06, //'00110',[8或16bit],KS C 5601 meLatinOrHebrew = 0x07, //'00111',[8bit],Latin/Hebrew (ISO 8859-8:1988) meLatin = 0x08, //'01000',[8bit],Latin (ISO 8859-1:1988) }; public: enum { MAX_CHAR_BUFFER = 350, //User Data的CHARi缓冲区中最多允许多少个字符 }; //类型: public: //类型:CDMA短消息Message Identifier字段 struct CMessageIdentifier { MessageType eMessageType; //消息类型 UINT uMessageId; //消息ID(如果不使用填0x0000) }; //类型:CDMA短消息User Data字段 //功能:保存CDMA短消息规范中User Data字段的内容 struct CUserData { MsgEncoding eMsgEncoding; //消息编码方式 UINT uMessageType; //消息类型(当m_uMsgEncoding为meIS91Extended时才有效并存在) UINT uNumFileds; //指示字符缓冲的容内有多少个字符 BYTE bCharBuffer[MAX_CHAR_BUFFER];//字符数据缓冲区 }; //属性: public: //**** CDMA短消息参数 **** BOOL m_bParamExisted[256]; //标识各短消息参数是否存在(以各参数的参数ID做为下标) CMessageIdentifier m_sMessageIdentifier; //消息标识符 CUserData m_sUserData; //用户数据 //************************* //操作: public: //功能:构造函数 CCDMASmsMessageDecoder(void); //功能:析构函数 ~CCDMASmsMessageDecoder(); //功能:设置指定短消息参数是否存在 //参数: // eParamId - [in]要指定的短消息参数的参数Id // bExisted - [in]标识该参数是否存在 //返回: // (无) //说明: // 本类对象构造时,默认所有参数都不存在,需要手动调用SetParameterExisted设置需要的参数 //为“存在”。 void SetParameterExisted(SubParameterId eParamId, BOOL bExisted = TRUE) { ASSERT(eParamId >= 0 && eParamId < (int)__countof(m_bParamExisted)); m_bParamExisted[eParamId] = bExisted; } //功能:判断指定的短消息参数是否存在 //参数: // eParamId - [in]指定要判断的短消息参数的参数Id //返回: // 如果指定的短消息参数存在则返回TRUE,否则返回FALSE. BOOL IsParameterExisted(SubParameterId eParamId) { ASSERT(eParamId >= 0 && eParamId < (int)__countof(m_bParamExisted)); return m_bParamExisted[eParamId]; } //功能:对短消息承载数据内容进行解码处理 //参数: // pbBuffer - [in]指向待解码的数据的缓冲区 // uSize - [in]指示待解码的数据的大小(字节数) //返回: // 若解码成功则返回TRUE, 否则返回FALSE; //说明: // 1) 本函数若成功返回,则解码后的结果保存到各"CDMA短消息参数"的成员函数中; BOOL DoDecode(LPCBYTE pbBuffer, UINT uSize); protected: //功能:从指定的比特数据流中提取指定的比特位的数据 //参数: // bitStream - [in]指示要从哪比特数据流对象中提取数据 // nmOfBits - [in]指示要取多少位的比特数据 //返回: // 返回提取结果 //异常: // throw (int) - 若读取失败将抛出int(-1)异常 DWORD ExtractBits(CBufferBitDataStream &bitStream, UINT numOfBits = 8); }; #endif
/********************************************************************** * 名 称: CDMASmsMessageEnDecoder.cpp (CDMA短消息承载数据编码解码类) * 功能描述: 实现对CDMA短消息承载数据的编码解码处理 **********************************************************************/ #include "stdafx.h" #include "CDMASmsMessageDecoder.h" #include "CBufferBitDataStream.h" //功能:构造函数 CCDMASmsMessageDecoder::CCDMASmsMessageDecoder(void) { ZeroElem(m_bParamExisted); } //功能:析构函数 CCDMASmsMessageDecoder::~CCDMASmsMessageDecoder() { } //功能:对短消息承载数据内容进行解码处理 //参数: // pbBuffer - [in]指向待解码的数据的缓冲区 // uSize - [in]指示待解码的数据的大小(字节数) //返回: // 若解码成功则返回TRUE, 否则返回FALSE; //说明: // 1) 本函数若成功返回,则解码后的结果保存到各"CDMA短消息参数"的成员函数中; BOOL CCDMASmsMessageDecoder::DoDecode(LPCBYTE pbBuffer, UINT uSize) { //清所有参数的存在标志 ZeroElem(m_bParamExisted); CBufferBitDataStream cBitStream((LPBYTE)pbBuffer, uSize); try { while (!cBitStream.IsGetDataEnd()) { DWORD tempData; //保存取到无用的临时数据 SubParameterId subParamId; //子参数ID DWORD paramLen; //参数的长度 //解码参数的基本信息 if (!cBitStream.GetBits(tempData, 8)) { break; } subParamId = (SubParameterId)tempData; SetParameterExisted(subParamId); paramLen = ExtractBits(cBitStream); //根据不同的参数ID进行不同的解码处理 switch (subParamId) { case spiMessageIdentifier: //** Message Identifier ** if (paramLen != 0x03) { return FALSE; } //** MESSAGE_TYPE ** m_sMessageIdentifier.eMessageType = (MessageType)ExtractBits(cBitStream, 4); //** MESSAGE_ID ** m_sMessageIdentifier.uMessageId = (UINT)ExtractBits(cBitStream, 16); //** HEADER_IND & RESERVED ** ExtractBits(cBitStream, 4); break; case spiUserData: //** User Data ** { unsigned long bits = 0; //** MSG_ENCODING ** m_sUserData.eMsgEncoding = (MsgEncoding)ExtractBits(cBitStream, 5); bits += 5; //** MESSAGE_TYPE ** if (m_sUserData.eMsgEncoding == meIS91Extended) { m_sUserData.uMessageType = ExtractBits(cBitStream, 8); bits += 8; } else { m_sUserData.uMessageType = 0; } //** NUM_FIELDS ** m_sUserData.uNumFileds = (UINT)ExtractBits(cBitStream, 8); bits += 8; //** CHARi ** UINT i; UINT uPos = 0; for (i = 0; i < m_sUserData.uNumFileds; i++) { //根据不同的消息编码有不同的提取方式 switch (m_sUserData.eMsgEncoding) { case me7BitASCII: case meIA5: //7bit 字符 m_sUserData.bCharBuffer[uPos++] = (BYTE)ExtractBits(cBitStream, 7); bits += 7; break; case meUNICODE: //16bit 字符 m_sUserData.bCharBuffer[uPos++] = (BYTE)ExtractBits(cBitStream); m_sUserData.bCharBuffer[uPos++] = (BYTE)ExtractBits(cBitStream); bits += 16; break; case meOctet: case meIS91Extended: case meLatinOrHebrew: case meLatin: case meShift_JIS: case meKS_C_5601: //meShift_JIS 和 meKS_C_5601目前只按8bit处理 default: //8bit 字符 m_sUserData.bCharBuffer[uPos++] = (BYTE)ExtractBits(cBitStream); bits += 8; break; } } //** RESERVED ** unsigned long reservedBits = 8 - (bits % 8); ExtractBits(cBitStream, reservedBits); break; } default: //暂不处理的子参数或不可识别的子参数ID { unsigned i; for (i = 0; i < paramLen; i++) { ExtractBits(cBitStream); } break; } } } //成功解码 return TRUE; } catch (int) { //解码失败 return FALSE; } } //功能:从指定的比特数据流中提取指定的比特位的数据 //参数: // bitStream - [in]指示要从哪比特数据流对象中提取数据 // nmOfBits - [in]指示要取多少位的比特数据 //返回: // 返回提取结果 //异常: // throw (int) - 若读取失败将抛出int(-1)异常 DWORD CCDMASmsMessageDecoder::ExtractBits(CBufferBitDataStream &bitStream, UINT numOfBits/* = 8*/) { DWORD data; if (bitStream.GetBits(data, numOfBits)) { return data; } else { //提取失败 throw (-1); } }
五、测试
// CDMASMSDecoder.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include "CDMASmsMessageDecoder.h" #include "CDMAChariDecoder.h" void DecodeTest(void) { //BYTE buffer[] = { // 0x00,0x03,0x10,0x0C,0x50,0x01,0x85,0x04,0x18,0x00,0x10,0x01,0x1F,0x80,0x5C,0x26,0x20,0x31,0x23, // 0x0B,0x83,0x83,0x63,0x4B,0x1B,0x0B,0xA3,0x4B,0x7B,0x71,0x7B,0xB3,0x73,0x21,0x73,0xBB,0x0B,0x81, // 0x73,0x6B,0x6B,0x99,0x6B,0x6B,0x2B,0x9B,0x9B,0x0B,0x3B,0x28,0x05,0xA4,0x3D,0x7C,0x24,0x64,0x14, // 0xC3,0x2A,0x73,0x99,0x81,0xAB,0x6B,0x43,0x89,0xBA,0x0B,0x3A,0x08,0x04,0x6C,0x84,0x1B,0x43,0xA3, // 0xA3,0x81,0xD1,0x79,0x79,0x89,0x81,0x71,0x91,0x99,0xA1,0x71,0x89,0x99,0xB9,0x71,0x89,0x89,0x7B, // 0x2A,0x73,0x99,0x81,0xAB,0x6B,0x43,0x89,0xBA,0x0B,0x3A,0x08,0x04,0x40,0x2C,0x08,0x18,0x15,0x18, // 0x04,0x48,0xBC,0x01,0x89,0x99,0xC1,0x91,0x99,0x89,0x91,0x89,0xC9,0x89,0xA9,0x7A,0xA2,0xCA,0x82, // 0x29,0xEA,0x82,0x62,0x6A,0x70,0x00 //}; //BYTE buffer[] = { // 0x00,0x03,0x05,0x75,0x50,0x01,0x81,0x03,0xF8,0x00,0x08,0x01,0x1F,0x80,0x5C,0x20,0x08,0x30,0xD5, // 0xF2,0x2B,0x73,0x1B,0x7B,0x23,0x4B,0x73,0x39,0x6A,0xB3,0x2B,0x93,0x9B,0x4B,0x7B,0x70,0x01,0x89, // 0x71,0xA0,0x05,0xA4,0x15,0x7C,0x24,0x64,0x14,0xC3,0x92,0x7A,0x89,0x81,0x81,0x82,0xAA,0x0A,0x22, // 0xAA,0x91,0x80,0x04,0x6C,0x84,0x48,0xBC,0x01,0x89,0x99,0xC1,0x91,0x99,0x89,0x91,0x89,0xC9,0x89, // 0xA9,0x7A,0xA2,0xCA,0x82,0x29,0xEA,0x82,0x62,0x6A,0x70,0x04,0x54,0x04,0x70,0x20,0x00,0x0A,0x01, // 0x9C,0x40,0x2C,0x08,0x18,0x15,0x18,0x04,0x1B,0x43,0xA3,0xA3,0x81,0xD1,0x79,0x79,0x89,0x81,0x71, // 0x91,0x99,0xA1,0x71,0x91,0xA9,0x89,0x71,0x89,0xC1,0x81,0xD1,0xC1,0x81,0x7A,0x42,0xC1,0xC2,0x91, // 0x81,0x88,0x00 //}; BYTE buffer[] = { 0x00,0x03,0x10,0x06,0xA0,0x01,0x85,0x04,0x18,0x00,0x10,0x01,0x1F,0x80,0x5C,0x23,0x48,0x31,0x23, 0x0B,0x83,0x83,0x63,0x4B,0x1B,0x0B,0xA3,0x4B,0x7B,0x71,0x7B,0xB3,0x73,0x21,0x73,0xBB,0x0B,0x81, 0x73,0x6B,0x6B,0x99,0x6B,0x6B,0x2B,0x9B,0x9B,0x0B,0x3B,0x28,0x05,0xA4,0x3D,0x7C,0x24,0x64,0x14, 0xC2,0x22,0x7B,0x5B,0xBB,0xC2,0x11,0x99,0xAB,0x63,0x22,0x92,0x08,0x04,0x6C,0x84,0x1B,0x43,0xA3, 0xA3,0x81,0xD1,0x79,0x79,0x89,0x81,0x71,0x91,0x99,0xA1,0x71,0x89,0x99,0xB9,0x71,0x89,0x89,0xD1, 0xC1,0x81,0xC1,0x81,0x7B,0xBB,0x0B,0x99,0x7A,0x22,0x7B,0x5B,0xBB,0xC2,0x11,0x99,0xAB,0x63,0x22, 0x92,0x08,0x04,0x40,0x2C,0x08,0x18,0x15,0x18,0x04,0x48,0x6C,0x01,0x89,0x99,0x99,0xC9,0x91,0xC1, 0xB9,0x89,0x91,0xA1,0xA8,0x04,0x50 }; /* BYTE buffer[] = { 0x00,0x03, 0x10,0x06,0xA0,0x01,0x0A,0x00,0x40,0x00, 0x10,0x0C,0x04,0x70,0x11,0x47,0xB8 };*/ CCDMASmsMessageDecoder coder; if (!coder.DoDecode(buffer, sizeof(buffer))) { printf("Decode fail!/n"); return; } if (coder.IsParameterExisted(CCDMASmsMessageDecoder::spiMessageIdentifier)) { printf("Message Identifier: /n"); printf(" .MESSAGE_TYPE = %u/n" " .MESSAGE_ID = %u/n", (unsigned)coder.m_sMessageIdentifier.eMessageType, coder.m_sMessageIdentifier.uMessageId); } if (coder.IsParameterExisted(CCDMASmsMessageDecoder::spiUserData)) { printf("User Data: /n"); printf(" MSG_ENCODING: %u/n", (unsigned)coder.m_sUserData.eMsgEncoding); printf(" MESSAGE_TYPE: %u/n", (unsigned)coder.m_sUserData.uMessageType); printf(" NUM_FIELDS: %u/n", (unsigned)coder.m_sUserData.uNumFileds); printf(" CHARi: /n"); unsigned i; for (i = 0; i < coder.m_sUserData.uNumFileds; i++) { printf("%02x ", coder.m_sUserData.bCharBuffer[i]); if ((i + 1) % 0x10 == 0) { printf("/n"); } } printf("/n"); if (coder.m_sUserData.uNumFileds > 8) { CDMAChariDecoder chari; if (!chari.DoDecode(coder.m_sUserData.bCharBuffer, sizeof(coder.m_sUserData.bCharBuffer),coder.m_sUserData.uNumFileds)) { printf("Decode fail!/n"); return; } printf("%s /n", &chari.m_mmsNotice.uTransactionId[0]); printf("%s /n", &chari.m_mmsNotice.uMMSFrom[0]); printf("%s /n", &chari.m_mmsNotice.bContentLocation[0]); } } } int _tmain(int argc, _TCHAR* argv[]) { DecodeTest(); return 0; }