본문 바로가기
kxLibrary

kxBuff Library Open Source code

by 두루물 2010. 9. 13.

OpenSource Published New version mybuff library here,

이것은 일전에 Intelligent-Memory-Buffer-Class-on-Non-MFCSDK-Platforms 라는 타이틀로 codeguru에 올렸던 mybufflib 의 확장된 최신 버전이다.

이전 버전은,
http://www.codeguru.com/cpp/misc/misc/memory/article.php/c14499/Intelligent-Memory-Buffer-Class-on-Non-MFCSDK-Platforms.htm

에 있음.


/*
 * kxBuffLibrary : krkim's eXtended Intelligent & Sequencial Linear Buffer Library
 * PURPOSE : Intelligent increasing buffer with a big buffer data,add to sequencial data,
 *           string,list like MFC String or PtrArray on Non-MFC platforms(general C/C++).
 *
 * Copyright(c) 2005-2010 Durumul.com ,Korea
 * Author  : K***(*******)
 * yeamaec@hanafos.com (http://www.durumul.com,http://krkim.net)
 *
 * Version : 1.0.5
 * This source is free to use as you like but leave this notice.
 * If you make any changes(bugfix,updating),please mail the new version to me.
 *
 * This material is provided "as is", with absolutely no warranty expressed
 * or implied. Any use is at your own risk.
 *
 * Permission to use or copy this software for any purpose is hereby granted
 * without fee, provided the above notices are retained on all copies.
 * Permission to modify the code and to distribute modified code is granted,
 * provided the above notices are retained, and a notice that the code was
 * modified is included with the above copyright notice.
 *
 */
/*
This source code is extended last version of mybufflib i published at some years ago,
http://www.codeguru.com/cpp/misc/misc/memory/article.php/c14499/Intelligent-Memory-Buffer-Class-on-Non-MFCSDK-Platforms.htm

*/
/*
  History:
    1.0.5  - 2010.07.11 <krkim> bugfix kxString constructor.
    1.0.3  - 2007.11.27 <krkim> add operators to IBuff.
    1.0.2  - 2007.11    <krkim> Renew TCHAR and LPTSTR for UNICODE Compatible.
    1.0.1  - 2006.12.07 <krkim> Add resize at kxList.
    1.0.0  - not support decreasing buffer.
    Initlal version 1.0 2005 12.15 KRKIM.
 */
#pragma once
#pragma warning (push)
#pragma warning(disable : 4996)

#ifndef KXBUFF__H
#define KXBUFF__H

#define KXBUFF_ASBIGSIZE         ( 1 << 24) /* := 16mb */
#define KXBUFF_GETBLOCKNUM(x,b)    ((x / b) + ((x % b) ? 1 : 0))
#define KXBUFF_GETBLOCKSIZE(x,b)   (KXBUFF_GETBLOCKNUM(x,b) * b + 1) /* + oddinary one byte */
#define KXBUFF_PREFIX   "Mb" /*map file prefix*/

#include <windef.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>
#include <strsafe.h>
#ifdef _KXBUFF_DISABLE_NO_VTABLE
#define KXBUFF_NO_VTABLE
#else
#define KXBUFF_NO_VTABLE __declspec(novtable)
#endif

#ifndef ASSERT
#define ASSERT( x ) ((void)0)
#define KFCASSERT( x ) ((void)0)
#endif

namespace kxBuffLib{

template < class _Ty = void>
class kxBuff
{
protected:
 _Ty *m_buff;
 int m_blksize;  /*total allocated block size*/
 int m_offset;   /*current used size(offset)*/
 HANDLE m_hFile, m_hFileMap;
 TCHAR *m_mapfile;
 int m_element_size;
 int KXBUFF_BLOCKSIZE;
public:
 void _init(){
  m_element_size = sizeof(TCHAR);
  m_blksize = m_offset = 0;
  m_buff = NULL;
  m_hFile = INVALID_HANDLE_VALUE;
  m_hFileMap = 0;
  m_mapfile = NULL;
  KXBUFF_BLOCKSIZE = 32768;
 }
 kxBuff(){
  _init();
 }
 inline kxBuff(LPCTSTR str){
  _init();
  addstr((LPTSTR)str);
 }
 inline kxBuff( const kxBuff & srcbuff){
  _init();
  _Ty *buff = (_Ty *)srcbuff.getdata();
  add(buff,srcbuff.getsize());
 }
 ~kxBuff(void){
  reset();
 }
 BOOL isvalidoffset(int offset){
  int size  = getsize();
  if(offset >= size || offset < 0) return false;
  return true;
 }

