//----------------------------------------------------------------------------
// Copyright (c) 1994, 1996 by Borland International, All Rights Reserved
//
/// \file
/// TString (& TUString) implementation (others functions are inline)
//----------------------------------------------------------------------------
#include <owl/pch.h>
#include <owl/defs.h>
#include <owl/wsyscls.h>
#include <owl/string.h>
#include <owl/private/memory.h>
#include <string.h>
 
namespace owl {
 
TUString TUString::Null;   // null TAutoStrings reference this object
 
//
// Take a wide char string & return an ANSI string in a new'd char[] buffer
//
char* TUString::ConvertWtoA(const wchar_t* src, size_t len)
{
  size_t size;
  char* dst;
#if defined WINELIB
  //convert from UTF32 (wchar in linux are UTF32) to UTF16 (WCHAR)
  size_t s = wcslen(src);
  WCHAR *auxSrc = new WCHAR[s*2]; //maximum possible
  int i, j;
  for (i=0, j=0; i<s && src[i]; i++) {
    if (src[i]<=0xFFFF)
      auxSrc[j++] = src[i];
    else { //convert into a surrogate pair
      wchar_t w=src[i]-0x10000;
      auxSrc[j++] = (w >> 10) + 0xD800;
      auxSrc[j++] = (w & 0x3FF)+0xDC00;
    }
  }
  auxSrc[j++] = 0 ;
  size = WideCharToMultiByte(CP_ACP, 0, auxSrc, len, 0, 0, 0, 0);
  dst = new char[size + (len != (size_t)-1)];  // room for null if fixed size
  size = WideCharToMultiByte(CP_ACP, 0, auxSrc, len, dst, size, 0, 0);
  delete auxSrc;
#else
  size = WideCharToMultiByte(CP_ACP, 0, src, static_cast<int>(len), 0, 0, 0, 0);
  dst = new char[size + (len != (size_t)-1)];  // room for null if fixed size
  size = WideCharToMultiByte(CP_ACP, 0, src, static_cast<int>(len), dst, static_cast<int>(size), 0, 0);
#endif
  if (len != (size_t)-1)
    dst[size] = 0;
  return dst;
}
 
//
// Take an ANSI char string & return a wide string in a new'd wchar_t[] buffer
//
wchar_t* TUString::ConvertAtoW(const char* src, size_t len)
{
  size_t size = MultiByteToWideChar(CP_ACP, 0, src, static_cast<int>(len), 0, 0);
  wchar_t* dst;
#if defined WINELIB
  WCHAR* auxDst = new WCHAR[size + (len != (size_t)-1)];
  size = MultiByteToWideChar(CP_ACP, 0, src, len, auxDst, size);
  if (len != (size_t)-1)
    auxDst[size] = 0;
 
  //Now convert from UTF16 to UTF32
  dst = new wchar_t[size + (len != (size_t)-1)];
  int i, j;
  for (i=0, j=0; i<size && auxDst[i]; i++) {
    if (auxDst[i]<0xD800 || auxDst[i]>0xDFFF)
      dst[j++] = auxDst[i];
    else { //it's a surrogate pair
      dst[j++] = 0x10000 + (auxDst[i] - 0xD800) <<10 + (auxDst[i+1] - 0xDC00);
      i++;
    }
  }
  dst[j] = 0;
  delete auxDst;
 
#else
  dst = new wchar_t[size + (len != (size_t)-1)];
  size = MultiByteToWideChar(CP_ACP, 0, src, static_cast<int>(len), dst, static_cast<int>(size));
  if (len != (size_t)-1)
    dst[size] = 0;
#endif
  return dst;
}
 
BSTR TUString::ConvertAtoBSTR(const char* src)
{
  size_t size = MultiByteToWideChar(CP_ACP, 0, src, -1, 0, 0);
  wchar_t* pWide = (wchar_t*)alloca(sizeof(wchar_t)*(size+1));
  size = MultiByteToWideChar(CP_ACP, 0, src, -1, pWide, static_cast<int>(size));
  pWide[size] = 0;
  return ::SysAllocString(pWide);
}
 
//------------------------------------------------------------------------
//
// Change UString to isCopy regardless of current type
//
char* TUString::ChangeToCopy()
{
  char* dst = 0;
  const char * src = 0;
  size_t len = 0;
  switch (Kind) {
    case isNull:
      return 0;
    case isConst:
      src = Const;
      len = strlen(Const);
      break;
    case isCopy:
      return Copy;
    case isWConst:
      dst = ConvertWtoA(WConst);
      break;
    case isWCopy:
      dst = ConvertWtoA(WCopy);
      break;
    case isBstr:
    case isExtBstr:
      dst = ConvertWtoA(Bstr, TOleAuto::SysStringLen(Bstr));
      break;
    case isString:
#if defined(UNICODE)
      dst = ConvertWtoA(GetOWLString().c_str(), GetOWLString().length());
#else
      src = GetOWLString().c_str();
      len = GetOWLString().length();
#endif
    default: //JJH added empty default construct
      break;
  }
  if (!dst)
  {
    dst = new char[len+1];
    memcpy(dst, src, len+1);
  }
  Free();
  Kind = isCopy;
  Copy = dst;
  return Copy;
}
 
//
// Change UString to isWCopy regardless of current type
//
wchar_t* TUString::ChangeToWCopy()
{
  wchar_t* dst = 0;
  const wchar_t* src = 0;
  size_t len = 0;
  switch (Kind) {
    case isNull:
      return 0;
    case isConst:
      dst = ConvertAtoW(Const);
      break;
    case isCopy:
      dst = ConvertAtoW(Copy);
      break;
    case isWConst:
      src = WConst;
      len = ::wcslen(WConst);
      break;
    case isWCopy:
      return WCopy;
    case isBstr:
    case isExtBstr:
      src = Bstr;
      len = TOleAuto::SysStringLen(Bstr);
      break;
    case isString:
#if defined(UNICODE)
      src = GetOWLString().c_str();
      len = GetOWLString().length();
#else
      dst = ConvertAtoW(GetOWLString().c_str(), GetOWLString().length());
#endif
  }
  if (!dst) {
    dst = new wchar_t[len+1];
    memcpy(dst, src, (len+1) * sizeof(wchar_t));
  }
  Free();
  Kind = isWCopy;
  WCopy = dst;
  return WCopy;
}
 
BSTR TUString::ConvertToBSTR()
{
  BSTR dst;
  switch (Kind) {
    case isNull:
      return 0;
    case isConst:
      dst = ConvertAtoBSTR(Const);
      break;
    case isCopy:
      dst = ConvertAtoBSTR(Copy);
      break;
    case isWConst:
      dst = ::SysAllocString(WConst);
      break;
    case isWCopy:
      dst = ::SysAllocString(WConst);
      break;
    case isBstr:
    case isExtBstr:
      return Bstr;
    case isString:
#if defined(UNICODE)
      dst = ::SysAllocString(GetOWLString().c_str());
#else
      dst = ConvertAtoBSTR(GetOWLString().c_str());
#endif
      break;
    default:
      CHECK(!"Unexpected Kind of TUString");
      return 0;
  }
  Free();
  Kind = isBstr;
  Bstr = dst;
  return Bstr;
}
 
//------------------------------------------------------------------------
// inline ctors used by Create functions.
// Note: these are never made public or exported from this unit
//
 
//
inline TUString::TUString(const char & str)
:
  Lang(0), Kind(isConst), RefCnt(1), Const(&str)
{
}
 
//
inline TUString::TUString(char& str)
:
  Lang(0),Kind(isCopy), RefCnt(1)
{
  Copy = new char[strlen(&str)+1];
  strcpy(Copy, &str);
}
 
 
//
inline TUString::TUString(const wchar_t& str)
:
  Lang(0), Kind(isWConst), RefCnt(1), WConst(&str)
{
}
 
//
inline TUString::TUString(wchar_t& str)
:
  Lang(0), Kind(isWCopy), RefCnt(1)
{
  WCopy = new wchar_t[::wcslen(&str)+1];
  ::wcscpy(WCopy, &str);
}
 
//
inline TUString::TUString(BSTR str, bool loan, TLangId lang)
:
  Lang(lang),
  Kind(loan ? isExtBstr : isBstr),
  RefCnt(int16(loan ? 2 : 1)),
  Bstr(str)
{
}
 
//
inline TUString::TUString(TSysStr& str, bool loan, TLangId lang)
:
  Lang(lang),
  Kind(loan ? isExtBstr : isBstr),
  RefCnt(int16(loan ? 2 : 1)),
  Bstr(str.operator BSTR())
{
}
 
//
//inline void* operator new(size_t, TStringRef** p) {return p;}
 
//
inline TUString::TUString(const tstring& str)
:
  Lang(0), Kind(isString), RefCnt(1)
{
  AllocOWLString(str);
}
 
//------------------------------------------------------------------------
// Static creation, or factory functions return pointers to new UStrings, or
// pointers to the Null UString
//
 
//
TUString* TUString::Create(const char * str)
{
  return str /*&& *str*/ ? new TUString(*str) : &++Null;
}
 
//
TUString* TUString::Create(char* str)
{
  return str /*&& *str*/ ? new TUString(*str) : &++Null;
}
 
//
TUString* TUString::Create(const wchar_t* str)
{
  return str /*&& *str*/ ? new TUString(*str) : &++Null;
}
 
//
TUString* TUString::Create(wchar_t* str)
{
  return str /*&& *str*/ ? new TUString(*str) : &++Null;
}
 
//
TUString* TUString::Create(BSTR str, bool loan, TLangId lang)
{
  if (str && TOleAuto::SysStringLen(str))
    return new TUString(str, loan, lang);
  if (!loan)
    TOleAuto::SysFreeString(str);
  return &++Null;
}
 
//
TUString* TUString::Create(TSysStr& str, bool loan, TLangId lang)
{
  return Create(str.operator BSTR(), loan, lang);
}
 
//
TUString* TUString::Create(const tstring& str)
{
  return str.length() ? new TUString(str) : &++Null;
}
 
//------------------------------------------------------------------------
//
//
 
//
TUString* TUString::Assign(const TUString& s)
{
  if (RefCnt == 1 && Kind != isNull && Kind != isExtBstr)
    Free();
  else
    --*this;
 
  CONST_CAST(TUString&,s).RefCnt++;
  return &CONST_CAST(TUString&,s);
}
 
//
TUString* TUString::Assign(const tstring& s)
{
  if (s.length() && RefCnt == 1 && Kind != isNull && Kind != isExtBstr)
  {
    Free();
    Kind = isString;
    AllocOWLString(s);
    return this;
  }
  else
  {
    --*this;
    return Create(s);
  }
}
 
//
TUString* TUString::Assign(const char * s)
{
  if (s && *s && RefCnt == 1 && Kind != isNull && Kind != isExtBstr) {
    Free();
    Kind = isConst;
    Const = s;
    return this;
  }
  else {
    --*this;
    return Create(s);
  }
}
 
//
TUString* TUString::Assign(char* s)
{
  if (s && *s && RefCnt == 1 && Kind != isNull && Kind != isExtBstr) {
    Free();
    Kind = isCopy;
    Copy = new char[strlen(s)+1];
    strcpy(Copy, s);
    return this;
  }
  else {
    --*this;
    return Create(s);
  }
}
 
//
TUString* TUString::Assign(const wchar_t* s)
{
  if (s && *s && RefCnt == 1 && Kind != isNull && Kind != isExtBstr) {
    Free();
    Kind = isWConst;
    WConst = s;
    return this;
  }
  else {
    --*this;
    return Create(s);
  }
}
 
//
TUString* TUString::Assign(wchar_t* s)
{
  if (s && *s && RefCnt == 1 && Kind != isNull && Kind != isExtBstr) {
    Free();
    Kind = isWCopy;
    WCopy = new wchar_t[::wcslen(s)+1];
    ::wcscpy(WCopy, s);
    return this;
  }
  else {
    --*this;
    return Create(s);
  }
}
 
//
TUString* TUString::Assign(BSTR str, TLangId lang)
{
  if (RefCnt==1 && Kind != isNull && Kind != isExtBstr) {
    Free();
    Kind = isBstr;
    Bstr = str;
    Lang = lang;
    if (Bstr && TOleAuto::SysStringLen(Bstr))
      return this;
    delete this;
    return &++Null;
  }
  else {
    --*this;
    return Create(str, false, lang);
  }
}
 
//------------------------------------------------------------------------
 
//
TUString::operator const char *() const
{
  switch (Kind) {
    case isNull:    return 0;
    case isConst:   return Const;
    case isCopy:    return Copy;
#if defined(UNICODE)
    case isString:  return CONST_CAST(TUString*,this)->ChangeToCopy();
#else
    case isString:  return GetOWLString().c_str();
#endif
    case isBstr:
    case isExtBstr: return CONST_CAST(TUString*,this)->ChangeToCopy();
    case isWConst:
    case isWCopy:   return CONST_CAST(TUString*,this)->ChangeToCopy();
    default: break; //JJH added empty default construct
  }
  return 0; // suppress warning
}
 
//
TUString::operator char*()
{
  return ChangeToCopy();
}
 
//
TUString::operator const wchar_t*() const
{
  switch (Kind) {
    case isNull:    return 0;
    case isWConst:  return WConst;
    case isWCopy:   return WCopy;
    case isBstr:
    case isExtBstr: return Bstr;
    case isConst:
    case isCopy:
#if defined(UNICODE)
      return CONST_CAST(TUString*,this)->ChangeToWCopy();
    case isString:  return GetOWLString().c_str();
#else
    case isString:  return CONST_CAST(TUString*,this)->ChangeToWCopy();
#endif
  }
  return 0; // suppress warning
}
 
//
TUString::operator wchar_t*()
{
  return ChangeToWCopy();
}
 
//------------------------------------------------------------------------
 
//
//
//
int TUString::Length() const
{
  switch (Kind) {
    case isNull:    return 0;
    case isWConst:  return static_cast<int>(::wcslen(WConst));
    case isWCopy:   return static_cast<int>(::wcslen(WCopy));
    case isBstr:
    case isExtBstr: return static_cast<int>(TOleAuto::SysStringLen(Bstr));
    case isConst:   return static_cast<int>(strlen(Const));
    case isCopy:    return static_cast<int>(strlen(Copy));
    case isString:  return static_cast<int>(GetOWLString().length());
      default: break; //JJH added empty default construct
}
  return 0; // suppress warning
}
 
//------------------------------------------------------------------------
 
//
// Revoke BSTR ownership from this UString, i.e. make this UString relinquish
//
void TUString::RevokeBstr(BSTR s)
{
  if (Kind != isExtBstr || Bstr != s)  // Don't have it anymore
    return;
  if (RefCnt == 1) {   // We go away. Assume that our envelope knows about this!
    Kind = isNull;
    delete this;
    return;
  }
  ChangeToWCopy();     // Make an appropriate copy of it
}
 
//
// Pass BSTR ownership to this UString
//
void TUString::ReleaseBstr(BSTR s)
{
  if (Kind == isExtBstr && Bstr == s) {
    Kind = isBstr;
    --*this;
  }
  else       // Has been overwritten with converted type, don't need anymore
    TOleAuto::SysFreeString(s);
}
 
//
// Free any resources held by this UString. Union & Kind left in random state;
// must be reinitialized before use.
//
void TUString::Free()
{
  switch (Kind) {
    case isCopy:    delete[] Copy; break;
    case isWCopy:   delete[] WCopy; break;
    case isBstr:    TOleAuto::SysFreeString(Bstr); break;
    case isString:  GetOWLString().~tstring(); break;
    default: break; //JJH added empty default construct
  }
  Lang = 0;
//Kind = isNull;  // for safety, not really needed
}
 
} // OWL namespace
/* ========================================================================== */
 

V1037 Two or more case-branches perform the same actions. Check lines: 207, 210

V742 Function receives an address of a 'char' type variable instead of pointer to a buffer. Inspect the first argument.

V742 Function receives an address of a 'char' type variable instead of pointer to a buffer. Inspect the second argument.

V742 Function receives an address of a 'char' type variable instead of pointer to a buffer. Inspect the first argument.

V742 Function receives an address of a 'char' type variable instead of pointer to a buffer. Inspect the second argument.

V1037 Two or more case-branches perform the same actions. Check lines: 481, 483

V575 The potential null pointer is passed into 'memcpy' function. Inspect the second argument.

V575 The potential null pointer is passed into 'memcpy' function. Inspect the second argument.

V659 Declarations of functions with 'TUString::Assign' name differ in the 'const' keyword only, but the bodies of these functions have different composition. This is suspicious and can possibly be an error. Check lines: 386, 401.

V659 Declarations of functions with 'TUString::Assign' name differ in the 'const' keyword only, but the bodies of these functions have different composition. This is suspicious and can possibly be an error. Check lines: 417, 432.