Skip to content

Instantly share code, notes, and snippets.

@farcaller
Created November 29, 2010 08:28
Show Gist options
  • Select an option

  • Save farcaller/719729 to your computer and use it in GitHub Desktop.

Select an option

Save farcaller/719729 to your computer and use it in GitHub Desktop.

Revisions

  1. farcaller created this gist Nov 29, 2010.
    192 changes: 192 additions & 0 deletions gistfile1.m
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,192 @@
    //
    // NSString+SMSCount.m
    // SmsProsto
    //
    // Created by Farcaller on 28.11.10.
    // Copyright 2010 Codeneedle LLC. All rights reserved.
    //

    #import "NSString+SMSCount.h"
    #include <iconv.h>
    #include <errno.h>

    static int gsm7_wctomb(unichar *r, unichar wc)
    {
    unsigned char s1, s2;
    s1 = (wc & 0xff00) >> 8;
    s2 = wc & 0x00ff;
    if( s1 == 0x00 ) {
    if( s2 == 0xA || s2 == 0xD ||
    (s2 >= 0x20 && s2 <= 0x23 ) || (s2 >= 0x25 && s2 <= 0x3f)
    || (s2 >= 0x41 && s2 <= 0x5A) || (s2 >= 0x61 && s2 <= 0x7A) ) {
    *r = s2;
    return 1;
    } else {
    switch( s2 ) {
    case 0x24: *r = 0x02; return 1;
    case 0x40: *r = 0x00; return 1;
    case 0x5b: *r = 0x1b3c; return 2;
    case 0x5c: *r = 0x1b2f; return 2;
    case 0x5d: *r = 0x1b3e; return 2;
    case 0x5e: *r = 0x1b14; return 2;
    case 0x5f: *r = 0x11; return 1;
    case 0x7b: *r = 0x1b28; return 2;
    case 0x7c: *r = 0x1b40; return 2;
    case 0x7d: *r = 0x1b29; return 2;
    case 0x7e: *r = 0x1b3d; return 2;
    case 0xa3: *r = 0x01; return 1;
    case 0xa4: *r = 0x24; return 1;
    case 0xa5: *r = 0x03; return 1;
    case 0xa7: *r = 0x5f; return 1;
    case 0xb0: *r = 0x24; return 1;
    case 0xbf: *r = 0x60; return 1;
    case 0xc5: *r = 0x0e; return 1;
    case 0xc6: *r = 0x1c; return 1;
    case 0xc7: *r = 0x09; return 1;
    case 0xc9: *r = 0x1f; return 1;
    case 0xc4: *r = 0x5b; return 1;
    case 0xd1: *r = 0x5d; return 1;
    case 0xd6: *r = 0x5c; return 1;
    case 0xd8: *r = 0x0b; return 1;
    case 0xdc: *r = 0x5e; return 1;
    case 0xdf: *r = 0x1e; return 1;
    case 0xe0: *r = 0x7f; return 1;
    case 0xe4: *r = 0x7b; return 1;
    case 0xe5: *r = 0x0f; return 1;
    case 0xe6: *r = 0x1d; return 1;
    case 0xe7: *r = 0x09; return 1;
    case 0xe8: *r = 0x04; return 1;
    case 0xe9: *r = 0x05; return 1;
    case 0xec: *r = 0x07; return 1;
    case 0xf1: *r = 0x7d; return 1;
    case 0xf2: *r = 0x08; return 1;
    case 0xf6: *r = 0x7c; return 1;
    case 0xf8: *r = 0x0c; return 1;
    case 0xf9: *r = 0x06; return 1;
    case 0xfc: *r = 0x7e; return 1;
    /* one way mappings */
    case 0xc0: *r = 0x41; return 1;
    case 0xc1: *r = 0x41; return 1;
    case 0xc2: *r = 0x41; return 1;
    case 0xc3: *r = 0x41; return 1;
    case 0xc8: *r = 0x45; return 1;
    case 0xca: *r = 0x45; return 1;
    case 0xcb: *r = 0x45; return 1;
    case 0xcc: *r = 0x49; return 1;
    case 0xcd: *r = 0x49; return 1;
    case 0xce: *r = 0x49; return 1;
    case 0xcf: *r = 0x49; return 1;
    case 0xd2: *r = 0x4f; return 1;
    case 0xd3: *r = 0x4f; return 1;
    case 0xd4: *r = 0x4f; return 1;
    case 0xd5: *r = 0x4f; return 1;
    case 0xd9: *r = 0x55; return 1;
    case 0xda: *r = 0x55; return 1;
    case 0xdb: *r = 0x55; return 1;
    case 0xdd: *r = 0x59; return 1;
    case 0xe1: *r = 0x61; return 1;
    case 0xe2: *r = 0x61; return 1;
    case 0xe3: *r = 0x61; return 1;
    case 0xea: *r = 0x65; return 1;
    case 0xeb: *r = 0x65; return 1;
    case 0xed: *r = 0x69; return 1;
    case 0xee: *r = 0x69; return 1;
    case 0xef: *r = 0x69; return 1;
    case 0xf3: *r = 0x6f; return 1;
    case 0xf4: *r = 0x6f; return 1;
    case 0xf5: *r = 0x6f; return 1;
    case 0xfa: *r = 0x75; return 1;
    case 0xfb: *r = 0x75; return 1;
    case 0xfd: *r = 0x79; return 1;
    case 0xff: *r = 0x79; return 1;
    }
    }
    return -1;
    } else if( s1 == 0x20 ) {
    if( s2 == 0xac ) {
    *r = 0x1b65; return 2;
    }
    } else if( s1 == 0x03 ) {
    switch( s2 ) {
    case 0x94: *r = 0x10; return 1;
    case 0xa6: *r = 0x12; return 1;
    case 0x93: *r = 0x13; return 1;
    case 0x9b: *r = 0x14; return 1;
    case 0xa9: *r = 0x15; return 1;
    case 0xa0: *r = 0x16; return 1;
    case 0xa8: *r = 0x17; return 1;
    case 0xa3: *r = 0x18; return 1;
    case 0x98: *r = 0x19; return 1;
    case 0x9e: *r = 0x1a; return 1;
    case 0x91: *r = 0x41; return 1;
    case 0x92: *r = 0x42; return 1;
    case 0x95: *r = 0x45; return 1;
    case 0x97: *r = 0x48; return 1;
    case 0x99: *r = 0x49; return 1;
    case 0x9a: *r = 0x4b; return 1;
    case 0x9c: *r = 0x4d; return 1;
    case 0x9d: *r = 0x4e; return 1;
    case 0x9f: *r = 0x4f; return 1;
    case 0xa1: *r = 0x50; return 1;
    case 0xa4: *r = 0x54; return 1;
    case 0xa5: *r = 0x55; return 1;
    case 0xa7: *r = 0x58; return 1;
    case 0x96: *r = 0x5a; return 1;
    }
    return -1;
    }
    return 0;
    };

    @implementation NSString (SMSCount)

    - (NSUInteger)smsLength
    {
    char *b = (char*)[self GSM7String];
    if(b) {
    int l = strlen(b);
    free(b);
    return l;
    } else {
    // can't encode, fallback to UCS-2BE
    return [self length]*2;
    }
    }

    - (const char *)GSM7String
    {
    char *ret = NULL;
    NSUInteger len = [self length];
    unichar *ibuf = malloc(len*sizeof(unichar));
    assert(ibuf);
    char *obuf = malloc(len*sizeof(unichar));
    assert(obuf);
    bzero(obuf, len*sizeof(unichar));
    NSRange r;
    r.length = len;
    r.location = 0;
    [self getCharacters:ibuf range:r];

    for(int i=0, j=0; i<len; ++i) {
    unichar ic = ibuf[i];
    unichar oc = 0;
    int l = gsm7_wctomb(&oc, ic);
    if(l < 1)
    goto final;
    unsigned char s1 = (oc & 0xff00) >> 8;
    unsigned char s2 = oc & 0x00ff;
    if(s1) {
    obuf[j++] = s1;
    }
    obuf[j++] = s2;
    }

    ret = strdup(obuf);

    final:
    free(ibuf);
    free(obuf);
    return ret;
    }

    @end