使用 Visual Studio 编译 wget 为库文件

本文介绍如何将wget程序改造成静态库,并解决由此产生的缓冲区溢出等问题。文中详细介绍了必要的代码修改,包括添加回调函数、调整main函数及处理下载进度提示等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

添加代码与预编译指令与上一篇使用 Visual Studio 编译 wget 为可执行文件一致,区别在于这回建的是静态库工程(编译为动态库过程类似:))

从wget的main函数开始读下来,发现问题不少,程序可能基于效率或者编码方便的因素,大量使用静态变量,导致在将其修改为静态库之后存在潜在危险。

需要修改的部分如下:

1、main.c文件,no_prefix函数:


  
static char *
no_prefix (
const char * s)
{
static char buffer[ 1024 ];
static char * p = buffer;
...
}

由于原程序使用指针p来指向尚未处理的数据,no_prefix函数调用一次p指针向后移动一段距离,直到buffer的末尾。

因为原有wget程序一次运行完成之后即退出,这段代码不会出问题,但在做为函数调用进行多次下载的时候,指针p没有移动到buffer的开头,就导致了缓冲区溢出问题。

只需在一次下载结束之后对其设置重置指针p的标志即可在下次执行下载任务开始前对指针p进行归位处理。

在no_prefix函数变量定义之后添加如下代码:

ContractedBlock.gif ExpandedBlockStart.gif View Code

   
if (g_iIsClearBufferPointer == 1 ) // g_iIsClearBufferPointer为全局变量作为Flag
{
g_iIsClearBufferPointer
= 0 ;
p
= buffer;
}

2、添加回调函数及其参数定义

ContractedBlock.gif ExpandedBlockStart.gif View Code

   
typedef enum {
Loading,
Complete,
Fail
= - 1
} DownloadInfoType;

typedef
struct DownloadInfo_tag
{
float Percent;
char * pInfoStr;
void * pTag;
DownloadInfoType InfoType;
} DownloadInfo;

typedef
void ( * DOWNLOAD_CALLBACK)(DownloadInfo);
DOWNLOAD_CALLBACK g_download_process_callback
= NULL;

3、外部调用下载所用函数:

ContractedBlock.gif ExpandedBlockStart.gif View Code

   
// ************************************
// Method: downloadFile
// FullName: downloadFile
// Access: public
// Returns: void
// Qualifier: 下载所用函数
// Parameter: char * pCmdStr:下载参数字符串,与wget命令行下载方式相同
// Parameter: DOWNLOAD_CALLBACK callbackFun:传入的回调函数指针
// ************************************
void downloadFile( char * pCmdStr, DOWNLOAD_CALLBACK callbackFun)
{
char ** cmd;
int iItemNum = 0 ;
int i;
g_download_process_callback
= callbackFun;
cmd
= ( char ** ) malloc( sizeof ( char * ) * MAX_CMD_NUM);
for (i = 0 ; i < MAX_CMD_NUM; i ++ )
{
cmd[i]
= ( char * ) malloc( sizeof ( char ) * MAX_PATH);
ZeroMemory(cmd[i], MAX_PATH);
}
divideCmdString(pCmdStr, cmd, MAX_CMD_NUM,
& iItemNum);

wget_main(iItemNum, cmd);  
// 原有wget的main函数

for (i = 0 ; i < MAX_CMD_NUM; i ++ )
{
free(cmd[i]);
cmd[i]
= NULL;
}
free(cmd);
cmd
= NULL;
}

4、模拟系统分割参数字符串供wget的原有main函数使用

ContractedBlock.gif ExpandedBlockStart.gif View Code

   
// ************************************
// Method: divideCmdString
// FullName: divideCmdString
// Access: public
// Returns: void
// Qualifier:
// Parameter: char * pCmdStr:输入参数串
// Parameter: char * * pItems:输出分割好的参数
// Parameter: int iMaxItemNum:最大参数数目
// Parameter: int * pIItemNum:分割得到的参数数目
// ************************************
void divideCmdString( char * pCmdStr, char ** pItems, int iMaxItemNum, int * pIItemNum)
{
if (pCmdStr != NULL && pItems != NULL && pIItemNum != NULL)
{
int iCmdLen = strlen(pCmdStr);
int iCounter = 0 ;
int iInnerCounter = 0 ;
int i;
for (i = 0 ; i < iCmdLen; i ++ )
{
if ( * (pCmdStr + i) == ' ' ) // 是空格
{
if (iInnerCounter > 0 )
{
pItems[iCounter][iInnerCounter]
= ' \0 ' ;
iInnerCounter
= 0 ;
iCounter
++ ;
if (iCounter >= iMaxItemNum)
{
* pIItemNum = -- iCounter;
return ;
}
}
}
else
{
pItems[iCounter][iInnerCounter]
= * (pCmdStr + i);
iInnerCounter
++ ;
}
}
pItems[iCounter][iInnerCounter]
= ' \0 ' ;
if (iInnerCounter == 0 )
{
* pIItemNum = iCounter;
}
else
{
* pIItemNum = ++ iCounter;
}

}
}

5、wget的main函数

第一个步骤是重置会引发错误的静态变量

ContractedBlock.gif ExpandedBlockStart.gif View Code

   
g_iIsClearBufferPointer = 1 ; // 清除no_prefix函数中静态变量指针
optind = 1 ; // 清除getopt.c文件中的同名变量
total_downloaded_bytes = 0 ; // 清除总下载量

第二个步骤是在函数中if (opt.recursive && opt.spider)的判断之后添加进度提示

ContractedBlock.gif ExpandedBlockStart.gif View Code

   
/* Print broken links. */
if (opt.recursive && opt.spider)
{
print_broken_links();
}
// 进度提示,此处为下载失败消息
if (total_downloaded_bytes == 0 )
{
DownloadInfo info;
ZeroMemory(
& info, sizeof (DownloadInfo));
info.InfoType
= Fail;
g_download_process_callback(info);
}
/* Print the downloaded sum. */

6、在ftp.c的ftp_retrieve_list函数中添加下载进度提示

ContractedBlock.gif ExpandedBlockStart.gif View Code

   
if (file_exists_p (con -> target))
{
int iLen = strlen(con -> target);
char * pSubStr = " .listing " ;
int iSubStrLen = strlen(pSubStr);
// 避免在检测listing文件时错误发送complete消息 // linsy
if (strcmp(con -> target + (iLen - iSubStrLen), pSubStr) != 0 )
{
DownloadInfo info;
info.InfoType
= Complete;
info.Percent
= 100 ;
g_download_process_callback(info);
}
}

7、mswindows.c,添加下载进度提示

ContractedBlock.gif ExpandedBlockStart.gif View Code

   
float g_fOldPercent = - 1 ;

void send_download_process_info( float percent)
{
DownloadInfo info;
if (g_fOldPercent == floor(percent))
{
return ;
}
g_fOldPercent
= floor(percent);
info.Percent
= floor(percent);

info.pInfoStr
= NULL;
if (info.Percent == 100 )
{
info.InfoType
= Complete;
}
else
{
info.InfoType
= Loading;
}

if (g_download_process_callback != NULL)
{
g_download_process_callback(info);
}

}

在void ws_percenttitle (double percentage_float)函数中添加调用:send_download_process_info(percentage_float);

接下来就可以开始使用wget的函数直接进行下载了。\(^o^)/~

转载于:https://www.cnblogs.com/blueglass/archive/2011/07/04/2097583.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值