 void reset(){
  if(isbigmode()){
   if(m_buff) UnmapViewOfFile(m_buff);
   if (m_hFileMap) CloseHandle(m_hFileMap);
   if (m_hFile != INVALID_HANDLE_VALUE) CloseHandle(m_hFile);
   if(m_mapfile){
    DeleteFile(m_mapfile);
    free(m_mapfile);
   }
   m_mapfile = NULL;
   m_hFile = INVALID_HANDLE_VALUE;
   m_hFileMap = 0;
   m_buff = 0;
   m_offset = 0;
  }
  else{
   if(m_buff)
    free(m_buff);
   m_offset  = m_blksize = 0;
   m_buff  = 0;
  }
 }

 _Ty* getdata(int offset = 0) const throw(){
  return( reinterpret_cast< _Ty* >(m_buff + offset));
 }

 operator LPCTSTR() const throw(){ return (LPCTSTR)m_buff; }
 operator LPTSTR() const throw(){ return (LPTSTR)m_buff; }
 //operator LPSTR() const throw(){ return (LPSTR)m_buff; }
 kxBuff& operator=(LPTSTR str){
  reset(); addstr(str);
  return (*this);
 }

 kxBuff& operator=(LPCTSTR str){
  reset(); addstr((LPTSTR)str);
  return (*this);
 }

 const kxBuff& operator=(const unsigned char * str){
  reset(); addstr((LPTSTR)str);
  return (*this);
 }

 kxBuff& operator=(const kxBuff& src){
  LPVOID pSrc      = src.getdata();
  LPVOID pOld      = getbuffer();
  if( pSrc != pOld){
   reset();
   add(pSrc,src.getsize());
  }
  return(*this);
 }

 inline const kxBuff& operator += (const kxBuff& src){
  LPVOID pSrc      = src.getdata();
  add(pSrc,src.getsize());
  return(*this);
 }

