view src/aci2/atb/ATBCommon.c @ 684:269554439ace

targets/fcdev3b.h: bring back CONFIG_TARGET_FCDEV3B C preprocessor symbol CONFIG_TARGET_FCMODEM is no longer used anywhere in our code base, thus it is being fully retired. OTOH, CONFIG_TARGET_FCDEV3B is being brought back: with our earlier FC modem family idea now being withdrawn in light of the discovery of Tango modules, FCDEV3B goes back to being its own unique target.
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 24 Sep 2020 20:21:51 +0000
parents 93999a60b835
children
line wrap: on
line source

/*******************************************************************************

					CONDAT (UK)

********************************************************************************                                                                              

 This software product is the property of Condat (UK) Ltd and may not be
 disclosed to any third party without the express permission of the owner.                                 
                                                                              
********************************************************************************

 $Project name:	                                                      
 $Project code:	                                                           
 $Module:		
 $File:		    ATBCommon.c
 $Revision:		                                                      
                                                                              
 $Author:		SH - Condat(UK)                                                         
 $Date:		                                                          
                                                                               
********************************************************************************
                                                                              
 Description: ATB Common functions and definitions.
    
                        
********************************************************************************

 $History: ATBCommon.c

	Mar 30, 2005	REF: CRR 29986	xpradipg
	Description: Optimisation 1: Removal of unused variables and dynamically
	allocate/ deallocate mbndata
	Solution: removed the definition of translation_ascii_2_unicode and added 
	the extern declaration

       March 24, 2005 REF: CRR MMI-FIX-9828 x0012852
	Description: BMI having problems with Umlauts ,especially "ü"
	Solution: g_translation_8bit_table[] array is modified . Changed codes 0x80 , 0x81,      
                     0x82 to ox81, 0x82 ,0x83 respectively.

	Jan 05, 2005 REF: CRR MMI-FIX-24757 xnkulkar
	Description: the display doesn´t show special chars correctly; if there is an "@" in the text, the "@" and 
			    text after is not visible
	Solution: Fix for MMI-SPR-25978 has solved the problem of data loss after '@' symbol. However, some other 
	              symbols (like ¥ etc.) were not displayed properly. Modified the g_translation_8bit_table[] array 
			to take care of all the special GSM character set .
 
	Nov 30, 2004 REF: CRR MMI-SPR-25978 xnkulkar
	Description: Messages:Not able to receive message after @ in the receiver phone (Bug raised in 3.x)
	Solution: in g_translation_8bit_table, the value for '@' symbol was used as 0x00. It has been
	              changed to 0x40 now.
 	
 	26-05-04      CRR 19656    Sandip and Deepa M.D
      	Fix for The Dsample doesn't display lines ( <CR> or <LF> ) in the SETUP IDLE 
	TEXT command.
	Fix for The idle screen is empty when a SETUP IDLE TEXT command is sent with 
	a long text ( 239 characters ).
	
	   
 $End

*******************************************************************************/

/* includes */
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#if defined (NEW_FRAME)

#include "typedefs.h"
#include "vsi.h"
#include "pei.h"
#include "custom.h"
#include "gsm.h"

#else

#include "STDDEFS.H"
#include "custom.h"
#include "gsm.h"
#include "vsi.h"

#endif

#include "mfw_mfw.h"
#include "mfw_win.h"
#include "mfw_kbd.h"
#include "mfw_tim.h"
#include "mfw_phb.h"
#include "mfw_sms.h"
#include "mfw_ss.h"
#include "mfw_icn.h"
#include "mfw_mnu.h"
#include "mfw_lng.h"
#include "mfw_sat.h"
#include "mfw_kbd.h"
#include "mfw_nm.h"
#include "mfw_cm.h"
#include "ATBCommon.h"

/*SPR2175, Added macro and tables for string conversion routines*/
#define MAX_STRING_LEN (5+MFW_NUM_LEN+MAX_MSG_LEN+4)

/*SPR 1508, changed codes 128, 129 and 130 to 129, 130, and 131 respectively.*/
static const char g_translation_ascii_table[128] = { 64, 156, 36, 157, 138, 131, 151, 141, 149, 129,
													 10,   2 ,  7,  32, 143, 134,   4,  95, 232, 226, 239, 234, 227,   5, 228,
											 		233, 240,  32, 146, 145, 225, 144,  32,  33,  34,  35,   1,  37,  38,  39,
											 		 40,  41,  42,  43,  44, 45,  46,  47,  48,  49,  50,  51,  52,  53,  54,
											 		 55,  56,  57,  58,  59,  60,  61,  62,  63, 173,  65,  66,  67,  68,  69,
											 		 70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84,
											 		 85,  86,  87,  88,  89,  90, 142, 153, 165, 154,  168, 06,  97,  98,  99,
											 		100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114,
											 		115, 116, 117, 118, 119, 120, 121, 122, 132, 148, 164, 130, 133};



