昨天和一个老程序员吃饭聊起codelphi,说很久以前,经常能从这里搜索到一些好的技术文章。
最近的工作也蛮辛苦。开始接触以前从来没有接触过的GNU/linux下的基于gcc的开发。两样东西都是现学的。工作了3个星期,只写了一个
电信smgp3协议的tlv参数解析包。所谓的tlv参数就是(tag
,length,value),tag表示一个指令标志,length,表示这个指令所携带数据的长度,value表示指令所携带的数据,用这种方式传递
参数可以很大程度的在不影响效率的情况下减少空参数所占的空间,节省网络带宽。贴部分代码给大家指正 
 #ifndef _PTLV_HPP
 #define _PTLV_HPP 
 #include <iostream>
 #include <iomanip>
 #include <string>
 #include <sys/types.h>
 /*sowpdu*/
 typedef unsigned short WORD;
 typedef unsigned char BYTE; 
 typedef int BOOL;
 #ifndef    TRUE
     #define    TRUE        1
     #define    FALSE        0
 #endif 
 ////////////////////////////////////////////////////////////////////////////////
 /*
   Name:  PTlv
   Copyright: 
   Author: 
   Date: 14-12-05 15:05
   Description: 
 */
 class PTlv{
   private:
     WORD tag;//tlv 标识 
     WORD len; //value 长度
     BYTE *value; //参数数据体 
     int byteOffset; 
   public:
     PTlv(WORD new_tag, WORD new_len, BYTE *new_value);
     PTlv(WORD new_tag, BYTE new_value);     
     PTlv();     
     void Clone(PTlv &src_tlv);     
     ~PTlv();     
     enum VALUE_TYPE{  //
       INTEGER_1          = 0x0001, //byte 
       INTEGER_2          = 0x0002, //word 
       OCTET_STRING       = 0x0003  //string 
     };     
     enum TLV_Tag{
       TLV_TP_PID             = 0x0001, //GSM协议类型。详细解释请参考GSM03.40中的9.2.3.9
       TLV_TP_UDHI            = 0x0002, //GSM协议类型。详细解释请参考GSM03.40中的9.2.3.23,仅使用1位,右对齐。
       TLV_LINK_ID            = 0x0003, //交易标识,用于唯一标识一次交易
       TLV_CHARGE_USER_TYPE   = 0x0004, //计费用户类型。
                                        // 0=对短消息接收方计费;
                                        // 1=对短消息发送方计费;
                                        // 2=对SP计费;
                                        // 3=表示本字段无效,对谁计费参见ChargeTermID或ChargeTermPseudo 字段。
       TLV_CHARGE_TERM_TYPE   = 0x0005, //计费用户的号码类型。
                                        // 0=真实号码;
                                        // 1=伪码;其它保留。
       TLV_CHARGE_TERM_PSEUDO = 0x0006, //计费用户的伪码
       TLV_DEST_TERM_TYPE     = 0x0007, //短消息接收方的号码类型。
                                        // 0=真实号码;
                                        // 1=伪码;其它保留
       TLV_DEST_TERM_PSEUDO   = 0x0008, //短消息接收方的伪码,当有多个接收方伪码时,要求每个接收方伪码的长度一样。
       TLV_PK_TOTAL           = 0x0009, //相同Msg_Id的消息总条数。
       TLV_PK_NUMBER          = 0x000A, //相同Msg_Id的消息序号,从1开始。
       TLV_SUBMIT_MSG_TYPE    = 0x000B, //SP发送的消息类型。
                                        // 0=普通短消息;
                                        // 1=WEB方式定制结果消息;
                                        // 2=WEB方式取消定制结果消息;
                                        // 3=终端方式定制结果消息;
                                        // 4=终端方式取消定制结果消息;
                                        // 5=包月扣费通知消息;
                                        // 6=WEB方式定制二次确认消息;
                                        // 7=WEB方式取消定制二次确认消息;
                                        // 8=终端方式定制二次确认消息;
                                        // 9=终端方式取消定制二次确认消息;
                                        // 10=WEB方式点播二次确认消息;
                                        // 11=终端方式点播二次确认消息(暂保留);
                                        // 12=群发请求;
                                        // 13:同步订购(包括点播和定制)关系;
                                        // 14:群发结果通知消息。
                                        // 无该字段时,默认为"普通短消息"
                                        // 15:同步订购(包括点播和定制)关系回复;其它保留;
       TLV_SP_DEAL_RESLT      = 0x000C, //SP对消息的处理结果
                                        // 0=成功;
                                        // 1=失败;其它保留。
                                        // 该字段在SubmitMsgType为0、5、6、7、8、9、10、11、14时无效。 
       TLV_SRC_TERM_TYPE      = 0x000D, //短消息发送方的号码类型。
                                        // 0=真实号码;
                                        // 1=伪码;其它保留。 
       TLV_SRC_TERM_PSEUDO    = 0x000E, //短消息发送方的伪码
       TLV_NODES_COUNT        = 0x000F, //经过的网关数量。该字段的初始值为1。 
       TLV_MSG_SRC            = 0x0010, //信息内容的来源。
                                        // 在固定网短消息业务中,MsgSrc填写SP的服务代码。
                                        // 在移动网短消息业务中,MsgSrc填写SP的企业代码。
       TLV_SRC_TYPE           = 0x0011, //传递给SP 的源号码的类型。
                                        // 0=真实号码;
                                        // 1=伪码;其它保留。
       TLV_M_SERVICE_ID       = 0x0012  //业务代码。用于移动网业务
     };     
     WORD getTag() const { return tag;}
     void setTag(WORD new_tag){ tag = new_tag; }     
     WORD getTLVLen() const { return 2+2+len; } 
     WORD getValueLen() const { return len;}
     int getOffset() const{ return byteOffset;}     
     BOOL getValue(BYTE *pstr, int value_len);     
     static BOOL IsValidTag(WORD the_tag);
     static std::string AliasByTag(WORD the_tag);     
     BOOL Decode(BYTE *pstr, int tlv_len);
     BOOL Encode(WORD the_tag, WORD the_len, BYTE *the_value);
     BOOL Encode(WORD new_tag, BYTE new_value);     
     void PrintOn(std::ostream & strm) const;
     void ToString(std::ostream & strm) const;     
     WORD getValueType(WORD the_tag) const;
   protected:       
 };
 ////////////////////////////////////////////////////////////////////////////////
 #endif //_TLV_HPP        
 //////////////////////////////tlv.cpp///////////////////////////////////////////////
 #include "TLV.hpp" 
 // PTLV//////////////////////////////////////////////////////////////////// 
 /**构造器
 *@param */
 PTlv::PTlv(WORD new_tag, WORD new_len, BYTE *new_value){
   Encode(new_tag, new_len, new_value);
 }  
 PTlv::PTlv(WORD new_tag, BYTE new_value){
   Encode(new_tag, new_value);
 } 
 PTlv::PTlv(){
   tag=0x0000;
   len=0x0000;
   value=0;
   byteOffset=0;
 } 
 /**/
 void PTlv::Clone(PTlv &src_tlv){
   tag = src_tlv.getTag();
   len = src_tlv.getValueLen();
   byteOffset= src_tlv.getOffset();
   if(value != NULL) {
     delete []value;
     value = NULL;
   }
   value = new BYTE[len];
   memset(value, 0, len);
   src_tlv.getValue(value,len);
 } 
 /*析构器*/
 PTlv::~PTlv(){
   if (value != NULL)
     delete []value;
   value      = NULL;
   byteOffset = 0;
   len        = 0;
 } 
 BOOL PTlv::IsValidTag(WORD the_tag){
   switch(the_tag){
     case TLV_TP_PID://             = 0x00000001,
     case TLV_TP_UDHI://            = 0x00000002,
     case TLV_LINK_ID://            = 0x00000003,
     case TLV_CHARGE_USER_TYPE://   = 0x00000004,
     case TLV_CHARGE_TERM_TYPE://   = 0x00000005,
     case TLV_CHARGE_TERM_PSEUDO:// = 0x00000006,
     case TLV_DEST_TERM_TYPE://     = 0x00000007,
     case TLV_DEST_TERM_PSEUDO://   = 0x00000008,
     case TLV_PK_TOTAL://           = 0x00000009,
     case TLV_PK_NUMBER://          = 0x0000000A,
     case TLV_SUBMIT_MSG_TYPE://    = 0x0000000B,
     case TLV_SP_DEAL_RESLT://      = 0x0000000C,
     case TLV_SRC_TERM_TYPE://      = 0x0000000D,
     case TLV_SRC_TERM_PSEUDO://    = 0x0000000E,
     case TLV_NODES_COUNT://        = 0x0000000F,
     case TLV_MSG_SRC://            = 0x00000010,
     case TLV_SRC_TYPE://           = 0x00000011,
     case TLV_M_SERVICE_ID://       = 0x00000012,
       return TRUE;
     default :
       return FALSE;
   }
 } 
 /**
 * 取得tag的别名
 * @param the_tag tag标识 
 * @return string 别名 
 */
 std::string PTlv::AliasByTag(WORD the_tag){
   switch(the_tag){
     case TLV_TP_PID:
       return "TLV_TP_PID";
     case TLV_TP_UDHI:
       return "TLV_TP_UDHI";
     case TLV_LINK_ID:
       return "TLV_LINK_ID";
     case TLV_CHARGE_USER_TYPE:
       return "TLV_CHARGE_USER_TYPE";
     case TLV_CHARGE_TERM_TYPE:
       return "TLV_CHARGE_TERM_TYPE";
     case TLV_CHARGE_TERM_PSEUDO:
       return "TLV_CHARGE_TERM_PSEUDO";
     case TLV_DEST_TERM_TYPE:
       return "TLV_DEST_TERM_TYPE";
     case TLV_DEST_TERM_PSEUDO:
       return "TLV_DEST_TERM_PSEUDO";
     case TLV_PK_TOTAL:
       return "TLV_PK_TOTAL";
     case TLV_PK_NUMBER:
       return "TLV_PK_NUMBER";
     case TLV_SUBMIT_MSG_TYPE:
       return "TLV_SUBMIT_MSG_TYPE";
     case TLV_SP_DEAL_RESLT:
       return "TLV_SP_DEAL_RESLT";
     case TLV_SRC_TERM_TYPE:
       return "TLV_SRC_TERM_TYPE";
     case TLV_SRC_TERM_PSEUDO:
       return "TLV_SRC_TERM_PSEUDO";
     case TLV_NODES_COUNT:
       return "TLV_NODES_COUNT";
     case TLV_MSG_SRC:
       return "TLV_MSG_SRC";
     case TLV_SRC_TYPE:
       return "TLV_SRC_TYPE";
     case TLV_M_SERVICE_ID:
       return "TLV_M_SERVICE_ID";
     default :
       return "TLV_UNKNOWN_TAG_ID";
   }
 }   
 void PTlv::PrintOn(std::ostream &strm) const{
   strm << "SMGP3_TLV:{\n";
  strm << std::setw(15) << "tag:" << AliasByTag(tag)
<< " 0x" << std::hex <<
std::setw(sizeof(tag))<< std::setfill('0') << tag <<
'\n';
   strm << std::setfill(' ') << std::setw(15) << "len:" << len << std::endl;
   strm << std::setfill(' ') << std::setw(17) << "value:" << value <<std::endl;
   strm <<  "}\n";
 } 
 void PTlv::ToString(std::ostream &strm) const{
  strm <<  "alias:" << AliasByTag(tag) << " len:"
<< len <<   " value:" << value <<'\n';
 } 
 WORD PTlv::getValueType(WORD the_tag) const{
   switch (the_tag) {
     case TLV_TP_PID:
     case TLV_CHARGE_USER_TYPE:
     case TLV_CHARGE_TERM_TYPE:
     case TLV_DEST_TERM_TYPE:
     case TLV_PK_TOTAL:
     case TLV_PK_NUMBER:
     case TLV_SUBMIT_MSG_TYPE:
     case TLV_SP_DEAL_RESLT:
     case TLV_SRC_TERM_TYPE:
     case TLV_NODES_COUNT:
     case TLV_SRC_TYPE:
     case TLV_TP_UDHI:{
       return INTEGER_1;
       break;
     }
     case TLV_CHARGE_TERM_PSEUDO:
     case TLV_SRC_TERM_PSEUDO:
     case TLV_DEST_TERM_PSEUDO:
     case TLV_MSG_SRC:
     case TLV_M_SERVICE_ID:
     case TLV_LINK_ID:{
       return OCTET_STRING; //20
       break;
     }
     default :
       return 0x00000000;
   }
 } 
 BOOL PTlv::getValue(BYTE *pstr, int value_len){
   assert(len >0 );
   assert(value != NULL );
   if (value_len < len) return FALSE;
   memset(pstr,0,value_len);
   memcpy(pstr,value,len);
   return TRUE;
 } 
 BOOL PTlv::Decode(BYTE *pstr, int tlv_len){
   memcpy(&tag, pstr, 2);
   memcpy(&len, pstr+2, 2);
   if (tlv_len < len)  //tlv包长度必须大于value长度 
     return FALSE;
   if (value != NULL) { //如果之前value有申请过空间,则先释放他 
     delete[] value;
     value = NULL;
   }   
   byteOffset = 0;
   value = new BYTE[len+1];
   //memset(value, 0, len+1);
   memcpy(value, pstr+4, len);
   return TRUE;
 } 
 BOOL PTlv::Encode(WORD the_tag, WORD the_len, BYTE *the_value){
   assert(the_value != NULL);
   assert(the_len > 0);
   tag=the_tag;   
   if(value != NULL ){
     delete [] value;
     value = NULL;
   }
   value = new BYTE[the_len];
   memset(value, 0, sizeof(BYTE)*the_len);   
   memcpy(value, (BYTE *)the_value, the_len);
   len = the_len;
   byteOffset = 0;
 } 
 BOOL PTlv::Encode(WORD the_tag, BYTE the_value){
   len=sizeof(BYTE);
   tag = the_tag;
   if (value != NULL){
     delete [] value;
     value = NULL; 
   }   
   value = new BYTE[len];
   memset(value,0,sizeof(BYTE)*len);
   byteOffset = 0;
   value[byteOffset++] = the_value;
 }