 void resize(int size){
  int oldoffset = m_offset;
  if(size == 0){
   reset();
   return;
  }
  if(!isbigmode() && size < KXBUFF_ASBIGSIZE){
   if(size > m_blksize){
    int newalloc = KXBUFF_GETBLOCKSIZE(size,KXBUFF_BLOCKSIZE);
    _Ty* newbuff = (_Ty*)realloc(m_buff,newalloc);
    if(!newbuff){
     newalloc = size;
     newbuff = (_Ty*)malloc(newalloc);
     memcpy(newbuff,m_buff,min(size,m_blksize));
     free(m_buff);m_buff = NULL;
    }
    m_buff = newbuff;
    memset((char*)m_buff + m_offset,0,newalloc - m_offset);
    m_blksize = newalloc;
   }
  }
  else if(size > m_blksize)
  {
   int wasbig = isbigmode();
   LPVOID oldbuff = m_buff;
   LPVOID mapping = 0;
   
   if (wasbig && m_buff){
    UnmapViewOfFile(m_buff);
    m_buff = NULL;
   }
   if (m_hFileMap) CloseHandle(m_hFileMap);
   m_hFileMap = 0;
   int newalloc = KXBUFF_GETBLOCKSIZE(size,KXBUFF_BLOCKSIZE);
   if(m_hFile == INVALID_HANDLE_VALUE)
   {
    TCHAR tmp[MAX_PATH];
    GetTempPath(MAX_PATH,tmp);
    if(m_mapfile)
     free(m_mapfile);
    m_mapfile = (TCHAR*)malloc(MAX_PATH+10);
    GetTempFileName(tmp,(LPTSTR)KXBUFF_PREFIX,0,m_mapfile);
    m_hFile = CreateFile(m_mapfile,GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_TEMPORARY|FILE_FLAG_DELETE_ON_CLOSE,NULL);
   }
   if(m_hFile != INVALID_HANDLE_VALUE)
    m_hFileMap = CreateFileMapping(m_hFile,NULL,PAGE_READWRITE,0,newalloc,NULL);
   if(m_hFileMap)
    mapping = MapViewOfFile(m_hFileMap,FILE_MAP_WRITE,0,0,newalloc);
   if(mapping && !wasbig && oldbuff && m_offset > 0){ /*copy from tiny buff*/
    memcpy(mapping,oldbuff,m_offset);
    free(m_buff);/*destroy*/
    m_buff = (_Ty*)mapping;
   }
   m_blksize = newalloc;
  }
  m_offset = size;
  if(m_buff && oldoffset > m_offset)
   memset((char*)m_buff + m_offset,0,oldoffset - m_offset);
 }
 int addstr(LPTSTR str){
  int len = 0;
  len = (str)? (int)_tcslen(str) : 0;
  return add(str,len);
 }
 int add(const _Ty* data,int len){
  if(data == NULL)
   return 0;
  int offset  = m_offset;
  int newsize = offset + len;
  if(len == 0 && *data == 0){ // ""
   if(m_buff)
    *(m_buff + m_offset) = 0;
   else{
    resize(1);
    *m_buff = 0;
    m_offset = 0;
   }
   return 0;
  }
  else if(len <= 0)
   return 0;
  resize(newsize);
  if(data)
   memcpy((char*)m_buff + offset,data,len);
  else
   memset((char*)m_buff + offset,0x00,len);
  return offset;/* return head position of inserting current data*/
 }
 
 int kxmemcmp(const void *b1, const void *b2, size_t n,int ignorecase = 0,int ignorenull = 1) const
 {
  const unsigned char *p1 = (const unsigned char*)b1;
  const unsigned char *p2 = (const unsigned char*)b2;
 
  if(ignorenull == 0 && (!b1||!b2)){
   if(b1 && !b2) return -1;
   if(!b1 && b2) return 1;
   if(!b1 && !b2) return 0;
  } 
  if(!n){
   if(b1 && b2){
    //if((char)*b1 == 0 && (char)*b2 == 0) return 0;
    //if((char)*b1 && (char)*b2 == 0) return -1;
    //if((char)*b1 == 0 && (char)*b2) return  1;
   }
   return 1;
  }
  for(size_t i = 0; i < n; i++){
   if(ignorenull == 0){//string비교의 경우 둘중 하나가 null만나는 곳 까지만
    if(p1[i] == 0x00 && p2[i] == 0x00)
     return 0;
    else if(p1[i] == 0x00)
     return -1;
    else if(p2[i] == 0x00)
     return 1;
   }
   if(p1[i] != p2[i]){
    if(ignorecase){
     int c1 = toupper(p1[i]);
     int c2 = toupper(p2[i]);
     if(c1 != c2)
      return p1[i]-p2[i];
    }
    return p1[i]-p2[i];
   }
  }
  return 0;
 }

 /* ignorecase = TRUE : ignore CASE SENSITIVE */
 int find(_Ty* str,int startpos,int len,int *lpelementindex,int ignorecase = 0,int ignorenull = 1){
  int size  = getsize();
  int offset = startpos;
  int findlen = len;
  int elementindex = 0;
  if(findlen <= 0)
   findlen = (int)_tcslen((LPCSTR)str);
  if(lpelementindex) *lpelementindex = -1;
  _Ty* p;
  while(offset < size){
   p = getbuffer(offset);
   int remainlen = size - offset;
   if(remainlen < findlen)
    return -1;
   if(!kxmemcmp(str,p,findlen,ignorecase,ignorenull)){
    if(lpelementindex) *lpelementindex = elementindex;
    return offset;
   }
   offset += m_element_size;
   elementindex ++;
  }
  return -1;
 }

