--- /dev/null
+// Copyright 2011 The Avalon Project Authors. All rights reserved.
+// Use of this source code is governed by the Apache License 2.0
+// that can be found in the LICENSE file.
+//
+// SMS encoding/decoding functions, which are based on examples from:
+// http://www.dreamfabric.com/sms/
+
+#include "pdu.h"
+
+#include <string.h>
+#include <time.h>
+#include <stdint.h>
+
+enum {
+ BITMASK_7BITS = 0x7F,
+ BITMASK_8BITS = 0xFF,
+ BITMASK_HIGH_4BITS = 0xF0,
+ BITMASK_LOW_4BITS = 0x0F,
+
+ TYPE_OF_ADDRESS_INTERNATIONAL_PHONE = 0x91,
+ TYPE_OF_ADDRESS_NATIONAL_SUBSCRIBER = 0xC8,
+
+ SMS_DELIVER_ONE_MESSAGE = 0x04,
+ SMS_SUBMIT = 0x11,
+
+ SMS_MAX_7BIT_TEXT_LENGTH = 160,
+};
+
+// Swap decimal digits of a number (e.g. 12 -> 21).
+static unsigned char
+SwapDecimalNibble(const unsigned char x)
+{
+ return (x / 16) + ((x % 16) * 10);
+}
+
+// Encode/Decode PDU: Translate ASCII 7bit characters to 8bit buffer.
+// SMS encoding example from: http://www.dreamfabric.com/sms/.
+//
+// 7-bit ASCII: "hellohello"
+// [0]:h [1]:e [2]:l [3]:l [4]:o [5]:h [6]:e [7]:l [8]:l [9]:o
+// 1101000 1100101 1101100 1101100 1101111 1101000 1100101 1101100 1101100 1101111
+// | ||| ||||| | ||||||| ||||||
+// /-------------/ ///-------/// /////-///// \------------\ ||||||| \\\\\\ .
+// | ||| ||||| | ||||||| ||||||
+// input buffer position
+// 10000000 22111111 33322222 44443333 55555333 66666655 77777776 98888888 --999999
+// | ||| ||||| | ||||||| ||||||
+// 8bit encoded buffer
+// 11101000 00110010 10011011 11111101 01000110 10010111 11011001 11101100 00110111
+// E8 32 9B FD 46 97 D9 EC 37
+
+
+// // Encode PDU message by merging 7 bit ASCII characters into 8 bit octets.
+// static int
+// EncodePDUMessage(const char* sms_text, int sms_text_length, unsigned char* output_buffer, int buffer_size)
+// {
+// // Check if output buffer is big enough.
+// if ((sms_text_length * 7 + 7) / 8 > buffer_size)
+// return -1;
+
+// int output_buffer_length = 0;
+// int carry_on_bits = 1;
+// int i = 0;
+
+// for (; i < sms_text_length - 1; ++i) {
+// output_buffer[output_buffer_length++] =
+// ((sms_text[i] & BITMASK_7BITS) >> (carry_on_bits - 1)) |
+// ((sms_text[i + 1] & BITMASK_7BITS) << (8 - carry_on_bits));
+// carry_on_bits++;
+// if (carry_on_bits == 8) {
+// carry_on_bits = 1;
+// ++i;
+// }
+// }
+
+
+// if (i < sms_text_length)
+// output_buffer[output_buffer_length++] = (sms_text[i] & BITMASK_7BITS) >> (carry_on_bits - 1);
+
+// return output_buffer_length;
+// }
+
+// // Decode PDU message by splitting 8 bit encoded buffer into 7 bit ASCII
+// // characters.
+// static int
+// DecodePDUMessage(const unsigned char* buffer, int buffer_length, char* output_sms_text, int sms_text_length)
+// {
+// int output_text_length = 0;
+// if (buffer_length > 0)
+// output_sms_text[output_text_length++] = BITMASK_7BITS & buffer[0];
+
+// int carry_on_bits = 1;
+// int i = 1;
+// for (; i < buffer_length; ++i) {
+
+// output_sms_text[output_text_length++] = BITMASK_7BITS & ((buffer[i] << carry_on_bits) | (buffer[i - 1] >> (8 - carry_on_bits)));
+
+// if (output_text_length == sms_text_length) break;
+
+// carry_on_bits++;
+
+// if (carry_on_bits == 8) {
+// carry_on_bits = 1;
+// output_sms_text[output_text_length++] = buffer[i] & BITMASK_7BITS;
+// if (output_text_length == sms_text_length) break;
+// }
+
+// }
+// if (output_text_length < sms_text_length) // Add last remainder.
+// output_sms_text[output_text_length++] = buffer[i - 1] >> (8 - carry_on_bits);
+
+// return output_text_length;
+// }
+
+// Encode a digit based phone number for SMS based format.
+static int
+EncodePhoneNumber(const char* phone_number, unsigned char* output_buffer, int buffer_size)
+{
+ int output_buffer_length = 0;
+ const int phone_number_length = strlen(phone_number);
+
+ // Check if the output buffer is big enough.
+ if ((phone_number_length + 1) / 2 > buffer_size)
+ return -1;
+
+ int i = 0;
+ for (; i < phone_number_length; ++i) {
+
+ if (phone_number[i] < '0' && phone_number[i] > '9')
+ return -1;
+
+ if (i % 2 == 0) {
+ output_buffer[output_buffer_length++] = BITMASK_HIGH_4BITS | (phone_number[i] - '0');
+ } else {
+ output_buffer[output_buffer_length - 1] =
+ (output_buffer[output_buffer_length - 1] & BITMASK_LOW_4BITS) |
+ ((phone_number[i] - '0') << 4);
+ }
+ }
+
+ return output_buffer_length;
+}
+
+// Decode a digit based phone number for SMS based format.
+static int
+DecodePhoneNumber(const unsigned char* buffer, int phone_number_length, char* output_phone_number)
+{
+ int i = 0;
+ for (; i < phone_number_length; ++i) {
+ if (i % 2 == 0)
+ output_phone_number[i] = (buffer[i / 2] & BITMASK_LOW_4BITS) + '0';
+ else
+ output_phone_number[i] = ((buffer[i / 2] & BITMASK_HIGH_4BITS) >> 4) + '0';
+ }
+ output_phone_number[phone_number_length] = '\0'; // Terminate C string.
+ return phone_number_length;
+}
+
+
+//参数:uni_in,要转码的Unicode编码地址,高字节在前
+//参数:utf8_out,转码后输出的utf8编码存储地址的指针,在转码后地址自动向后移编
+//返回值:下一个Unicode编码地址
+uint8_t *uni2utf8 (const uint8_t *uni_in,uint8_t **utf8_out)
+{
+ uint16_t c=0;
+ if ((uni_in)&&(c=(uni_in[0]<<8)|uni_in[1],c))
+ {
+ if (c<0x80)
+ {
+ **utf8_out=c;
+ (*utf8_out)++;
+ return (uint8_t*)uni_in+2;
+ }
+ else
+ {
+ (*utf8_out)[0]=0xe0;
+ (*utf8_out)[0]|=uni_in[0]>>4;
+ (*utf8_out)[1]=0x80;
+ (*utf8_out)[1]|=((uni_in[0]<<2)|(uni_in[1]>>6))&0x3f;
+ (*utf8_out)[2]=0x80;
+ (*utf8_out)[2]|=(uni_in[1])&0x3f;
+ (*utf8_out)+=3;
+ return (uint8_t*)uni_in+2;
+ }
+ }
+ return 0;
+}
+//参数:utf8_in,要转码的UTF8编码地址,高字节在前
+//参数:uni_out,转码后输出的uni编码存储地址的指针,在转码后地址自动向后移编
+//返回值:下一个utf8编码地址
+uint8_t *utf82uni (const uint8_t *uft8_in,uint8_t **uni_out)
+{
+ if ((uft8_in)&&(*uft8_in))
+ {
+ if (uft8_in[0]<0x80)
+ {
+ (*uni_out)[0]=0;
+ (*uni_out)[1]=*uft8_in;
+ (*uni_out)+=2;
+ return (uint8_t*)uft8_in+1;
+ }
+ else
+ {
+ (*uni_out)[0]=uft8_in[0]<<4;
+ (*uni_out)[0]|=(uft8_in[1]>>2)&0x0f;
+ (*uni_out)[1]=(uft8_in[1]<<6);
+ (*uni_out)[1]|=(uft8_in[2])&0x3f;
+ (*uni_out)+=2;
+ return (uint8_t*)uft8_in+3;
+ }
+ }
+ return 0;
+}
+
+
+
+
+// // Encode a SMS message to PDU、
+// int
+// pdu_encode(const char* service_center_number, const char* phone_number, const char* sms_text,
+// unsigned char* output_buffer, int buffer_size)
+// {
+// if (buffer_size < 2)
+// return -1;
+
+// int output_buffer_length = 0;
+
+// // 1. Set SMS center number.
+// int length = 0;
+// if (service_center_number && strlen(service_center_number) > 0) {
+// output_buffer[1] = TYPE_OF_ADDRESS_INTERNATIONAL_PHONE;
+// length = EncodePhoneNumber(service_center_number,
+// output_buffer + 2, buffer_size - 2);
+// if (length < 0 && length >= 254)
+// return -1;
+// length++; // Add type of address.
+// }
+// output_buffer[0] = length;
+// output_buffer_length = length + 1;
+// if (output_buffer_length + 4 > buffer_size)
+// return -1; // Check if it has space for four more bytes.
+
+// // 2. Set type of message.
+// output_buffer[output_buffer_length++] = SMS_SUBMIT;
+// output_buffer[output_buffer_length++] = 0x00; // Message reference.
+
+// // 3. Set phone number.
+// output_buffer[output_buffer_length] = strlen(phone_number);
+// output_buffer[output_buffer_length + 1] = TYPE_OF_ADDRESS_INTERNATIONAL_PHONE;
+// length = EncodePhoneNumber(phone_number,
+// output_buffer + output_buffer_length + 2,
+// buffer_size - output_buffer_length - 2);
+// output_buffer_length += length + 2;
+// if (output_buffer_length + 4 > buffer_size)
+// return -1; // Check if it has space for four more bytes.
+
+
+// // 4. Protocol identifiers.
+// output_buffer[output_buffer_length++] = 0x00; // TP-PID: Protocol identifier.
+// output_buffer[output_buffer_length++] = 0x00; // TP-DCS: Data coding scheme.
+// output_buffer[output_buffer_length++] = 0xB0; // TP-VP: Validity: 10 days
+
+// // 5. SMS message.
+// const int sms_text_length = strlen(sms_text);
+// if (sms_text_length > SMS_MAX_7BIT_TEXT_LENGTH)
+// return -1;
+// output_buffer[output_buffer_length++] = sms_text_length;
+// length = EncodePDUMessage(sms_text, sms_text_length,
+// output_buffer + output_buffer_length,
+// buffer_size - output_buffer_length);
+// if (length < 0)
+// return -1;
+// output_buffer_length += length;
+
+// return output_buffer_length;
+// }
+
+int pdu_decode(unsigned char* buffer, int buffer_length,
+ struct tm* output_sms_time, int* output_sms_zone,time_t *output_sms_timestamp,
+ char* output_sender_phone_number, int sender_phone_number_size,
+ char* output_sms_text, int sms_text_size)
+{
+
+ if (buffer_length <= 0)
+ {
+ printf(" buffer_len <=0 \n");
+ return -1;
+ }
+ const int sms_deliver_start = 1 + buffer[0];
+ if (sms_deliver_start + 1 > buffer_length)
+ {
+ printf("delive_start +1 > buffer_len\n");
+ return -2;
+ }
+ if ((buffer[sms_deliver_start] & SMS_DELIVER_ONE_MESSAGE) != SMS_DELIVER_ONE_MESSAGE)
+ {
+ printf("buffer[%d]=%02X",sms_deliver_start,buffer[sms_deliver_start]);
+ return -3;
+ }
+
+ const int sender_number_length = buffer[sms_deliver_start + 1];
+ if (sender_number_length + 1 > sender_phone_number_size)
+ {
+ return -4; // Buffer too small to hold decoded phone number.
+ }
+
+ // const int sender_type_of_address = buffer[sms_deliver_start + 2];
+ DecodePhoneNumber(buffer + sms_deliver_start + 3, sender_number_length, output_sender_phone_number);
+
+ const int sms_pid_start = sms_deliver_start + 3 + (buffer[sms_deliver_start + 1] + 1) / 2;
+#if 0
+ // Decode timestamp.
+ struct tm sms_broken_time;
+ sms_broken_time.tm_year = 100 + SwapDecimalNibble(buffer[sms_pid_start + 2]);
+ sms_broken_time.tm_mon = SwapDecimalNibble(buffer[sms_pid_start + 3]) - 1;
+ sms_broken_time.tm_mday = SwapDecimalNibble(buffer[sms_pid_start + 4]);
+ sms_broken_time.tm_hour = SwapDecimalNibble(buffer[sms_pid_start + 5]);
+ sms_broken_time.tm_min = SwapDecimalNibble(buffer[sms_pid_start + 6]);
+ sms_broken_time.tm_sec = SwapDecimalNibble(buffer[sms_pid_start + 7]);
+ const char gmt_offset = SwapDecimalNibble(buffer[sms_pid_start + 8]);
+ // GMT offset is expressed in 15 minutes increments.
+ (*output_sms_time) = mktime(&sms_broken_time) - gmt_offset * 15 * 60;
+ printf(" %04d-%02d-%02d %02d:%02d:%02d offset %d\n",sms_broken_time.tm_year,sms_broken_time.tm_mon,sms_broken_time.tm_mday,sms_broken_time.tm_hour,sms_broken_time.tm_min,sms_broken_time.tm_sec,gmt_offset);
+#else
+ output_sms_time->tm_year = 100 + SwapDecimalNibble(buffer[sms_pid_start + 2]);
+ output_sms_time->tm_mon = SwapDecimalNibble(buffer[sms_pid_start + 3]) - 1;
+ output_sms_time->tm_mday = SwapDecimalNibble(buffer[sms_pid_start + 4]);
+ output_sms_time->tm_hour = SwapDecimalNibble(buffer[sms_pid_start + 5]);
+ output_sms_time->tm_min = SwapDecimalNibble(buffer[sms_pid_start + 6]);
+ output_sms_time->tm_sec = SwapDecimalNibble(buffer[sms_pid_start + 7]);
+ const char gmt_offset = SwapDecimalNibble(buffer[sms_pid_start + 8]);
+ // GMT offset is expressed in 15 minutes increments.
+ (*output_sms_zone) = gmt_offset * 15 * 60;
+ (*output_sms_timestamp) = mktime(output_sms_time) ;
+
+#endif
+ const int sms_start = sms_pid_start + 2 + 7;
+ if (sms_start + 1 > buffer_length) return -5; // Invalid input buffer.
+
+ const int output_sms_text_length = buffer[sms_start];
+ if (sms_text_size < output_sms_text_length) return -6; // Cannot hold decoded buffer.
+ printf("output_sms_text_length %d, index %d\n",output_sms_text_length,sms_start + 1);
+
+
+ unsigned char * unicodebuf=buffer+sms_start+1;
+ int unicodebuflen=buffer_length-(sms_start+1);
+ char * utf8p=output_sms_text;
+ int jj;
+ for(jj=0; jj < unicodebuflen/2;jj++){
+ uni2utf8((const uint8_t *)(unicodebuf+jj*2),&utf8p);
+ }
+ int decoded_sms_text_size = (utf8p - output_sms_text);
+ // const int decoded_sms_text_size = DecodePDUMessage(buffer + sms_start + 1, buffer_length - (sms_start + 1),
+ // output_sms_text, output_sms_text_length);
+
+ // if (decoded_sms_text_size != output_sms_text_length) return -7; // Decoder length is not as expected.
+ // printf("decoded_sms_text_size %d\n",decoded_sms_text_size);
+ // Add a C string end.
+ if (decoded_sms_text_size < sms_text_size)
+ output_sms_text[decoded_sms_text_size] = 0;
+ else
+ output_sms_text[sms_text_size-1] = 0;
+
+ return decoded_sms_text_size;
+}
+
+
+// 十六进制数据映射表
+static const char HexTbl[]={"0123456789ABCDEF"};
+
+// 十六进制字符转为数字
+static unsigned char HexChar2Number(char hex)
+{
+ unsigned char value = 0;
+ if(hex >= '0' && hex <= '9')
+ {
+ value = hex - '0';
+ }
+ else if(hex >= 'A' && hex <= 'Z')
+ {
+ value = hex - 'A' + 10;
+ }
+ else if(hex >= 'a' && hex <= 'z')
+ {
+ value = hex - 'a' + 10;
+ }
+
+ return value;
+}
+
+// 两个十六进制字符转为十进制数据
+static unsigned char strHex2Byte(char *pHex)
+{
+ unsigned char value;
+ value = HexChar2Number(pHex[0]) << 4;
+ value |= HexChar2Number(pHex[1]);
+
+ return value;
+}
+
+
+int strHex2bytearray(char *inputHexstr, char *output_bytes, int *max_output_bytes_count)
+{
+ if(inputHexstr == NULL || output_bytes == NULL || max_output_bytes_count == NULL)
+ {
+ return -1;
+ }
+ int inputlen=strlen(inputHexstr);
+ if (inputlen%2 != 0 || inputlen<2)
+ return -2;
+ int outputlen = inputlen/2;
+ if (*max_output_bytes_count < outputlen)
+ {
+ outputlen = *max_output_bytes_count;
+ }
+ for (int i = 0; i< outputlen ; i++)
+ {
+ output_bytes[i]=strHex2Byte(&inputHexstr[i*2]);
+ }
+ *max_output_bytes_count = outputlen;
+ return 0;
+
+}
+
+
+
+// int main_pdu_decode_example()
+// {
+
+// struct tm sms_broken_time={0};
+// time_t sms_broken_timestamp=0;
+// int timezone = 0; //单位15分钟
+// char phone_number[24]={0};
+// int phone_number_size=24;
+// char text[256]={0};
+// int text_size=256;
+
+// /**
+// strHex2bytearray 0891683108705505F0240D91685125419665F1000842508281025223108BA152127684597D597D768457FA91D1 ret 0
+// output_sms_text_length 16, index 29
+// pdustr len 45,phonenumb:8615521469561 ,text:计划的好好的基金 ,txtlen:24, receive time 0124-04-28 18:20:25 offset 28800 , timestampe 1716891625
+// */
+
+// char * inputpdutxt="0891683108705505F0240D91685125419665F1000842508281025223108BA152127684597D597D768457FA91D1";
+// int ret=strHex2bytearray(inputpdutxt,text,&text_size);
+// printf("strHex2bytearray %s ret %d\n",inputpdutxt,ret);
+// ret = pdu_decode(text,text_size,&sms_broken_time,&timezone,&sms_broken_timestamp,phone_number,phone_number_size,text,text_size);
+// printf("pdustr len %d,phonenumb:%s ,text:%s ,txtlen:%d, ",text_size,phone_number,text,ret);
+// printf("receive time %04d-%02d-%02d %02d:%02d:%02d offset %d , timestampe %d\n",sms_broken_time.tm_year,sms_broken_time.tm_mon,sms_broken_time.tm_mday,sms_broken_time.tm_hour,sms_broken_time.tm_min,sms_broken_time.tm_sec,
+// timezone,sms_broken_timestamp);
+
+// return 0;
+// }
+
+// int main()
+// {
+// return main_pdu_decode_example();
+// }
\ No newline at end of file