aboutsummaryrefslogtreecommitdiffstats
path: root/telephony/gsm.c
diff options
context:
space:
mode:
Diffstat (limited to 'telephony/gsm.c')
-rw-r--r--telephony/gsm.c1220
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;
-}