 int getsize()  const { return m_offset; }
 int getblkcount()   { return (m_blksize/KXBUFF_BLOCKSIZE); }
 int getblksize()    { return m_blksize; }
 _Ty* getbuffer(int offset = 0)  { return m_buff == NULL ? NULL : (_Ty*)((_Ty*)m_buff + offset); }
 int isbigmode()     { return ((m_hFile == INVALID_HANDLE_VALUE ) ? false : true);}
};

////////////////////////////////////////////////////////////////////////////////
// List Buff
template < class _Ty>
class kxList : public kxBuff<_Ty>/*like CPtrArray*/
{
public:
 kxList(){
  m_element_size = sizeof(_Ty);
  KXBUFF_BLOCKSIZE = m_element_size * 2;
 }
 ~kxList(){}
 virtual int find(_Ty data,int *lpelementindex = 0,int comparesize = 0){/* return offset,lpindex is list index*/
  int size  = kxBuff::getsize();
  int compsize = (comparesize > 0) ? comparesize :m_element_size;
  return kxBuff::find(&data,0,compsize,lpelementindex);
 }

 virtual int add(_Ty data){
  return kxBuff::add(&data,m_element_size);
 }

 //virtual int addlen(_Ty data,int len)
 //{
 // return m_list.add(&data,len);
 //}
 virtual int addlen(LPVOID data,int len){
  return kxBuff::add(data,len);
 }

 _Ty * get(int offset){
  if(!isvalidoffset(offset))
   return NULL;
  _Ty * p = (LPVOID)kxBuff::getbuffer(offset);
  return p;
 }

 _Ty getat(int index,int *lpoffset = 0){
  int size   = getsize();
  int offset = index * m_element_size;
  if(lpoffset) *lpoffset = -1;
  if(isvalidoffset(offset)){
   LPVOID p = (LPVOID)kxBuff::getbuffer(offset);
   if(lpoffset) *lpoffset = offset;
   _Ty rv = *(_Ty *)p;
   return rv;
  }
  return NULL;
 }
 virtual void insertat(int index,_Ty data){
  int size   = getsize();
  int offset = (index + 1) * m_element_size;
  if(!isvalidoffset(offset)){
   resize(offset);
   offset = index * m_element_size;
   LPVOID p = (LPVOID)kxBuff::getbuffer(offset);
   memcpy(p,&data,m_element_size);
  }
  else{
   resize(size + m_element_size);
   LPVOID p = (LPVOID)kxBuff::getbuffer((index + 1) * m_element_size);
   LPVOID q = (LPVOID)kxBuff::getbuffer((index) * m_element_size);

   memmove(p,q,size-m_element_size);
   memset(q, 0, m_element_size);
   memcpy(q,&data,m_element_size);
  }
 }

 virtual void setat(int index,_Ty data){
  int size   = getsize();
  int offset = index * m_element_size;
  if(isvalidoffset(offset)){
   LPVOID p = (LPVOID)kxBuff::getbuffer(offset);
   memcpy(p,&data,m_element_size);
  }
 }

