关于短信内容格式及压缩方法

2023-11-04 05:58

本文主要是介绍关于短信内容格式及压缩方法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 

author: scruffybear

release time: 29/08/2007

如有转载,请注明出处,并保持文章的完整性,谢谢!

 七月份做警务通的项目,涉及到对已有的短信内容进行修改的问题,也就是所说的对COS打补丁修改短信内容的问题,联系本项目在这里对G网短信和C网短信的格式和压缩方法进行简单介绍。
1,G网短信的一般格式
   G网短信格式完全遵守《GSM03.40规范》,所以很容易通过现有规范对现有短信进行解析。卡片按照《GSM11.14规范》来组织短信,发送短信的command tag为‘13’,SMS TPDU tag为‘0B/8B’,更详细内容请参见该规范,现用一条具体短信解释格式如下:
   Fetch指令取得短信内容:
   A01200002FSWD02D81030A130082028183850D8077ED4FE153D190014E2D20268B13010008819494881100080812345678123456789000
      Command Details   01/81 03 0A(Command number) 13(command tag) 00(Command Qualifier)    此项是强制的(Mandatory)
      Device identities 02/82 02 81(SIM) 83(Network) 此项是强制的(Mandatory)
      Alpha identifier  05/85 0D 8077ED4FE153D190014E2D2026(短信发送中…) 此项应该是可选的(Optional)
      Address tag   此例中没有,举例:06/86 08FFFFFFFFFFFFFFFF   此项应该是可选的(Optional)
      SMS TPDU tag  0B/8B 13 01000881949488110008081234567812345678(此项内容在GSM03.40规范中解释) 
   SMS TPDU内容由《GSM03.40规范》进行解释,具体可参见该规范9.2节,Service Provided by the SM-TL(The Short Message Transfer Layer),现仅对具体本条短信的TPDU进行解释,内容如上:0B/8B 13 01000881949488110008081234567812345678,此短信为SUBMIT类型:
      TP-MTI(TP-Message-Type-Indicator)等, 01,bit1,bit0最低两位为01,表示短信内容为SMS-SUBMIT (in the direction MS to SC),bit4,bit3为00,表示短信中无TP-VP字段:0 0 TP-VP field not present
      TP-MR(TP-Message-Reference) 00
      TPDA(TP-Destination-Address) 088194948811,TPDA的长度为(len+1)/2+1,在本例中,为(8+1)/2+1=5  
      TP-PID(TP-Protocol-Identifier) 00
      TP-DCS(TP-Data-Coding-Scheme) 08
      TP-VP(TP-Validity-Period) 此短信中无,该项表示短信的有效期。
      TP-UDL+TPUD(TP-User-Data-Length+TP-User-Data) 081234567812345678
      注意:TPUDL长度为实现压缩前的长度。
    以上说明针对具体短信,更多情况请参照相应规范,在此不赘述。          
   
