/***************************************************************************
 *   copyright           : (C) 2002 by Hendrik Sattler                     *
 *   mail                : post@hendrik-sattler.de                         *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include "smscoding.h"

#include <charsets.h>
#include <helper.h>

#include <string.h>

static
ucs4char_t* sms_data_gsm_decode (uint8_t* input, unsigned int udl,
				 int header_present)
{
  gsmchar_t decoded[160+1];
  unsigned int state=0, inc=0, outc=0;
  unsigned char first=0, end=0;
  unsigned int i=0;
  uint8_t headersize = 0;

  if (input == NULL) {
    return NULL;
  }

  memset(decoded,0,sizeof(decoded));

  if (header_present) {
    headersize = input[0] + 1;
  }

  //7bit-GSM octet decoding
  state = (headersize*8)/7;
  if (headersize%7 != 0) ++state;
  inc = headersize;
  while (state < udl && outc < 160) {
    i = state%8;
    if (i == 0) {
      //character at state 0 needs no shifting
      decoded[outc] = input[inc] & 0x7F;
    } else {
      //shifting dependent on state (1-7)
      first = (input[inc+1]) << i;
      end = (input[inc]) >> (8-i);
      decoded[outc] = (first | end) & 0x7F;
      ++inc;
    }
    if (decoded[outc] == 0) { //special char '@'
      decoded[outc] = 128;
    }
    ++outc;
    ++state;
  }

  return convert_from_gsm(decoded);
}

static
ucs4char_t* sms_data_ucs2_decode (uint8_t* input, unsigned int udl,
				  int header_present)
{
  ucs4char_t* retval;
  ucs2char_t* temp;
  uint8_t headersize = 0;
  size_t i = 0;

  if (input == NULL) return NULL;
  if (header_present) {
    headersize = input[0] + 1;
    if (headersize > udl) return NULL;
    input += headersize;
    udl -= headersize;
  }

  temp = ucs2ndup((ucs2char_t*)input,udl/2);
  /* convert to host byte order */
  for (; temp[i] != 0; ++i) temp[i] = betohs(temp[i]);
  retval = convert_from_ucs2(temp);
  mem_realloc(temp,0);
  return retval;
}

static
ucs4char_t* sms_data_8bit_decode (uint8_t* input, unsigned int udl,
				  int header_present)
{
  ucs4char_t* retval;
  uint8_t headersize = 0;
  char* temp;

  if (input == NULL) return NULL;
  if (header_present) {
    headersize = input[0] + 1;
    if (headersize > udl) return NULL;
    input += headersize;
    udl -= headersize;
  }
  
  temp = strn_dup((char*)input,udl);
  retval = convert_to_internal("ISO-8859-1",temp,udl);
  return retval;
}

ucs4char_t* sms_data_decode (enum sms_encoding encoding,
			     uint8_t* input, unsigned int udl,
			     int header_present)
{
  switch (encoding) {
  case SMS_CHARSET_GSM: //all encodings of uncompressed 7bit
    return sms_data_gsm_decode(input,udl,header_present);
  case SMS_CHARSET_UCS2: //all encodings of uncompressed 16bit unicode
    return sms_data_ucs2_decode(input,udl,header_present);
  case SMS_CHARSET_8BIT: //all encodings of 8bit data: ASCII assumed
    return sms_data_8bit_decode(input,udl,header_present);
  default: //never happens
    return NULL;
  }
}
