pscp 項目上傳中文文件亂碼問題
putty工程是一個開源項目,可用於遠程連接Linux 機器。其中pscp項目是其中的一個子項目,可用於加密地文件傳輸,類似於Linux系統中的scp命令,但在windows系統中運行pscp.exe,傳輸中文名字的文件到遠程機器中時,遠程機器的文件名會出現亂碼,這是由於windows系統中使用ANSI字符編碼和遠程機器使用UTF-8字符編碼不同導致的。
下面介紹如果修改pscp源碼,使其支持中文文件的傳輸
1.下載putty 工程
putty工程源代碼下載:https://the.earth.li/~sgtatham/putty/latest/putty-src.zip
2.用VS 打開工程putty-0.70\windows\VS2012\putty.sln
3.編譯項目pscp
如果出現報錯:無法找到文件“version.h”
請先修改項目屬性,屬性->配置屬性->VC++目錄,在包含目錄中添加路徑 $(ProjectDir)..\..\..\
4.添加兩個文件,winencode.h和winencode.c 增加字符編碼轉換的函數
winencode.h
#ifndef PUTTY_ENCODE_H
#define PUTTY_ENCODE_H
#include <Windows.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* ansi轉utf16
* @srcStr 源字符串
* @destLen 目標字符串長度(不是size),不包括('\0')
* @return 目標字符串指針,帶(L'\0')結尾
*/
wchar_t* ansi_2_utf16(const char* srcStr, int *destLen);
/**
* utf16轉ansi
* @srcStr 源字符串
* @destLen 目標字符串長度,不包括('\0')
* @return 目標字符串指針,帶(L'\0')結尾
*/
char* utf16_2_ansi(const wchar_t* srcStr, int *destLen);
char* utf16_2_utf8(const wchar_t* srcStr, int *destLen);
wchar_t* utf8_2_utf16(const char* srcStr, int *destLen);
char* ansi_2_utf8(const char* srcStr, int *destLen);
char* utf8_2_ansi(const char* srcStr, int *destLen);
#ifdef __cplusplus
}
#endif
#endif
winencode.c
#include "winencode.h"
wchar_t* ansi_2_utf16(const char* srcStr, int *destLen)
{
// 獲取轉換後長度(已經包括'\0')
int len = MultiByteToWideChar(CP_ACP, 0, srcStr, -1, 0, 0);
len += (len == 0);
wchar_t* rst = (wchar_t*)malloc(len * 2);
// 轉換
len = MultiByteToWideChar(CP_ACP, 0, srcStr, -1, rst, len);
len += (len == 0);
rst[len - 1] = '\0';
if (destLen)
*destLen = len - 1;
return rst;
}
char* utf16_2_ansi(const wchar_t* srcStr, int *destLen)
{
// 獲取轉換後長度(已經包括'\0')
int len = WideCharToMultiByte(CP_ACP, 0, srcStr, -1, 0, 0, NULL, NULL);
len += (len == 0);
char* rst = (char*)malloc(len);
// 轉換
len = WideCharToMultiByte(CP_ACP, 0, srcStr, -1, rst, len, NULL, NULL);
len += (len == 0);
rst[len - 1] = '\0';
if (destLen)
*destLen = len - 1;
return rst;
}
wchar_t* utf8_2_utf16(const char* srcStr, int *destLen)
{
// 獲取轉換後長度(已經包括'\0')
int len = MultiByteToWideChar(CP_UTF8, 0, srcStr, -1, 0, 0);
len += (len == 0);
wchar_t* rst = (wchar_t*)malloc(len * 2);
// 轉換
len = MultiByteToWideChar(CP_UTF8, 0, srcStr, -1, rst, len);
len += (len == 0);
rst[len - 1] = '\0';
if (destLen)
*destLen = len - 1;
return rst;
}
char* utf16_2_utf8(const wchar_t* srcStr, int *destLen)
{
// 獲取轉換後長度(已經包括'\0')
int len = WideCharToMultiByte(CP_UTF8, 0, srcStr, -1, 0, 0, NULL, NULL);
len += (len == 0);
char* rst = (char*)malloc(len);
// 轉換
len = WideCharToMultiByte(CP_UTF8, 0, srcStr, -1, rst, len, NULL, NULL);
len += (len == 0);
rst[len - 1] = '\0';
if (destLen)
*destLen = len - 1;
return rst;
}
char* ansi_2_utf8(const char* srcStr, int *destLen)
{
wchar_t* utf16Str = ansi_2_utf16(srcStr, 0);
char* utf8Str = utf16_2_utf8(utf16Str, destLen);
free(utf16Str);
return utf8Str;
}
char* utf8_2_ansi(const char* srcStr, int *destLen)
{
wchar_t* utf16Str = utf8_2_utf16(srcStr, 0);
char* ansiStr = utf16_2_ansi(utf16Str, destLen);
free(utf16Str);
return ansiStr;
}
5. 修改文件sftp.c
添加頭文件 #include "winencode.h"
修改fxp_open_send()函數
/*
* Open a file.
*/
struct sftp_request *fxp_open_send(const char *path, int type,
struct fxp_attrs *attrs)
{
struct sftp_request *req = sftp_alloc_request();
struct sftp_packet *pktout;
char * utf8_path;
utf8_path = ansi_2_utf8(path, 0);
pktout = sftp_pkt_init(SSH_FXP_OPEN);
sftp_pkt_adduint32(pktout, req->id);
sftp_pkt_addstring(pktout, utf8_path);
sftp_pkt_adduint32(pktout, type);
free(utf8_path);
if (attrs)
sftp_pkt_addattrs(pktout, *attrs);
else
sftp_pkt_adduint32(pktout, 0); /* empty ATTRS structure */
sftp_send(pktout);
return req;
}