#include "rslib.h"
#pragma hdrstop

/* we don't trust the standard library implementations */

#ifdef __MWERKS__ // lousy compiler
int strnicmp(const char*a,const char*b, size_t l)
{
 for ( size_t i=0; i<l; i++)
  {
   int x = toupper(a[i])-toupper(b[i]);
   if (x) return x;
  }
 return 0;
}

int stricmp(const char*a,const char*b)
{
 size_t i;
 for (i=0 ; a[i] && b[i]; i++)
  {
   int x = toupper(a[i])-toupper(b[i]);
   if (x) return x;
  }
 return a[i] - b[i];
}
#endif

bool strsplit(const char * in, const char * split,TStr& before,TStr& after)
{
 const char * c = stristr(in,split);
 if (!c) return false;
 before.Resize(c-in,in);
 after.Resize(strlen(c) - strlen(split),c+strlen(split));
 return true;
}


void TStr::replace(const char* remove, const char * replace)
{

 TChars stream;
 size_t l1 = strlen(remove);
 size_t l2 = strlen(replace);

 char * d = str;
 while (*d)
 {
  char * c = stristr(d,(char*)remove);
  if (!c) break;
  stream.Append(d,c-d);
  if (l2) stream.Append(replace,l2);
  d = c + l1;
 }
 stream << d;
 Set(stream.buf,stream.size);
}

inline char * myAppend(char*d,const char *s)
  {size_t i = strlen(s); memmove(d,s,i); return d+i;}

char * ConcatStrings(const char ** c)
    {
     size_t len = 0;
     char * str;
     const char **p = c;
     while (*p) len += strlen(*(p++));

     str = AllocStr(len);

     char * s = str;
     while (*c) s = myAppend(s,*(c++));
     str[len] = 0;
     return str;
    }; //appends a list of strings

TStr::TStr(char ** c)
    {
     str=ConcatStrings((const char ** )c);
    }


TStr::TStr(const char * s1,const char * s2,const char * s3,const char * s4,
               const char * s5,const char * s6,const char * s7,const char * s8,
               const char * s9,const char * sA,const char * sB,const char * sC)
    {
    const char * array[14];
    array[0] = s1;
    array[1] = s2;
    array[2] = s3;
    array[3] = s4;
    array[4] = s5;
    array[5] = s6;
    array[6] = s7;
    array[7] = s8;
    array[8] = s9;
    array[9] = sA;
    array[10]= sB;
    array[11]= sC;
    array[12]=0;
    str=ConcatStrings(array);
    } //appends a list of strings

    TStr::TStr(const char ** c)
    {str=ConcatStrings(c);
    } //appends a list of strings
/*
    TStr::TStr( HINSTANCE instance,...)
    {
     int count = 0;
     va_list ap;

     int arg;
     va_start(ap, instance);
     while ((arg = va_arg(ap,int)) != 0) { count++;}
     va_end(ap);

#ifdef UNICODE
#define RESOURCE_LENGTH 512
#else
#define RESOURCE_LENGTH 256
#endif

     str = AllocStr(count * RESOURCE_LENGTH);
     char * c = str;

     va_start(ap, instance);
     while ((arg = va_arg(ap,int)) != 0)
      {
       int i = LoadString(instance,arg,c,RESOURCE_LENGTH);
       if (i) c += i;
       else c += wsprintf(c,"?%d?",i);
      }
     va_end(ap);
    }
 */
    TStr::TStr() {str=AllocStr(0u);}

    TStr::TStr(const char * c)
             {str=AllocStr(c);}

    TStr::TStr(const char * c, size_t len)
    			 {str=AllocStr(len);
              memcpy(str,c,len);
             }

    TStr::TStr(size_t len,char v )
    			 {str=AllocStr(len);
              memset(str,v,len);}

    TStr::TStr(size_t len)
    			 {str=AllocStr(len);
              str[0]=0;}

    TStr::TStr(const TStr& ts)
            {str = AllocStr(ts.str);}

    TStr::~TStr()
     {
      FreeStr(str) ; //delete [] str;
      str="";
     }

    void TStr::Truncate(size_t len)
    {
     if (strlen(str) > len) str[len]=0;
    }

    void TStr::Resize(size_t len,const char * c)
    {
     char * ns = AllocStr(len);
     strncpy(ns,c?c:str,len);
     delete [] str;
     str = ns;
    }

    void TStr::Set(const char * c, size_t length)
    {
      if (!c)
      {
       str[0]=0;
       return;
      }

      if (!c[0])
      {
       str[0]=0;
       return;
      }
      
     char* ns = AllocStr(length);
     memcpy(ns,c,length);
     delete [] str;
     ns[length] = 0;
     str = ns;
    }

    TStr & TStr::operator = (const char * c)
    {
     if (c == NULL)
      {
       str[0] = 0;
       return *this;
      }

     Set(c,strlen(c));
     return *this;
    }

    TStr & TStr::operator += (const char * c)
    {
     if (!c || ! *c) return *this;
     char * ns;
     size_t b = strlen(str);
     size_t a = strlen(c);
     ns = AllocStr(a+b);
     memmove(ns,str,b);
     memmove(ns+b,c,a);
     ns[a+b]=0;
     delete [] str;
     str=ns;
     return *this;
    }

    void TStr::Exchange(TStr&ts)
    {
     char * s = str;
     str = ts.str;
     ts.str = s;
    }