 virtual void removeoffset(int offset){
  int size  = getsize();
  LPVOID p = (LPVOID)kxBuff::getbuffer(offset);
  if(offset + m_element_size <= size){
   memcpy(p,(char *)p + m_element_size,size - (offset + m_element_size));
  }
  kxBuff::resize(size - m_element_size);
 }
 virtual void removeat(int index){
  int offset = -1;
  int size  = getsize();
  getat(index,&offset);/*no LPSTR checking for including NULL*/
  if(isvalidoffset(offset)) /*found*/
   removeoffset(offset);         
 }
 virtual void removeall(){
  kxBuff::reset();
 }
 virtual int getcount(){ /*number of index elements*/
  return getsize() / m_element_size;
 }
 _Ty operator[](int nIndex)
 {
  return getat(nIndex);
 }
};

//메모리 한 주소에 연속적으로  들어가는 linear string list
template < class _Ty>
class kxListString : public kxBuff<_Ty>
{
public:
 kxListString()
 {
  KXBUFF_BLOCKSIZE = 512;
 }
 ~kxListString(){}
 virtual BOOL isvalidoffset(int offset){
  if(!kxBuff::isvalidoffset(offset))
   return false;

  if(offset > 0){
   CHAR *p = (CHAR *)kxBuff::getbuffer(offset - 1);
   if(p != NULL) return false;
  }
  return true;
 }
 /* insensitive = TRUE : ignore CASE SENSITIVE */
 virtual int find(LPTSTR str,int *lpelementindex,int ignorecase = 0){/* return offset,lpindex is list index*/
  int size  = kxBuff::getsize();
  int offset = 0;
  int elementindex   = 0;
  int findlen = (int)_tcslen(str);
  TCHAR *p;
  if(lpelementindex) *lpelementindex = -1;
  while(offset < size){
   p = (TCHAR *)kxBuff::getbuffer(offset);
   if(!kxmemcmp(p,str,findlen,ignorecase,0)){
    if(lpelementindex) *lpelementindex = elementindex;
    return offset;
   }
   int len = (int)_tcslen(p);//null다음으로
   offset += (len + 1);
   elementindex ++;
  }
  return -1;
 }
 LPTSTR operator[](int index)
 {
  return getat(index);
 }
 virtual LPTSTR getat(int index,int *lpoffset = 0){
  int size  = kxBuff::getsize();
  int offset = 0;
  int ipos   = 0;
  TCHAR *p;
  if(lpoffset) *lpoffset = -1;
  while(offset < size){
   p = (TCHAR *)kxBuff::getbuffer(offset);
   if(index == ipos){
    if(lpoffset) *lpoffset = offset;
    return p;
   }
   int len = (int)_tcslen(p) + 1;
   offset +=  len;
   ipos ++;
  }
  return NULL;
 }

 virtual int addforce(LPTSTR str){ /*no find action,force add like list*/
  int len = (str == NULL )? 1:((int)_tcslen(str) + 1);
  return kxBuff::add(str,len);
 }
 virtual int add(LPTSTR str,int insensitive = 0){
  int offset  = find(str,NULL,insensitive);
  if(offset >= 0 && insensitive > -1 )
   return offset; /*insensitive = -1 to force add without compare */
  int len = (str == NULL )? 1:((int)_tcslen(str) + 1);
  return kxBuff::add(str,len);
 }
 virtual int addlen(_Ty* data,int len)
 {
  return kxBuff::add(data,len);
 }

 virtual void removeoffset(int offset)
 {
  int size  = kxBuff::getsize();
  TCHAR *p = (TCHAR *)kxBuff::getbuffer(offset);
  int len = (int)_tcslen(p) + 1;
  if(offset + len < size)
   memcpy(p,p + len,size - (offset + len));
  kxBuff::resize(size - len);
 }
 virtual void removeat(int index)
 {
  int offset = -1;
  getat(index,&offset);/*no LPSTR checking for including NULL*/
  if(isvalidoffset(offset)) /*found*/
   removeoffset(offset);         
 }
 virtual int getcount() /*number of index elements*/
 {
  int size  = kxBuff::getsize();
  int offset= 0;
  int index = 0;
  TCHAR *p;
  while(offset < size){
   p = (TCHAR *)kxBuff::getbuffer(offset);
   int len = (int)_tcslen(p) + 1;
   offset +=  len;
   index ++;
  }
  return index;
 }
 virtual TCHAR *GetBuffer(int offset = 0){
  return (TCHAR *)kxBuff::getbuffer(offset);
 }
 virtual void removeall(){kxBuff::reset();}
};

/*
mystr is clone class for action like MFC CString using non MFC Project fluent string management.
2006.03.18 KRKIM.

Usage mystr example

mystr text,text2;
text = "test text";
text2 = text;
LPCSTR sztext = text;

*/
class kxString : public kxBuff<CHAR>
{
public:
 kxString(){
  KXBUFF_BLOCKSIZE = sizeof(CHAR) * 2;/*bugfix*/
 }
 ~kxString(){
 }
 inline kxString(LPCTSTR pszString){
  KXBUFF_BLOCKSIZE = sizeof(CHAR) * 2;/*bugfix*/
  Set(pszString);
 }
 inline kxString(const kxString & strSrc){
  KXBUFF_BLOCKSIZE = sizeof(CHAR) * 2;/*bugfix*/
  Set((LPCTSTR)strSrc.GetBuffer());
 }
 inline kxString(TCHAR ch, int nRepeat = 1)
 {
  if (nRepeat >= 1){
   resize(nRepeat);
   memset(GetBuffer(), ch, nRepeat);
  }
 }
public:
 LPCTSTR cstr(){
  return (LPCTSTR)GetBuffer();
 }
 LPTSTR str(){
  return (LPTSTR)GetBuffer();
 }
 LPCTSTR Get(int pos = 0){
  return (LPCTSTR)kxBuff::getbuffer(pos);
 }
 void Set(LPCTSTR pszString,int len = -1){
  if(!pszString) return;
  if(len == -1)
   len = (int)_tcslen(pszString);
  kxBuff::reset();
  if(!pszString) return;
  kxBuff::add(pszString,len);
 }
 void SetLength(int len){//버퍼를 주어진 길이로 맞춤,뒷부분자를때유용
  kxBuff::resize(len);
  addstr("");
 }