2,G网短信的压缩及汇编实现
   由于补丁中需要对G网短信做压缩,而且不方便调用已有函数,故用汇编实现了G网的短信压缩。
   G网短信压缩格式在TP-DCS中指示,TP-DCS在《GSM03.38》中有说明,一般都采用将7bit编码压缩成8bit编码方式,这种压缩方式也在《GSM03.38》中有详细说明。
   压缩编码方式将8字节的7bit编码压缩成7字节的8bit编码,也就是说160字节长短信可以压缩为140字节的短信,压缩了20字节,具体压缩方法如下: 
   原始的8字节未压缩编码如下:
      - bits number:
        6    5   4   3   2   1   0
        1a 1b 1c 1d 1e 1f 1g
        2a 2b 2c 2d 2e 2f  2g
        3a 3b 3c 3d 3e 3f  3g
        4a 4b 4c 4d  4e 4f 4g
        5a 5b 5c  5d 5e 5f 5g
        6a 6b  6c 6d 6e 6f 6g 
        7a 7b 7c 7d 7e 7f 7g
        8a 8b 8c 8d 8e 8f 8g
  经过压缩后的8bit编码如下:
   
    - eight characters in seven octets:
    - bits number: 
      7   6   5   4   3   2   1   0
     2g 1a 1b 1c 1d 1e 1f 1g
     3f 3g 2a 2b 2c 2d 2e 2f
     4e 4f 4g 3a 3b 3c 3d 3e
     5d 5e 5f 5g 4a 4b 4c 4d
     6c 6d 6e 6f 6g 5a 5b 5c
     7b 7c 7d 7e 7f 7g 6a 6b
     8a 8b 8c 8d 8e 8f 8g 7a
    从以上的压缩方法可以看出,第一个压缩后字节是第一个7bit在最高位加上第二个7bit的最低位,第二个压缩字节是第二个7bit的高六位加上第三个7bit的低两位,依次类推。 第七个压缩后字节(最后一个压缩字节)是第七个7bit的最高位加上整个第八个7bit的七位。这样就实现了将8个字节的7bit编码压缩成7个字节的8bit编码。
    举一个具体的例子,字符串3132333435363738是7bit编码,现压缩成8bit编码。
    3132333435363738转换为bit为00110001(31) 00110010(32) 00110011(33) 00110100(34) 00110101(35) 00110110(36) 00110111(37) 00111000(38),进行转换,过程如下:
    a,转换31,32的最低位到31的最高位,可以看到31不变,第一个压缩后字节为31
    b,转换32,32由于取了最低位,相当于向右移了一位,为00011001,将33的低两位放在右移一位的31高位上,也就为11011001,即D9。
    c,转换33,33由于取了低两位,相当于向右移了两位,为00001100,将34的低三位放在右移两位的33高位上,也就为10001100,即8C。
    d,转换34,34由于取了低三位,相当于向右移了三位,为00000110,将35的低四位放在右移三位的34高位上,也就为01010110,即56。
    e,转换35,35由于取了低四位,相当于向右移了四位,为00000011,将36的低五位放在右移四位的35高位上,也就为10110011,即B3。
    f,转换36,36由于取了低五位,相当于向右移了五位,为00000001,将37的低六位放在右移五位的36高位上,也就为11011101,即DD。
    g,转换37,37由于取了低六位,相当于向右移了六位,为00000000,将整个38的七位放在右移六位的37高位上,也就是1110000,即70。
    到此7位编码的3132333435363738压缩为了7字节的31D98C56B3DD70,也就是说压缩掉了一字节。
    在进行编码实现时,可以将压缩前的短信每8字节为一组进行处理,处理为压缩后的七字节,这样形成外层循环。循环次数为短信长度除以8再向上取整,例如11/8=1, 1+1 = 2,也就是经过两次循环。进行内层循环处理时,需要进行七次循环,循环到n(0<n<8)次时,首先将当前字节右移n-1位,取后一字节的低n位,放在当前字节右移n-1位后的高n位,这样就可以完成对8字节的压缩,进而完成对整个短信的压缩。
    由于涉及到很多相关的前后环境变量的处理,这里仅列出汇编实现的框架(此处为标准51汇编,双DPTR)如下:
 

     ; DPTR和DPTR1都指向短信开始处,R1中存放外层循环变量,内层循环变量为R2,初始值为1,R3中存放需要转换字符的总长度,并已设置好。
     ; 实际上每一次内层循环,都是两字节一处理,这里将两字节分别称为第一字节和第二字节。
     ; 每一次层循环过程是取第二字节的低R2放在第一字节的高R2位上,然后将第二字节右移R2位后作为下一次内层循环的第一字节。
    MOVX  A ,  @DPTR
    MOV   R6
,  A       ; 在进行第一次处理之前预设R6为第一字节内容。
  out_transbegin:     ; 外层循环开始处,循环[len/8](注意是向上取整)次。   
    MOV  R2 ,   # 1       ; 进行外层循环之前,需要将内层循环变更R2设置为1
  transbegin:        ; 内层循环开始处,循环7次。
    MOV  A ,   R6      ; the 2nd number of  last  loop as the first number.
    MOV  R5 ,   A    ; R5  store the 1st number.
    INC  DPTR
    MOVX  A
,   @DPTR
    MOV  R6
,   A    ; R6  store   2rd  number.
    
    MOV  R0
,   A    ; 将第二个字节存放在R0中,以备后用。
    
    MOV  A
,   R2      ; 2*2*...*2(R2个2)-1
    MOV  R7 ,   A     
    LCALL  POWER2   
; POWER2为2的N次方,N从R7传入,POWER2函数实现很简单,这里不列出。
    CLR  C
    SUBB  A