static const int g_translation_unicode[128] = { 0x0040, 0x00A3, 0x0024, 0x00A5, 0x00E8, 0x00E9, 0x00F9, 0x00EC, 0x00F2, 0x00C7, 0x000A, 0x00D8, 0x00F8,
												0x000D, 0x00C5, 0x00E5, 0x0394, 0x005F, 0x03A6, 0x0393, 0x039B, 0x03A9, 0x03A0, 0x03A8, 0x03A3, 0x0398,
												0x039E, 0x03A2, 0x00C6, 0x00E6, 0x00DF, 0x00C9, 0x0020, 0x0021, 0x0022, 0x0023, 0x00A4, 0x0025, 0x0026,
												0x0027, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, 0x0030, 0x0031, 0x0032, 0x0033,
												0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, 0x00A1,
												0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D,
												0x004E, 0x004F, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005A,
												0x00C4, 0x00D6, 0x00D1, 0x00DC, 0x00A7, 0x00BF, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
												0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074,
												0x0075,	0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x00E4, 0x00F6, 0x00F1, 0x00FC,	0x00E0};

/*SPR 1508, added conversion table*/												
//	Mar 30, 2005	REF: CRR 29986	xpradipg
//	remove the definition of the table
#ifdef FF_MMI_OPTIM
extern const int translation_ascii_2_unicode[];
#else
static const int translation_ascii_2_unicode[256] = { 
	0x0000, 0x00A4, 0x00d8, 0xFFFF, 0x0394, 0x03A8, 0x00BF, 0x00F8, 0xFFFF, 0xFFFF, 0x000A, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
	0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
	0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026,0x0027, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
	0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
	0x0040,0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
	0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005A, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x005F, 
	0xFFFF, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
	0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,

	0xFFFF, 0x00C7, 0x00FC, 0x00E9, 0x00E4, 0x00E0, 0x00E5, 0xFFFF, 0xFFFF, 0xFFFF, 0x00E8, 0xFFFF, 0xFFFF, 0x00EC, 0x00C4, 0x00C5, 
	0x00C9, 0x00E6, 0x00C6, 0xFFFF, 0x00F6, 0x00F2, 0xFFFF, 0x00F9, 0xFFFF, 0x00D6, 0x00DC, 0xFFFF, 0x00A3, 0x00A5, 0xFFFF, 0xFFFF,
	0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x00F1, 0x00D1, 0xFFFF, 0xFFFF, 0x00A7, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x00A1, 0xFFFF, 0xFFFF,
	0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
	0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
	0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
	0xFFFF, 0x00DF, 0x0393, 0x03A0, 0x03A3, 0xFFFF, 0xFFFF, 0xFFFF, 0x03A6, 0x0398, 0x03A9, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x039B, 
	0x039E, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF
	};
#endif	
//	MMI_FIX-19656   Using 8 bit table for dispay start
//	Nov 30, 2004 REF: CRR MMI-SPR-25978 xnkulkar
//	Description: Messages:Not able to receive message after @ in the receiver phone (Bug raised in 3.x)
//	Solution: in g_translation_8bit_table, the value for '@' symbol was used as 0x00. It has been
//	              changed to 0x40 now.

//	Jan 05, 2005 REF: CRR MMI-FIX-24757 xnkulkar
//	Description: the display doesn´t show special chars correctly; if there is an "@" in the text, the "@" and 
//			    text after is not visible
//	Solution: Fix for MMI-SPR-25978 has solved the problem of data loss after '@' symbol. However, some other 
//                 symbols (like ¥ etc.) were not displayed properly. Modified the g_translation_8bit_table[] array 
//		       to take care of all the special GSM character set .

//   March 24, 2005 REF: CRR MMI-FIX-9828 x0012852
//   Description: BMI having problems with Umlauts ,especially "ü"
//   Solution: g_translation_8bit_table[] array is modified . Changed codes 0x80 , 0x81,      
//                 0x82 to ox81, 0x82 ,0x83 respectively.