 void Append(LPCTSTR pszString){
  kxBuff::addstr((LPTSTR)pszString);
 }

 void Delete(){
  kxBuff::reset();
 }

 void Format(LPCTSTR pszFormat,...){
  va_list arglist;
  va_start(arglist,pszFormat);
  FormatV((LPCSTR)pszFormat, arglist );
  va_end(arglist);
 }

 void FormatV(LPCSTR pszFormat, va_list args){
  int nLength = 4096;//_vscprintf( pszFormat, args );
  //nLength = _vscprintf( pszFormat, args );
  LPTSTR pszBuffer = (LPTSTR)malloc(nLength + 1);
  if(!pszBuffer) return;
  *(pszBuffer+nLength) = 0x00;
  //int l = STRSAFE_MAX_CCH * sizeof(TCHAR);
  //vsprintf((LPSTR)pszBuffer, pszFormat, args );
  vsnprintf((LPSTR)pszBuffer,nLength, pszFormat, args);
  kxBuff::reset();
  kxBuff::add(pszBuffer,nLength);
  free(pszBuffer);
 }
 TCHAR operator[](int offset) const
 {
  return (TCHAR)*(m_buff + offset);
 }
 operator LPCTSTR() const throw(){
  return (LPCTSTR)GetBuffer();
 }

 //operator LPSTR() const throw(){
 // return (LPSTR)kxBuff::LPTSTR();
 //}
 operator LPTSTR() const throw(){
  return (LPTSTR)GetBuffer();
 }

 //LPTSTR operator&() throw()
 //{
 // return (LPTSTR)GetBuffer();
 //}

 // Assignment operators
 kxString& operator=(LPTSTR pszString){
  Set((LPCTSTR)pszString);
  return (*this);
 }

 kxString& operator=(LPCTSTR pszString){
  Set(pszString);
  return (*this);
 }

 const kxString& operator=(const unsigned char * pszString){
  Set((LPCTSTR)pszString);
  return (*this);
 }

 LPTSTR GetBuffer(int pos = 0) const throw(){
  return (reinterpret_cast<LPTSTR>(kxBuff::getdata(pos)));
 }

 kxString& operator=(const kxString& strSrc){
  LPCTSTR pSrc = (LPCTSTR)strSrc.GetBuffer();
  LPCTSTR pOld = GetBuffer();
  if(pSrc != pOld)
   Set(pSrc);
  return (*this);
 }

 friend bool operator==(const kxString& str1, LPCTSTR psz2) throw(){
  return (str1.Compare((LPTSTR)psz2) == 0);
 }

 friend bool operator==( const kxString& str1, const kxString& str2) throw(){
  return (str1.Compare((LPTSTR)str2.GetBuffer()) == 0 );
 }

