finally, I finished the patch for both unicode build and ansi build.
I also find why unicode build so unstable for me.
There are 3 new operator to allocate memory, the size just rtfstr.GetLength() + 5, but for T2CA(rtfstr), the size may large than the length of rtfstr. So I change the code here as
After that, the unicode build work fine for me now.
here is the patch, I've test under Chinese Windows XP, it work for me for both unicode and ansi version.
Code: Select all
diff -Nur source.orig\FtpControlSocket.cpp source.patched\FtpControlSocket.cpp
--- source.orig\FtpControlSocket.cpp Sat Jan 15 19:46:52 2005
+++ source.patched\FtpControlSocket.cpp Sun Feb 27 20:31:06 2005
@@ -146,6 +146,8 @@
m_useZlib = false;
m_zlibSupported = false;
m_zlibLevel = 8;
+
+ m_bUTF8 = false;
}
CFtpControlSocket::~CFtpControlSocket()
@@ -459,7 +461,7 @@
m_Operation.nOpState == CONNECT_GSS_NEEDPASS ||
m_Operation.nOpState == CONNECT_GSS_NEEDUSER)
{
- if (!m_RecvBuffer.empty() && m_RecvBuffer.front() != _T(""))
+ if (!m_RecvBuffer.empty() && m_RecvBuffer.front() != "")
{
//Incoming reply from server during async is not allowed
DoClose();
@@ -474,7 +476,7 @@
}
else if (m_Operation.nOpState == CONNECT_SYST)
{
- if (GetReplyCode() == 2 && m_RecvBuffer.front().GetLength() > 7 && m_RecvBuffer.front().Mid(3, 4) == _T(" MVS"))
+ if (GetReplyCode() == 2 && m_RecvBuffer.front().GetLength() > 7 && m_RecvBuffer.front().Mid(3, 4) == " MVS")
{
if (m_CurrentServer.nServerType & FZ_SERVERTYPE_FTP)
m_CurrentServer.nServerType |= FZ_SERVERTYPE_SUB_FTP_MVS;
@@ -552,8 +554,10 @@
{ // authentication succeeded, we're now get the response to the CWD command
if (GetReplyCode() == 2) // we're logged on
{
- if (Send("FEAT"))
+ if (Send("FEAT")) {
+ m_bUTF8 = false;
m_Operation.nOpState = CONNECT_FEAT;
+ }
return;
}
else
@@ -581,8 +585,10 @@
DoClose();
return;
case LO: //LO means we are logged on
- if (Send("FEAT"))
+ if (Send("FEAT")) {
+ m_bUTF8 = false;
m_Operation.nOpState = CONNECT_FEAT;
+ }
return;
}
}
@@ -659,6 +665,7 @@
temp="PASS "+m_CurrentServer.pass+"@"+CCrypt::decrypt(COptions::GetOption(OPTION_FWPASS));
break;
}
+ m_bUTF8 = false;
// send command, get response
if(!Send(temp))
return;
@@ -679,7 +686,7 @@
LogMessage(__FILE__, __LINE__, this,FZ_LOG_INFO, _T("Socket has been closed, don't process receive") );
return;
}
- m_MultiLine=_T("");
+ m_MultiLine="";
CString str;
str.Format(IDS_STATUSMSG_CONNECTEDWITH, m_ServerName);
ShowStatus(str,0);
@@ -694,13 +701,25 @@
{
if ((buffer[i]=='\r')||(buffer[i]=='\n')||(buffer[i]==0))
{
- if (!m_RecvBuffer.empty() && m_RecvBuffer.back()!=_T("") )
+ if (!m_RecvBuffer.empty() && m_RecvBuffer.back()!="" )
{
- ShowStatus(m_RecvBuffer.back(), 3);
+ if (m_bUTF8) {
+ // convert from UTF-8 to ANSI
+ int len = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)m_RecvBuffer.back(), -1, NULL, 0);
+ char *p1 = new char[len * 2 + 1];
+ char *p2 = new char[len * 2 + 1];
+ MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)m_RecvBuffer.back(), -1 , (LPWSTR)p1, len*2);
+ WideCharToMultiByte(CP_ACP, 0,(LPCWSTR)p1, -1, p2, len*2, NULL, NULL);
+ m_RecvBuffer.back() = p2;
+ delete [] p1;
+ delete [] p2;
+ }
+ CString temp_str = m_RecvBuffer.back();
+ ShowStatus(temp_str, 3);
//Check for multi-line responses
if (m_RecvBuffer.back().GetLength()>3)
{
- if (m_MultiLine != _T(""))
+ if (m_MultiLine != "")
{
if (m_RecvBuffer.back().Left(4) != m_MultiLine)
{
@@ -709,7 +728,7 @@
}
else // end of multi-line found
{
- m_MultiLine = _T("");
+ m_MultiLine = "";
m_pOwner->PostThreadMessage(m_pOwner->m_nInternalMessageID,FZAPI_THREADMSG_PROCESSREPLY,0);
}
}
@@ -725,7 +744,7 @@
}
else
m_RecvBuffer.pop_back();
- m_RecvBuffer.push_back(_T(""));
+ m_RecvBuffer.push_back("");
}
}
else
@@ -733,7 +752,7 @@
//The command may only be 2000 chars long. This ensures that a malicious user can't
//send extremely large commands to fill the memory of the server
if (m_RecvBuffer.empty())
- m_RecvBuffer.push_back(_T(""));
+ m_RecvBuffer.push_back("");
if (m_RecvBuffer.back().GetLength()<2000)
m_RecvBuffer.back()+=buffer[i];
}
@@ -811,7 +830,7 @@
{
if (!m_pOwner->IsConnected())
{
- m_MultiLine=_T("");
+ m_MultiLine="";
m_pOwner->SetConnected(TRUE);
CString str;
str.Format(m_pSslLayer ? IDS_STATUSMSG_CONNECTEDWITHSSL : IDS_STATUSMSG_CONNECTEDWITH, m_ServerName);
@@ -832,8 +851,36 @@
ShowStatus(str,2);
str+="\r\n";
- LPCSTR lpszAsciiSend=T2CA(str);
- int res = CAsyncSocketEx::Send(lpszAsciiSend,strlen(lpszAsciiSend));
+ int res;
+ if (m_bUTF8) {
+#if defined(_UNICODE)
+ // Convert unicode to ascii first
+ LPCSTR lpszAsciiSend=T2CA(str);
+ // Convert Unicode to UTF-8
+ int len = MultiByteToWideChar(CP_ACP, 0, lpszAsciiSend, -1, NULL, 0);
+ char *p1 = new char[len * 2 + 1];
+ char *p2 = new char[len * 2 + 1];
+ MultiByteToWideChar(CP_ACP, 0, lpszAsciiSend, -1 , (LPWSTR)p1, len*2);
+ WideCharToMultiByte(CP_UTF8, 0,(LPCWSTR)p1, -1, p2, len*2, NULL, NULL);
+ res = CAsyncSocketEx::Send(p2, strlen(p2));
+ delete [] p1;
+ delete [] p2;
+#else
+ // Convert ANSI to UTF-8
+ int len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
+ char *p1 = new char[len * 2 + 1];
+ char *p2 = new char[len * 2 + 1];
+ MultiByteToWideChar(CP_ACP, 0, str, -1 , (LPWSTR)p1, len*2);
+ WideCharToMultiByte(CP_UTF8, 0,(LPCWSTR)p1, -1, p2, len*2, NULL, NULL);
+ res = CAsyncSocketEx::Send(p2, strlen(p2));
+ delete [] p1;
+ delete [] p2;
+#endif
+ }
+ else {
+ LPCSTR lpszAsciiSend=T2CA(str);
+ res = CAsyncSocketEx::Send(lpszAsciiSend,strlen(lpszAsciiSend));
+ }
if (!res)
{
if (GetLastError()!=WSAEWOULDBLOCK)
@@ -878,6 +925,8 @@
m_zlibSupported = false;
m_zlibLevel = 0;
+ m_bUTF8 = false;
+
CControlSocket::Close();
}
@@ -2075,9 +2124,9 @@
{
int res=GetReplyCode();
if (res == 2 || res == 3 || //Creation successful
- m_RecvBuffer.front()==_T("550 Directory already exists") )//Creation was successful, although someone else did the work for us
+ m_RecvBuffer.front()=="550 Directory already exists" )//Creation was successful, although someone else did the work for us
{
- if (m_RecvBuffer.front()==_T("550 Directory already exists") )
+ if (m_RecvBuffer.front()=="550 Directory already exists" )
printf("OK");
CServerPath path2=pData->MKDCurrent;
if (path2.HasParent())
@@ -2204,8 +2253,9 @@
}
CServerPath path;
+ CString temp_str = m_RecvBuffer.front().Mid(pos1+1,pos2-pos1-1);
path.SetServer(m_CurrentServer);
- if (!path.SetPath(m_RecvBuffer.front().Mid(pos1+1,pos2-pos1-1)))
+ if (!path.SetPath(temp_str))
{
LogMessage(__FILE__, __LINE__, this, FZ_LOG_WARNING, _T("Can't parse path, CServerPath::SetPath() failed."));
nReplyError = FZ_REPLY_ERROR;
@@ -2297,8 +2347,8 @@
if (pData->bPasv)
{
- int i=m_RecvBuffer.front().Find( _T("(") );
- int j=j=m_RecvBuffer.front().Find( _T(")") );
+ int i=m_RecvBuffer.front().Find( "(" );
+ int j=j=m_RecvBuffer.front().Find( ")" );
// extract connect port number and IP from string returned by server
if (i==-1 || j==-1 || (i+11)>=j)
{
@@ -2400,7 +2450,7 @@
m_Operation.nOpState=FILETRANSFER_LIST_LIST;
break;
case FILETRANSFER_LIST_LIST:
- if (!m_RecvBuffer.front().CompareNoCase(_T("550 No members found.")) && (m_CurrentServer.nServerType & FZ_SERVERTYPE_SUB_FTP_MVS))
+ if (!m_RecvBuffer.front().CompareNoCase("550 No members found.") && (m_CurrentServer.nServerType & FZ_SERVERTYPE_SUB_FTP_MVS))
{
ShowStatus(IDS_STATUSMSG_DIRLISTSUCCESSFUL, 0);
@@ -2610,8 +2660,8 @@
{
if (pData->bPasv)
{
- int i=m_RecvBuffer.front().Find( _T("(") );
- int j=j=m_RecvBuffer.front().Find( _T(")") );
+ int i=m_RecvBuffer.front().Find( "(" );
+ int j=j=m_RecvBuffer.front().Find( ")" );
// extract connect port number and IP from string returned by server
if(i==-1 || j==-1 || (GetFamily() == AF_INET && (i+11) >= j))
{
@@ -4269,7 +4319,7 @@
CMakeDirData *pData=(CMakeDirData *)m_Operation.pData;
int res=GetReplyCode();
if (res==2 || res==3 || //Creation successful
- m_RecvBuffer.front()==_T("550 Directory already exists") )//Creation was successful, although someone else did the work for us
+ m_RecvBuffer.front()=="550 Directory already exists" )//Creation was successful, although someone else did the work for us
{ //Create dir entry in parent dir
CServerPath path2=pData->Current;
if (path2.HasParent())
@@ -4637,7 +4687,7 @@
case FZ_ASYNCREQUEST_GSS_AUTHFAILED:
if (m_Operation.nOpMode!=CSMODE_CONNECT || m_Operation.nOpState!=CONNECT_GSS_FAILED)
break;
- if (!m_RecvBuffer.empty() && m_RecvBuffer.front()!= _T(""))
+ if (!m_RecvBuffer.empty() && m_RecvBuffer.front()!= "")
{
DoClose();
break;
@@ -4868,13 +4918,16 @@
return TRUE;
}
-void CFtpControlSocket::DiscardLine(CString line)
+void CFtpControlSocket::DiscardLine(CStringA line)
{
if (m_Operation.nOpMode == CSMODE_CONNECT && m_Operation.nOpState == CONNECT_FEAT)
{
line.MakeUpper();
- if (line == _T(" MODE Z") || line.Left(8) == _T(" MODE Z "))
+ if (line == " MODE Z" || line.Left(8) == " MODE Z ")
m_zlibSupported = true;
+ if (line == " UTF8" || line.Left(8) == " UTF8 ") {
+ m_bUTF8 = true;
+ }
}
}
diff -Nur source.orig\FtpControlSocket.h source.patched\FtpControlSocket.h
--- source.orig\FtpControlSocket.h Mon Jun 07 22:59:10 2004
+++ source.patched\FtpControlSocket.h Sun Feb 27 17:10:18 2005
@@ -110,17 +110,17 @@
BOOL ParsePwdReply(CString reply);
- void DiscardLine(CString line);
+ void DiscardLine(CStringA line);
bool NeedModeCommand();
bool NeedOptsCommand();
CFile *m_pDataFile;
CTransferSocket *m_pTransferSocket;
- CString m_MultiLine;
+ CStringA m_MultiLine;
CTime m_LastSendTime;
CString m_ServerName;
- std::list<CString> m_RecvBuffer;
+ std::list<CStringA> m_RecvBuffer;
CTime m_LastRecvTime;
class CListData;
class CFileTransferData;
@@ -129,6 +129,8 @@
bool m_useZlib;
bool m_zlibSupported;
int m_zlibLevel;
+
+ bool m_bUTF8;
private:
BOOL m_bCheckForTimeout;
diff -Nur source.orig\FtpListResult.cpp source.patched\FtpListResult.cpp
--- source.orig\FtpListResult.cpp Sun Feb 27 00:35:57 2005
+++ source.patched\FtpListResult.cpp Sun Feb 27 21:04:21 2005
@@ -142,11 +142,12 @@
#endif
-CFtpListResult::CFtpListResult(t_server server)
+CFtpListResult::CFtpListResult(t_server server, bool bUTF8)
{
listhead=curpos=0;
m_server = server;
+ m_bUTF8 = bUTF8;
pos=0;
@@ -369,8 +370,23 @@
while (line)
{
int tmp;
- char *tmpline=new char[strlen(line)+1];
- strcpy(tmpline, line);
+ char *tmpline;
+
+ if (m_bUTF8) {
+ // convert from UTF-8 to ANSI
+ int len = MultiByteToWideChar(CP_UTF8, 0, line, -1, NULL, 0);
+ char *p1 = new char[len * 2 + 1];
+ char *p2 = new char[len * 2 + 1];
+ MultiByteToWideChar(CP_UTF8, 0, line, -1 , (LPWSTR)p1, len*2);
+ WideCharToMultiByte(CP_ACP, 0,(LPCWSTR)p1, -1, p2, len*2, NULL, NULL);
+ tmpline = p2;
+ delete [] p1;
+ //delete [] p2;
+ }
+ else {
+ tmpline=new char[strlen(line)+1];
+ strcpy(tmpline, line);
+ }
if (parseLine(tmpline, strlen(tmpline), direntry, tmp))
{
delete [] tmpline;
@@ -541,8 +557,23 @@
break;
}
int tmp;
- char *tmpline = new char[strlen(line)+1];
- strcpy(tmpline, line);
+ char *tmpline;
+
+ if (m_bUTF8) {
+ // convert from UTF-8 to ANSI
+ int len = MultiByteToWideChar(CP_UTF8, 0, line, -1, NULL, 0);
+ char *p1 = new char[len * 2 + 1];
+ char *p2 = new char[len * 2 + 1];
+ MultiByteToWideChar(CP_UTF8, 0, line, -1 , (LPWSTR)p1, len*2);
+ WideCharToMultiByte(CP_ACP, 0,(LPCWSTR)p1, -1, p2, len*2, NULL, NULL);
+ tmpline = p2;
+ delete [] p1;
+ //delete [] p2;
+ }
+ else {
+ tmpline=new char[strlen(line)+1];
+ strcpy(tmpline, line);
+ }
if (parseLine(tmpline, strlen(tmpline), direntry, tmp))
{
delete [] tmpline;
@@ -2129,12 +2160,31 @@
void CFtpListResult::copyStr(CString &target, int pos, const char *source, int len) const
{
+#if defined(_UNICODE)
+ if (pos != 0) {
+ int i;
+ LPTSTR pBuffer = target.GetBuffer(pos + len);
+ ASSERT(pBuffer);
+ for (i = 0; i < len; i++)
+ pBuffer[pos + i] = source[i];
+ target.ReleaseBuffer(pos + len);
+ }
+ else {
+ USES_CONVERSION;
+ char *p = new char[len+1];
+ memcpy(p, source, len);
+ p[len] = '\0';
+ target = A2CT(p);
+ delete [] p;
+ }
+#else
int i;
LPTSTR pBuffer = target.GetBuffer(pos + len);
ASSERT(pBuffer);
for (i = 0; i < len; i++)
pBuffer[pos + i] = source[i];
target.ReleaseBuffer(pos + len);
+#endif
}
BOOL CFtpListResult::parseAsIBM(const char *line, const int linelen, t_directory::t_direntry &direntry)
diff -Nur source.orig\FtpListResult.h source.patched\FtpListResult.h
--- source.orig\FtpListResult.h Fri Jan 14 14:50:46 2005
+++ source.patched\FtpListResult.h Sun Feb 27 00:16:17 2005
@@ -55,9 +55,10 @@
{
public:
t_server m_server;
+ bool m_bUTF8;
void SendToMessageLog(HWND hWnd, UINT nMsg);
void AddData(char *data,int size);
- CFtpListResult(t_server server);
+ CFtpListResult(t_server server, bool bUTF8 = false);
~CFtpListResult();
t_directory::t_direntry *getList(int &num, CTime EntryTime);
diff -Nur source.orig\StatusCtrl.cpp source.patched\StatusCtrl.cpp
--- source.orig\StatusCtrl.cpp Wed Oct 27 16:18:18 2004
+++ source.patched\StatusCtrl.cpp Sun Feb 27 20:54:51 2005
@@ -135,7 +135,7 @@
rtfstr += "} ";
- char *buffer = new char[rtfstr.GetLength() + 5];
+ char *buffer = new char[rtfstr.GetLength()*2 + 5];
strcpy(buffer + 4, T2CA(rtfstr));
*(int *)buffer = 0;
@@ -279,7 +279,7 @@
CString rtfstr = m_RTFHeader;
rtfstr += "} ";
- char *buffer = new char[rtfstr.GetLength() + 5];
+ char *buffer = new char[rtfstr.GetLength()*2 + 5];
strcpy(buffer + 4, T2CA(rtfstr));
*(int *)buffer = 0;
@@ -324,7 +324,7 @@
__time64_t t = _time64(0);
if (!strftime(buf, 100, "[%H:%M:%S] ", _localtime64(&t)))
buf[0] = 0;
- CString stime = A2CT(buf);
+ stime = A2CT(buf);
}
CString str;
@@ -371,7 +371,7 @@
rtfstr += "} ";
- char *buffer = new char[rtfstr.GetLength() + 5]; //Make it large enough to hold unicode data
+ char *buffer = new char[rtfstr.GetLength()*2 + 5]; //Make it large enough to hold unicode data
strcpy(buffer + 4, T2CA(rtfstr));
*(int *)buffer = 0;
diff -Nur source.orig\TransferSocket.cpp source.patched\TransferSocket.cpp
--- source.orig\TransferSocket.cpp Sun Feb 20 12:30:52 2005
+++ source.patched\TransferSocket.cpp Sun Feb 27 00:14:15 2005
@@ -79,7 +79,7 @@
m_pSslLayer = NULL;
m_pGssLayer = NULL;
- m_pListResult = new CFtpListResult(pOwner->m_CurrentServer);
+ m_pListResult = new CFtpListResult(pOwner->m_CurrentServer, pOwner->m_bUTF8);
m_LastUpdateTime.QuadPart = 0;
memset(&m_zlibStream, 0, sizeof(m_zlibStream));
PS. I change some variable and function to use CStringA, not CString, because the response string receive from ftp server is not an unicode string. It's easy for me to convert the string from multi-byte to unicode line by line, not byte by byte.