[svn-commits] may: branch may/smpp r411579 - in /team/may/smpp/branches/10/addons: ./ smpp/
SVN commits to the Digium repositories
svn-commits at lists.digium.com
Mon Mar 31 12:38:16 CDT 2014
Author: may
Date: Mon Mar 31 12:38:09 2014
New Revision: 411579
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=411579
Log:
add smpp_recode function to transcode smpp data from/to utf8
add gsm.c/.h helper files for that from android sources
Added:
team/may/smpp/branches/10/addons/smpp/
team/may/smpp/branches/10/addons/smpp/gsm.c (with props)
team/may/smpp/branches/10/addons/smpp/gsm.h (with props)
Modified:
team/may/smpp/branches/10/addons/Makefile
team/may/smpp/branches/10/addons/res_smpp.c
Modified: team/may/smpp/branches/10/addons/Makefile
URL: http://svnview.digium.com/svn/asterisk/team/may/smpp/branches/10/addons/Makefile?view=diff&rev=411579&r1=411578&r2=411579
==============================================================================
--- team/may/smpp/branches/10/addons/Makefile (original)
+++ team/may/smpp/branches/10/addons/Makefile Mon Mar 31 12:38:09 2014
@@ -25,6 +25,8 @@
h323/MULTIMEDIA-SYSTEM-CONTROLDec.o h323/MULTIMEDIA-SYSTEM-CONTROLEnc.o
H323CFLAGS:=-Iooh323c/src -Iooh323c/src/h323
+
+GSMOBJS:=gsm.o
ALL_C_MODS:=app_mysql \
app_saycountpl \
@@ -66,11 +68,13 @@
$(if $(filter format_mp3,$(EMBEDDED_MODS)),modules.link,format_mp3.so): mp3/common.o mp3/dct64_i386.o mp3/decode_ntom.o mp3/layer3.o mp3/tabinit.o mp3/interface.o
chan_ooh323.o: _ASTCFLAGS+=$(H323CFLAGS)
-res_smpp.o: _ASTCFLAGS+=-I/usr/local/include
-res_smpp.so: LIBS+=-L/usr/local/lib -lsmpp34
+res_smpp.o: _ASTCFLAGS+=-I.
+res_smpp.so: LIBS+=-lsmpp34
$(if $(filter chan_ooh323,$(EMBEDDED_MODS)),modules.link,chan_ooh323.so): _ASTCFLAGS+=$(H323CFLAGS)
$(if $(filter chan_ooh323,$(EMBEDDED_MODS)),modules.link,chan_ooh323.so): $(addprefix ooh323c/src/,$(H323OBJS)) chan_ooh323.o ooh323cDriver.o
$(addprefix ooh323c/src/,$(H323OBJS)) chan_ooh323.o ooh323cDriver.o: _ASTCFLAGS+=$(call MOD_ASTCFLAGS,chan_ooh323)
+$(if $(filter res_smpp,$(EMBEDDED_MODS)),modules.link,res_smpp.so): $(addprefix smpp/,$(GSMOBJS)) res_smpp.o
+$(addprefix smpp/,$(GSMOBJS)) res_smpp.o: _ASTCFLAGS+=$(call MOD_ASTCFLAGS,res_smpp)
.PHONY: check_mp3
Modified: team/may/smpp/branches/10/addons/res_smpp.c
URL: http://svnview.digium.com/svn/asterisk/team/may/smpp/branches/10/addons/res_smpp.c?view=diff&rev=411579&r1=411578&r2=411579
==============================================================================
--- team/may/smpp/branches/10/addons/res_smpp.c (original)
+++ team/may/smpp/branches/10/addons/res_smpp.c Mon Mar 31 12:38:09 2014
@@ -55,12 +55,36 @@
#include "asterisk/causes.h"
#include "asterisk/message.h"
+/*** DOCUMENTATION
+ <function name="smpp_recode" language="en_US">
+ <synopsis>
+ transcode message base64 content from/to UTF-8
+ </synopsis>
+ <syntax>
+ <parameter name="direction" required="true">
+ <para>from or to UTF8</para>
+ </parameter>
+ <parameter name="smpp encdoning" required="true">
+ <para>ucs-2 or gsm8</para>
+ </parameter>
+ <parameter name="string" required="true">
+ <para>input string</para>
+ </parameter>
+ </syntax>
+ <description>
+ <para>Returns the transcoded string in base64.</para>
+ </description>
+
+ </function>
+***/
+
#define MODULE_DESCRIPTION "SMPP messaging resource module"
#include "smpp34.h"
#include "smpp34_structs.h"
#include "smpp34_params.h"
+#include "smpp/gsm.h"
#define TRUE 1
#define FALSE 0
@@ -1708,6 +1732,97 @@
#undef FORMAT2
}
+
+static int smpp_recode(struct ast_channel *chan, const char *cmd, char *arguments, char *buf, size_t len)
+{
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(direction);
+ AST_APP_ARG(smpp_charset);
+ AST_APP_ARG(text);
+ );
+
+ int incount = 0, outcount = 0;
+ char *parse;
+ char *text = NULL;
+ unsigned char *tmpin, *tmp;
+ char esm_class[1024] = "";
+ int offset = 0;
+
+
+
+
+ if (ast_strlen_zero(arguments)) {
+ ast_log(LOG_WARNING, "Syntax: SMPP_RECODE(<from/to>,<CHARSET>,<text>) - missing arguments!\n");
+ return -1;
+ }
+
+ parse = ast_strdupa(arguments);
+ AST_STANDARD_APP_ARGS(args, parse);
+ if (args.argc < 3) {
+ ast_log(LOG_WARNING, "Syntax: SMPP_RECODE(<from/to>,<CHARSET>,<text>) - missing arguments!\n");
+ return -1;
+ }
+
+ text = args.text;
+ if (!(tmpin = ast_alloca(strlen(text)))) {
+ ast_log(LOG_ERROR, "can't allocate buffer memory\n");
+ return -1;
+ }
+ if (!(tmp = ast_alloca(strlen(text)*2))) {
+ ast_log(LOG_ERROR, "can't allocate buffer memory\n");
+ return -1;
+ }
+ incount = ast_base64decode(tmpin, text, sizeof(tmpin)-1);
+
+// check UDH header on message data
+
+ if (ast_func_read(chan, "MESSAGE_DATA(esm_class)", esm_class, sizeof(esm_class)) != -1) {
+ if (atoi(esm_class) & 0x40) {
+ offset = tmpin[0] + 1;
+ if (offset >= incount) {
+ offset = 0; // the case of incorrect message
+ } else {
+ incount -= offset;
+ }
+ }
+ }
+
+ if (!strcasecmp(args.direction, "from")) {
+ if (!strcasecmp(args.smpp_charset, "ucs2")) {
+ outcount = ucs2_to_utf8(tmpin + offset, incount, tmp);
+ ast_base64encode(buf, (void *)tmp, outcount, len);
+ goto doneok;
+ }
+ if (!strcasecmp(args.smpp_charset, "gsm8")) {
+ outcount = utf8_from_gsm8(tmpin + offset, incount, tmp);
+ ast_base64encode(buf, (void *)tmp, outcount, len);
+ goto doneok;
+ }
+ }
+ if (!strcasecmp(args.direction, "to")) {
+ if (!strcasecmp(args.smpp_charset, "ucs2")) {
+ outcount = utf8_to_ucs2(tmpin + offset, incount, tmp) * 2; // 2 bytes on UCS2 char
+ ast_base64encode(buf, (void *)tmp, outcount, len);
+ goto doneok;
+ }
+ if (!strcasecmp(args.smpp_charset, "gsm8")) {
+ outcount = utf8_to_gsm8(tmpin + offset, incount, tmp);
+ ast_base64encode(buf, (void *)tmp, outcount, len);
+ goto doneok;
+ }
+ }
+
+ ast_log(LOG_WARNING, "Wrong direction: %s\n", args.direction);
+ return -1;
+
+doneok:
+
+ ast_free(tmp);
+ ast_free(tmpin);
+ return 0;
+}
+
+
static const struct ast_msg_tech smpp_msg_tech = {
.name = "smpp",
.msg_send = smpp_msg_send,
@@ -1719,9 +1834,18 @@
AST_CLI_DEFINE(handle_cli_smpp_show_peers, "Show SMPP peers"),
};
+static struct ast_custom_function acf_smpprecode = {
+ .name = "SMPP_RECODE",
+ .read = smpp_recode,
+};
+
static int load_module(void)
{
if (ast_msg_tech_register(&smpp_msg_tech)) {
+ return AST_MODULE_LOAD_FAILURE;
+ }
+
+ if (ast_custom_function_register(&acf_smpprecode)) {
return AST_MODULE_LOAD_FAILURE;
}
@@ -1755,6 +1879,7 @@
ast_msg_tech_unregister(&smpp_msg_tech);
ast_cli_unregister_multiple(cli_smpp, sizeof(cli_smpp) / sizeof(struct ast_cli_entry));
+ ast_custom_function_unregister(&acf_smpprecode);
stop_monitor_threads();
destroy_smscs();
Added: team/may/smpp/branches/10/addons/smpp/gsm.c
URL: http://svnview.digium.com/svn/asterisk/team/may/smpp/branches/10/addons/smpp/gsm.c?view=auto&rev=411579
==============================================================================
--- team/may/smpp/branches/10/addons/smpp/gsm.c (added)
+++ team/may/smpp/branches/10/addons/smpp/gsm.c Mon Mar 31 12:38:09 2014
@@ -1,0 +1,1220 @@
+/* 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;
+}
Propchange: team/may/smpp/branches/10/addons/smpp/gsm.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/may/smpp/branches/10/addons/smpp/gsm.c
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: team/may/smpp/branches/10/addons/smpp/gsm.c
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: team/may/smpp/branches/10/addons/smpp/gsm.h
URL: http://svnview.digium.com/svn/asterisk/team/may/smpp/branches/10/addons/smpp/gsm.h?view=auto&rev=411579
==============================================================================
--- team/may/smpp/branches/10/addons/smpp/gsm.h (added)
+++ team/may/smpp/branches/10/addons/smpp/gsm.h Mon Mar 31 12:38:09 2014
@@ -1,0 +1,198 @@
+/* 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.
+*/
+#ifndef _android_gsm_h
+#define _android_gsm_h
+
+/** USEFUL TYPES
+ **/
+
+typedef unsigned char byte_t;
+typedef byte_t* bytes_t;
+typedef const byte_t* cbytes_t;
+
+/** BCD
+ **/
+
+/* convert a 8-bit value into the corresponding nibble-bcd byte */
+extern byte_t gsm_int_to_bcdi( int value );
+
+/* convert a nibble-bcd byte into an int, invalid nibbles are silently converted to 0 */
+extern int gsm_int_from_bcdi( byte_t value );
+
+/** HEX
+ **/
+
+/* try to convert a hex string into a byte string, assumes 'dst' is properly sized, and hexlen is even.
+ * returns the number of bytes on exit, or -1 in case of badly formatted data */
+extern int gsm_hex_to_bytes ( cbytes_t hex, int hexlen, bytes_t dst );
+
+/* convert a hex string into a byte string, assumes 'dst' is properly sized, and hexlen is even.
+ * no checks are performed */
+extern void gsm_hex_to_bytes0 ( cbytes_t hex, int hexlen, bytes_t dst );
+
+/* convert a byte string into a hex string, assumes 'hex' is properly sized */
+extern void gsm_hex_from_bytes( char* hex, cbytes_t src, int srclen );
+
+/* convert a hexchar to an int, returns -1 on error */
+extern int gsm_hexchar_to_int( char c );
+
+/* convert a hexchar to an int, returns 0 on error */
+extern int gsm_hexchar_to_int0( char c );
+
+/* convert a 2-char hex value into an int, returns -1 on error */
+extern int gsm_hex2_to_byte( const char* hex );
+
+/* convert a 2-char hex value into an int, returns 0 on error */
+extern int gsm_hex2_to_byte0( const char* hex );
+
+/* convert a 4-char hex value into an int, returns -1 on error */
+extern int gsm_hex4_to_short( const char* hex );
+
+/* convert a 4-char hex value into an int, returns 0 on error */
+extern int gsm_hex4_to_short0( const char* hex );
+
+/* write a byte to a 2-byte hex string */
+extern void gsm_hex_from_byte( char* hex, int val );
+
+extern void gsm_hex_from_short( char* hex, int val );
+
+/** UTF-8 and GSM Alphabet
+ **/
+
+/* check that a given utf8 string is well-formed, returns 1 on success, 0 otherwise */
+extern int utf8_check( cbytes_t utf8, int utf8len );
+
+/* check that all characters in a given utf8 string can be encoded into the GSM alphabet.
+ returns 1 if TRUE, 0 otherwise */
+extern int utf8_check_gsm7( cbytes_t utf8, int utf8len );
+
[... 134 lines stripped ...]
More information about the svn-commits
mailing list