 friend bool operator!=(const kxString& str1, const kxString& str2) throw(){
  return (str1.Compare((LPTSTR)str2.GetBuffer()) != 0 );
 }

 friend bool operator!=(const kxString& str1, LPCTSTR psz2) throw(){
  return (str1.Compare((LPTSTR) psz2 ) != 0);
 }

 friend bool operator!=(const kxString& str1, LPTSTR psz2) throw(){
  return (str1.Compare((LPTSTR) psz2 ) != 0);
 }

 BOOL operator==( const kxString& str1)
 {
  return (Compare((LPTSTR)str1.GetBuffer()) == 0);
 }
 BOOL operator==( LPCTSTR psz1)
 {
  return (Compare((LPTSTR)psz1) == 0);
 }
 BOOL operator!=(const kxString& str1)
 {
  return (Compare((LPTSTR)str1.GetBuffer()) != 0 );
 }
 BOOL operator!=( LPCTSTR psz1)
 {
  return (Compare((LPTSTR) psz1) != 0);
 }
 inline const kxString& operator += (const kxString& strSrc){
  LPCTSTR pSrc = strSrc.GetBuffer();
  Append(pSrc);
  return (*this);
 }

 friend kxString operator+(const kxString& pszSrc1, const kxString& pszSrc2){
  kxString strResult = pszSrc1;
  strResult.Append(pszSrc2);
  return strResult;
 }

 friend kxString operator+(LPCTSTR pszSrc1, const kxString& pszSrc2){
  kxString strResult = pszSrc1;
  strResult.Append(pszSrc2);
  return strResult;
 }
 friend kxString operator+(const kxString& pszSrc1, LPCTSTR pszSrc2){
  kxString strResult = pszSrc1;
  strResult.Append(pszSrc2);
  return strResult;
 }
 
 kxString& operator+=(LPTSTR pszSrc)
 {
  Append(pszSrc);
  return (*this);
 }
 kxString& operator+=(LPCTSTR pszSrc)
 {
  Append(pszSrc);
  return (*this);
 }
 const kxString& operator+=(TCHAR ch)
 {
  ASSERT( ch != _T( '\0' ));
  int nLen = GetLength();
  resize( nLen + 1);
  *GetBuffer(nLen) = ch;
  return *this;
 }
 
 inline int Compare(LPTSTR pszString,int ignorecase = 0) const
 {
  LPCTSTR psz = GetBuffer();
  if(psz == NULL && pszString == NULL) return 0;
  if(psz == NULL && pszString)         return 1;
  if(psz && pszString == NULL)         return -1;
  if(*psz && *pszString == NULL) return -1;
  if(*psz == NULL && *pszString) return 1;
  if(*psz == NULL && *pszString == NULL) return 0;

  //return _tcscmp(pOld,(LPCTSTR)pszString);
  int complen = (int)_tcslen(pszString);
  int mylen = (int)_tcslen(psz);
  if(mylen != complen)
   return complen - mylen;
  return kxBuff::kxmemcmp((LPCVOID)psz,(LPCVOID)pszString,complen,0,1);
 }

 inline int CompareNoCase(LPTSTR pszString) const
 {
  return Compare(pszString,1);
 }
 LPTSTR GetString(){ return GetBuffer(); }
 int GetLength() const{ return kxBuff::getsize();}
 BOOL IsEmpty() const{ return(GetLength() < 1 || !*GetBuffer());}

 BOOL OemToAnsi(){
  int nLength = GetLength();
  LPTSTR pszBuffer = GetBuffer();
  BOOL fSuccess=::OemToCharBuff(pszBuffer, pszBuffer, nLength);
  return fSuccess;
 }
 BOOL AnsiToOem(){
  int nLength = GetLength();
  LPTSTR pszBuffer = GetBuffer();
  BOOL fSuccess=::CharToOemBuffA(pszBuffer, pszBuffer, nLength);
  return fSuccess;
 }

