doubango/tinySMS/src/tsms_packing.c
c732d49e
 #if HAVE_CRT
 #define _CRTDBG_MAP_ALLOC 
 #include <stdlib.h> 
 #include <crtdbg.h>
 #endif //HAVE_CRT
 /*
74ca6d11
 * Copyright (C) 2020, University of the Basque Country (UPV/EHU)
c732d49e
 * Contact for licensing options: <licensing-mcpttclient(at)mcopenplatform(dot)com>
 *
 * The original file was part of Open Source Doubango Framework
 * Copyright (C) 2010-2011 Mamadou Diop.
 * Copyright (C) 2012 Doubango Telecom <http://doubango.org>
 *
 * This file is part of Open Source Doubango Framework.
 *
 * DOUBANGO 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 3 of the License, or
 * (at your option) any later version.
 *
 * DOUBANGO 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 DOUBANGO.
 *
 */
 
 /**@file tsms_packing.c
  * @brief SMS Packing (3GPP TS 23.038 subclause 6.1.2).
  *
  * @author Mamadou Diop <diopmamadou(at)doubango.org>
  *
 
  */
 #include "tinysms/tsms_packing.h"
 
 #include "tinysms/tsms_etsi_gsm_03_38.h"
 
 #include "tsk_memory.h"
 #include "tsk_string.h"
 #include "tsk_debug.h"
 
 #include <string.h> /* strlen() */
 
 /**@defgroup tsms_packing_group SMS Packing
 */
 
 /**@ingroup tsms_packing_group
 * Converts ASCII string to GSM 7-bit characters as per 3GPP TS 23.038 v911 section 6.1.2.1.
 * @param ascii Null-Terminated ascii string to convert.
 * @retval Buffer containing GSM 7-bit characters if succeed and @a Null otherwise.
 * @sa @ref tsms_pack_from_7bit
 */
 tsk_buffer_t* tsms_pack_to_7bit(const char* ascii)
 {
 	/* 3GPP TS 23.038 - 6.1.2.1.1	Packing of 7-bit characters
 		If a character number $ is noted in the following way:
 			b7	b6	b5	b4	b3	b2	b1
 			$a	$b	$c	$d	$e	$f	$g
 		The packing of the 7-bitscharacters in octets is done by completing the octets with zeros on the left.
 		For examples, packing: $
 		-	one character in one octet:
 		-	bits number:
 			7	6	5	4	3	2	1	0
 			0	1a	1b	1c	1d	1e	1f	1g
 
 		-	two characters in two octets:
 		-	bits number:
 			7	6	5	4	3	2	1	0
 			2g	1a	1b	1c	1d	1e	1f	1g
 			0	0	2a	2b	2c	2d	2e	2f
 
 		-	three characters in three 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
 			0	0	0	3a	3b	3c	3d	3e
 
 		-	seven 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
 			0	0	0	0	0	0	0	7a
 
 		-	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
 
 		The bit number zero is always transmitted first.
 		Therefore, in 140 octets, it is possible to pack (140x8)/7=160 characters.
 	*/
 	tsk_buffer_t* ret = tsk_null;
 	uint8_t* _ret = tsk_null;
 	register tsk_size_t len, bcount = 1/*1-7*/, index = 0, retindex = 0, retlen = 0;
 	const uint8_t* pascii = (const uint8_t*)ascii;
 	
 	if(!ascii || !(len = strlen(ascii))){
 		TSK_DEBUG_WARN("Null or Empty ascci string.");
 		goto bail;
 	}
 	
 	retlen = len - (len/7) + 1;
 	#if HAVE_CRT //Debug memory
 	if(!(_ret = calloc(retlen, sizeof(uint8_t)))){
 		
 	#else
 	if(!(_ret = tsk_calloc(retlen, sizeof(uint8_t)))){
 		
 	#endif //HAVE_CRT
 		goto bail;
 	}
 	
 	while(index < len){
 		if(index == 0){
 			_ret[retindex] |= (pascii[index] & (0xFF >> bcount)) |
 				(pascii[index+1] << (8 - bcount));
 		}
 		else{
 			_ret[retindex] = ((pascii[index] >> (bcount - 1))& (0xFF >> bcount))
 							| (pascii[index+1] <<(8-bcount));
 		}		
 		
 		/* how many bytes to use to complete on the left? */
 		if(++bcount == 8){
 			bcount = 1, ++index;
 		}
 		/* next */
 		retindex++;
 		index++;
 	}
 	
 	/* creat ret */
 	ret = tsk_buffer_create(_ret, (retlen-1));
 bail:
 	TSK_FREE(_ret);
 	
 	return ret;
 }
 
 /**@ingroup tsms_packing_group
 * Converts ASCII string to UCS-2(2-byte Universal Character Set) characters.
 * @param ascii Null-Terminated ascii string to convert.
 * @retval Buffer containing UCS-2 characters if succeed and @a Null otherwise.
 * @sa @ref tsms_pack_from_ucs2
 */
 tsk_buffer_t* tsms_pack_to_ucs2(const char* ascii)
 {
 	register tsk_size_t i, j;
 	tsk_size_t len, retlen = 0;
 	uint8_t* str = tsk_null;
 	tsk_buffer_t* ret = tsk_null;
 
 	if(!ascii || !(len=strlen(ascii))){
 		TSK_DEBUG_WARN("Null or Empty gsm7bit buffer.");
 		goto bail;
 	}
 	#if HAVE_CRT //Debug memory
 	if(!(str = calloc(len, sizeof(uint8_t)*2))){
 		
 	#else
 	if(!(str = tsk_calloc(len, sizeof(uint8_t)*2))){
 		
 	#endif //HAVE_CRT
 		goto bail;
 	}
 
 	/* very bas way to do conversion ==> to be fixed */
 	for(i=0; i<len; i++){
 		for(j=0; j<TSMS_ETSI_GSM_03_38_COUNT; j++){
 			if((uint8_t)ascii[i] == (uint8_t)(TSMS_ETSI_GSM_03_38[j][1] & 0xFF)){
 				retlen++; /* 00 */
 				*(str + retlen++) = (TSMS_ETSI_GSM_03_38[j][0] & 0xFF);
 			}
 		}
 	}
 
 	/* create buffer */
 	ret = tsk_buffer_create(str, retlen);
 
 bail:
 	TSK_FREE(str);
 	return ret;
 }
 
 /**@ingroup tsms_packing_group
 * Converts ASCII string to 8-bit characters.
 * @param ascii Null-terminated ascii string to convert.
 * @retval Buffer containing 8-bit characters if succeed and @a Null otherwise.
 * @sa @ref tsms_pack_from_8bit
 */
 tsk_buffer_t* tsms_pack_to_8bit(const char* ascii)
 {
 	register tsk_size_t i, j;
 	tsk_size_t len, retlen = 0;
 	uint8_t* str = tsk_null;
 	tsk_buffer_t* ret = tsk_null;
 
 	if(!ascii || !(len=strlen(ascii))){
 		TSK_DEBUG_WARN("Null or Empty gsm7bit buffer.");
 		goto bail;
 	}
 	#if HAVE_CRT //Debug memory
 	if(!(str = calloc(len, sizeof(uint8_t)))){
 		
 	#else
 	if(!(str = tsk_calloc(len, sizeof(uint8_t)))){
 		
 	#endif //HAVE_CRT
 		goto bail;
 	}
 
 	/* very bas way to do conversion ==> to be fixed */
 	for(i = 0; i<len; i++){
 		for(j = 0; j<TSMS_ETSI_GSM_03_38_COUNT; j++){
 			if((uint8_t)ascii[i] == (uint8_t)(TSMS_ETSI_GSM_03_38[j][1] & 0xFF)){
 				*(str + retlen++) = (TSMS_ETSI_GSM_03_38[j][0] & 0xFF);
 				continue;
 			}
 		}
 	}
 	
 	/* create buffer */
 	ret = tsk_buffer_create(str, retlen);
 
 bail:
 	TSK_FREE(str);
 	return ret;
 }
 
 /**@ingroup tsms_packing_group
 * Converts GSM 7-bit characters to ASCII string.
 * @param gsm7bit Buffer containing GSM 7-bit characters to convert.
 * @param size The size of the buffer.
 * @retval Null-terminated ASCII string, ready to be shown to the screen.
 * @sa @ref tsms_pack_to_7bit
 */
 char* tsms_pack_from_7bit(const void* gsm7bit, tsk_size_t size)
 {
 	char* ret = tsk_null;
 	register tsk_size_t bcount = 1/*1-7*/, index = 0, retindex = 0, retsize = 0;
 	const uint8_t* pgsm7bit = gsm7bit;
 	
 	if(!gsm7bit || !size){
 		TSK_DEBUG_WARN("Null or Empty gsm7bit buffer.");
 		goto bail;
 	}
 	
 	// dup the gsm7bit buffer
 	retsize = size + (size/7) + 1; // variable used for debug
 	#if HAVE_CRT //Debug memory
 	if(!(ret = calloc(retsize, sizeof(uint8_t)))){
 		
 	#else
 	if(!(ret = tsk_calloc(retsize, sizeof(uint8_t)))){
 		
 	#endif //HAVE_CRT
 		goto bail;
 	}
 	
 	while(index < size){
 		ret[retindex] = (pgsm7bit[index] & (0xFF >>bcount));
 		if(index){
 			ret[retindex] = (ret[retindex] << (bcount - 1)) 
 				| (pgsm7bit[index-1] >> (8 - bcount + 1));
 		}
 
 		/* how many bytes to use to complete on the right? */
 		if(bcount++ == 8){
 			bcount = 1, --index;
 		}
 		/* next */
 		index++;
 		retindex++;
 	}
 	
 	/* special one */
 	if(!(size%7)){
 		ret[retindex] = pgsm7bit[size-1]>>1;
 	}
 	
 bail:
 	
 	return ret;
 }
 
 /**@ingroup tsms_packing_group
 * Converts UCS-2(2-byte Universal Character Set) characters to ASCII string.
 * @param ucs2 Buffer containing UCS-2 characters to convert.
 * @param size The size of the buffer.
 * @retval Null-terminated ASCII string, ready to be shown to the screen.
 * @sa @ref tsms_pack_to_ucs2
 */
 char* tsms_pack_from_ucs2(const void* ucs2, tsk_size_t size)
 {
 	register tsk_size_t i, j;
 	char* ret = tsk_null;
 	
 	const uint16_t* pucs2 = ucs2;
 
 	if(!ucs2 || !size){
 		TSK_DEBUG_WARN("Null or Empty gsm8bit buffer.");
 		goto bail;
 	}
 	#if HAVE_CRT //Debug memory
 	if(!(ret = calloc(size+1, sizeof(uint8_t)))){
 		
 	#else
 	if(!(ret = tsk_calloc(size+1, sizeof(uint8_t)))){
 		
 	#endif //HAVE_CRT
 		goto bail;
 	}
 
 	for(i=0; i<size; i++){
 		for(j=0; j<TSMS_ETSI_GSM_03_38_COUNT; j++){
 			if(*(pucs2 + i) == (TSMS_ETSI_GSM_03_38[j][0])){
 				*(ret+i) = (TSMS_ETSI_GSM_03_38[j][1] & 0xFF);
 				continue;
 			}
 		}
 	}
 
 bail:
 	return ret;
 }
 
 /**@ingroup tsms_packing_group
 * Converts 8-bit characters to ASCII string.
 * @param gsm8bit Buffer containing GSM 8-bit characters to convert.
 * @param size The size of the buffer.
 * @retval Null-terminated ASCII string, ready to be shown to the screen.
 * @sa @ref tsms_pack_to_8bit
 */
 char* tsms_pack_from_8bit(const void* gsm8bit, tsk_size_t size)
 {
 	register tsk_size_t i, j;
 	char* ret = tsk_null;
 	
 	const uint8_t* pgsm8bit = gsm8bit;
 
 	if(!gsm8bit || !size){
 		TSK_DEBUG_WARN("Null or Empty gsm8bit buffer.");
 		goto bail;
 	}
 	#if HAVE_CRT //Debug memory
 	if(!(ret = calloc(size+1, sizeof(uint8_t)))){
 		
 	#else
 	if(!(ret = tsk_calloc(size+1, sizeof(uint8_t)))){
 		
 	#endif //HAVE_CRT
 		goto bail;
 	}
 
 	/* Very bad way to do convertion ==> to be changed */
 	for(i=0; i<size; i++){
 		for(j=0; j<TSMS_ETSI_GSM_03_38_COUNT; j++){
 			if(*(pgsm8bit + i) == (TSMS_ETSI_GSM_03_38[j][0] & 0xFF)){
 				*(ret+i) = (TSMS_ETSI_GSM_03_38[j][1] & 0xFF);
 				continue;
 			}
 		}
 	}
 
 bail:
 	return ret;
 }