,   #01H      ; 2*2*...*2-1即2的R2次方减一,2exp(R2)-1
    ANL  A ,   R6   ;   2nd number & 111...11, 取后一字节的低R2位,例如第一次循环,取最低位。 2exp(1)-1 = 1, 取最低位,如果为2exp(2)-1=3,取最低两位。
    MOV  R6 ,   A    ; R6 store the anl result  
    
    MOV  A
,   # 8       ; 计算8-R2,取了第二个字节的低R2位后,再左移(8-R2)位,最后与第一个字节进行或操作。
    CLR  C
    SUBB  A
,   R2     ; 8-R2
    MOV  R7 ,   A      ; R7是输入参数,即左移次数。
    MOV  A ,   R6      ; ANL操作的后再左移(8-R2)位,放在第一个字节的高位。
    LCALL  LFRotateN    ; 左位移(8-R2)位,LFRotateN很简单,不列出,结果放在A里。
    
    ORL  A
,   R5    ; 进行或操作,将第二个字节的低R2位放在第一个字节的高R2位上。     
    MOVX  @DPTR1 ,   A         ; 结果存放在DPTR1所指的地方。
    
    MOV  A
,   R2
    MOV  R7
,   A     ; 右移次数。
    MOV  A ,   R0     ; 前面保存的第二字节在R0中,这里右移R2位,作为下一次循环的第一字节。
    LCALL  RTRotateN     ; 右移R2位操作,RTRotateN很简单,不列出,结果放在A里。
    MOV  R6 ,   A     ; R6作为下一次循环的第一字节。    
    
    
    INC DPTR1    
; 写指针DPTR1加1
    INC R2        ; 内层循环变量加1
    
    MOV  A
,   R3    ; R3  is the len
    CLR  C
    SUBB  A
,   # 1
    MOV  R3
,   A     ; R3也就是转换的总长度减一, R3=R3-1
    JZ  transend    ; 如果长度为0,则表示已经处理完所有字节,即出。   
    CJNE  R2 ,   # 8 ,  transbegin    ; 循环范围为1~7
    
    INC  DPTR     
; outer loop proceed,进入下一次外层循环前的准备工作。
    MOVX  A ,   @DPTR
    MOV  R6
,   A     ; 进入下一个8字节处理之前预设第一字节为R6
    
    MOV  A
,   R3    ; R3是短信长度,进入下一次处层循环时,R3长度也要减1,处理的是下一个8字节的头两个字节。
    CLR  C
    SUBB  A
,   # 1
    MOV  R3
,   A
    JZ  transend    
    
    DJNZ  R1
,   out_transbegin    ; loop [len/8] times, 如果R1没减到0,则进入到下层循环。        
                
  transend:   

       以上是7bit编码压缩为8bit编码的算法实现。
      
3 C网短信压缩方法 
    C网短信按照《中国联通800MHz CDMA数字蜂窝移动通信网UTK技术要求》规范进行组织,现简单地解释一条具体短信内容:
      A01200003ASWD038810308130082028183850F806B63572853D19001002E002E002EC81C000002100204080B813193612004F7080B000320000001041017FFE09000          
    这里与G网短信类似,分别为主动式UIM命令标签(13),Alpha标识符(85)(O),设备标识(82),CDMA SMS TPDU(C8)

    C81C000002100204080B813193612004F7080B000320000001041017FFE09000是CDMA SMS TPDU内容,解析如下:
      C81C(tag+len)
      00  (段消息类型:00 SMS point to point)
      00 02 1002   (TAG:teleservice identifier)
      04 08 0B813193612004F7  (Destination Address )
      08 0B 00 03 200000 01 04 1017FFE0  (Bearer Data)
     
     Bearer Data为080B000320000001041017FFE0,进行拆分,
     08 0B(tag+len)
     00 03 200000  (Message Identifier )
     01 04 1017FFE0 (User data )
     首先将0104后内容1017FFE0转换为bit:0001 0000  0001 0111  1111 1111  1110 0000
     前5bit为编码类型,为00010,表示为7bit编码,进行划分即为:00010 0000001 0111111 11111111 00000
    
     以上仅对具体短信进行分析,更多情况请参考《TIA-EIA-637-A》。
     