 int FindString(LPCTSTR szFind,BOOL ignorecase = 0){
  //if(!m_buff) return -1;
  //if(szFind == NULL) return -1;
  //LPTSTR find = _tcsstr(m_buff,szFind);
  //if(!find) return -1;
  //return (int)(find - m_buff);
  int compsize = (int)_tcslen(szFind);
  return kxBuff::find((CHAR*)szFind,0,compsize,0,ignorecase,0);
 }

 int FindChar(TCHAR ch,BOOL bReverse = FALSE){
  LPTSTR buff = GetBuffer();
 
  if(!buff) return -1;
  LPCTSTR find;
  find = (bReverse) ? _tcsrchr(buff,ch) : _tcschr(buff,ch);
  if(!find) return -1;
  return (int)(find - buff);
 }

 // Replace all occurrences of character 'chOld' with character 'chNew'
 int Replace(CHAR chOld,CHAR chNew){
  int nCount = 0;
  LPTSTR psz = GetBuffer();
  while(psz && *psz){
   if(*psz == chOld){
    *psz = chNew;
    nCount++;
   }
   psz++;
  }
  return (nCount);
 }
 inline BOOL IsSpace(TCHAR ch)
 {
  switch (ch)
  {
   case _T(' '):
   case _T('\t'):
   case _T('\r'):
   case _T('\n'):
     return TRUE;
  }

  return FALSE;
 }
 kxString &TrimLeft(){
  LPTSTR pszLeft = GetBuffer();
  while(pszLeft && IsSpace(*pszLeft))
   pszLeft = CharNext(pszLeft);
  LPTSTR pszBuffer = GetString();
  if(pszLeft != pszBuffer){
   int iFirst = int(pszLeft - pszBuffer);
   int nDataLength = GetLength()-iFirst;
   Set(pszLeft,nDataLength);
  }
  return (*this);
 }

 kxString &TrimRight(){
  // find beginning of trailing spaces by starting
  // at beginning (DBCS aware)

  LPTSTR psz = GetString();
  LPTSTR pszLast = NULL;
  while(*psz != 0){
   if(IsSpace(*psz)){
    if(pszLast == NULL)
     pszLast = psz;
   }
   else
    pszLast = NULL;
   psz = CharNext(psz);
  }
  if(pszLast != NULL){
   // truncate at trailing space start
   int iLast = int(pszLast-GetString());
   SetLength(iLast);
  }
  return (*this);
 }

 kxString &Trim(){
  return(TrimRight().TrimLeft());
 }
 void LoadString(HINSTANCE hInst,int nID)
 {
  resize(256);
  ::LoadString(hInst, nID,GetBuffer(), 256);
 }

 kxString Mid(int nFirst, int nCount)
 {
  kxString lpMid;
  if (nFirst <0) nFirst=0;
  if(nCount ==0) nCount=GetLength();
  if (nCount > (GetLength()-nFirst) ) nCount =GetLength()-nFirst;
  lpMid.SetLength( nCount );
  _tcsncpy( lpMid.GetBuffer(), GetBuffer(nFirst), nCount );
  return lpMid;
 }

 kxString Mid(int nFirst)
 {
  return Mid(nFirst);
 }

 kxString Left(int nCount)
 {
  ASSERT( nCount <= GetLength());
  kxString cdest;
  cdest.SetLength(nCount);
  _tcsncpy( cdest.GetBuffer(), GetBuffer(), nCount );
  return cdest;
 }

 kxString Right(int nCount)
 {
  ASSERT( nCount <= GetLength());
  kxString cdest;
  cdest.SetLength(nCount);
  _tcsncpy( cdest.GetBuffer(), GetBuffer(GetLength()-nCount), nCount );
  return cdest;
 }
 void MakeUpper()
 {
  _tcsupr(GetBuffer());
 }
 void MakeLower()
 {
  _tcslwr(GetBuffer());
 }

 //TODO:: ReverseFind,ReplaceText
};

}

using namespace kxBuffLib;

#endif
#pragma warning (pop)


Update Info::

2011.01.26

bugfix in resize() ,1바이트짜리 데이타 추가시 버퍼오버런 발생 오류 수정

if(size > m_blksize) ==> if(size >= m_blksize)


NEW VERSION