diff options
Diffstat (limited to 'telephony/gsm.c')
-rw-r--r-- | telephony/gsm.c | 1220 |
1 files changed, 0 insertions, 1220 deletions
diff --git a/telephony/gsm.c b/telephony/gsm.c deleted file mode 100644 index b55578d..0000000 --- a/telephony/gsm.c +++ /dev/null @@ -1,1220 +0,0 @@ -/* Copyright (C) 2007-2008 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program 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. -*/ -#include "gsm.h" -#include <stdlib.h> -#include <string.h> - -/** UTILITIES - **/ -byte_t -gsm_int_to_bcdi( int value ) -{ - return (byte_t)((value / 10) | ((value % 10) << 4)); -} - -int -gsm_int_from_bcdi( byte_t val ) -{ - int ret = 0; - - if ((val & 0xf0) <= 0x90) - ret = (val >> 4); - - if ((val & 0x0f) <= 0x90) - ret |= (val % 0xf)*10; - - return ret; -} - -#if 0 -static int -gsm_bcdi_to_ascii( cbytes_t bcd, int bcdlen, bytes_t dst ) -{ - static byte_t bcdichars[14] = "0123456789*#,N"; - - int result = 0; - int shift = 0; - - while (bcdlen > 0) { - int c = (bcd[0] >> shift) & 0xf; - - if (c == 0xf && bcdlen == 1) - break; - - if (c < 14) { - if (dst) dst[result] = bcdichars[c]; - result += 1; - } - bcdlen --; - shift += 4; - if (shift == 8) { - bcd++; - shift = 0; - } - } - return result; -} -#endif - -#if 0 -static int -gsm_bcdi_from_ascii( cbytes_t ascii, int asciilen, bytes_t dst ) -{ - cbytes_t end = ascii + asciilen; - int result = 0; - int phase = 0x01; - - while (ascii < end) { - int c = *ascii++; - - if (c == '*') - c = 11; - else if (c == '#') - c = 12; - else if (c == ',') - c = 13; - else if (c == 'N') - c = 14; - else { - c -= '0'; - if ((unsigned)c >= 10) - break; - } - phase = (phase << 4) | c; - if (phase & 0x100) { - if (dst) dst[result] = (byte_t) phase; - result += 1; - phase = 0x01; - } - } - if (phase != 0x01) { - if (dst) dst[result] = (byte_t)( phase | 0xf0 ); - result += 1; - } - return result; -} -#endif - -int -gsm_hexchar_to_int( char c ) -{ - if ((unsigned)(c - '0') < 10) - return c - '0'; - if ((unsigned)(c - 'a') < 6) - return 10 + (c - 'a'); - if ((unsigned)(c - 'A') < 6) - return 10 + (c - 'A'); - return -1; -} - -int -gsm_hexchar_to_int0( char c ) -{ - int ret = gsm_hexchar_to_int(c); - - return (ret < 0) ? 0 : ret; -} - -int -gsm_hex2_to_byte( const char* hex ) -{ - int hi = gsm_hexchar_to_int(hex[0]); - int lo = gsm_hexchar_to_int(hex[1]); - - if (hi < 0 || lo < 0) - return -1; - - return ( (hi << 4) | lo ); -} - -int -gsm_hex4_to_short( const char* hex ) -{ - int hi = gsm_hex2_to_byte(hex); - int lo = gsm_hex2_to_byte(hex+2); - - if (hi < 0 || lo < 0) - return -1; - - return ((hi << 8) | lo); -} - -int -gsm_hex2_to_byte0( const char* hex ) -{ - int hi = gsm_hexchar_to_int0(hex[0]); - int lo = gsm_hexchar_to_int0(hex[1]); - - return (byte_t)( (hi << 4) | lo ); -} - -void -gsm_hex_from_byte( char* hex, int val ) -{ - static const char hexdigits[] = "0123456789abcdef"; - - hex[0] = hexdigits[(val >> 4) & 15]; - hex[1] = hexdigits[val & 15]; -} - -void -gsm_hex_from_short( char* hex, int val ) -{ - gsm_hex_from_byte( hex, (val >> 8) ); - gsm_hex_from_byte( hex+2, val ); -} - - - -/** HEX - **/ -void -gsm_hex_to_bytes0( cbytes_t hex, int hexlen, bytes_t dst ) -{ - int nn; - - for (nn = 0; nn < hexlen/2; nn++ ) { - dst[nn] = (byte_t) gsm_hex2_to_byte0( (const char*)hex+2*nn ); - } - if (hexlen & 1) { - dst[nn] = gsm_hexchar_to_int0( hex[2*nn] ) << 4; - } -} - -int -gsm_hex_to_bytes( cbytes_t hex, int hexlen, bytes_t dst ) -{ - int nn; - - if (hexlen & 1) /* must be even */ - return -1; - - for (nn = 0; nn < hexlen/2; nn++ ) { - int c = gsm_hex2_to_byte( (const char*)hex+2*nn ); - if (c < 0) return -1; - dst[nn] = (byte_t) c; - } - return hexlen/2; -} - -void -gsm_hex_from_bytes( char* hex, cbytes_t src, int srclen ) -{ - int nn; - - for (nn = 0; nn < srclen; nn++) { - gsm_hex_from_byte( hex + 2*nn, src[nn] ); - } -} - -/** ROPES - **/ - -void -gsm_rope_init( GsmRope rope ) -{ - rope->data = NULL; - rope->pos = 0; - rope->max = 0; - rope->error = 0; -} - -void -gsm_rope_init_alloc( GsmRope rope, int count ) -{ - rope->data = rope->data0; - rope->pos = 0; - rope->max = sizeof(rope->data0); - rope->error = 0; - - if (count > 0) { - rope->data = calloc( count, 1 ); - rope->max = count; - - if (rope->data == NULL) { - rope->error = 1; - rope->max = 0; - } - } -} - -int -gsm_rope_done( GsmRope rope ) -{ - int result = rope->error; - - if (rope->data && rope->data != rope->data0) - free(rope->data); - - rope->data = NULL; - rope->pos = 0; - rope->max = 0; - rope->error = 0; - - return result; -} - - -bytes_t -gsm_rope_done_acquire( GsmRope rope, int *psize ) -{ - bytes_t result = rope->data; - - *psize = rope->pos; - if (result == rope->data0) { - result = malloc( rope->pos ); - if (result != NULL) - memcpy( result, rope->data, rope->pos ); - } - return result; -} - - -int -gsm_rope_ensure( GsmRope rope, int new_count ) -{ - if (rope->data != NULL) { - int old_max = rope->max; - bytes_t old_data = rope->data == rope->data0 ? NULL : rope->data; - int new_max = old_max; - bytes_t new_data; - - while (new_max < new_count) { - new_max += (new_max >> 1) + 4; - } - new_data = realloc( old_data, new_max ); - if (new_data == NULL) { - rope->error = 1; - return -1; - } - rope->data = new_data; - rope->max = new_max; - } else { - rope->max = new_count; - } - return 0; -} - -static int -gsm_rope_can_grow( GsmRope rope, int count ) -{ - if (!rope->data || rope->error) - return 0; - - if (rope->pos + count > rope->max) - { - if (rope->data == NULL) - rope->max = rope->pos + count; - - else if (rope->error || - gsm_rope_ensure( rope, rope->pos + count ) < 0) - return 0; - } - return 1; -} - -void -gsm_rope_add_c( GsmRope rope, char c ) -{ - if (gsm_rope_can_grow(rope, 1)) { - rope->data[ rope->pos ] = (byte_t) c; - } - rope->pos += 1; -} - -void -gsm_rope_add( GsmRope rope, const void* buf, int buflen ) -{ - if (gsm_rope_can_grow(rope, buflen)) { - memcpy( rope->data + rope->pos, (const char*)buf, buflen ); - } - rope->pos += buflen; -} - -void* -gsm_rope_reserve( GsmRope rope, int count ) -{ - void* result = NULL; - - if (gsm_rope_can_grow(rope, count)) - { - if (rope->data != NULL) - result = rope->data + rope->pos; - } - rope->pos += count; - - return result; -} - -/* skip a given number of Unicode characters in a utf-8 byte string */ -cbytes_t -utf8_skip( cbytes_t utf8, - cbytes_t utf8end, - int count) -{ - cbytes_t p = utf8; - cbytes_t end = utf8end; - - for ( ; count > 0; count-- ) { - int c; - - if (p >= end) - break; - - c = *p++; - if (c > 128) { - while (p < end && (p[0] & 0xc0) == 0x80) - p++; - } - } - return p; -} - - -static __inline__ int -utf8_next( cbytes_t *pp, cbytes_t end ) -{ - cbytes_t p = *pp; - int result = -1; - - if (p < end) { - int c= *p++; - if (c >= 128) { - if ((c & 0xe0) == 0xc0) - c &= 0x1f; - else if ((c & 0xf0) == 0xe0) - c &= 0x0f; - else - c &= 0x07; - - while (p < end && (p[0] & 0xc0) == 0x80) { - c = (c << 6) | (p[0] & 0x3f); - p ++; - } - } - result = c; - *pp = p; - } - return result; -} - - -__inline__ int -utf8_write( bytes_t utf8, int offset, int v ) -{ - int result; - - if (v < 128) { - result = 1; - if (utf8) - utf8[offset] = (byte_t) v; - } else if (v < 0x800) { - result = 2; - if (utf8) { - utf8[offset+0] = (byte_t)( 0xc0 | (v >> 6) ); - utf8[offset+1] = (byte_t)( 0x80 | (v & 0x3f) ); - } - } else if (v < 0x10000) { - result = 3; - if (utf8) { - utf8[offset+0] = (byte_t)( 0xe0 | (v >> 12) ); - utf8[offset+1] = (byte_t)( 0x80 | ((v >> 6) & 0x3f) ); - utf8[offset+2] = (byte_t)( 0x80 | (v & 0x3f) ); - } - } else { - result = 4; - if (utf8) { - utf8[offset+0] = (byte_t)( 0xf0 | ((v >> 18) & 0x7) ); - utf8[offset+1] = (byte_t)( 0x80 | ((v >> 12) & 0x3f) ); - utf8[offset+2] = (byte_t)( 0x80 | ((v >> 6) & 0x3f) ); - utf8[offset+3] = (byte_t)( 0x80 | (v & 0x3f) ); - } - } - return result; -} - -static __inline__ int -ucs2_write( bytes_t ucs2, int offset, int v ) -{ - if (ucs2) { - ucs2[offset+0] = (byte_t) (v >> 8); - ucs2[offset+1] = (byte_t) (v); - } - return 2; -} - -int -utf8_check( cbytes_t p, int utf8len ) -{ - cbytes_t end = p + utf8len; - int result = 0; - - if (p) { - while (p < end) { - int c = *p++; - if (c >= 128) { - int len; - if ((c & 0xe0) == 0xc0) { - len = 1; - } - else if ((c & 0xf0) == 0xe0) { - len = 2; - } - else if ((c & 0xf8) == 0xf0) { - len = 3; - } - else - goto Exit; /* malformed utf-8 */ - - if (p+len > end) /* string too short */ - goto Exit; - - for ( ; len > 0; len--, p++ ) { - if ((p[0] & 0xc0) != 0x80) - goto Exit; - } - } - } - result = 1; - } -Exit: - return result; -} - -/** UCS2 to UTF8 - **/ - -/* convert a UCS2 string into a UTF8 byte string, assumes 'buf' is correctly sized */ -int -ucs2_to_utf8( cbytes_t ucs2, - int ucs2len, - bytes_t buf ) -{ - int nn; - int result = 0; - - for (nn = 0; nn < ucs2len; ucs2 += 2, nn++) { - int c= (ucs2[0] << 8) | ucs2[1]; - result += utf8_write(buf, result, c); - } - return result; -} - -/* count the number of UCS2 chars contained in a utf8 byte string */ -int -utf8_to_ucs2( cbytes_t utf8, - int utf8len, - bytes_t ucs2 ) -{ - cbytes_t p = utf8; - cbytes_t end = p + utf8len; - int result = 0; - - while (p < end) { - int c = utf8_next(&p, end); - - if (c < 0) - break; - - result += ucs2_write(ucs2, result, c); - } - return result/2; -} - - - -/** GSM ALPHABET - **/ - -#define GSM_7BITS_ESCAPE 0x1b -#define GSM_7BITS_UNKNOWN 0 - -static const unsigned short gsm7bits_to_unicode[128] = { - '@', 0xa3, '$', 0xa5, 0xe8, 0xe9, 0xf9, 0xec, 0xf2, 0xc7, '\n', 0xd8, 0xf8, '\r', 0xc5, 0xe5, -0x394, '_',0x3a6,0x393,0x39b,0x3a9,0x3a0,0x3a8,0x3a3,0x398,0x39e, 0, 0xc6, 0xe6, 0xdf, 0xc9, - ' ', '!', '"', '#', 0xa4, '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', - 0xa1, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', - 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 0xc4, 0xd6,0x147, 0xdc, 0xa7, - 0xbf, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0xe4, 0xf6, 0xf1, 0xfc, 0xe0, -}; - -static const unsigned short gsm7bits_extend_to_unicode[128] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\f', 0, 0, 0, 0, 0, - 0, 0, 0, 0, '^', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, '{', '}', 0, 0, 0, 0, 0,'\\', - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '[', '~', ']', 0, - '|', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0,0x20ac, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - - -static int -unichar_to_gsm7( int unicode ) -{ - int nn; - for (nn = 0; nn < 128; nn++) { - if (gsm7bits_to_unicode[nn] == unicode) { - return nn; - } - } - return -1; -} - -static int -unichar_to_gsm7_extend( int unichar ) -{ - int nn; - for (nn = 0; nn < 128; nn++) { - if (gsm7bits_extend_to_unicode[nn] == unichar) { - return nn; - } - } - return -1; -} - - -/* return the number of septets needed to encode a unicode charcode */ -static int -unichar_to_gsm7_count( int unicode ) -{ - int nn; - - nn = unichar_to_gsm7(unicode); - if (nn >= 0) - return 1; - - nn = unichar_to_gsm7_extend(unicode); - if (nn >= 0) - return 2; - - return 0; -} - - -cbytes_t -utf8_skip_gsm7( cbytes_t utf8, cbytes_t utf8end, int gsm7len ) -{ - cbytes_t p = utf8; - cbytes_t end = utf8end; - - while (gsm7len >0) { - cbytes_t q = p; - int c = utf8_next( &q, end ); - int len; - - if (c < 0) - break; - - len = unichar_to_gsm7_count( c ); - if (len == 0) /* unknown chars are replaced by spaces */ - len = 1; - - if (len > gsm7len) - break; - - gsm7len -= len; - p = q; - } - return p; -} - - -int -utf8_check_gsm7( cbytes_t utf8, - int utf8len ) -{ - cbytes_t utf8end = utf8 + utf8len; - - while (utf8 < utf8end) { - int c = utf8_next( &utf8, utf8end ); - if (unichar_to_gsm7_count(c) == 0) - return 0; - } - return 1; -} - - -int -utf8_from_gsm7( cbytes_t src, - int septet_offset, - int septet_count, - bytes_t utf8 ) -{ - int shift = (septet_offset & 7); - int escaped = 0; - int result = 0; - - src += (septet_offset >> 3); - for ( ; septet_count > 0; septet_count-- ) - { - int c = (src[0] >> shift) & 0x7f; - int v; - - if (shift > 1) { - c = ((src[1] << (8-shift)) | c) & 0x7f; - } - - if (escaped) { - v = gsm7bits_extend_to_unicode[c]; - } else if (c == GSM_7BITS_ESCAPE) { - escaped = 1; - goto NextSeptet; - } else { - v = gsm7bits_to_unicode[c]; - } - - result += utf8_write( utf8, result, v ); - - NextSeptet: - shift += 7; - if (shift >= 8) { - shift -= 8; - src += 1; - } - } - return result; -} - - -int -utf8_from_gsm8( cbytes_t src, int count, bytes_t utf8 ) -{ - int result = 0; - int escaped = 0; - - - for ( ; count > 0; count-- ) - { - int c = *src++; - - if (c == 0xff) - break; - - if (c == GSM_7BITS_ESCAPE) { - if (escaped) { /* two escape characters => one space */ - c = 0x20; - escaped = 0; - } else { - escaped = 1; - continue; - } - } - else - { - if (c >= 0x80) { - c = 0x20; - escaped = 0; - } else if (escaped) { - c = gsm7bits_extend_to_unicode[c]; - } else - c = gsm7bits_to_unicode[c]; - } - - result += utf8_write( utf8, result, c ); - } - return result; -} - -/* convert a GSM 7-bit message into a unicode character array - * the 'dst' array must contain at least 160 chars. the function - * returns the number of characters decoded - * - * assumes the 'dst' array has at least septet_count items, returns the - * number of unichars really written - */ -int -ucs2_from_gsm7( bytes_t ucs2, - cbytes_t src, - int septet_offset, - int septet_count ) -{ - const unsigned char* p = src + (septet_offset >> 3); - int shift = (septet_offset & 7); - int escaped = 0; - int result = 0; - - for ( ; septet_count > 0; septet_count-- ) - { - unsigned val = (p[0] >> shift) & 0x7f; - - if (shift > 1) - val = (val | (p[1] << (8-shift))) & 0x7f; - - if (escaped) { - int c = gsm7bits_to_unicode[val]; - - result += ucs2_write(ucs2, result, c); - escaped = 0; - } - else if (val == GSM_7BITS_ESCAPE) { - escaped = 1; - } - else { - val = gsm7bits_extend_to_unicode[val]; - if (val == 0) - val = 0x20; - - result += ucs2_write( ucs2, result, val ); - } - } - return result/2; -} - - -/* count the number of septets required to write a utf8 string */ -static int -utf8_to_gsm7_count( cbytes_t utf8, int utf8len ) -{ - cbytes_t utf8end = utf8 + utf8len; - int result = 0; - - while ( utf8 < utf8end ) { - int len; - int c = utf8_next( &utf8, utf8end ); - - if (c < 0) - break; - - len = unichar_to_gsm7_count(c); - if (len == 0) /* replace non-representables with space */ - len = 1; - - result += len; - } - return result; -} - -typedef struct { - bytes_t dst; - unsigned pad; - int bits; - int offset; -} BWriterRec, *BWriter; - -static void -bwriter_init( BWriter writer, bytes_t dst, int start ) -{ - int shift = start & 7; - - writer->dst = dst + (start >> 3); - writer->pad = 0; - writer->bits = shift; - writer->offset = start; - - if (shift > 0) { - writer->pad = writer->dst[0] & ~(0xFF << shift); - } -} - -static void -bwriter_add7( BWriter writer, unsigned value ) -{ - writer->pad |= (unsigned)(value << writer->bits); - writer->bits += 7; - if (writer->bits >= 8) { - writer->dst[0] = (byte_t)writer->pad; - writer->bits -= 8; - writer->pad >>= 8; - writer->dst += 1; - } - writer->offset += 7; -} - -static int -bwriter_done( BWriter writer ) -{ - if (writer->bits > 0) { - writer->dst[0] = (byte_t)writer->pad; - writer->pad = 0; - writer->bits = 0; - writer->dst += 1; - } - return writer->offset; -} - -/* convert a utf8 string to a gsm7 byte string - return the number of septets written */ -int -utf8_to_gsm7( cbytes_t utf8, int utf8len, bytes_t dst, int offset ) -{ - const unsigned char* utf8end = utf8 + utf8len; - BWriterRec writer[1]; - - if (dst == NULL) - return utf8_to_gsm7_count(utf8, utf8len); - - bwriter_init( writer, dst, offset ); - while ( utf8 < utf8end ) { - int c = utf8_next( &utf8, utf8end ); - int nn; - - if (c < 0) - break; - - nn = unichar_to_gsm7(c); - if (nn >= 0) { - bwriter_add7( writer, nn ); - continue; - } - - nn = unichar_to_gsm7_extend(c); - if (nn >= 0) { - bwriter_add7( writer, GSM_7BITS_ESCAPE ); - bwriter_add7( writer, nn ); - continue; - } - - /* unknown => replaced by space */ - bwriter_add7( writer, 0x20 ); - } - return bwriter_done( writer ); -} - - -int -utf8_to_gsm8( cbytes_t utf8, int utf8len, bytes_t dst ) -{ - const unsigned char* utf8end = utf8 + utf8len; - int result = 0; - - while ( utf8 < utf8end ) { - int c = utf8_next( &utf8, utf8end ); - int nn; - - if (c < 0) - break; - - nn = unichar_to_gsm7(c); - if (nn >= 0) { - if (dst) - dst[result] = (byte_t)nn; - result += 1; - continue; - } - - nn = unichar_to_gsm7_extend(c); - if (nn >= 0) { - if (dst) { - dst[result+0] = (byte_t) GSM_7BITS_ESCAPE; - dst[result+1] = (byte_t) nn; - } - result += 2; - continue; - } - - /* unknown => space */ - if (dst) - dst[result] = 0x20; - result += 1; - } - return result; -} - - -int -ucs2_to_gsm7( cbytes_t ucs2, int ucs2len, bytes_t dst, int offset ) -{ - const unsigned char* ucs2end = ucs2 + ucs2len*2; - BWriterRec writer[1]; - - bwriter_init( writer, dst, offset ); - while ( ucs2 < ucs2end ) { - int c = *ucs2++; - int nn; - - for (nn = 0; nn < 128; nn++) { - if ( gsm7bits_to_unicode[nn] == c ) { - bwriter_add7( writer, nn ); - goto NextUnicode; - } - } - for (nn = 0; nn < 128; nn++) { - if ( gsm7bits_extend_to_unicode[nn] == c ) { - bwriter_add7( writer, GSM_7BITS_ESCAPE ); - bwriter_add7( writer, nn ); - goto NextUnicode; - } - } - - /* unknown */ - bwriter_add7( writer, 0x20 ); - - NextUnicode: - ; - } - return bwriter_done( writer ); -} - - -int -ucs2_to_gsm8( cbytes_t ucs2, int ucs2len, bytes_t dst ) -{ - const unsigned char* ucs2end = ucs2 + ucs2len*2; - bytes_t dst0 = dst; - - while ( ucs2 < ucs2end ) { - int c = *ucs2++; - int nn; - - for (nn = 0; nn < 128; nn++) { - if ( gsm7bits_to_unicode[nn] == c ) { - *dst++ = (byte_t)nn; - goto NextUnicode; - } - } - for (nn = 0; nn < 128; nn++) { - if ( gsm7bits_extend_to_unicode[nn] == c ) { - dst[0] = (byte_t) GSM_7BITS_ESCAPE; - dst[1] = (byte_t) nn; - dst += 2; - goto NextUnicode; - } - } - - /* unknown */ - *dst++ = 0x20; - - NextUnicode: - ; - } - return (dst - dst0); -} - -int -gsm_bcdnum_to_ascii( cbytes_t bcd, int count, bytes_t dst ) -{ - int result = 0; - int shift = 0; - - while (count > 0) { - int c = (bcd[0] >> shift) & 0xf; - - if (c == 15 && count == 1) /* ignore trailing 0xf */ - break; - - if (c >= 14) - c = 0; - - if (dst) dst[result] = "0123456789*#,N"[c]; - result += 1; - - shift += 4; - if (shift == 8) { - shift = 0; - bcd += 1; - } - } - return result; -} - - -int -gsm_bcdnum_from_ascii( cbytes_t ascii, int asciilen, bytes_t dst ) -{ - cbytes_t end = ascii + asciilen; - int result = 0; - int phase = 0x01; - - while (ascii < end) { - int c = *ascii++; - - if (c == '*') - c = 10; - else if (c == '#') - c = 11; - else if (c == ',') - c = 12; - else if (c == 'N') - c = 13; - else { - c -= '0'; - if ((unsigned)c >= 10U) - return -1; - } - phase = (phase << 4) | c; - result += 1; - if (phase & 0x100) { - if (dst) dst[result/2] = (byte_t) phase; - phase = 0x01; - } - } - - if (result & 1) { - if (dst) dst[result/2] = (byte_t)(phase | 0xf0); - } - return result; -} - -/** ADN: Abbreviated Dialing Number - **/ - -#define ADN_FOOTER_SIZE 14 -#define ADN_OFFSET_NUMBER_LENGTH 0 -#define ADN_OFFSET_TON_NPI 1 -#define ADN_OFFSET_NUMBER_START 2 -#define ADN_OFFSET_NUMBER_END 11 -#define ADN_OFFSET_CAPABILITY_ID 12 -#define ADN_OFFSET_EXTENSION_ID 13 - -/* see 10.5.1 of 3GPP 51.011 */ -static int -sim_adn_alpha_to_utf8( cbytes_t alpha, cbytes_t end, bytes_t dst ) -{ - int result = 0; - - /* ignore trailing 0xff */ - while (alpha < end && end[-1] == 0xff) - end--; - - if (alpha >= end) - return 0; - - if (alpha[0] == 0x80) { /* UCS/2 source encoding */ - alpha += 1; - result = ucs2_to_utf8( alpha, (end-alpha)/2, dst ); - } - else - { - int is_ucs2 = 0; - int len = 0, base = 0; - - if (alpha+3 <= end && alpha[0] == 0x81) { - is_ucs2 = 1; - len = alpha[1]; - base = alpha[2] << 7; - alpha += 3; - if (len > end-alpha) - len = end-alpha; - } else if (alpha+4 <= end && alpha[0] == 0x82) { - is_ucs2 = 1; - len = alpha[1]; - base = (alpha[2] << 8) | alpha[3]; - alpha += 4; - if (len > end-alpha) - len = end-alpha; - } - - if (is_ucs2) { - end = alpha + len; - while (alpha < end) { - int c = alpha[0]; - if (c >= 0x80) { - result += utf8_write(dst, result, base + (c & 0x7f)); - alpha += 1; - } else { - /* GSM character set */ - int count; - for (count = 0; alpha+count < end && alpha[count] < 128; count++) - ; - result += utf8_from_gsm8(alpha, count, (dst ? dst+result : NULL)); - alpha += count; - } - } - } - else { - result = utf8_from_gsm8(alpha, end-alpha, dst); - } - } - return result; -} - -#if 0 -static int -sim_adn_alpha_from_utf8( cbytes_t utf8, int utf8len, bytes_t dst ) -{ - int result = 0; - - if (utf8_check_gsm7(utf8, utf8len)) { - /* GSM 7-bit compatible, encode directly as 8-bit string */ - result = utf8_to_gsm8(utf8, utf8len, dst); - } else { - /* otherwise, simply try UCS-2 encoding, nothing more serious at the moment */ - if (dst) { - dst[0] = 0x80; - } - result = 1 + utf8_to_ucs2(utf8, utf8len, dst ? (dst+1) : NULL)*2; - } - return result; -} -#endif - -int -sim_adn_record_from_bytes( SimAdnRecord rec, cbytes_t data, int len ) -{ - cbytes_t end = data + len; - cbytes_t footer = end - ADN_FOOTER_SIZE; - int num_len; - - rec->adn.alpha[0] = 0; - rec->adn.number[0] = 0; - rec->ext_record = 0xff; - - if (len < ADN_FOOTER_SIZE) - return -1; - - /* alpha is optional */ - if (len > ADN_FOOTER_SIZE) { - cbytes_t dataend = data + len - ADN_FOOTER_SIZE; - int count = sim_adn_alpha_to_utf8(data, dataend, NULL); - - if (count > sizeof(rec->adn.alpha)-1) /* too long */ - return -1; - - sim_adn_alpha_to_utf8(data, dataend, rec->adn.alpha); - rec->adn.alpha[count] = 0; - } - - num_len = footer[ADN_OFFSET_NUMBER_LENGTH]; - if (num_len > 11) - return -1; - - /* decode TON and number to ASCII, NOTE: this is lossy !! */ - { - int ton = footer[ADN_OFFSET_TON_NPI]; - bytes_t number = (bytes_t) rec->adn.number; - int len = sizeof(rec->adn.number)-1; - int count; - - if (ton != 0x81 && ton != 0x91) - return -1; - - if (ton == 0x91) { - *number++ = '+'; - len -= 1; - } - - count = gsm_bcdnum_to_ascii( footer + ADN_OFFSET_NUMBER_START, - num_len*2, number ); - number[count] = 0; - } - return 0; -} - -int -sim_adn_record_to_bytes( SimAdnRecord rec, bytes_t data, int datalen ) -{ - bytes_t end = data + datalen; - bytes_t footer = end - ADN_FOOTER_SIZE; - int ton = 0x81; - cbytes_t number = (cbytes_t) rec->adn.number; - - if (number[0] == '+') { - ton = 0x91; - number += 1; - } - footer[0] = (strlen((const char*)number)+1)/2 + 1; - /* XXXX: TODO */ - return 0; -} |