/*
#ifndef CP_UTF8
#define CP_UTF8 65001
#endif
*/
//UTF-16 from UTF-8.

size_t UTF8ToUCS2C(const char* in,uint16 &c)
{
 if ((in[0] & 0x80) == 0) {c=in[0]; return 1;} //1 character OK

 // 110xxxxx 10xxxxxx
 if (((in[0] & 0xe0) == 0xc0) && ((in[1] & 0xc0) == 0x80))
  { c = uint16( ((in[0] & 0x1f) << 6) | (in[1] & 0x3f)); return 2;}

 // 1110xxxx 10xxxxxx 10xxxxxx
 if (((in[0] & 0xf0) == 0xe0) && ((in[1] & 0xc0) == 0x80) && ((in[2] & 0xc0 )== 0x80))
  { c = uint16(((in[0] & 0x0f) << 12) | ((in[1] & 0x3f) << 6)| (in[2] & 0x3f)); return 3;}

 // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
 if (((in[0] & 0xf8) == 0xf0) && ((in[1] & 0xc0) == 0x80) && ((in[2] & 0xc0 )== 0x80)&& ((in[3] & 0xc0) == 0x80))
  { c = uint16(((in[0] & 0x0f) << 18) | ((in[1] & 0x3f) << 12)| ((in[2] & 0x3f) <<6)| ((in[3] & 0x3f))); return 4;}

 return 0; //error
}

///returns the number of characters (not bytes) needed  (not including the final null)
size_t UTF8ToUCS2Length(const char* in,size_t max)
{
 uint16 x;
 size_t length=0;
 if (in) while (*in && max)
  {
   size_t a = UTF8ToUCS2C(in,x);
   if (!a) break;
   length++;
   max-= a;
   in += a;
  }
 return length;
}

///returns the number of characters (not bytes) converted (not including the final null)
size_t UTF8ToUCS2(const char* in,uint16 * out,size_t max)
{
 size_t length=0;
 size_t cur=0;
 if (in) while (in[cur] && cur < max)
  {
   size_t a = UTF8ToUCS2C(in+cur,*out);
   if (!a) break;
   length++;
   out++;
   cur += a;
  }
 *out = 0;
 return length;
}

size_t UCS2ToUTF8C(unsigned in, char* out)
{
  if (in < 0x80)
  {
	  out[0]=(char)in;
	  return 1;
  }
  else if (in < 0x800) //can be described in 11 bits
  {
	  out[1] = (char)((in & 0x3f) | 0x80);
	  out[0] = (char)((in >> 6)   | 0xc0);
	  return 2;
  }
  else if (in < 0x10000) //16 bits?
  {
	  out[2] = (char)((in & 0x3f) | 0x80);
	  out[1] = (char)(((in >> 6) & 0x3f) | 0x80);
	  out[0] = (char)((in >> 12)  | 0xe0);
	  return 3;
  }
  else //21 bits
  {
     out[3] = (char)((in & 0x3f) | 0x80);
	  out[2] = (char)(((in >> 6) & 0x3f) | 0x80);
	  out[1] = (char)(((in >> 12) & 0x3f) | 0x80);
	  out[0] = (char)(((in >> 18) & 0x07) | 0xf0);
	  return 4;
  }
}

///returns the number of bytes (not not characters) needed (not including the final null)
size_t UCS2ToUTF8Length(const uint16* in,size_t max)
{
 size_t length =0;
 char d[3];
 if (in) while (*in && max)
 {
  length += UCS2ToUTF8C(*in,d);
  in++;
  max--;
 }
 return length;
}
                                           
///returns the length of the result string (not including the final null)
size_t UCS2ToUTF8(const uint16* in,char* out,size_t max)
{
 if (in) while (*in && max)
 {
  size_t a = UCS2ToUTF8C(*in,out);
  out += a;
  in++;
  max--;
 }
 *out = 0;
}

WStr::WStr(const char* x,size_t max)
 //Allocate enough space.
   : data(UTF8ToUCS2Length(x,max) * sizeof(uint16))
   {
    UTF8ToUCS2(x,data.w(),max);
   }

TStr::TStr(const uint16* x,size_t len)
{
 str = AllocStr(UCS2ToUTF8Length(x,len));
 UCS2ToUTF8(x,str,len);
}

#if 0
WStr::WStr(const char* x)
 //Allocate enough space.
   : data(MultiByteToWideChar(CP_UTF8,0,x,strlen(x),NULL,0) * sizeof(uint16))
   {//copy
    MultiByteToWideChar(CP_UTF8,0,x,strlen(x),data.w(),data.size/sizeof(uint16));
   }

TStr::TStr(const uint16* x)
{
 size_t l = WideCharToMultiByte(CP_UTF8,0,x,wcslen(x),NULL,0,NULL,NULL);
 str = AllocStr(l);
 WideCharToMultiByte(CP_UTF8,0,x,wcslen(x),str,l,NULL,NULL);
}
#endif
//------------------------------------------------------------------------