4, 参考文档:
       1,GSM11.14
       2, GSM03.40
       3, GSM03.38
       4, 中国联通800MHz CDMA数字蜂窝移动通信网UTK技术要求 
       5, TIA-EIA-637-A  

这篇关于关于短信内容格式及压缩方法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/343704

相关文章

Python中注释使用方法举例详解

《Python中注释使用方法举例详解》在Python编程语言中注释是必不可少的一部分,它有助于提高代码的可读性和维护性,:本文主要介绍Python中注释使用方法的相关资料,需要的朋友可以参考下... 目录一、前言二、什么是注释?示例:三、单行注释语法:以 China编程# 开头,后面的内容为注释内容示例:示例:四

一文详解Git中分支本地和远程删除的方法

《一文详解Git中分支本地和远程删除的方法》在使用Git进行版本控制的过程中,我们会创建多个分支来进行不同功能的开发,这就容易涉及到如何正确地删除本地分支和远程分支,下面我们就来看看相关的实现方法吧... 目录技术背景实现步骤删除本地分支删除远程www.chinasem.cn分支同步删除信息到其他机器示例步骤

在Golang中实现定时任务的几种高效方法

《在Golang中实现定时任务的几种高效方法》本文将详细介绍在Golang中实现定时任务的几种高效方法,包括time包中的Ticker和Timer、第三方库cron的使用,以及基于channel和go... 目录背景介绍目的和范围预期读者文档结构概述术语表核心概念与联系故事引入核心概念解释核心概念之间的关系

Mysql常见的SQL语句格式及实用技巧

《Mysql常见的SQL语句格式及实用技巧》本文系统梳理MySQL常见SQL语句格式,涵盖数据库与表的创建、删除、修改、查询操作,以及记录增删改查和多表关联等高级查询,同时提供索引优化、事务处理、临时... 目录一、常用语法汇总二、示例1.数据库操作2.表操作3.记录操作 4.高级查询三、实用技巧一、常用语

在Linux终端中统计非二进制文件行数的实现方法

《在Linux终端中统计非二进制文件行数的实现方法》在Linux系统中,有时需要统计非二进制文件(如CSV、TXT文件)的行数,而不希望手动打开文件进行查看,例如,在处理大型日志文件、数据文件时,了解... 目录在linux终端中统计非二进制文件的行数技术背景实现步骤1. 使用wc命令2. 使用grep命令

Python中Tensorflow无法调用GPU问题的解决方法

《Python中Tensorflow无法调用GPU问题的解决方法》文章详解如何解决TensorFlow在Windows无法识别GPU的问题,需降级至2.10版本,安装匹配CUDA11.2和cuDNN... 当用以下代码查看GPU数量时,gpuspython返回的是一个空列表,说明tensorflow没有找到

XML重复查询一条Sql语句的解决方法

《XML重复查询一条Sql语句的解决方法》文章分析了XML重复查询与日志失效问题,指出因DTO缺少@Data注解导致日志无法格式化、空指针风险及参数穿透,进而引发性能灾难,解决方案为在Controll... 目录一、核心问题:从SQL重复执行到日志失效二、根因剖析:DTO断裂引发的级联故障三、解决方案:修复

利用Python脚本实现批量将图片转换为WebP格式

《利用Python脚本实现批量将图片转换为WebP格式》Python语言的简洁语法和库支持使其成为图像处理的理想选择,本文将介绍如何利用Python实现批量将图片转换为WebP格式的脚本,WebP作为... 目录简介1. python在图像处理中的应用2. WebP格式的原理和优势2.1 WebP格式与传统

C++ 检测文件大小和文件传输的方法示例详解

《C++检测文件大小和文件传输的方法示例详解》文章介绍了在C/C++中获取文件大小的三种方法,推荐使用stat()函数,并详细说明了如何设计一次性发送压缩包的结构体及传输流程,包含CRC校验和自动解... 目录检测文件的大小✅ 方法一:使用 stat() 函数(推荐)✅ 用法示例:✅ 方法二:使用 fsee

Java继承映射的三种使用方法示例

《Java继承映射的三种使用方法示例》继承在Java中扮演着重要的角色,它允许我们创建一个类(子类),该类继承另一个类(父类)的所有属性和方法,:本文主要介绍Java继承映射的三种使用方法示例,需... 目录前言一、单表继承(Single Table Inheritance)1-1、原理1-2、使用方法1-