static const char g_translation_8bit_table[256] ={ 
	0x40, 0x9C, 0x24, 0x9D, 0x8A, 0x83, 0x97, 0x8D, 0x95, 0x81, 0x0A, 0x02, 0x07, 0x20, 0x8F, 0x86,   
	0x04, 0x5F, 0xE8, 0xE2, 0xEF, 0xEA, 0xE3, 0x05, 0xE4, 0xE9,0xF0, 0xFF, 0x92, 0x91, 0xE1, 0x90,   
	0x20, 0x21, 0x22, 0x23, 0x01, 0x25, 0x26,0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,  
	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
	0xAD,0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x8E, 0x99, 0xA5, 0x9A, 0xA8,    
	0x06, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,  
	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x84, 0x94, 0xA4, 0x82, 0x85,  

	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
//MMI_FIX-19656   Using 8 bit table for dispay start

static char convertUCS2_2_ascii_char(char* ipString);
static char convertUCS2_2_gsm_char(char* ipString);
static USHORT ATB_swap_bytes(USHORT character);

/*******************************************************************************

 $Function:    	convertUCS2_2_ascii_char

 $Description:	convert unicode char to ASCII char. Added for SPR 1508. 
 				moved here for SPR 2175

 $Returns:		ASCII char
 $Arguments:	pointer to first byte of unicode char
*******************************************************************************/
static char convertUCS2_2_ascii_char(char* ipString) 
{
	U16 word_code;
	BOOL match_found= FALSE;
	int k;
	char debug[60];
	
	word_code = ipString[0]*0x100 + ipString[1];
	sprintf(debug, "Word code: %d", word_code);
	TRACE_EVENT(debug);
	if (word_code <= 0xFF)
		if (translation_ascii_2_unicode[word_code] == word_code)
			return word_code;
		

		for (k=0; k < 256; k++)
		{	if(translation_ascii_2_unicode[k] == word_code)
			{	sprintf(debug, "Match found: %d, %d", word_code, k);
				TRACE_EVENT(debug);
				match_found = TRUE;
				return k;
			}
							
		}

	if (!match_found)
	{	TRACE_EVENT("No match");

		return 0x3F;/*question mark*/
	}
}
/*******************************************************************************

 $Function:    	convertUCS2_2_ascii_char

 $Description:	convert unicode char to GSM char.  Added for SPR 1508.
 				moved here for SPR 2175

 $Returns:		GSM char
 $Arguments:	pointer to first byte of unicode char
*******************************************************************************/
static char convertUCS2_2_gsm_char(char* ipString) 
{
	U16 word_code;
	BOOL match_found= FALSE;
	int k;
	word_code = ipString[0]*0x100 + ipString[1];
			
					
	if ( word_code > 0x7F || g_translation_unicode[word_code] != word_code)
	{	

		for (k=0; k < 256; k++)
		{	if(g_translation_unicode[k] == word_code)
			{
				match_found = TRUE;
				return k;
			}
							
		}
	}
	else
		return word_code;
	if (!match_found)
	{	return '?';
	}
}
/*******************************************************************************

 $Function:    	ATB_convert_String

 $Description:	Convert a string into an ascii string with 0x80 as first word if data is unicode
 				moved here and renamed for SPR 2175
 $Returns:		execution status

 $Arguments:	ipString - input byte array
 				ipDataType - type of input data
 				ipLength - length of input string (in bytes) 
				opString - output byte array
 				opDataType - type of output data
 				opLength - length of output string (in bytes) 
*******************************************************************************/
/* MC, SPR 1257, merged in b-sample version of this function*/
int ATB_convert_String(			char * ipString,	UBYTE ipDataType,	int ipLength,
										char * opString, 	UBYTE opDataType,	int opLength, UBYTE addNull)
{
	int i;/*SPR 1946, changed from byte to int*/
	int j;/*SPR 1946, changed from byte to int*/
    /*JVJ SPR1298 Converted to dynamic variable */
	UBYTE* text_8bit = NULL;/*SPR1991, don't alloacte this till it's needed*/ 
	int  len;/*SPR 1946, changed from byte to int*/
  	
	
#ifdef TRACE_SMSREAD

  char buf[150];
  sprintf(buf, "opString%x ipString%x ipLength%d opLength%d",opString, ipString, ipLength, opLength);
  TRACE_EVENT(buf);
#endif
  
	if ((opString == NULL) || (ipString==NULL) || (opLength ==0))
		return (FALSE);
	if (ipLength>MAX_STRING_LEN)
		{
		TRACE_EVENT("Too long, returning.");
		return;
		}
	opString[0] = 'X';
	opString[1] = '?';
	opString[2] = 0x00;
	
#ifdef TRACE_SMSREAD
  sprintf(buf,"iDT: %d,iL:%d, oDT:%d, oL:%d, A0:%d",ipDataType,ipLength,opDataType,opLength,addNull);
  TRACE_EVENT(buf);
#endif
  
		
	switch (ipDataType)
	{
	case MFW_DCS_UCS2:
			if (opDataType == MFW_DCS_UCS2)
			{	//Copy array and add 0x80, 0x7F as first word
				if (ipLength < opLength)
					len = ipLength;
				else
					len = opLength;
		/*SPR 1507, copy the bytes in pairs*/
				for (i=0;i<len;i+=2)
				{ opString[i] = ipString[i];
					opString[i+1] = ipString[i+1];
				}
				if (i+1<opLength)
				{
					opString[i  ] = 0x00;
					opString[i+1] = 0x00;
				}
			}
			else if ((opDataType == MFW_DCS_8bits) ||
					(opDataType == MFW_ASCII))
			{			
				if ((ipLength/2 ) < opLength)
					len = ipLength/2;
				else
					len = opLength;

				for (i=0;i<len;i++)
				{	/*SPR 1508, use new functions to convert to ASCII/GSM*/
					if (opDataType == MFW_ASCII)
						opString[i] = convertUCS2_2_ascii_char(&ipString[i*2]);
					else
						opString[i] = convertUCS2_2_gsm_char(&ipString[i*2]);
				}
				if (len<opLength)
				{
					opString[len  ] = 0x00;
				}
	
			}
			else	//Output data type is 7 bits - not implemented
			{
			}
			break;
	case MFW_DCS_8bits:
		
			if (opDataType == MFW_DCS_UCS2)
			{	//Convert data to unicode
				if (ipLength*2 < opLength)
					len = ipLength;
				else
					len = opLength/2;
#ifdef TRACE_SMSREAD
				sprintf(buf, "8->UCS2, len:%d", len);
				TRACE_EVENT(buf);
#endif				
				for (i = 0; i < len; i++)
				{	/*SPR 1508 use table to convert to Unicode*/
					opString[i*2]   = (g_translation_unicode[ipString[i]]>>8)&0x00FF;
					opString[i*2+1] = (g_translation_unicode[ipString[i]])&0x00FF;
				}
				if (len*2+1 < opLength)
				{
					opString[len*2]   = 0x00;
					opString[len*2+1] = 0x00;
				}
			}
			else if (opDataType == MFW_DCS_8bits)
			{	//Data already in correct format - copy
				if (ipLength < opLength)
					len = ipLength;
				else
					len = opLength;
				for (i=0;i<len;i++)
					{
					opString[i] = g_translation_8bit_table[ipString[i]];
					}
				if (len<opLength)
					opString[len] = 0x00;
			}
			else if (opDataType == MFW_ASCII)	// SH - translate characters, don't change bit width
			{
				len = ipLength;
				if (len > opLength)
					len = opLength;
				for (i=0;i<len;i++)
					{
					opString[i] = g_translation_8bit_table[ipString[i]];
					}
				if (len<opLength)
					opString[len] = 0x00;

				//MMI_FIX-19656   Using 8 bit table for mapping end
			}
			else // convert data to 7bit
			{
				len = utl_cvt8To7 ((UBYTE *)ipString , ipLength, (UBYTE*)opString, 0);
			}
		break;
	case MFW_DCS_7bits:
	default:
		/*SPR 1991, allocate memory to conversion buffer*/
		text_8bit = (UBYTE*)mfwAlloc(MAX_STRING_LEN+1);  
		
			if (opDataType == MFW_DCS_7bits) //text string is already in this format
			{
				//Data already in correct format - copy
				if (ipLength < opLength)
					len = ipLength;
				else
					len = opLength;
				for (i=0;i<len;i++)
					opString[i] = ipString[i];
				if (len<opLength)
					opString[len] = 0x00;
			}
			else if (opDataType == MFW_DCS_8bits)
			{
				len = utl_cvt7To8 ((UBYTE *)ipString , ipLength, (UBYTE *)opString, 0 );
				if (len <opLength)
					opString[len] = 0x00;
        else
          opString[opLength]=0x00;
			}
			else if (opDataType == MFW_ASCII)	// SH - expand to 8 bit and convert chars
			{
				len = utl_cvt7To8 ((UBYTE *)ipString , ipLength, text_8bit, 0 );
				if (len > opLength)
					len = opLength;
  				for (i = 0; i < len; i++)
					{
					opString[i] = g_translation_ascii_table[UBYTEToChar(text_8bit[i])];
					}
				if (len <opLength)
					opString[len] = 0x00;
			}
			else
			{	//Convert to unicode
				len = utl_cvt7To8 ((UBYTE *)ipString , ipLength, text_8bit, 0);
				if (len*2 > opLength)
					len = opLength/2;
				for (i = 0; i < len; i++)
				{/*SPR 1508, use new table to convert to Unicode*/
					opString[i*2]   = (g_translation_unicode[ipString[i]]>>8)&0x00FF;
					opString[i*2+1] = g_translation_unicode[UBYTEToChar(text_8bit[i])];
				}
				if (len*2+1 < opLength)
				{
					opString[len*2]   = 0x00;
					opString[len*2+1] = 0x00;
				}
			}
		break;
		
	case MFW_ASCII:
			if (ipLength <=0)
				ipLength = strlen(ipString); //calculate length if not supplied
			if (opDataType == MFW_DCS_UCS2)
			{	//Convert data to unicode
				if (ipLength*2 < opLength)
					len = ipLength;
				else
					len = opLength/2;
				for (i = 0; i < len; i++)
				{	/*SPR 1508, convert to Unicode using new table*/
					opString[i*2]   = (translation_ascii_2_unicode[ ipString[i]]>>8)&0x00FF;
					opString[i*2+1] = (translation_ascii_2_unicode[ ipString[i]])&0x00FF;
				}
				if (len*2+1 < opLength)
				{
					opString[len*2]   = 0x00;
					opString[len*2+1] = 0x00;
				}
			}
			else if (opDataType == MFW_ASCII)
			{	//Data already in correct format - copy
				if (ipLength < opLength)
					len = ipLength;
				else
					len = opLength;
				for (i=0;i<len;i++)
					opString[i] = ipString[i];
				if (len<opLength)
					opString[len] = 0x00;
			}
			else if (opDataType == MFW_DCS_8bits || opDataType == MFW_DCS_7bits)	// SH - translate characters, don't change bit width
			{

				if (ipLength < opLength)
					len = ipLength;
				else
					len = opLength;
				for (i=0;i<len;i++)
					{
					opString[i] = ipString[i];
					if (ipString[i]>=128 || g_translation_ascii_table[ipString[i]]!=ipString[i])
						{
						for (j=0; j<128; j++)			// Reverse translation
							{
							if (ipString[i] == g_translation_ascii_table[j])
								opString[i] = j;
							}
						#ifdef TRACE_SMSREAD
						sprintf(buf, "Converted %x to %x", ipString[i], opString[i]);
						TRACE_EVENT(buf);
						#endif
						}
					}
				if (len<opLength)
					opString[len] = 0x00;
			}
			if (opDataType == MFW_DCS_7bits) // convert data to 7bit
			{
				len = utl_cvt8To7 ((UBYTE *)ipString , ipLength, (UBYTE*)opString, 0);
			}
		break;
	}

	if (addNull)
	{	//Add 0x00 (or 0x00,0x00) to end of array

	/*SPR925 - SH - changed so NULL is in right place for unicode*/
		if (opDataType == MFW_DCS_UCS2)
		{
			if (len*2+1>opLength)
				len = opLength/2;

			opString[len*2] = 0x00;
			opString[len*2+1] = 0x00;
		}
		else
		{
			if (len>opLength)
				len = opLength;

			opString[len] = 0x00;
		}
	/* end SPR925 */
	}
	/*SPR 1991, free memory only if it has been allocated*/
	if (text_8bit!= NULL)
        mfwFree(text_8bit,MAX_STRING_LEN+1);
	return TRUE;
}



/*******************************************************************************

 $Function:    	ATB_mem_Alloc

 $Description:	ATB memory allocation function.
 
 $Returns:		Address if successful, null if not.

 $Arguments:	Size of memory to be allocated.
 
*******************************************************************************/

UBYTE* ATB_mem_Alloc(USHORT size)
{
	return (UBYTE *)mfwAlloc(size);
}


/*******************************************************************************

 $Function:    	ATB_mem_Free

 $Description:	Frees memory allocated by the ATB
 
 $Returns:		None.

 $Arguments:	address		- Pointer to memory to free
 				size		- Size of the allocated block
 
*******************************************************************************/

void ATB_mem_Free(UBYTE* address, USHORT size)
{
	mfwFree(address,size);
	return;
}
/*******************************************************************************

 $Function:		ATB_swap_bytes

 $Description:	Returns a unicode character with the bytes swapped. Added for SPR2175

 $Returns:		USHORT

 $Arguments:	USHORT

*******************************************************************************/
static USHORT ATB_swap_bytes(USHORT character)
{
	return ((UNICODE_NONASCII&character) << 8) + ((UNICODE_ASCII&character) >>8);

}

/*******************************************************************************

 $Function:		ATB_char_GSM

 $Description:	Returns the GSM of the provided ascii character.Added for SPR 2175.

 $Returns:		A GSM character

 $Arguments:	character - The ascii character

*******************************************************************************/

char ATB_char_GSM(char ascii_character)
{	int i;
	/*check if GSM and ASCII encoding are the same value*/
	if (g_translation_ascii_table[ascii_character] == ascii_character)
		return ascii_character;
	
	/*otherwise we have to search for the correct entry in the GSM to ASCII table*/
	for (i=0; i<128; i++)
	{
		if (g_translation_ascii_table[i] == ascii_character)
			return i;

	}
}
/*******************************************************************************

 $Function:		ATB_char_Ascii

 $Description:	Returns the ascii of the provided unicode character

 $Returns:		An ascii character

 $Arguments:	character - The unicode character

*******************************************************************************/

char ATB_char_Ascii(USHORT character)
{	int i;

	/*SPR2175, rewrote function*/
	/*if the first byte of the character is the same as the ASCII code, return the first byte*/
	if (translation_ascii_2_unicode[((character & UNICODE_ASCII)>>8)] == ((character & UNICODE_ASCII)>>8))
		return (char)((character & UNICODE_ASCII)>>8);
	
	/*otherwise we have to search for the correct entry in the ASCII to unicode table*/
	for (i=0; i<256; i++)
	{
		if (translation_ascii_2_unicode[i] == ATB_swap_bytes(character))
			return i;

	}
}


/*******************************************************************************

 $Function:		ATB_char_Unicode

 $Description:	Returns the unicode of the provided ascii character

 $Returns:		A unicode character

 $Arguments:	character - The ascii character

*******************************************************************************/

USHORT ATB_char_Unicode(char character)
{	/*SPR 2175, re-wrote function*/
	USHORT table_value;
	USHORT return_value = NULL;
	/*look up corresponding Unicode char in table*/
	table_value= translation_ascii_2_unicode[character];

	/*swap bytes as little-endian*/
	return_value = ATB_swap_bytes(table_value);

	return return_value;
}


/*******************************************************************************

 $Function:		ATB_char_IsAscii

 $Description:	Returns TRUE if the unicode character provided is ascii

 $Returns:		TRUE or FALSE

 $Arguments:	character - The unicode character

*******************************************************************************/

BOOL ATB_char_IsAscii(USHORT character)
{
	BOOL	result = FALSE;

	if (character & UNICODE_NONASCII)					// Make sure character is ASCII
	{
		result = FALSE;
	}
	else
	{
		result = TRUE;
	}

	return result;
}


/*******************************************************************************

 $Function:		ATB_char_IsAlphabetic

 $Description:	Return TRUE if unicode character is part of latin alphabet

 $Returns:		TRUE or FALSE

 $Arguments:	character - The unicode character

*******************************************************************************/

BOOL ATB_char_IsAlphabetic(USHORT character)
{
	BOOL	result = FALSE;
	UBYTE	asciiChar; 

	if (ATB_char_IsAscii(character))					// Make sure character is ASCII
	{
		asciiChar = ATB_char_Ascii(character);
		if ( (asciiChar >='A') && (asciiChar <='Z') )
			result = TRUE;
		else if ( (asciiChar >='a') && (asciiChar <='z') )
			result = TRUE;
	}

	return result;
}


/*******************************************************************************

 $Function:		ATB_char_IsNumierc

 $Description:	Return TRUE if unicode character is a digit, 0-9

 $Returns:		TRUE or FALSE

 $Arguments:	character - The unicode character

*******************************************************************************/

BOOL ATB_char_IsNumeric(USHORT character)
{
	BOOL	result = FALSE;
	UBYTE	asciiChar;
 
	if (ATB_char_IsAscii(character))				// Make sure character is ASCII
	{
		asciiChar = ATB_char_Ascii(character);
		if ( (asciiChar >='0') && (asciiChar <='9') )
			result = TRUE;
	}

	return result;
}

/*******************************************************************************

 $Function:		ATB_char_IsVisible

 $Description:	Return TRUE if unicode character is visible, i.e. not ascii <32

 $Returns:		TRUE or FALSE

 $Arguments:	character - The unicode character

*******************************************************************************/

BOOL ATB_char_IsVisible(USHORT character)
{
	BOOL	result = TRUE;
	UBYTE	asciiChar; 

	if (ATB_char_IsAscii(character))					// Make sure character is ASCII
	{
		asciiChar = ATB_char_Ascii(character);
		/*SPR 2175, if ASCII value has no unicode equivalent assume not visible*/
		if (translation_ascii_2_unicode[asciiChar] == 0xFFFF)
			result = FALSE;
	}

	return result;
}


/*******************************************************************************

 $Function:		ATB_string_Size

 $Description:	Return the size in bytes of a character in the string

 $Returns:		No. of bytes per character

 $Arguments:	text	- The text string

*******************************************************************************/
  
UBYTE ATB_string_Size(T_ATB_TEXT *text)
{
	UBYTE size;
	
	switch(text->dcs)
	{
		case ATB_DCS_UNICODE:
			size = 2;
			break;

		default:
			size = 1;
			break;
	}
	
	return size;
}


/*******************************************************************************

 $Function:		ATB_string_SetChar

 $Description:	Set a character in the string to a value.  Use this function rather than
 				accessing text data directly; it allows transparent ASCII and Unicode
 				handling.
 
 $Returns:		None

 $Arguments:	text		- The text string
 				textIndex	- The position of the character to set
 				character	- The unicode character to set it to

*******************************************************************************/
  
void ATB_string_SetChar(T_ATB_TEXT *text, USHORT textIndex, USHORT character)
{
	USHORT *unicode;
	
	if (text->dcs==ATB_DCS_UNICODE)
	{
		unicode = (USHORT *)text->data;
		unicode[textIndex] = character;
	}
	else
		text->data[textIndex] = ATB_char_Ascii(character);

	return;
}


/*******************************************************************************

 $Function:		ATB_string_GetChar

 $Description:	Gets the value of a character in the string.  Use this function rather than
 				accessing text data directly; it allows transparent ASCII and Unicode
 				handling.
 
 $Returns:		The unicode character at the required position

 $Arguments:	text		- The text string
 				textIndex	- The position of the character to get

*******************************************************************************/

USHORT ATB_string_GetChar(T_ATB_TEXT *text, USHORT textIndex)
{
	USHORT *unicode;
	USHORT character;
	
	if (text->dcs==ATB_DCS_UNICODE)
	{
		unicode = (USHORT *)text->data;
		character = unicode[textIndex];
	}
	else
		character = ATB_char_Unicode(text->data[textIndex]);

	return character;
}


/*******************************************************************************

 $Function:		ATB_string_MoveLeft

 $Description:	Move part of string left by 'offset' characters
 
 $Returns:		TRUE if the operation was successful

 $Arguments:	text		- The text string
 				textIndex	- The place where the newly moved section is to go
 				offset		- The number of characters to move the section left by

*******************************************************************************/
  
BOOL ATB_string_MoveLeft(T_ATB_TEXT *text, USHORT textIndex, USHORT offset)
{
	BOOL outcome;
	USHORT character;
	
	/* Copy until end of line char reached */

	while ((textIndex+offset)<=text->len)
	{
		character = ATB_string_GetChar(text, textIndex+offset);
		ATB_string_SetChar(text, textIndex, character);
		textIndex++;
	}
	outcome = TRUE;
	text->len -= offset;
	
	return outcome;
}


/*******************************************************************************

 $Function:		ATB_string_MoveRight

 $Description:	Move part of string right by 'offset' characters
 
 $Returns:		TRUE if the operation was successful

 $Arguments:	text		- The text string
 				textIndex	- The start of the section to be moved right
 				offset		- The number of characters to move the section right by
 				size		- The maximum possible length of the string

*******************************************************************************/

BOOL ATB_string_MoveRight(T_ATB_TEXT *text, USHORT textStart, USHORT offset, USHORT size)
{
	int textIndex;
	BOOL outcome;
	USHORT character;
	
	textIndex = text->len;
	
	if ((text->len+ offset) < size)	/* SPR#1995 - SH - <= should be < */
	{
		while (textIndex >= textStart)
		{
			character = ATB_string_GetChar(text, textIndex);
			ATB_string_SetChar(text, textIndex+offset, character);
			textIndex--;
		}
		text->len += offset;
		outcome = TRUE;
	}
	else
		outcome = FALSE;
	
	return outcome;
}


/*******************************************************************************

 $Function:		ATB_string_Length

 $Description:	Returns the length of the string, also setting the 'len' parameter of
 				the text structure
 
 $Returns:		Length of the string in characters

 $Arguments:	text		- The text string

*******************************************************************************/

USHORT ATB_string_Length(T_ATB_TEXT* text)
{
	USHORT 	length;

	if (text->dcs==ATB_DCS_UNICODE)
	{
		text->len = ATB_string_UCLength((USHORT *)text->data);
	}
	else
	{
		text->len = strlen((char *)text->data);
	}
	
	return text->len;
}


/*******************************************************************************

 $Function:		ATB_string_UCLength

 $Description:	Returns the length of the provided unicode string
 
 $Returns:		Length of the string in characters

 $Arguments:	text		- Pointer to the unicode string

*******************************************************************************/

USHORT ATB_string_UCLength(USHORT* text)
{
	USHORT 	length = 0;

	while (text[length]!=UNICODE_EOLN)
	{
		length++;
	}
	
	return (length);
}


/*******************************************************************************

 $Function:		ATB_string_Copy

 $Description:	Copy 'src' string into 'dest' string.
 
 $Returns:		None.

 $Arguments:	dest		- The destination string (allocated by caller)
 				src			- The source string (allocated by caller)

*******************************************************************************/

void ATB_string_Copy(T_ATB_TEXT* dest, T_ATB_TEXT* src)
{
	USHORT textIndex;
	USHORT character; 

	dest->dcs = src->dcs;
	
	for (textIndex=0; textIndex<src->len; textIndex++)
	{
		character = ATB_string_GetChar(src, textIndex);
		ATB_string_SetChar(dest, textIndex, character);
	}

	ATB_string_SetChar(dest, textIndex, UNICODE_EOLN);
	dest->len = textIndex;

	return;
}


/*******************************************************************************

 $Function:		ATB_string_Concat

 $Description:	Concatenate the second string, adding it to the end of the first.
 				N.B. The strings don't have to have the same DCS.
 
 $Returns:		None.

 $Arguments:	dest		- The destination string (allocated by caller)
 				src			- The source string (allocated by caller)

*******************************************************************************/

void ATB_string_Concat(T_ATB_TEXT* dest, T_ATB_TEXT* src)
{
	USHORT textIndex;
	USHORT character;
 	TRACE_EVENT_P4("dest_len:%d, src len:%d, dest dcs: %d, src dcs:%d", dest->len, src->len, dest->dcs, src->dcs);
 	
	for (textIndex = 0; textIndex<src->len; textIndex++)
	{
		character = ATB_string_GetChar(src, textIndex);
		/*SPR 2512, use destination length */
		ATB_string_SetChar(dest, textIndex+dest->len, character);
	}
	
	dest->len += src->len;
	/*SPR 2512, use destination length to find point to insert termination*/
	ATB_string_SetChar(dest, dest->len, UNICODE_EOLN);

	return;
}


/*******************************************************************************

 $Function:		ATB_string_Concat

 $Description:	Return position of character in string, or -1 if not found
 
 $Returns:		Position of character in string

 $Arguments:	text		- The text string to search
 				findChar	- The character to find

*******************************************************************************/

SHORT ATB_string_FindChar(T_ATB_TEXT* text, USHORT findChar)
{
	USHORT textIndex;
	SHORT foundPos;
	USHORT character;
	 
	textIndex = 0;
	foundPos = -1;

	character = ATB_string_GetChar(text, 0);

	while (character!=UNICODE_EOLN && foundPos==-1)
	{
		if (character==findChar)
			foundPos = (int)textIndex;
		textIndex++;
		character = ATB_string_GetChar(text, textIndex);
	}
	
	return foundPos;
}


/*******************************************************************************

 $Function:		ATB_string_ToUnicode

 $Description:	Convert a string to a unicode string.  Memory for the unicode
  				string should be allocated before calling.  Returns a pointer to the
  				unicode string.
  
 $Returns:		None.

 $Arguments:	dest		- The destination string (allocated by caller)
 				src			- The source string (allocated by caller)

*******************************************************************************/

void ATB_string_ToUnicode(T_ATB_TEXT *dest, T_ATB_TEXT *src)
{
	USHORT textIndex;
	USHORT character; 
	
	dest->dcs = ATB_DCS_UNICODE;

	for (textIndex=0; textIndex<src->len; textIndex++)
	{
		character = ATB_string_GetChar(src, textIndex);
		ATB_string_SetChar(dest, textIndex, character);
	}

	ATB_string_SetChar(dest, textIndex, UNICODE_EOLN);
	dest->len = textIndex;

	return;
}


/*******************************************************************************

 $Function:		ATB_string_ToAscii

 $Description:	Convert a string to an ascii string.  Memory for the ascii
  				string should be allocated before calling.  Returns a pointer to the
  				ascii string.
  
 $Returns:		None.

 $Arguments:	dest		- The destination string (allocated by caller)
 				src			- The source string (allocated by caller)

*******************************************************************************/

void ATB_string_ToAscii(T_ATB_TEXT *dest, T_ATB_TEXT *src)
{
	USHORT textIndex;
	USHORT character;
	 
	dest->dcs = ATB_DCS_ASCII;

	for (textIndex = 0; textIndex<src->len; textIndex++)
	{
		character = ATB_string_GetChar(src, textIndex);

		if (ATB_char_IsAscii(character) && ATB_char_IsVisible(character)) // Filter out non-ascii characters
		{
			character = ATB_char_Unicode('?');
		}

		ATB_string_SetChar(dest, textIndex, character);
	}

	return;
}


/*******************************************************************************

 $Function:		ATB_string_ToUnicode

 $Description:	Moves index position through text
  
 $Returns:		The new index.

 $Arguments:	text		- The text string
				textIndex	- Current position within the text buffer
				offset		- Negative for backwards movement, positive for forwards
							  movement.

*******************************************************************************/ 

USHORT ATB_string_IndexMove(T_ATB_TEXT *text, USHORT textIndex, SHORT offset)
{ 
	while (textIndex>0 && offset<0)
	{
		textIndex--;
		offset++;
	}

	while (ATB_string_GetChar(text, textIndex)!=UNICODE_EOLN && offset>0)
	{
		textIndex++;
		offset--;
	}

	return textIndex;
}