2006-02-17 13:35:04 +00:00
|
|
|
/* <!-- copyright */
|
|
|
|
/*
|
2006-09-21 15:31:24 +00:00
|
|
|
* aria2 - The high speed download utility
|
2006-02-17 13:35:04 +00:00
|
|
|
*
|
|
|
|
* Copyright (C) 2006 Tatsuhiro Tsujikawa
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
2010-01-05 16:01:46 +00:00
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
2006-09-21 15:31:24 +00:00
|
|
|
*
|
|
|
|
* In addition, as a special exception, the copyright holders give
|
|
|
|
* permission to link the code of portions of this program with the
|
|
|
|
* OpenSSL library under certain conditions as described in each
|
|
|
|
* individual source file, and distribute linked combinations
|
|
|
|
* including the two.
|
|
|
|
* You must obey the GNU General Public License in all respects
|
|
|
|
* for all of the code used other than OpenSSL. If you modify
|
|
|
|
* file(s) with this exception, you may extend this exception to your
|
|
|
|
* version of the file(s), but you are not obligated to do so. If you
|
|
|
|
* do not wish to do so, delete this exception statement from your
|
|
|
|
* version. If you delete this exception statement from all source
|
|
|
|
* files in the program, then also delete it here.
|
2006-02-17 13:35:04 +00:00
|
|
|
*/
|
|
|
|
/* copyright --> */
|
2009-10-22 15:35:33 +00:00
|
|
|
#include "util.h"
|
2008-11-27 15:29:15 +00:00
|
|
|
|
2006-11-09 14:04:46 +00:00
|
|
|
#include <signal.h>
|
2008-05-24 11:56:24 +00:00
|
|
|
#include <limits.h>
|
|
|
|
#include <stdint.h>
|
2008-11-27 15:29:15 +00:00
|
|
|
|
2008-02-08 15:53:45 +00:00
|
|
|
#include <cerrno>
|
|
|
|
#include <cassert>
|
|
|
|
#include <cstring>
|
2008-10-07 13:40:12 +00:00
|
|
|
#include <cstdio>
|
2008-05-24 11:56:24 +00:00
|
|
|
#include <cstdlib>
|
2007-11-27 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
Rewritten to add content-type support.
* src/DownloadHandler.{h, cc}
* src/BtPostDownloadHandler.{h, cc}
* test/BtPostDownloadHandlerTest.cc
* src/MetalinkPostDownloadHandler.{h, cc}
* test/MetalinkPostDownloadHandlerTest.cc
* src/PostDownloadHandler.{h, cc}
* src/DownloadHandlerConstants.{h, cc}
* src/RequestGroup.cc
* src/HttpResponseCommand.cc
* src/FtpNegotiationCommand.cc
* src/SingleFileDownloadContext.{h, cc}
* src/RequestGroup.h
* src/RequestGroupCriteria.h
* src/ContentTypeRequestGroupCriteria.h
Added 'mem' option value for --follow-metalink,
--follow-torrent.
If it is give, metalink/torrent file is not written to the disk,
but
just is kept in memory. Parsing is occurred on memory.
* src/MetalinkHelper.{h, cc}
* src/MetalinkProcessor.h
* src/Xml2MetalinkProcessor.{h, cc}
* test/Xml2MetalinkProcessorTest.cc
* src/DownloadHandlerFactory.{h, cc}
* test/DownloadHandlerFactoryTest.cc
* src/PreDownloadHandler.{h, cc}
* src/OptionHandlerFactory.cc
* src/DefaultBtContext.{h, cc}
* test/DefaultBtContextTest.cc
* src/version_usage.cc
* src/Metalink2RequestGroup.{h, cc}
* src/RequestGroup.{h, cc}
* src/a2functional.h
* test/a2functionalTest.cc
* src/MemoryBufferPreDownloadHandler.{h, cc}
* src/OptionHandlerImpl.h
* src/prefs.h
* src/Util.{h, cc}
* test/UtilTest.cc
Keep DownloadResult rather than RequestGroup after downloads to
reduce
memory usage.
* src/RequestGroupMan.{h, cc}
* src/DownloadEngine.cc
* src/BtDependency.{h, cc}: Changed the type of dependee from
WeakHandle to SharedHandle because WeakHandle could be null.
* src/RequestGroup.{h, cc}
* src/DownloadEngineFactory.cc
* src/DownloadResult.h
Set totalLength after download finished
* src/UnknownLengthPieceStorage.{h, cc}
Keep torrent file specified in metalink in memory.
* src/Metalink2RequestGroup.cc
* src/BtDependency.cc
* src/TrueRequestGroupCriteria.h
Fixed the bug: seekg is used where seekp should be used.
* src/ByteArrayDiskWriter.cc
* test/ByteArraydiskWriterTest.cc
2007-11-27 12:27:10 +00:00
|
|
|
#include <sstream>
|
2008-06-09 11:47:19 +00:00
|
|
|
#include <ostream>
|
2008-02-08 15:53:45 +00:00
|
|
|
#include <algorithm>
|
2009-10-22 14:43:42 +00:00
|
|
|
#include <fstream>
|
|
|
|
#include <iomanip>
|
2007-08-14 14:51:08 +00:00
|
|
|
#ifndef HAVE_SLEEP
|
|
|
|
# ifdef HAVE_WINSOCK_H
|
|
|
|
# define WIN32_LEAN_AND_MEAN
|
|
|
|
# include <windows.h>
|
|
|
|
# endif // HAVE_WINSOCK_H
|
|
|
|
#endif // HAVE_SLEEP
|
|
|
|
|
2009-10-22 14:43:42 +00:00
|
|
|
#ifdef HAVE_LIBGCRYPT
|
|
|
|
# include <gcrypt.h>
|
|
|
|
#elif HAVE_LIBSSL
|
|
|
|
# include <openssl/rand.h>
|
|
|
|
# include "SimpleRandomizer.h"
|
|
|
|
#endif // HAVE_LIBSSL
|
|
|
|
|
2008-11-27 15:29:15 +00:00
|
|
|
#include "File.h"
|
|
|
|
#include "message.h"
|
|
|
|
#include "Randomizer.h"
|
|
|
|
#include "a2netcompat.h"
|
|
|
|
#include "DlAbortEx.h"
|
|
|
|
#include "BitfieldMan.h"
|
|
|
|
#include "DefaultDiskWriter.h"
|
|
|
|
#include "FatalException.h"
|
|
|
|
#include "FileEntry.h"
|
2010-11-20 08:21:36 +00:00
|
|
|
#include "fmt.h"
|
2008-11-27 15:29:15 +00:00
|
|
|
#include "A2STR.h"
|
|
|
|
#include "array_fun.h"
|
2010-03-19 08:56:17 +00:00
|
|
|
#include "bitfield.h"
|
2010-04-01 15:41:53 +00:00
|
|
|
#include "DownloadHandlerConstants.h"
|
|
|
|
#include "RequestGroup.h"
|
2010-07-16 14:22:57 +00:00
|
|
|
#include "LogFactory.h"
|
2010-11-20 08:21:36 +00:00
|
|
|
#include "Logger.h"
|
2010-07-16 14:22:57 +00:00
|
|
|
#include "Option.h"
|
2010-12-04 09:14:27 +00:00
|
|
|
#include "DownloadContext.h"
|
|
|
|
|
2010-01-23 10:02:56 +00:00
|
|
|
#ifdef ENABLE_MESSAGE_DIGEST
|
2010-11-11 02:56:24 +00:00
|
|
|
# include "MessageDigest.h"
|
2011-02-05 14:38:51 +00:00
|
|
|
# include "message_digest_helper.h"
|
2010-01-23 10:02:56 +00:00
|
|
|
#endif // ENABLE_MESSAGE_DIGEST
|
2008-11-27 15:29:15 +00:00
|
|
|
|
2008-06-01 08:23:32 +00:00
|
|
|
// For libc6 which doesn't define ULLONG_MAX properly because of broken limits.h
|
|
|
|
#ifndef ULLONG_MAX
|
|
|
|
# define ULLONG_MAX 18446744073709551615ULL
|
|
|
|
#endif // ULLONG_MAX
|
|
|
|
|
2008-02-08 15:53:45 +00:00
|
|
|
namespace aria2 {
|
|
|
|
|
2009-10-22 15:09:00 +00:00
|
|
|
namespace util {
|
|
|
|
|
2010-10-09 16:49:02 +00:00
|
|
|
const std::string DEFAULT_STRIP_CHARSET("\r\n\t ");
|
2006-02-17 13:35:04 +00:00
|
|
|
|
2010-10-09 16:22:56 +00:00
|
|
|
std::string strip(const std::string& str, const std::string& chars)
|
|
|
|
{
|
|
|
|
return stripIter(str.begin(), str.end(), chars);
|
|
|
|
}
|
|
|
|
|
2010-10-10 03:39:00 +00:00
|
|
|
void divide
|
|
|
|
(std::pair<std::string, std::string>& hp, const std::string& src, char delim)
|
2007-10-11 16:58:24 +00:00
|
|
|
{
|
2010-10-10 03:39:00 +00:00
|
|
|
std::string::const_iterator first = src.begin();
|
|
|
|
std::string::const_iterator last = src.end();
|
|
|
|
std::string::const_iterator dpos = std::find(first, last, delim);
|
|
|
|
if(dpos == last) {
|
2010-10-09 16:49:02 +00:00
|
|
|
hp.first = strip(src);
|
2008-05-13 14:15:23 +00:00
|
|
|
hp.second = A2STR::NIL;
|
2007-03-15 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
To handle Segment as SegmentHandle:
* src/AbstractCommand.cc (execute): Rewritten.
* src/SegmentMan.h: Segment -> SegmentHandle
Introducded HttpResponse class, HttpRequest class to improve
code
extensiveness and make it clear:
* src/HttpDownloadCommand.cc: transfer encoders are now managed
by
HttpResponse class.
* src/HttpRequest.h, src/HttpRequest.cc: New class.
* src/HttpResponse.h, src/HttpResponse.cc: New class.
* src/HttpConnection.cc: Contruction of http request were moved
to
HttpRequest class.
* src/HttpResponseCommand.h, src/HttpResponseCommand.cc:
Refactored.
* src/HttpRequestCommand.cc (executeInternal): Rewritten.
* src/HttpAuthConfig.h: New class.
* src/Range.h: New class.
To make FtpTunnel{Request, Response}Command and
HttpProxy{Request, Response}Command derived from
AbstractProxy{Request, Response}Command:
* src/FtpTunnelResponseCommand.h,
src/FtpTunnelResponseCommand.cc:
Derived from AbstractProxyRequestCommand class.
* src/FtpTunnelRequestCommand.h, src/FtpTunnelRequestCommand.cc:
Derived from AbstractProxyResponseCommand class.
* src/HttpProxyRequestCommand.h, src/HttpProxyRequestCommand.cc:
Derived from AbstractProxyRequestCommand class.
* src/HttpProxyResponseCommand.h,
src/HttpProxyResponseCommand.cc:
Derived from AbstractProxyResponseCommand class.
* src/AbstractProxyRequestCommand.h,
src/AbstractProxyRequestCommand.cc
: New class.
* src/AbstractProxyResponseCommand.h,
src/AbstractProxyResponseCommand.cc: New class.
To add netrc support:
* src/Netrc.h, src/Netrc.cc: New class.
* src/Util.h, src/Util.cc (split): New function.
* src/HttpHeader.cc (getRange): Fixed so that it inspects
"Content-Range" header instead of "Range" header.
* src/HttpHeader.h
(getStatus): Removed.
(setStatus): Removed.
* src/Segment.h
(getPositionToWrite): New function.
2007-03-15 15:07:18 +00:00
|
|
|
} else {
|
2010-10-10 03:39:00 +00:00
|
|
|
hp.first = stripIter(first, dpos);
|
|
|
|
hp.second = stripIter(dpos+1, last);
|
2007-03-15 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
To handle Segment as SegmentHandle:
* src/AbstractCommand.cc (execute): Rewritten.
* src/SegmentMan.h: Segment -> SegmentHandle
Introducded HttpResponse class, HttpRequest class to improve
code
extensiveness and make it clear:
* src/HttpDownloadCommand.cc: transfer encoders are now managed
by
HttpResponse class.
* src/HttpRequest.h, src/HttpRequest.cc: New class.
* src/HttpResponse.h, src/HttpResponse.cc: New class.
* src/HttpConnection.cc: Contruction of http request were moved
to
HttpRequest class.
* src/HttpResponseCommand.h, src/HttpResponseCommand.cc:
Refactored.
* src/HttpRequestCommand.cc (executeInternal): Rewritten.
* src/HttpAuthConfig.h: New class.
* src/Range.h: New class.
To make FtpTunnel{Request, Response}Command and
HttpProxy{Request, Response}Command derived from
AbstractProxy{Request, Response}Command:
* src/FtpTunnelResponseCommand.h,
src/FtpTunnelResponseCommand.cc:
Derived from AbstractProxyRequestCommand class.
* src/FtpTunnelRequestCommand.h, src/FtpTunnelRequestCommand.cc:
Derived from AbstractProxyResponseCommand class.
* src/HttpProxyRequestCommand.h, src/HttpProxyRequestCommand.cc:
Derived from AbstractProxyRequestCommand class.
* src/HttpProxyResponseCommand.h,
src/HttpProxyResponseCommand.cc:
Derived from AbstractProxyResponseCommand class.
* src/AbstractProxyRequestCommand.h,
src/AbstractProxyRequestCommand.cc
: New class.
* src/AbstractProxyResponseCommand.h,
src/AbstractProxyResponseCommand.cc: New class.
To add netrc support:
* src/Netrc.h, src/Netrc.cc: New class.
* src/Util.h, src/Util.cc (split): New function.
* src/HttpHeader.cc (getRange): Fixed so that it inspects
"Content-Range" header instead of "Range" header.
* src/HttpHeader.h
(getStatus): Removed.
(setStatus): Removed.
* src/Segment.h
(getPositionToWrite): New function.
2007-03-15 15:07:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-03-05 14:38:49 +00:00
|
|
|
std::string itos(int64_t value, bool comma)
|
|
|
|
{
|
|
|
|
bool flag = false;
|
|
|
|
std::string str;
|
|
|
|
if(value < 0) {
|
|
|
|
if(value == INT64_MIN) {
|
|
|
|
if(comma) {
|
|
|
|
str = "-9,223,372,036,854,775,808";
|
|
|
|
} else {
|
|
|
|
str = "-9223372036854775808";
|
|
|
|
}
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
flag = true;
|
|
|
|
value = -value;
|
|
|
|
}
|
|
|
|
str = uitos(value, comma);
|
|
|
|
if(flag) {
|
|
|
|
str.insert(str.begin(), '-');
|
|
|
|
}
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2009-10-22 15:09:00 +00:00
|
|
|
int64_t difftv(struct timeval tv1, struct timeval tv2) {
|
2008-03-15 04:19:46 +00:00
|
|
|
if((tv1.tv_sec < tv2.tv_sec) ||
|
|
|
|
((tv1.tv_sec == tv2.tv_sec) && (tv1.tv_usec < tv2.tv_usec))) {
|
2006-02-17 13:35:04 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2007-07-21 08:56:16 +00:00
|
|
|
return ((int64_t)(tv1.tv_sec-tv2.tv_sec)*1000000+
|
2010-01-05 16:01:46 +00:00
|
|
|
tv1.tv_usec-tv2.tv_usec);
|
2006-02-17 13:35:04 +00:00
|
|
|
}
|
|
|
|
|
2009-10-22 15:09:00 +00:00
|
|
|
int32_t difftvsec(struct timeval tv1, struct timeval tv2) {
|
2006-04-12 13:55:43 +00:00
|
|
|
if(tv1.tv_sec < tv2.tv_sec) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return tv1.tv_sec-tv2.tv_sec;
|
|
|
|
}
|
|
|
|
|
2009-10-22 15:09:00 +00:00
|
|
|
bool startsWith(const std::string& target, const std::string& part) {
|
2006-02-28 02:25:45 +00:00
|
|
|
if(target.size() < part.size()) {
|
|
|
|
return false;
|
|
|
|
}
|
2008-05-13 14:15:23 +00:00
|
|
|
if(part.empty()) {
|
2006-02-28 02:25:45 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if(target.find(part) == 0) {
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-22 15:09:00 +00:00
|
|
|
bool endsWith(const std::string& target, const std::string& part) {
|
2006-02-21 12:27:17 +00:00
|
|
|
if(target.size() < part.size()) {
|
|
|
|
return false;
|
|
|
|
}
|
2008-05-13 14:15:23 +00:00
|
|
|
if(part.empty()) {
|
2006-02-28 02:25:45 +00:00
|
|
|
return true;
|
|
|
|
}
|
2006-03-05 06:32:01 +00:00
|
|
|
if(target.rfind(part) == target.size()-part.size()) {
|
2006-02-21 12:27:17 +00:00
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2006-02-21 15:01:05 +00:00
|
|
|
|
2009-10-22 15:09:00 +00:00
|
|
|
std::string replace(const std::string& target, const std::string& oldstr, const std::string& newstr) {
|
2008-05-13 14:15:23 +00:00
|
|
|
if(target.empty() || oldstr.empty()) {
|
2006-02-21 15:01:05 +00:00
|
|
|
return target;
|
|
|
|
}
|
2008-02-08 15:53:45 +00:00
|
|
|
std::string result;
|
|
|
|
std::string::size_type p = 0;
|
|
|
|
std::string::size_type np = target.find(oldstr);
|
|
|
|
while(np != std::string::npos) {
|
2009-06-06 12:33:07 +00:00
|
|
|
result += target.substr(p, np-p);
|
|
|
|
result += newstr;
|
2006-02-21 15:01:05 +00:00
|
|
|
p = np+oldstr.size();
|
|
|
|
np = target.find(oldstr, p);
|
|
|
|
}
|
|
|
|
result += target.substr(p);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2010-02-19 10:54:40 +00:00
|
|
|
bool isAlpha(const char c)
|
|
|
|
{
|
|
|
|
return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z');
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isDigit(const char c)
|
|
|
|
{
|
|
|
|
return '0' <= c && c <= '9';
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isHexDigit(const char c)
|
|
|
|
{
|
|
|
|
return isDigit(c) || ('A' <= c && c <= 'F') || ('a' <= c && c <= 'f');
|
|
|
|
}
|
|
|
|
|
2010-03-02 15:14:39 +00:00
|
|
|
bool isHexDigit(const std::string& s)
|
|
|
|
{
|
|
|
|
for(std::string::const_iterator i = s.begin(), eoi = s.end(); i != eoi; ++i) {
|
|
|
|
if(!isHexDigit(*i)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-10-22 15:09:00 +00:00
|
|
|
bool inRFC3986ReservedChars(const char c)
|
2008-11-27 15:29:15 +00:00
|
|
|
{
|
|
|
|
static const char reserved[] = {
|
|
|
|
':' , '/' , '?' , '#' , '[' , ']' , '@',
|
|
|
|
'!' , '$' , '&' , '\'' , '(' , ')',
|
|
|
|
'*' , '+' , ',' , ';' , '=' };
|
2010-03-25 13:51:10 +00:00
|
|
|
return std::find(vbegin(reserved), vend(reserved), c) != vend(reserved);
|
2008-11-27 15:29:15 +00:00
|
|
|
}
|
|
|
|
|
2009-10-22 15:09:00 +00:00
|
|
|
bool inRFC3986UnreservedChars(const char c)
|
2007-11-11 04:25:56 +00:00
|
|
|
{
|
2008-11-27 15:29:15 +00:00
|
|
|
static const char unreserved[] = { '-', '.', '_', '~' };
|
2010-02-19 10:54:40 +00:00
|
|
|
return isAlpha(c) || isDigit(c) ||
|
2010-03-25 13:51:10 +00:00
|
|
|
std::find(vbegin(unreserved), vend(unreserved), c) != vend(unreserved);
|
2007-11-11 04:25:56 +00:00
|
|
|
}
|
|
|
|
|
2010-02-19 10:54:40 +00:00
|
|
|
bool inRFC2978MIMECharset(const char c)
|
|
|
|
{
|
|
|
|
static const char chars[] = {
|
|
|
|
'!', '#', '$', '%', '&',
|
|
|
|
'\'', '+', '-', '^', '_',
|
|
|
|
'`', '{', '}', '~'
|
|
|
|
};
|
|
|
|
return isAlpha(c) || isDigit(c) ||
|
2010-03-25 13:51:10 +00:00
|
|
|
std::find(vbegin(chars), vend(chars), c) != vend(chars);
|
2010-02-19 10:54:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool inRFC2616HttpToken(const char c)
|
|
|
|
{
|
|
|
|
static const char chars[] = {
|
|
|
|
'!', '#', '$', '%', '&', '\'', '*', '+', '-', '.',
|
|
|
|
'^', '_', '`', '|', '~'
|
|
|
|
};
|
|
|
|
return isAlpha(c) || isDigit(c) ||
|
2010-03-25 13:51:10 +00:00
|
|
|
std::find(vbegin(chars), vend(chars), c) != vend(chars);
|
2010-02-19 10:54:40 +00:00
|
|
|
}
|
|
|
|
|
2010-10-02 07:54:43 +00:00
|
|
|
namespace {
|
|
|
|
bool isUtf8Tail(unsigned char ch)
|
|
|
|
{
|
2010-10-09 14:22:49 +00:00
|
|
|
return in(ch, 0x80u, 0xbfu);
|
2010-10-02 07:54:43 +00:00
|
|
|
}
|
2010-10-30 14:53:40 +00:00
|
|
|
} // namespace
|
2010-10-02 07:54:43 +00:00
|
|
|
|
|
|
|
bool isUtf8(const std::string& str)
|
|
|
|
{
|
|
|
|
for(std::string::const_iterator s = str.begin(), eos = str.end(); s != eos;
|
|
|
|
++s) {
|
|
|
|
unsigned char firstChar = *s;
|
|
|
|
// See ABNF in http://tools.ietf.org/search/rfc3629#section-4
|
2010-10-09 14:22:49 +00:00
|
|
|
if(in(firstChar, 0x20u, 0x7eu) ||
|
|
|
|
firstChar == 0x09u || firstChar == 0x0au ||firstChar == 0x0du) {
|
2010-10-02 07:54:43 +00:00
|
|
|
// UTF8-1 (without ctrl chars)
|
2010-10-09 14:22:49 +00:00
|
|
|
} else if(in(firstChar, 0xc2u, 0xdfu)) {
|
2010-10-02 07:54:43 +00:00
|
|
|
// UTF8-2
|
|
|
|
if(++s == eos || !isUtf8Tail(*s)) {
|
|
|
|
return false;
|
|
|
|
}
|
2010-10-09 14:22:49 +00:00
|
|
|
} else if(0xe0u == firstChar) {
|
2010-10-02 07:54:43 +00:00
|
|
|
// UTF8-3
|
2010-10-09 14:22:49 +00:00
|
|
|
if(++s == eos || !in(static_cast<unsigned char>(*s), 0xa0u, 0xbfu) ||
|
2010-10-02 07:54:43 +00:00
|
|
|
++s == eos || !isUtf8Tail(*s)) {
|
|
|
|
return false;
|
|
|
|
}
|
2010-10-09 14:22:49 +00:00
|
|
|
} else if(in(firstChar, 0xe1u, 0xecu) || in(firstChar, 0xeeu, 0xefu)) {
|
2010-10-02 07:54:43 +00:00
|
|
|
// UTF8-3
|
|
|
|
if(++s == eos || !isUtf8Tail(*s) ||
|
|
|
|
++s == eos || !isUtf8Tail(*s)) {
|
|
|
|
return false;
|
|
|
|
}
|
2010-10-09 14:22:49 +00:00
|
|
|
} else if(0xedu == firstChar) {
|
2010-10-02 07:54:43 +00:00
|
|
|
// UTF8-3
|
2010-10-09 14:22:49 +00:00
|
|
|
if(++s == eos || !in(static_cast<unsigned char>(*s), 0x80u, 0x9fu) ||
|
2010-10-02 07:54:43 +00:00
|
|
|
++s == eos || !isUtf8Tail(*s)) {
|
|
|
|
return false;
|
|
|
|
}
|
2010-10-09 14:22:49 +00:00
|
|
|
} else if(0xf0u == firstChar) {
|
2010-10-02 07:54:43 +00:00
|
|
|
// UTF8-4
|
2010-10-09 14:22:49 +00:00
|
|
|
if(++s == eos || !in(static_cast<unsigned char>(*s), 0x90u, 0xbfu) ||
|
2010-10-02 07:54:43 +00:00
|
|
|
++s == eos || !isUtf8Tail(*s) ||
|
|
|
|
++s == eos || !isUtf8Tail(*s)) {
|
|
|
|
return false;
|
|
|
|
}
|
2010-10-09 14:22:49 +00:00
|
|
|
} else if(in(firstChar, 0xf1u, 0xf3u)) {
|
2010-10-02 07:54:43 +00:00
|
|
|
// UTF8-4
|
|
|
|
if(++s == eos || !isUtf8Tail(*s) ||
|
|
|
|
++s == eos || !isUtf8Tail(*s) ||
|
|
|
|
++s == eos || !isUtf8Tail(*s)) {
|
|
|
|
return false;
|
|
|
|
}
|
2010-10-09 14:22:49 +00:00
|
|
|
} else if(0xf4u == firstChar) {
|
2010-10-02 07:54:43 +00:00
|
|
|
// UTF8-4
|
2010-10-09 14:22:49 +00:00
|
|
|
if(++s == eos || !in(static_cast<unsigned char>(*s), 0x80u, 0x8fu) ||
|
2010-10-02 07:54:43 +00:00
|
|
|
++s == eos || !isUtf8Tail(*s) ||
|
|
|
|
++s == eos || !isUtf8Tail(*s)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-10-02 08:31:28 +00:00
|
|
|
std::string percentEncode(const unsigned char* target, size_t len)
|
|
|
|
{
|
2008-02-08 15:53:45 +00:00
|
|
|
std::string dest;
|
2009-06-06 12:33:07 +00:00
|
|
|
for(size_t i = 0; i < len; ++i) {
|
2010-10-02 08:31:28 +00:00
|
|
|
if(inRFC3986UnreservedChars(target[i])) {
|
2006-03-21 14:12:51 +00:00
|
|
|
dest += target[i];
|
2010-10-02 08:31:28 +00:00
|
|
|
} else {
|
2010-11-20 09:36:14 +00:00
|
|
|
dest.append(fmt("%%%02X", target[i]));
|
2006-03-21 14:12:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return dest;
|
|
|
|
}
|
|
|
|
|
2010-03-07 14:24:21 +00:00
|
|
|
std::string percentEncode(const std::string& target)
|
2009-10-22 15:09:00 +00:00
|
|
|
{
|
2010-03-07 14:24:21 +00:00
|
|
|
return percentEncode(reinterpret_cast<const unsigned char*>(target.c_str()),
|
2010-10-02 08:31:28 +00:00
|
|
|
target.size());
|
2009-10-22 15:09:00 +00:00
|
|
|
}
|
|
|
|
|
2010-03-07 14:24:21 +00:00
|
|
|
std::string torrentPercentEncode(const unsigned char* target, size_t len) {
|
2008-02-08 15:53:45 +00:00
|
|
|
std::string dest;
|
2009-06-06 12:33:07 +00:00
|
|
|
for(size_t i = 0; i < len; ++i) {
|
2010-02-19 10:54:40 +00:00
|
|
|
if(isAlpha(target[i]) || isDigit(target[i])) {
|
2006-08-14 11:38:28 +00:00
|
|
|
dest += target[i];
|
|
|
|
} else {
|
2010-11-20 09:36:14 +00:00
|
|
|
dest.append(fmt("%%%02X", target[i]));
|
2006-08-14 11:38:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return dest;
|
|
|
|
}
|
|
|
|
|
2010-03-07 14:24:21 +00:00
|
|
|
std::string torrentPercentEncode(const std::string& target)
|
2009-10-22 15:09:00 +00:00
|
|
|
{
|
2010-03-07 14:24:21 +00:00
|
|
|
return torrentPercentEncode
|
2009-10-22 15:09:00 +00:00
|
|
|
(reinterpret_cast<const unsigned char*>(target.c_str()), target.size());
|
|
|
|
}
|
|
|
|
|
2010-03-07 14:29:40 +00:00
|
|
|
std::string percentDecode(const std::string& target) {
|
2008-02-08 15:53:45 +00:00
|
|
|
std::string result;
|
2010-02-28 16:04:52 +00:00
|
|
|
for(std::string::const_iterator itr = target.begin(), eoi = target.end();
|
|
|
|
itr != eoi; ++itr) {
|
2006-10-18 14:57:00 +00:00
|
|
|
if(*itr == '%') {
|
2006-08-28 12:40:41 +00:00
|
|
|
if(itr+1 != target.end() && itr+2 != target.end() &&
|
2010-02-19 10:54:40 +00:00
|
|
|
isHexDigit(*(itr+1)) && isHexDigit(*(itr+2))) {
|
2010-01-05 16:01:46 +00:00
|
|
|
result += parseInt(std::string(itr+1, itr+3), 16);
|
|
|
|
itr += 2;
|
2006-08-28 12:40:41 +00:00
|
|
|
} else {
|
2010-01-05 16:01:46 +00:00
|
|
|
result += *itr;
|
2006-08-28 12:40:41 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
result += *itr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2009-10-22 15:09:00 +00:00
|
|
|
std::string toHex(const unsigned char* src, size_t len) {
|
2010-03-04 17:01:29 +00:00
|
|
|
std::string out(len*2, '\0');
|
|
|
|
std::string::iterator o = out.begin();
|
|
|
|
const unsigned char* last = src+len;
|
|
|
|
for(const unsigned char* i = src; i != last; ++i) {
|
|
|
|
*o = (*i >> 4);
|
2010-10-09 14:22:49 +00:00
|
|
|
*(o+1) = (*i)&0x0fu;
|
2010-03-04 17:01:29 +00:00
|
|
|
for(int j = 0; j < 2; ++j) {
|
|
|
|
if(*o < 10) {
|
|
|
|
*o += '0';
|
|
|
|
} else {
|
|
|
|
*o += 'a'-10;
|
|
|
|
}
|
|
|
|
++o;
|
|
|
|
}
|
2006-03-21 14:12:51 +00:00
|
|
|
}
|
2010-03-04 17:01:29 +00:00
|
|
|
return out;
|
2006-03-21 14:12:51 +00:00
|
|
|
}
|
|
|
|
|
2009-10-22 15:09:00 +00:00
|
|
|
std::string toHex(const char* src, size_t len)
|
|
|
|
{
|
|
|
|
return toHex(reinterpret_cast<const unsigned char*>(src), len);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string toHex(const std::string& src)
|
|
|
|
{
|
|
|
|
return toHex(reinterpret_cast<const unsigned char*>(src.c_str()), src.size());
|
|
|
|
}
|
|
|
|
|
2010-10-30 16:02:15 +00:00
|
|
|
namespace {
|
|
|
|
unsigned int hexCharToUInt(unsigned char ch)
|
2009-11-22 14:30:51 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
if('a' <= ch && ch <= 'f') {
|
|
|
|
ch -= 'a';
|
|
|
|
ch += 10;
|
|
|
|
} else if('A' <= ch && ch <= 'F') {
|
|
|
|
ch -= 'A';
|
|
|
|
ch += 10;
|
|
|
|
} else if('0' <= ch && ch <= '9') {
|
|
|
|
ch -= '0';
|
|
|
|
} else {
|
|
|
|
ch = 255;
|
|
|
|
}
|
|
|
|
return ch;
|
|
|
|
}
|
2010-10-30 16:02:15 +00:00
|
|
|
} // namespace
|
2009-11-22 14:30:51 +00:00
|
|
|
|
|
|
|
std::string fromHex(const std::string& src)
|
|
|
|
{
|
|
|
|
std::string dest;
|
|
|
|
if(src.size()%2) {
|
|
|
|
return dest;
|
|
|
|
}
|
2010-06-26 14:03:14 +00:00
|
|
|
for(size_t i = 0, eoi = src.size(); i < eoi; i += 2) {
|
2010-01-05 16:01:46 +00:00
|
|
|
unsigned char high = hexCharToUInt(src[i]);
|
|
|
|
unsigned char low = hexCharToUInt(src[i+1]);
|
|
|
|
if(high == 255 || low == 255) {
|
|
|
|
dest.clear();
|
|
|
|
return dest;
|
|
|
|
}
|
|
|
|
dest += (high*16+low);
|
2009-11-22 14:30:51 +00:00
|
|
|
}
|
|
|
|
return dest;
|
|
|
|
}
|
|
|
|
|
2009-10-22 15:09:00 +00:00
|
|
|
FILE* openFile(const std::string& filename, const std::string& mode) {
|
2006-03-21 14:12:51 +00:00
|
|
|
FILE* file = fopen(filename.c_str(), mode.c_str());
|
|
|
|
return file;
|
|
|
|
}
|
|
|
|
|
2009-10-22 15:09:00 +00:00
|
|
|
bool isPowerOf(int num, int base) {
|
2006-03-31 16:15:23 +00:00
|
|
|
if(base <= 0) { return false; }
|
|
|
|
if(base == 1) { return true; }
|
|
|
|
|
|
|
|
while(num%base == 0) {
|
|
|
|
num /= base;
|
|
|
|
if(num == 1) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2006-04-06 12:52:16 +00:00
|
|
|
|
2009-10-22 15:09:00 +00:00
|
|
|
std::string secfmt(time_t sec) {
|
2008-02-08 15:53:45 +00:00
|
|
|
std::string str;
|
2006-04-06 12:52:16 +00:00
|
|
|
if(sec >= 3600) {
|
2009-06-06 12:33:07 +00:00
|
|
|
str = itos(sec/3600);
|
|
|
|
str += "h";
|
2006-04-06 12:52:16 +00:00
|
|
|
sec %= 3600;
|
|
|
|
}
|
|
|
|
if(sec >= 60) {
|
2008-03-09 12:24:01 +00:00
|
|
|
int min = sec/60;
|
2006-04-06 12:52:16 +00:00
|
|
|
if(min < 10) {
|
|
|
|
str += "0";
|
|
|
|
}
|
2009-06-06 12:33:07 +00:00
|
|
|
str += itos(min);
|
|
|
|
str += "m";
|
2006-04-06 12:52:16 +00:00
|
|
|
sec %= 60;
|
|
|
|
}
|
|
|
|
if(sec < 10) {
|
|
|
|
str += "0";
|
|
|
|
}
|
2009-06-06 12:33:07 +00:00
|
|
|
str += itos(sec);
|
|
|
|
str += "s";
|
2006-04-06 12:52:16 +00:00
|
|
|
return str;
|
|
|
|
}
|
2006-04-19 17:23:58 +00:00
|
|
|
|
2008-03-09 12:24:01 +00:00
|
|
|
int getNum(const char* buf, int offset, size_t length) {
|
2006-04-28 15:55:11 +00:00
|
|
|
char* temp = new char[length+1];
|
|
|
|
memcpy(temp, buf+offset, length);
|
|
|
|
temp[length] = '\0';
|
2008-03-09 12:24:01 +00:00
|
|
|
int x = strtol(temp, 0, 10);
|
2006-04-28 15:55:11 +00:00
|
|
|
delete [] temp;
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
2009-10-22 15:09:00 +00:00
|
|
|
int32_t parseInt(const std::string& s, int32_t base)
|
2007-11-21 16:14:40 +00:00
|
|
|
{
|
2010-02-21 15:04:14 +00:00
|
|
|
int64_t v = parseLLInt(s, base);
|
|
|
|
if(v < INT32_MIN || INT32_MAX < v) {
|
2010-11-20 09:36:14 +00:00
|
|
|
throw DL_ABORT_EX(fmt(MSG_STRING_INTEGER_CONVERSION_FAILURE,
|
|
|
|
s.c_str()));
|
2007-11-21 16:14:40 +00:00
|
|
|
}
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2010-11-15 12:52:03 +00:00
|
|
|
bool parseIntNoThrow(int32_t& result, const std::string& s, int base)
|
|
|
|
{
|
|
|
|
// Without trim, strtol(" -1 ",..) emits error.
|
|
|
|
std::string trimed = strip(s);
|
|
|
|
if(trimed.empty()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
char* stop;
|
|
|
|
errno = 0;
|
|
|
|
long int v = strtol(trimed.c_str(), &stop, base);
|
|
|
|
if(*stop != '\0') {
|
|
|
|
return false;
|
|
|
|
} else if(((v == LONG_MAX || v == LONG_MIN) && (errno == ERANGE)) ||
|
|
|
|
v < INT32_MIN || INT32_MAX < v) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
result = v;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-10-22 15:09:00 +00:00
|
|
|
uint32_t parseUInt(const std::string& s, int base)
|
2008-03-09 15:03:47 +00:00
|
|
|
{
|
2010-02-21 15:04:14 +00:00
|
|
|
uint64_t v = parseULLInt(s, base);
|
|
|
|
if(UINT32_MAX < v) {
|
2010-11-20 09:36:14 +00:00
|
|
|
throw DL_ABORT_EX(fmt(MSG_STRING_INTEGER_CONVERSION_FAILURE,
|
|
|
|
s.c_str()));
|
2008-03-09 15:03:47 +00:00
|
|
|
}
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2009-11-12 15:34:55 +00:00
|
|
|
bool parseUIntNoThrow(uint32_t& result, const std::string& s, int base)
|
|
|
|
{
|
2010-11-15 12:52:03 +00:00
|
|
|
// Without trim, strtol(" -1 ",..) emits error.
|
2010-10-09 16:49:02 +00:00
|
|
|
std::string trimed = strip(s);
|
2009-11-12 15:34:55 +00:00
|
|
|
if(trimed.empty()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// We don't allow negative number.
|
|
|
|
if(trimed[0] == '-') {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
char* stop;
|
|
|
|
errno = 0;
|
|
|
|
unsigned long int v = strtoul(trimed.c_str(), &stop, base);
|
|
|
|
if(*stop != '\0') {
|
|
|
|
return false;
|
|
|
|
} else if(((v == ULONG_MAX) && (errno == ERANGE)) || (v > UINT32_MAX)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
result = v;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-10-22 15:09:00 +00:00
|
|
|
int64_t parseLLInt(const std::string& s, int32_t base)
|
2007-11-21 16:14:40 +00:00
|
|
|
{
|
2010-10-09 16:49:02 +00:00
|
|
|
std::string trimed = strip(s);
|
2007-11-22 14:44:40 +00:00
|
|
|
if(trimed.empty()) {
|
2010-11-20 09:36:14 +00:00
|
|
|
throw DL_ABORT_EX(fmt(MSG_STRING_INTEGER_CONVERSION_FAILURE,
|
|
|
|
"empty string"));
|
2007-11-22 11:17:35 +00:00
|
|
|
}
|
2007-11-21 16:14:40 +00:00
|
|
|
char* stop;
|
|
|
|
errno = 0;
|
2007-11-22 14:44:40 +00:00
|
|
|
int64_t v = strtoll(trimed.c_str(), &stop, base);
|
2007-11-21 16:14:40 +00:00
|
|
|
if(*stop != '\0') {
|
2010-11-20 09:36:14 +00:00
|
|
|
throw DL_ABORT_EX(fmt(MSG_STRING_INTEGER_CONVERSION_FAILURE,
|
|
|
|
trimed.c_str()));
|
2008-03-15 04:19:46 +00:00
|
|
|
} else if(((v == INT64_MIN) || (v == INT64_MAX)) && (errno == ERANGE)) {
|
2010-11-20 09:36:14 +00:00
|
|
|
throw DL_ABORT_EX(fmt(MSG_STRING_INTEGER_CONVERSION_FAILURE,
|
|
|
|
trimed.c_str()));
|
2008-03-15 04:19:46 +00:00
|
|
|
}
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2010-10-09 14:22:49 +00:00
|
|
|
bool parseLLIntNoThrow(int64_t& result, const std::string& s, int base)
|
|
|
|
{
|
2010-11-15 12:52:03 +00:00
|
|
|
// Without trim, strtol(" -1 ",..) emits error.
|
2010-10-09 16:49:02 +00:00
|
|
|
std::string trimed = strip(s);
|
2010-10-09 14:22:49 +00:00
|
|
|
if(trimed.empty()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
char* stop;
|
|
|
|
errno = 0;
|
|
|
|
int64_t v = strtoll(trimed.c_str(), &stop, base);
|
|
|
|
if(*stop != '\0') {
|
|
|
|
return false;
|
|
|
|
} else if(((v == INT64_MIN) || (v == INT64_MAX)) && (errno == ERANGE)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
result = v;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-10-22 15:09:00 +00:00
|
|
|
uint64_t parseULLInt(const std::string& s, int base)
|
2008-03-15 04:19:46 +00:00
|
|
|
{
|
2010-10-09 16:49:02 +00:00
|
|
|
std::string trimed = strip(s);
|
2008-03-15 04:19:46 +00:00
|
|
|
if(trimed.empty()) {
|
2010-11-20 09:36:14 +00:00
|
|
|
throw DL_ABORT_EX(fmt(MSG_STRING_INTEGER_CONVERSION_FAILURE,
|
|
|
|
"empty string"));
|
2008-03-15 04:19:46 +00:00
|
|
|
}
|
|
|
|
// We don't allow negative number.
|
|
|
|
if(trimed[0] == '-') {
|
2010-11-20 09:36:14 +00:00
|
|
|
throw DL_ABORT_EX(fmt(MSG_STRING_INTEGER_CONVERSION_FAILURE,
|
|
|
|
trimed.c_str()));
|
2008-03-15 04:19:46 +00:00
|
|
|
}
|
|
|
|
char* stop;
|
|
|
|
errno = 0;
|
|
|
|
uint64_t v = strtoull(trimed.c_str(), &stop, base);
|
|
|
|
if(*stop != '\0') {
|
2010-11-20 09:36:14 +00:00
|
|
|
throw DL_ABORT_EX(fmt(MSG_STRING_INTEGER_CONVERSION_FAILURE,
|
|
|
|
trimed.c_str()));
|
2008-03-15 04:19:46 +00:00
|
|
|
} else if((v == ULLONG_MAX) && (errno == ERANGE)) {
|
2010-11-20 09:36:14 +00:00
|
|
|
throw DL_ABORT_EX(fmt(MSG_STRING_INTEGER_CONVERSION_FAILURE,
|
|
|
|
trimed.c_str()));
|
2007-11-21 16:14:40 +00:00
|
|
|
}
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2009-10-22 15:09:00 +00:00
|
|
|
IntSequence parseIntRange(const std::string& src)
|
2007-11-21 16:14:40 +00:00
|
|
|
{
|
|
|
|
IntSequence::Values values;
|
2008-02-08 15:53:45 +00:00
|
|
|
std::string temp = src;
|
2007-11-21 16:14:40 +00:00
|
|
|
while(temp.size()) {
|
2010-10-10 03:39:00 +00:00
|
|
|
std::pair<std::string, std::string> p;
|
|
|
|
divide(p, temp, ',');
|
2007-11-21 16:14:40 +00:00
|
|
|
temp = p.second;
|
|
|
|
if(p.first.empty()) {
|
|
|
|
continue;
|
|
|
|
}
|
2008-02-08 15:53:45 +00:00
|
|
|
if(p.first.find("-") == std::string::npos) {
|
2009-10-22 15:09:00 +00:00
|
|
|
int32_t v = parseInt(p.first.c_str());
|
2007-11-21 16:14:40 +00:00
|
|
|
values.push_back(IntSequence::Value(v, v+1));
|
|
|
|
} else {
|
2010-10-10 03:39:00 +00:00
|
|
|
std::pair<std::string, std::string> vp;
|
|
|
|
divide(vp, p.first.c_str(), '-');
|
2007-11-21 16:14:40 +00:00
|
|
|
if(vp.first.empty() || vp.second.empty()) {
|
2010-11-20 09:36:14 +00:00
|
|
|
throw DL_ABORT_EX(fmt(MSG_INCOMPLETE_RANGE, p.first.c_str()));
|
2007-11-21 16:14:40 +00:00
|
|
|
}
|
2009-10-22 15:09:00 +00:00
|
|
|
int32_t v1 = parseInt(vp.first.c_str());
|
|
|
|
int32_t v2 = parseInt(vp.second.c_str());
|
2007-11-21 16:14:40 +00:00
|
|
|
values.push_back(IntSequence::Value(v1, v2+1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return values;
|
|
|
|
}
|
|
|
|
|
2010-10-30 16:02:15 +00:00
|
|
|
namespace {
|
|
|
|
void computeHeadPieces
|
2009-12-06 11:35:45 +00:00
|
|
|
(std::vector<size_t>& indexes,
|
|
|
|
const std::vector<SharedHandle<FileEntry> >& fileEntries,
|
|
|
|
size_t pieceLength,
|
|
|
|
uint64_t head)
|
|
|
|
{
|
|
|
|
if(head == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for(std::vector<SharedHandle<FileEntry> >::const_iterator fi =
|
2010-02-28 16:04:52 +00:00
|
|
|
fileEntries.begin(), eoi = fileEntries.end(); fi != eoi; ++fi) {
|
2009-12-06 11:35:45 +00:00
|
|
|
if((*fi)->getLength() == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
size_t lastIndex =
|
|
|
|
((*fi)->getOffset()+std::min(head, (*fi)->getLength())-1)/pieceLength;
|
|
|
|
for(size_t index = (*fi)->getOffset()/pieceLength;
|
2010-01-05 16:01:46 +00:00
|
|
|
index <= lastIndex; ++index) {
|
2009-12-06 11:35:45 +00:00
|
|
|
indexes.push_back(index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-10-30 16:02:15 +00:00
|
|
|
} // namespace
|
2009-12-06 11:35:45 +00:00
|
|
|
|
2010-10-30 16:02:15 +00:00
|
|
|
namespace {
|
|
|
|
void computeTailPieces
|
2009-12-06 11:35:45 +00:00
|
|
|
(std::vector<size_t>& indexes,
|
|
|
|
const std::vector<SharedHandle<FileEntry> >& fileEntries,
|
|
|
|
size_t pieceLength,
|
|
|
|
uint64_t tail)
|
|
|
|
{
|
|
|
|
if(tail == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for(std::vector<SharedHandle<FileEntry> >::const_iterator fi =
|
2010-02-28 16:04:52 +00:00
|
|
|
fileEntries.begin(), eoi = fileEntries.end(); fi != eoi; ++fi) {
|
2009-12-06 11:35:45 +00:00
|
|
|
if((*fi)->getLength() == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
uint64_t endOffset = (*fi)->getLastOffset();
|
|
|
|
size_t fromIndex =
|
|
|
|
(endOffset-1-(std::min(tail, (*fi)->getLength())-1))/pieceLength;
|
|
|
|
for(size_t index = fromIndex; index <= (endOffset-1)/pieceLength;
|
2010-01-05 16:01:46 +00:00
|
|
|
++index) {
|
2009-12-06 11:35:45 +00:00
|
|
|
indexes.push_back(index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-10-30 16:02:15 +00:00
|
|
|
} // namespace
|
2009-12-06 11:35:45 +00:00
|
|
|
|
2009-11-29 06:43:38 +00:00
|
|
|
void parsePrioritizePieceRange
|
|
|
|
(std::vector<size_t>& result, const std::string& src,
|
|
|
|
const std::vector<SharedHandle<FileEntry> >& fileEntries,
|
2009-12-07 12:49:19 +00:00
|
|
|
size_t pieceLength,
|
|
|
|
uint64_t defaultSize)
|
2009-11-29 06:43:38 +00:00
|
|
|
{
|
|
|
|
std::vector<size_t> indexes;
|
|
|
|
std::vector<std::string> parts;
|
|
|
|
split(src, std::back_inserter(parts), ",", true);
|
2010-02-28 16:04:52 +00:00
|
|
|
for(std::vector<std::string>::const_iterator i = parts.begin(),
|
|
|
|
eoi = parts.end(); i != eoi; ++i) {
|
2009-11-29 06:43:38 +00:00
|
|
|
if((*i) == "head") {
|
2009-12-07 12:49:19 +00:00
|
|
|
computeHeadPieces(indexes, fileEntries, pieceLength, defaultSize);
|
2009-11-29 06:43:38 +00:00
|
|
|
} else if(util::startsWith(*i, "head=")) {
|
|
|
|
std::string sizestr = std::string((*i).begin()+(*i).find("=")+1,
|
2010-01-05 16:01:46 +00:00
|
|
|
(*i).end());
|
2009-12-06 11:35:45 +00:00
|
|
|
computeHeadPieces(indexes, fileEntries, pieceLength,
|
2010-01-05 16:01:46 +00:00
|
|
|
std::max((int64_t)0, getRealSize(sizestr)));
|
2009-11-29 06:43:38 +00:00
|
|
|
} else if((*i) == "tail") {
|
2009-12-07 12:49:19 +00:00
|
|
|
computeTailPieces(indexes, fileEntries, pieceLength, defaultSize);
|
2009-11-29 06:43:38 +00:00
|
|
|
} else if(util::startsWith(*i, "tail=")) {
|
|
|
|
std::string sizestr = std::string((*i).begin()+(*i).find("=")+1,
|
2010-01-05 16:01:46 +00:00
|
|
|
(*i).end());
|
2009-12-06 11:35:45 +00:00
|
|
|
computeTailPieces(indexes, fileEntries, pieceLength,
|
2010-01-05 16:01:46 +00:00
|
|
|
std::max((int64_t)0, getRealSize(sizestr)));
|
2009-11-29 06:43:38 +00:00
|
|
|
} else {
|
2010-11-20 09:36:14 +00:00
|
|
|
throw DL_ABORT_EX(fmt("Unrecognized token %s", (*i).c_str()));
|
2009-11-29 06:43:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
std::sort(indexes.begin(), indexes.end());
|
|
|
|
indexes.erase(std::unique(indexes.begin(), indexes.end()), indexes.end());
|
|
|
|
result.insert(result.end(), indexes.begin(), indexes.end());
|
|
|
|
}
|
|
|
|
|
2010-02-19 10:54:40 +00:00
|
|
|
// Converts ISO/IEC 8859-1 string to UTF-8 string. If there is a
|
|
|
|
// character not in ISO/IEC 8859-1, returns empty string.
|
2010-02-17 16:09:19 +00:00
|
|
|
std::string iso8859ToUtf8(const std::string& src)
|
|
|
|
{
|
|
|
|
std::string dest;
|
2010-02-28 16:04:52 +00:00
|
|
|
for(std::string::const_iterator itr = src.begin(), eoi = src.end();
|
|
|
|
itr != eoi; ++itr) {
|
2010-02-17 16:09:19 +00:00
|
|
|
unsigned char c = *itr;
|
2010-10-09 14:22:49 +00:00
|
|
|
if(0xa0u <= c) {
|
|
|
|
if(c <= 0xbfu) {
|
|
|
|
dest += 0xc2u;
|
2010-02-17 16:09:19 +00:00
|
|
|
} else {
|
2010-10-09 14:22:49 +00:00
|
|
|
dest += 0xc3u;
|
2010-02-17 16:09:19 +00:00
|
|
|
}
|
2010-10-09 14:22:49 +00:00
|
|
|
dest += c&(~0x40u);
|
|
|
|
} else if(0x80u <= c && c <= 0x9fu) {
|
2010-02-19 10:54:40 +00:00
|
|
|
return A2STR::NIL;
|
2010-02-17 16:09:19 +00:00
|
|
|
} else {
|
|
|
|
dest += c;
|
|
|
|
}
|
2007-07-18 11:36:41 +00:00
|
|
|
}
|
2010-02-17 16:09:19 +00:00
|
|
|
return dest;
|
|
|
|
}
|
|
|
|
|
2010-10-30 16:02:15 +00:00
|
|
|
namespace {
|
2010-05-06 12:49:50 +00:00
|
|
|
template<typename OutputIterator>
|
2010-10-30 16:02:15 +00:00
|
|
|
void parseParam(OutputIterator out, const std::string& header)
|
2010-05-06 12:49:50 +00:00
|
|
|
{
|
|
|
|
for(std::string::const_iterator i = header.begin(), eoi = header.end();
|
|
|
|
i != eoi;) {
|
|
|
|
std::string::const_iterator paramFirst = i;
|
|
|
|
std::string::const_iterator paramLast = paramFirst;
|
|
|
|
for(; paramLast != eoi && *paramLast != '=' && *paramLast != ';';
|
|
|
|
++paramLast);
|
|
|
|
std::string param;
|
|
|
|
if(paramLast == eoi || *paramLast == ';') {
|
|
|
|
// No value, parmname only
|
|
|
|
param = std::string(paramFirst, paramLast);
|
|
|
|
} else {
|
|
|
|
for(; paramLast != eoi && *paramLast != '"' && *paramLast != ';';
|
|
|
|
++paramLast);
|
|
|
|
if(paramLast != eoi && *paramLast == '"') {
|
|
|
|
// quoted-string
|
|
|
|
++paramLast;
|
|
|
|
for(; paramLast != eoi && *paramLast != '"'; ++paramLast);
|
|
|
|
if(paramLast != eoi) {
|
|
|
|
++paramLast;
|
|
|
|
}
|
|
|
|
param = std::string(paramFirst, paramLast);
|
|
|
|
for(; paramLast != eoi && *paramLast != ';'; ++paramLast);
|
|
|
|
} else {
|
|
|
|
param = std::string(paramFirst, paramLast);
|
|
|
|
}
|
|
|
|
}
|
2010-10-09 16:49:02 +00:00
|
|
|
param = strip(param);
|
2010-05-06 12:49:50 +00:00
|
|
|
*out++ = param;
|
|
|
|
if(paramLast == eoi) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
i = paramLast;
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
}
|
2010-10-30 16:02:15 +00:00
|
|
|
} // namespace
|
2010-05-06 12:49:50 +00:00
|
|
|
|
2010-02-17 16:09:19 +00:00
|
|
|
std::string getContentDispositionFilename(const std::string& header)
|
|
|
|
{
|
|
|
|
std::string filename;
|
|
|
|
std::vector<std::string> params;
|
2010-05-06 12:49:50 +00:00
|
|
|
parseParam(std::back_inserter(params), header);
|
2010-02-28 16:04:52 +00:00
|
|
|
for(std::vector<std::string>::const_iterator i = params.begin(),
|
|
|
|
eoi = params.end(); i != eoi; ++i) {
|
|
|
|
const std::string& param = *i;
|
2010-02-17 16:09:19 +00:00
|
|
|
static const std::string keyName = "filename";
|
2010-02-19 10:54:40 +00:00
|
|
|
if(!startsWith(toLower(param), keyName) || param.size() == keyName.size()) {
|
2010-02-17 16:09:19 +00:00
|
|
|
continue;
|
|
|
|
}
|
2010-02-28 16:04:52 +00:00
|
|
|
std::string::const_iterator markeritr = param.begin()+keyName.size();
|
2010-02-19 10:54:40 +00:00
|
|
|
if(*markeritr == '*') {
|
2010-02-17 16:09:19 +00:00
|
|
|
// See RFC2231 Section4 and draft-reschke-rfc2231-in-http.
|
|
|
|
// Please note that this function doesn't do charset conversion
|
|
|
|
// except that if iso-8859-1 is specified, it is converted to
|
|
|
|
// utf-8.
|
2010-02-19 10:54:40 +00:00
|
|
|
++markeritr;
|
|
|
|
for(; markeritr != param.end() && *markeritr == ' '; ++markeritr);
|
|
|
|
if(markeritr == param.end() || *markeritr != '=') {
|
|
|
|
continue;
|
|
|
|
}
|
2010-02-17 16:09:19 +00:00
|
|
|
std::pair<std::string, std::string> paramPair;
|
2010-10-10 03:39:00 +00:00
|
|
|
divide(paramPair, param, '=');
|
2010-02-17 16:09:19 +00:00
|
|
|
std::string value = paramPair.second;
|
|
|
|
std::vector<std::string> extValues;
|
|
|
|
split(value, std::back_inserter(extValues), "'", false, true);
|
|
|
|
if(extValues.size() != 3) {
|
|
|
|
continue;
|
|
|
|
}
|
2010-02-19 10:54:40 +00:00
|
|
|
bool bad = false;
|
|
|
|
const std::string& charset = extValues[0];
|
2010-02-28 16:04:52 +00:00
|
|
|
for(std::string::const_iterator j = charset.begin(), eoi = charset.end();
|
|
|
|
j != eoi; ++j) {
|
2010-02-19 10:54:40 +00:00
|
|
|
// Since we first split parameter by ', we can safely assume
|
|
|
|
// that ' is not included in charset.
|
|
|
|
if(!inRFC2978MIMECharset(*j)) {
|
|
|
|
bad = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(bad) {
|
2010-02-17 16:09:19 +00:00
|
|
|
continue;
|
|
|
|
}
|
2010-02-19 10:54:40 +00:00
|
|
|
bad = false;
|
|
|
|
value = extValues[2];
|
2010-02-28 16:04:52 +00:00
|
|
|
for(std::string::const_iterator j = value.begin(), eoi = value.end();
|
|
|
|
j != eoi; ++j){
|
2010-02-19 10:54:40 +00:00
|
|
|
if(*j == '%') {
|
|
|
|
if(j+1 != value.end() && isHexDigit(*(j+1)) &&
|
|
|
|
j+2 != value.end() && isHexDigit(*(j+2))) {
|
|
|
|
j += 2;
|
|
|
|
} else {
|
|
|
|
bad = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if(*j == '*' || *j == '\'' || !inRFC2616HttpToken(*j)) {
|
|
|
|
bad = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(bad) {
|
|
|
|
continue;
|
|
|
|
}
|
2010-03-07 15:06:48 +00:00
|
|
|
value = percentDecode(value);
|
2010-02-19 10:54:40 +00:00
|
|
|
if(toLower(extValues[0]) == "iso-8859-1") {
|
2010-02-17 16:09:19 +00:00
|
|
|
value = iso8859ToUtf8(value);
|
|
|
|
}
|
2010-03-07 15:06:48 +00:00
|
|
|
if(!detectDirTraversal(value) &&
|
|
|
|
value.find(A2STR::SLASH_C) == std::string::npos) {
|
|
|
|
filename = value;
|
|
|
|
}
|
|
|
|
if(!filename.empty()) {
|
|
|
|
break;
|
|
|
|
}
|
2010-02-19 10:54:40 +00:00
|
|
|
} else {
|
|
|
|
for(; markeritr != param.end() && *markeritr == ' '; ++markeritr);
|
|
|
|
if(markeritr == param.end() || *markeritr != '=') {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
std::pair<std::string, std::string> paramPair;
|
2010-10-10 03:39:00 +00:00
|
|
|
divide(paramPair, param, '=');
|
2010-02-19 10:54:40 +00:00
|
|
|
std::string value = paramPair.second;
|
|
|
|
if(value.empty()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
std::string::iterator filenameLast;
|
|
|
|
if(*value.begin() == '\'' || *value.begin() == '"') {
|
|
|
|
char qc = *value.begin();
|
|
|
|
for(filenameLast = value.begin()+1;
|
|
|
|
filenameLast != value.end() && *filenameLast != qc;
|
|
|
|
++filenameLast);
|
|
|
|
} else {
|
|
|
|
filenameLast = value.end();
|
|
|
|
}
|
2010-03-07 15:06:48 +00:00
|
|
|
static const std::string TRIMMED("\r\n\t '\"");
|
|
|
|
value = percentDecode(std::string(value.begin(), filenameLast));
|
2010-10-09 16:49:02 +00:00
|
|
|
value = strip(value, TRIMMED);
|
2010-03-07 15:06:48 +00:00
|
|
|
value.erase(std::remove(value.begin(), value.end(), '\\'), value.end());
|
|
|
|
if(!detectDirTraversal(value) &&
|
|
|
|
value.find(A2STR::SLASH_C) == std::string::npos) {
|
|
|
|
filename = value;
|
|
|
|
}
|
2010-02-19 10:54:40 +00:00
|
|
|
// continue because there is a chance we can find filename*=...
|
2010-02-17 16:09:19 +00:00
|
|
|
}
|
2009-03-04 14:49:10 +00:00
|
|
|
}
|
2010-02-17 16:09:19 +00:00
|
|
|
return filename;
|
2006-05-09 15:54:14 +00:00
|
|
|
}
|
2006-05-18 17:08:29 +00:00
|
|
|
|
2009-10-22 15:09:00 +00:00
|
|
|
std::string randomAlpha(size_t length, const RandomizerHandle& randomizer) {
|
2007-11-29 11:33:50 +00:00
|
|
|
static const char *random_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
2008-02-08 15:53:45 +00:00
|
|
|
std::string str;
|
2009-06-06 12:33:07 +00:00
|
|
|
for(size_t i = 0; i < length; ++i) {
|
2008-03-09 12:24:01 +00:00
|
|
|
size_t index = randomizer->getRandomNumber(strlen(random_chars));
|
2007-07-23 13:04:48 +00:00
|
|
|
str += random_chars[index];
|
2006-06-22 15:26:18 +00:00
|
|
|
}
|
|
|
|
return str;
|
|
|
|
}
|
2006-07-03 14:19:23 +00:00
|
|
|
|
2009-10-22 15:09:00 +00:00
|
|
|
std::string toUpper(const std::string& src) {
|
2008-02-08 15:53:45 +00:00
|
|
|
std::string temp = src;
|
|
|
|
std::transform(temp.begin(), temp.end(), temp.begin(), ::toupper);
|
2006-07-03 14:19:23 +00:00
|
|
|
return temp;
|
|
|
|
}
|
|
|
|
|
2009-10-22 15:09:00 +00:00
|
|
|
std::string toLower(const std::string& src) {
|
2008-02-08 15:53:45 +00:00
|
|
|
std::string temp = src;
|
|
|
|
std::transform(temp.begin(), temp.end(), temp.begin(), ::tolower);
|
2006-07-03 14:19:23 +00:00
|
|
|
return temp;
|
|
|
|
}
|
2006-08-11 12:29:55 +00:00
|
|
|
|
2010-10-10 02:51:38 +00:00
|
|
|
void uppercase(std::string& s)
|
|
|
|
{
|
|
|
|
std::transform(s.begin(), s.end(), s.begin(), ::toupper);
|
|
|
|
}
|
|
|
|
|
|
|
|
void lowercase(std::string& s)
|
|
|
|
{
|
|
|
|
std::transform(s.begin(), s.end(), s.begin(), ::tolower);
|
|
|
|
}
|
|
|
|
|
2010-01-28 14:25:16 +00:00
|
|
|
bool isNumericHost(const std::string& name)
|
|
|
|
{
|
|
|
|
struct addrinfo hints;
|
|
|
|
struct addrinfo* res;
|
|
|
|
memset(&hints, 0, sizeof(hints));
|
|
|
|
hints.ai_family = AF_UNSPEC;
|
|
|
|
hints.ai_flags = AI_NUMERICHOST;
|
|
|
|
if(getaddrinfo(name.c_str(), 0, &hints, &res)) {
|
2006-08-11 12:29:55 +00:00
|
|
|
return false;
|
|
|
|
}
|
2010-01-28 14:25:16 +00:00
|
|
|
freeaddrinfo(res);
|
|
|
|
return true;
|
2006-08-11 12:29:55 +00:00
|
|
|
}
|
2006-11-09 14:04:46 +00:00
|
|
|
|
2009-10-22 15:09:00 +00:00
|
|
|
void setGlobalSignalHandler(int sig, void (*handler)(int), int flags) {
|
2007-07-23 13:04:48 +00:00
|
|
|
#ifdef HAVE_SIGACTION
|
2006-11-09 14:04:46 +00:00
|
|
|
struct sigaction sigact;
|
|
|
|
sigact.sa_handler = handler;
|
|
|
|
sigact.sa_flags = flags;
|
|
|
|
sigemptyset(&sigact.sa_mask);
|
2007-07-31 16:45:16 +00:00
|
|
|
sigaction(sig, &sigact, NULL);
|
2007-07-23 13:04:48 +00:00
|
|
|
#else
|
|
|
|
signal(sig, handler);
|
|
|
|
#endif // HAVE_SIGACTION
|
2006-11-09 14:04:46 +00:00
|
|
|
}
|
2007-01-23 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
To add chunk checksum validation:
* src/MetalinkEntry.h
(MetalinkChunkChecksum.h): New include.
(chunkChecksum): New variable.
* src/Request.h
(method): New variable.
(setMethod): New function.
(getMethod): New function.
(METHOD_GET): New static constant.
(METHOD_HEAD): New static constant.
* src/Xml2MetalinkProcessor.h
(getPieceHash): New function.
* src/PieceStorage.h
(markAllPiecesDone): New function.
(checkIntegrity): New function.
* src/FileAllocator.h
(NullFileAllocationMonitor.h): New include.
(FileAllocator): Initialize fileAllocationMonitor with new
NullFileAllocationMonitor().
* src/MultiDiskAdaptor.h
(messageDigest.h): Remove include.
(ctx): Removed.
(hashUpdate): Added ctx.
(MultiDiskAdaptor): Removed ctx.
(sha1Sum): Renamed as messageDigest.
(messageDigest): New function.
* src/UrlRequestInfo.h
(HeadResult): New class.
(digestAlgo): New variable.
(chunkChecksumLength): New variable.
(chunkChecksums): New variable.
(getHeadResult): New function.
(UrlRequestInfo): Added digestAlgo, chunkChecksumLength.
(setDigestAlgo): New function.
(setChunkChecksumLength): New function.
(setChunkChecksums): New function.
* src/DefaultPieceStorage.cc
(DiskAdaptorWriter.h): New include.
(ChunkChecksumValidator.h): New include.
(markAllPiecesDone): New function.
(checkIntegrity): New function.
* src/DefaultBtContext.h
(getPieceHashes): New function.
* src/TorrentRequestInfo.cc
(execute): Try to validate chunk checksum if file already exists
and
.aria2 file doesn't there and user allows aria2 to overwrite it.
* src/messageDigest.h
(~MessageDigestContext): Added digestFree().
* src/MetalinkRequestInfo.cc
(execute): Set digestAlgo, chunkChecksum, chunkChecksums to
reqInfo.
* src/DiskAdaptor.h
(messageDigest.h): New include.
(sha1Sum): Renamed as messageDigest.
(messageDigest): New function.
* src/DownloadCommand.h
(PeerStat.h): New include.
(maxDownloadSpeedLimit): New variable.
(startupIdleTime): New variable.
(lowestDownloadSpeedLimit): New variable.
(peerStat): New variable.
(setMaxDownloadSpeedLimit): New function.
(setStartupIdleTime): New function.
(setLowestDownloadSPeedLimit): New function.
* src/BtContext.h
(getPieceHashes): New function.
* src/main.cc
(main): Set PREF_REALTIME_CHUNK_CHECKSUM and
PREF_CHECK_INTEGRITY
option to true for testing purpose.
* src/BtPieceMessage.cc
(checkPieceHash): Use messageDigest
* src/DownloadEngine.cc
(SetDescriptor): Removed.
(AccumulateActiveCommand): Removed.
(waitData): Rewritten.
(updateFdSet): Rewritten.
* src/MultiDiskAdaptor.cc
(hashUpdate): Added ctx.
(sha1Sum): Renamed as messageDigest.
(messageDigest): New function.
* src/BitfieldMan.h
(isBitRangeSet): New function.
(unsetBitRange): New function.
* src/ByteArrayDiskWriter.h
(sha1Sum): Renamed as messageDigest.
(messageDigest): New function.
* src/ConsoleDownloadEngine.cc
(calculateStatistics): If nspeed < 0 then set nspeed to 0.
* src/DiskWriter.h
(messageDigest.h): New include.
(sha1Sum): Renamed as messageDigest.
(messageDigest): New function.
* src/ChunkChecksumValidator.h: New class.
* src/DiskAdaptorWriter.h: New class.
* src/prefs.h
(PREF_REALTIME_CHUNK_CHECKSUM): New definition.
(PREF_CHECK_INTEGRITY): New definition.
* src/HttpResponseCommand.cc
(handleDefaultEncoding): Added method "HEAD" handling.
Removed the call to
e->segmentMan->shouldCancelDownloadForSafety().
(handleOtherEncoding):
Added the call to
e->segmentMan->shouldCancelDownloadForSafety().
(createHttpDownloadCommand): Set maxDownloadSpeedLimit,
startupIdleTime, lowestDownloadSpeedLimit to command.
* src/SegmentMan.h
(getSegmentEntryByIndex): New function.
(getSegmentEntryByCuid): New function.
(getSegmentEntryIteratorByCuid): New function.
(diskWriter): DiskWriter -> DiskWriterHandle
(pieceHashes): New variable.
(chunkHashLength): New variable.
(digestAlgo): New variable.
(FindPeerStat): Removed.
(getPeerStat): Rewritten.
(markAllPiecesDone): New function.
(checkIntegrity): New function.
(tryChunkChecksumValidation): New function.
(isChunkChecksumValidationReady): New function.
* src/BitfieldMan.cc
(BitfieldMan): Initialized bitfieldLength, blocks to 0.
(BitfieldMan): Initialized blockLength, totalLength,
bitfieldLength,
blocks to 0.
(isBitRangeSet): New function.
(unsetBitRange): New function.
* src/FtpNegotiateCommand.cc
(executeInternal): Set maxDownloadSpeedLimit,
startupIdleTime, lowestDownloadSpeedLimit to command.
(recvSize): Added method "HEAD" handling.
Removed the call to
e->segmentMan->shouldCancelDownloadForSafety().
* src/AbstractSingleDiskAdaptor.cc
(sha1Sum): Renamed as messageDigest.
(messageDigest): New function.
* src/AbstractSingleDiskAdaptor.h
(sha1Sum): Renamed as messageDigest.
(messageDigest): New function.
* src/Util.h
(indexRange): New function.
* src/MetalinkEntry.cc
(MetalinkEntry): Initialized chunkChecksum to 0.
* src/ShaVisitor.cc
(~ShaVisitor): Removed the call to ctx.digestFree().
* src/SegmentMan.cc
(ChunkChecksumValidator.h): New include.
(SegmentMan): Initialized chunkHashLength to 0. Initialized
digestAlgo
to DIGEST_ALGO_SHA1.
(~SegmentMan): Removed diskWriter.
(FindSegmentEntryByIndex): Removed.
(FindSegmentEntryByCuid): Removed.
(checkoutSegment): Rewritten.
(findSlowerSegmentEntry): Rewritten.
(getSegment): Rewritten.
(updateSegment): Rewritten.
(completeSegment): Rewritten.
(markAllPiecesDone): New function.
(checkIntegrity): New function.
(isChunkChecksumValidationReady): New function.
(tryChunkChecksumValidation): New function.
* src/Xml2MetalinkProcessor.cc
(getEntry): Get size and set it to entry.
Get chunk checksum and set it to entry.
(getPieceHash): New function.
* src/Util.cc
(sha1Sum): Removed ctx.digestFree()
(fileChecksum): Removed ctx.digestFree()
(indexRange): New function.
* src/Request.cc
(METHOD_GET): New variable.
(METHOD_HEAD): New variable.
(Request): Added method.
* src/UrlRequestInfo.cc
(FatalException.h): New include.
(message.h): New include.
(operator<<): Added operator<< for class HeadResult.
(getHeadResult): New function.
(execute): Get filename and size in separate download engine.
* src/ChunkChecksumValidator.cc: New class.
* src/DownloadCommand.cc:
(DownloadCommand): Added peerStat.
(executeInternal): Use maxDownloadSpeedLimit member instead of
getting
the value from Option.
The buffer size is now 16KB.
Use peerStat member instead of getting it from SegmentMan.
Use startupIdleTime member instead of gettingit from Option.
Added chunk checksum validation.
* src/AbstractDiskWriter.cc
(AbstractDiskWriter): Removed ctx.
(~AbstractDiskWriter): Removed ctx.digestFree()
(writeDataInternal): Returns the return value of write.
(readDataInternal): Returns the return value of read.
(sha1Sum): Renamed as messageDigest
(messageDigest): New function.
* src/AbstractDiwkWriter.h
(messageDigest.h): Removed include.
(ctx): Removed.
(sha1Sum): Renamed as messageDigest
(messageDigest): New function.
* src/DefaultPieceStorage.h
(markAllPiecesDone): New function.
(checkIntegrity): New function.
* src/NullFileAllocationMonitor.h: New class.
2007-01-24 15:55:34 +00:00
|
|
|
|
2009-10-22 15:09:00 +00:00
|
|
|
std::string getHomeDir()
|
2007-03-18 15:42:34 +00:00
|
|
|
{
|
|
|
|
const char* p = getenv("HOME");
|
|
|
|
if(p) {
|
|
|
|
return p;
|
|
|
|
} else {
|
2011-02-12 09:38:13 +00:00
|
|
|
#ifdef __MINGW32__
|
|
|
|
p = getenv("USERPROFILE");
|
|
|
|
if(p) {
|
|
|
|
return p;
|
|
|
|
} else {
|
|
|
|
p = getenv("HOMEDRIVE");
|
|
|
|
if(p) {
|
|
|
|
std::string homeDir = p;
|
|
|
|
p = getenv("HOMEPATH");
|
|
|
|
if(p) {
|
|
|
|
homeDir += p;
|
|
|
|
return homeDir;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2008-05-13 14:15:23 +00:00
|
|
|
return A2STR::NIL;
|
2007-03-18 15:42:34 +00:00
|
|
|
}
|
|
|
|
}
|
2007-03-26 12:16:57 +00:00
|
|
|
|
2009-10-22 15:09:00 +00:00
|
|
|
int64_t getRealSize(const std::string& sizeWithUnit)
|
2007-03-26 12:16:57 +00:00
|
|
|
{
|
2008-02-08 15:53:45 +00:00
|
|
|
std::string::size_type p = sizeWithUnit.find_first_of("KM");
|
|
|
|
std::string size;
|
2007-07-21 08:56:16 +00:00
|
|
|
int32_t mult = 1;
|
2008-02-08 15:53:45 +00:00
|
|
|
if(p == std::string::npos) {
|
2007-03-26 12:16:57 +00:00
|
|
|
size = sizeWithUnit;
|
|
|
|
} else {
|
|
|
|
if(sizeWithUnit[p] == 'K') {
|
|
|
|
mult = 1024;
|
|
|
|
} else if(sizeWithUnit[p] == 'M') {
|
|
|
|
mult = 1024*1024;
|
|
|
|
}
|
|
|
|
size = sizeWithUnit.substr(0, p);
|
|
|
|
}
|
2009-10-22 15:09:00 +00:00
|
|
|
int64_t v = parseLLInt(size);
|
2007-11-22 11:17:35 +00:00
|
|
|
|
|
|
|
if(v < 0) {
|
2010-11-20 09:36:14 +00:00
|
|
|
throw DL_ABORT_EX(fmt("Negative value detected: %s", sizeWithUnit.c_str()));
|
2008-03-15 04:19:46 +00:00
|
|
|
} else if(INT64_MAX/mult < v) {
|
2010-11-20 09:36:14 +00:00
|
|
|
throw DL_ABORT_EX(fmt(MSG_STRING_INTEGER_CONVERSION_FAILURE,
|
|
|
|
"overflow/underflow"));
|
2007-11-22 11:17:35 +00:00
|
|
|
}
|
|
|
|
return v*mult;
|
2007-03-26 12:16:57 +00:00
|
|
|
}
|
2007-06-05 11:37:25 +00:00
|
|
|
|
2009-10-22 15:09:00 +00:00
|
|
|
std::string abbrevSize(int64_t size)
|
2007-06-05 11:37:25 +00:00
|
|
|
{
|
|
|
|
if(size < 1024) {
|
2009-10-22 15:09:00 +00:00
|
|
|
return itos(size, true);
|
2007-06-05 11:37:25 +00:00
|
|
|
}
|
|
|
|
char units[] = { 'K', 'M' };
|
2008-03-09 12:24:01 +00:00
|
|
|
size_t numUnit = sizeof(units)/sizeof(char);
|
|
|
|
size_t i = 0;
|
2010-10-09 14:22:49 +00:00
|
|
|
int r = size&0x3ffu;
|
2007-06-10 12:01:32 +00:00
|
|
|
size >>= 10;
|
2007-06-05 11:37:25 +00:00
|
|
|
for(; i < numUnit-1 && size >= 1024; ++i) {
|
2010-10-09 14:22:49 +00:00
|
|
|
r = size&0x3ffu;
|
2007-06-05 11:37:25 +00:00
|
|
|
size >>= 10;
|
2007-06-30 09:52:39 +00:00
|
|
|
}
|
2009-10-22 15:09:00 +00:00
|
|
|
std::string result = itos(size, true);
|
2010-01-28 14:33:23 +00:00
|
|
|
result += A2STR::DOT_C;
|
2009-10-22 15:09:00 +00:00
|
|
|
result += itos(r*10/1024);
|
2009-06-06 12:33:07 +00:00
|
|
|
result += units[i];
|
|
|
|
result += "i";
|
|
|
|
return result;
|
2007-06-05 11:37:25 +00:00
|
|
|
}
|
2007-06-10 07:55:43 +00:00
|
|
|
|
2009-10-22 15:09:00 +00:00
|
|
|
void sleep(long seconds) {
|
2007-08-14 14:51:08 +00:00
|
|
|
#ifdef HAVE_SLEEP
|
|
|
|
::sleep(seconds);
|
|
|
|
#elif defined(HAVE_USLEEP)
|
|
|
|
::usleep(seconds * 1000000);
|
|
|
|
#elif defined(HAVE_WINSOCK2_H)
|
|
|
|
::Sleep(seconds * 1000);
|
|
|
|
#else
|
|
|
|
#error no sleep function is available (nanosleep?)
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2009-10-22 15:09:00 +00:00
|
|
|
void usleep(long microseconds) {
|
2007-08-14 14:51:08 +00:00
|
|
|
#ifdef HAVE_USLEEP
|
|
|
|
::usleep(microseconds);
|
|
|
|
#elif defined(HAVE_WINSOCK2_H)
|
|
|
|
|
2010-01-05 16:01:46 +00:00
|
|
|
LARGE_INTEGER current, freq, end;
|
2007-08-14 14:51:08 +00:00
|
|
|
|
2010-01-05 16:01:46 +00:00
|
|
|
static enum {GET_FREQUENCY, GET_MICROSECONDS, SKIP_MICROSECONDS} state = GET_FREQUENCY;
|
2007-08-14 14:51:08 +00:00
|
|
|
|
2010-01-05 16:01:46 +00:00
|
|
|
if (state == GET_FREQUENCY) {
|
|
|
|
if (QueryPerformanceFrequency(&freq))
|
|
|
|
state = GET_MICROSECONDS;
|
|
|
|
else
|
|
|
|
state = SKIP_MICROSECONDS;
|
|
|
|
}
|
|
|
|
|
|
|
|
long msec = microseconds / 1000;
|
|
|
|
microseconds %= 1000;
|
2007-08-14 14:51:08 +00:00
|
|
|
|
2010-01-05 16:01:46 +00:00
|
|
|
if (state == GET_MICROSECONDS && microseconds) {
|
|
|
|
QueryPerformanceCounter(&end);
|
2007-08-14 14:51:08 +00:00
|
|
|
|
2010-01-05 16:01:46 +00:00
|
|
|
end.QuadPart += (freq.QuadPart * microseconds) / 1000000;
|
2007-08-14 14:51:08 +00:00
|
|
|
|
2010-01-05 16:01:46 +00:00
|
|
|
while (QueryPerformanceCounter(¤t) && (current.QuadPart <= end.QuadPart))
|
|
|
|
/* noop */ ;
|
|
|
|
}
|
2007-08-14 14:51:08 +00:00
|
|
|
|
2010-01-05 16:01:46 +00:00
|
|
|
if (msec)
|
|
|
|
Sleep(msec);
|
2007-08-14 14:51:08 +00:00
|
|
|
#else
|
2010-01-05 16:01:46 +00:00
|
|
|
#error no usleep function is available (nanosleep?)
|
2007-08-14 14:51:08 +00:00
|
|
|
#endif
|
|
|
|
}
|
2007-08-28 11:51:20 +00:00
|
|
|
|
2009-10-22 15:09:00 +00:00
|
|
|
bool isNumber(const std::string& what)
|
2007-08-28 11:51:20 +00:00
|
|
|
{
|
|
|
|
if(what.empty()) {
|
|
|
|
return false;
|
|
|
|
}
|
2010-02-28 16:04:52 +00:00
|
|
|
for(std::string::const_iterator i = what.begin(), eoi = what.end();
|
|
|
|
i != eoi; ++i) {
|
2010-02-19 14:33:39 +00:00
|
|
|
if(!isDigit(*i)) {
|
2007-08-28 11:51:20 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-10-22 15:09:00 +00:00
|
|
|
bool isLowercase(const std::string& what)
|
2007-08-28 11:51:20 +00:00
|
|
|
{
|
|
|
|
if(what.empty()) {
|
|
|
|
return false;
|
|
|
|
}
|
2010-06-26 14:03:14 +00:00
|
|
|
for(uint32_t i = 0, eoi = what.size(); i < eoi; ++i) {
|
2007-08-28 11:51:20 +00:00
|
|
|
if(!('a' <= what[i] && what[i] <= 'z')) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-10-22 15:09:00 +00:00
|
|
|
bool isUppercase(const std::string& what)
|
2007-08-28 11:51:20 +00:00
|
|
|
{
|
|
|
|
if(what.empty()) {
|
|
|
|
return false;
|
|
|
|
}
|
2010-06-26 14:03:14 +00:00
|
|
|
for(uint32_t i = 0, eoi = what.size(); i < eoi; ++i) {
|
2007-08-28 11:51:20 +00:00
|
|
|
if(!('A' <= what[i] && what[i] <= 'Z')) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-10-22 15:09:00 +00:00
|
|
|
unsigned int alphaToNum(const std::string& alphabets)
|
2007-08-28 11:51:20 +00:00
|
|
|
{
|
|
|
|
if(alphabets.empty()) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
char base;
|
|
|
|
if(islower(alphabets[0])) {
|
|
|
|
base = 'a';
|
|
|
|
} else {
|
|
|
|
base = 'A';
|
|
|
|
}
|
2008-03-09 15:03:47 +00:00
|
|
|
uint64_t num = 0;
|
2010-06-26 14:03:14 +00:00
|
|
|
for(size_t i = 0, eoi = alphabets.size(); i < eoi; ++i) {
|
2008-03-09 15:03:47 +00:00
|
|
|
unsigned int v = alphabets[i]-base;
|
2007-08-28 11:51:20 +00:00
|
|
|
num = num*26+v;
|
2008-03-09 15:03:47 +00:00
|
|
|
if(num > UINT32_MAX) {
|
|
|
|
return 0;
|
|
|
|
}
|
2007-08-28 11:51:20 +00:00
|
|
|
}
|
|
|
|
return num;
|
|
|
|
}
|
|
|
|
|
2009-10-22 15:09:00 +00:00
|
|
|
void mkdirs(const std::string& dirpath)
|
2007-11-05 15:13:55 +00:00
|
|
|
{
|
|
|
|
File dir(dirpath);
|
2010-11-09 14:43:47 +00:00
|
|
|
if(!dir.mkdirs()) {
|
|
|
|
int errNum = errno;
|
|
|
|
if(!dir.isDir()) {
|
2010-12-01 12:26:58 +00:00
|
|
|
throw DL_ABORT_EX3
|
|
|
|
(errNum,
|
|
|
|
fmt(EX_MAKE_DIR, dir.getPath().c_str(),
|
|
|
|
safeStrerror(errNum).c_str()),
|
|
|
|
error_code::DIR_CREATE_ERROR);
|
2010-11-09 14:43:47 +00:00
|
|
|
}
|
2007-11-05 15:13:55 +00:00
|
|
|
}
|
|
|
|
}
|
2007-11-13 10:10:11 +00:00
|
|
|
|
2009-10-22 15:09:00 +00:00
|
|
|
void convertBitfield(BitfieldMan* dest, const BitfieldMan* src)
|
2007-11-13 10:10:11 +00:00
|
|
|
{
|
2008-03-08 08:04:28 +00:00
|
|
|
size_t numBlock = dest->countBlock();
|
|
|
|
for(size_t index = 0; index < numBlock; ++index) {
|
|
|
|
if(src->isBitSetOffsetRange((uint64_t)index*dest->getBlockLength(),
|
2010-01-05 16:01:46 +00:00
|
|
|
dest->getBlockLength())) {
|
2007-11-13 10:10:11 +00:00
|
|
|
dest->setBit(index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-11-27 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
Rewritten to add content-type support.
* src/DownloadHandler.{h, cc}
* src/BtPostDownloadHandler.{h, cc}
* test/BtPostDownloadHandlerTest.cc
* src/MetalinkPostDownloadHandler.{h, cc}
* test/MetalinkPostDownloadHandlerTest.cc
* src/PostDownloadHandler.{h, cc}
* src/DownloadHandlerConstants.{h, cc}
* src/RequestGroup.cc
* src/HttpResponseCommand.cc
* src/FtpNegotiationCommand.cc
* src/SingleFileDownloadContext.{h, cc}
* src/RequestGroup.h
* src/RequestGroupCriteria.h
* src/ContentTypeRequestGroupCriteria.h
Added 'mem' option value for --follow-metalink,
--follow-torrent.
If it is give, metalink/torrent file is not written to the disk,
but
just is kept in memory. Parsing is occurred on memory.
* src/MetalinkHelper.{h, cc}
* src/MetalinkProcessor.h
* src/Xml2MetalinkProcessor.{h, cc}
* test/Xml2MetalinkProcessorTest.cc
* src/DownloadHandlerFactory.{h, cc}
* test/DownloadHandlerFactoryTest.cc
* src/PreDownloadHandler.{h, cc}
* src/OptionHandlerFactory.cc
* src/DefaultBtContext.{h, cc}
* test/DefaultBtContextTest.cc
* src/version_usage.cc
* src/Metalink2RequestGroup.{h, cc}
* src/RequestGroup.{h, cc}
* src/a2functional.h
* test/a2functionalTest.cc
* src/MemoryBufferPreDownloadHandler.{h, cc}
* src/OptionHandlerImpl.h
* src/prefs.h
* src/Util.{h, cc}
* test/UtilTest.cc
Keep DownloadResult rather than RequestGroup after downloads to
reduce
memory usage.
* src/RequestGroupMan.{h, cc}
* src/DownloadEngine.cc
* src/BtDependency.{h, cc}: Changed the type of dependee from
WeakHandle to SharedHandle because WeakHandle could be null.
* src/RequestGroup.{h, cc}
* src/DownloadEngineFactory.cc
* src/DownloadResult.h
Set totalLength after download finished
* src/UnknownLengthPieceStorage.{h, cc}
Keep torrent file specified in metalink in memory.
* src/Metalink2RequestGroup.cc
* src/BtDependency.cc
* src/TrueRequestGroupCriteria.h
Fixed the bug: seekg is used where seekp should be used.
* src/ByteArrayDiskWriter.cc
* test/ByteArraydiskWriterTest.cc
2007-11-27 12:27:10 +00:00
|
|
|
|
2009-10-22 15:09:00 +00:00
|
|
|
std::string toString(const BinaryStreamHandle& binaryStream)
|
2007-11-27 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
Rewritten to add content-type support.
* src/DownloadHandler.{h, cc}
* src/BtPostDownloadHandler.{h, cc}
* test/BtPostDownloadHandlerTest.cc
* src/MetalinkPostDownloadHandler.{h, cc}
* test/MetalinkPostDownloadHandlerTest.cc
* src/PostDownloadHandler.{h, cc}
* src/DownloadHandlerConstants.{h, cc}
* src/RequestGroup.cc
* src/HttpResponseCommand.cc
* src/FtpNegotiationCommand.cc
* src/SingleFileDownloadContext.{h, cc}
* src/RequestGroup.h
* src/RequestGroupCriteria.h
* src/ContentTypeRequestGroupCriteria.h
Added 'mem' option value for --follow-metalink,
--follow-torrent.
If it is give, metalink/torrent file is not written to the disk,
but
just is kept in memory. Parsing is occurred on memory.
* src/MetalinkHelper.{h, cc}
* src/MetalinkProcessor.h
* src/Xml2MetalinkProcessor.{h, cc}
* test/Xml2MetalinkProcessorTest.cc
* src/DownloadHandlerFactory.{h, cc}
* test/DownloadHandlerFactoryTest.cc
* src/PreDownloadHandler.{h, cc}
* src/OptionHandlerFactory.cc
* src/DefaultBtContext.{h, cc}
* test/DefaultBtContextTest.cc
* src/version_usage.cc
* src/Metalink2RequestGroup.{h, cc}
* src/RequestGroup.{h, cc}
* src/a2functional.h
* test/a2functionalTest.cc
* src/MemoryBufferPreDownloadHandler.{h, cc}
* src/OptionHandlerImpl.h
* src/prefs.h
* src/Util.{h, cc}
* test/UtilTest.cc
Keep DownloadResult rather than RequestGroup after downloads to
reduce
memory usage.
* src/RequestGroupMan.{h, cc}
* src/DownloadEngine.cc
* src/BtDependency.{h, cc}: Changed the type of dependee from
WeakHandle to SharedHandle because WeakHandle could be null.
* src/RequestGroup.{h, cc}
* src/DownloadEngineFactory.cc
* src/DownloadResult.h
Set totalLength after download finished
* src/UnknownLengthPieceStorage.{h, cc}
Keep torrent file specified in metalink in memory.
* src/Metalink2RequestGroup.cc
* src/BtDependency.cc
* src/TrueRequestGroupCriteria.h
Fixed the bug: seekg is used where seekp should be used.
* src/ByteArrayDiskWriter.cc
* test/ByteArraydiskWriterTest.cc
2007-11-27 12:27:10 +00:00
|
|
|
{
|
2008-02-08 15:53:45 +00:00
|
|
|
std::stringstream strm;
|
2007-11-27 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
Rewritten to add content-type support.
* src/DownloadHandler.{h, cc}
* src/BtPostDownloadHandler.{h, cc}
* test/BtPostDownloadHandlerTest.cc
* src/MetalinkPostDownloadHandler.{h, cc}
* test/MetalinkPostDownloadHandlerTest.cc
* src/PostDownloadHandler.{h, cc}
* src/DownloadHandlerConstants.{h, cc}
* src/RequestGroup.cc
* src/HttpResponseCommand.cc
* src/FtpNegotiationCommand.cc
* src/SingleFileDownloadContext.{h, cc}
* src/RequestGroup.h
* src/RequestGroupCriteria.h
* src/ContentTypeRequestGroupCriteria.h
Added 'mem' option value for --follow-metalink,
--follow-torrent.
If it is give, metalink/torrent file is not written to the disk,
but
just is kept in memory. Parsing is occurred on memory.
* src/MetalinkHelper.{h, cc}
* src/MetalinkProcessor.h
* src/Xml2MetalinkProcessor.{h, cc}
* test/Xml2MetalinkProcessorTest.cc
* src/DownloadHandlerFactory.{h, cc}
* test/DownloadHandlerFactoryTest.cc
* src/PreDownloadHandler.{h, cc}
* src/OptionHandlerFactory.cc
* src/DefaultBtContext.{h, cc}
* test/DefaultBtContextTest.cc
* src/version_usage.cc
* src/Metalink2RequestGroup.{h, cc}
* src/RequestGroup.{h, cc}
* src/a2functional.h
* test/a2functionalTest.cc
* src/MemoryBufferPreDownloadHandler.{h, cc}
* src/OptionHandlerImpl.h
* src/prefs.h
* src/Util.{h, cc}
* test/UtilTest.cc
Keep DownloadResult rather than RequestGroup after downloads to
reduce
memory usage.
* src/RequestGroupMan.{h, cc}
* src/DownloadEngine.cc
* src/BtDependency.{h, cc}: Changed the type of dependee from
WeakHandle to SharedHandle because WeakHandle could be null.
* src/RequestGroup.{h, cc}
* src/DownloadEngineFactory.cc
* src/DownloadResult.h
Set totalLength after download finished
* src/UnknownLengthPieceStorage.{h, cc}
Keep torrent file specified in metalink in memory.
* src/Metalink2RequestGroup.cc
* src/BtDependency.cc
* src/TrueRequestGroupCriteria.h
Fixed the bug: seekg is used where seekp should be used.
* src/ByteArrayDiskWriter.cc
* test/ByteArraydiskWriterTest.cc
2007-11-27 12:27:10 +00:00
|
|
|
char data[2048];
|
|
|
|
while(1) {
|
2009-11-15 12:55:50 +00:00
|
|
|
int32_t dataLength = binaryStream->readData
|
|
|
|
(reinterpret_cast<unsigned char*>(data), sizeof(data), strm.tellp());
|
2007-11-27 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
Rewritten to add content-type support.
* src/DownloadHandler.{h, cc}
* src/BtPostDownloadHandler.{h, cc}
* test/BtPostDownloadHandlerTest.cc
* src/MetalinkPostDownloadHandler.{h, cc}
* test/MetalinkPostDownloadHandlerTest.cc
* src/PostDownloadHandler.{h, cc}
* src/DownloadHandlerConstants.{h, cc}
* src/RequestGroup.cc
* src/HttpResponseCommand.cc
* src/FtpNegotiationCommand.cc
* src/SingleFileDownloadContext.{h, cc}
* src/RequestGroup.h
* src/RequestGroupCriteria.h
* src/ContentTypeRequestGroupCriteria.h
Added 'mem' option value for --follow-metalink,
--follow-torrent.
If it is give, metalink/torrent file is not written to the disk,
but
just is kept in memory. Parsing is occurred on memory.
* src/MetalinkHelper.{h, cc}
* src/MetalinkProcessor.h
* src/Xml2MetalinkProcessor.{h, cc}
* test/Xml2MetalinkProcessorTest.cc
* src/DownloadHandlerFactory.{h, cc}
* test/DownloadHandlerFactoryTest.cc
* src/PreDownloadHandler.{h, cc}
* src/OptionHandlerFactory.cc
* src/DefaultBtContext.{h, cc}
* test/DefaultBtContextTest.cc
* src/version_usage.cc
* src/Metalink2RequestGroup.{h, cc}
* src/RequestGroup.{h, cc}
* src/a2functional.h
* test/a2functionalTest.cc
* src/MemoryBufferPreDownloadHandler.{h, cc}
* src/OptionHandlerImpl.h
* src/prefs.h
* src/Util.{h, cc}
* test/UtilTest.cc
Keep DownloadResult rather than RequestGroup after downloads to
reduce
memory usage.
* src/RequestGroupMan.{h, cc}
* src/DownloadEngine.cc
* src/BtDependency.{h, cc}: Changed the type of dependee from
WeakHandle to SharedHandle because WeakHandle could be null.
* src/RequestGroup.{h, cc}
* src/DownloadEngineFactory.cc
* src/DownloadResult.h
Set totalLength after download finished
* src/UnknownLengthPieceStorage.{h, cc}
Keep torrent file specified in metalink in memory.
* src/Metalink2RequestGroup.cc
* src/BtDependency.cc
* src/TrueRequestGroupCriteria.h
Fixed the bug: seekg is used where seekp should be used.
* src/ByteArrayDiskWriter.cc
* test/ByteArraydiskWriterTest.cc
2007-11-27 12:27:10 +00:00
|
|
|
strm.write(data, dataLength);
|
|
|
|
if(dataLength == 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return strm.str();
|
|
|
|
}
|
2007-11-28 14:22:28 +00:00
|
|
|
|
|
|
|
#ifdef HAVE_POSIX_MEMALIGN
|
|
|
|
/**
|
|
|
|
* In linux 2.6, alignment and size should be a multiple of 512.
|
|
|
|
*/
|
2009-10-22 15:09:00 +00:00
|
|
|
void* allocateAlignedMemory(size_t alignment, size_t size)
|
2007-11-28 14:22:28 +00:00
|
|
|
{
|
|
|
|
void* buffer;
|
2008-03-09 12:24:01 +00:00
|
|
|
int res;
|
2007-11-28 14:22:28 +00:00
|
|
|
if((res = posix_memalign(&buffer, alignment, size)) != 0) {
|
2009-05-18 15:07:15 +00:00
|
|
|
throw FATAL_EXCEPTION
|
2010-11-20 09:36:14 +00:00
|
|
|
(fmt("Error in posix_memalign: %s",
|
|
|
|
util::safeStrerror(res).c_str()));
|
2007-11-28 14:22:28 +00:00
|
|
|
}
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
#endif // HAVE_POSIX_MEMALIGN
|
2008-02-08 15:53:45 +00:00
|
|
|
|
2008-05-08 11:18:36 +00:00
|
|
|
std::pair<std::string, uint16_t>
|
2009-10-22 15:09:00 +00:00
|
|
|
getNumericNameInfo(const struct sockaddr* sockaddr, socklen_t len)
|
2008-05-08 11:18:36 +00:00
|
|
|
{
|
|
|
|
char host[NI_MAXHOST];
|
|
|
|
char service[NI_MAXSERV];
|
|
|
|
int s = getnameinfo(sockaddr, len, host, NI_MAXHOST, service, NI_MAXSERV,
|
2010-01-05 16:01:46 +00:00
|
|
|
NI_NUMERICHOST|NI_NUMERICSERV);
|
2008-05-08 11:18:36 +00:00
|
|
|
if(s != 0) {
|
2010-11-20 09:36:14 +00:00
|
|
|
throw DL_ABORT_EX(fmt("Failed to get hostname and port. cause: %s",
|
|
|
|
gai_strerror(s)));
|
2008-05-08 11:18:36 +00:00
|
|
|
}
|
|
|
|
return std::pair<std::string, uint16_t>(host, atoi(service)); // TODO
|
|
|
|
}
|
|
|
|
|
2009-10-22 15:09:00 +00:00
|
|
|
std::string htmlEscape(const std::string& src)
|
2009-01-25 09:58:40 +00:00
|
|
|
{
|
|
|
|
std::string dest;
|
2010-02-28 16:04:52 +00:00
|
|
|
for(std::string::const_iterator i = src.begin(), eoi = src.end();
|
|
|
|
i != eoi; ++i) {
|
2009-01-25 09:58:40 +00:00
|
|
|
char ch = *i;
|
|
|
|
if(ch == '<') {
|
|
|
|
dest += "<";
|
|
|
|
} else if(ch == '>') {
|
|
|
|
dest += ">";
|
|
|
|
} else if(ch == '&') {
|
|
|
|
dest += "&";
|
|
|
|
} else if(ch == '\'') {
|
|
|
|
dest += "'";
|
|
|
|
} else if(ch == '"') {
|
|
|
|
dest += """;
|
|
|
|
} else {
|
|
|
|
dest += ch;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return dest;
|
|
|
|
}
|
|
|
|
|
2009-03-07 03:10:53 +00:00
|
|
|
std::map<size_t, std::string>::value_type
|
2009-10-22 15:09:00 +00:00
|
|
|
parseIndexPath(const std::string& line)
|
2009-03-07 03:10:53 +00:00
|
|
|
{
|
2010-10-10 03:39:00 +00:00
|
|
|
std::pair<std::string, std::string> p;
|
|
|
|
divide(p, line, '=');
|
2009-03-07 03:10:53 +00:00
|
|
|
size_t index = parseUInt(p.first);
|
|
|
|
if(p.second.empty()) {
|
2010-11-20 09:36:14 +00:00
|
|
|
throw DL_ABORT_EX(fmt("Path with index=%u is empty.",
|
|
|
|
static_cast<unsigned int>(index)));
|
2009-03-07 03:10:53 +00:00
|
|
|
}
|
|
|
|
return std::map<size_t, std::string>::value_type(index, p.second);
|
|
|
|
}
|
|
|
|
|
2009-10-22 15:09:00 +00:00
|
|
|
std::map<size_t, std::string> createIndexPathMap(std::istream& i)
|
2009-03-07 03:10:53 +00:00
|
|
|
{
|
|
|
|
std::map<size_t, std::string> indexPathMap;
|
|
|
|
std::string line;
|
|
|
|
while(getline(i, line)) {
|
|
|
|
indexPathMap.insert(indexPathMap.begin(), parseIndexPath(line));
|
|
|
|
}
|
|
|
|
return indexPathMap;
|
|
|
|
}
|
|
|
|
|
2009-10-22 14:43:42 +00:00
|
|
|
void generateRandomData(unsigned char* data, size_t length)
|
|
|
|
{
|
|
|
|
#ifdef HAVE_LIBGCRYPT
|
|
|
|
gcry_randomize(data, length, GCRY_STRONG_RANDOM);
|
|
|
|
#elif HAVE_LIBSSL
|
|
|
|
if(RAND_bytes(data, length) != 1) {
|
|
|
|
for(size_t i = 0; i < length; ++i) {
|
|
|
|
data[i] = SimpleRandomizer::getInstance()->getRandomNumber(UINT8_MAX+1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
std::ifstream i("/dev/urandom", std::ios::binary);
|
2009-11-02 14:04:28 +00:00
|
|
|
i.read(reinterpret_cast<char*>(data), length);
|
2009-10-22 14:43:42 +00:00
|
|
|
#endif // HAVE_LIBSSL
|
|
|
|
}
|
|
|
|
|
2009-12-23 13:16:57 +00:00
|
|
|
bool saveAs
|
|
|
|
(const std::string& filename, const std::string& data, bool overwrite)
|
|
|
|
{
|
|
|
|
if(!overwrite && File(filename).exists()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
std::string tempFilename = strconcat(filename, "__temp");
|
2010-04-13 15:23:31 +00:00
|
|
|
{
|
|
|
|
std::ofstream out(tempFilename.c_str(), std::ios::binary);
|
|
|
|
if(!out) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
out << data;
|
|
|
|
out.flush();
|
|
|
|
if(!out) {
|
|
|
|
return false;
|
|
|
|
}
|
2009-12-23 13:16:57 +00:00
|
|
|
}
|
|
|
|
return File(tempFilename).renameTo(filename);
|
|
|
|
}
|
|
|
|
|
2010-01-11 14:01:20 +00:00
|
|
|
std::string applyDir(const std::string& dir, const std::string& relPath)
|
|
|
|
{
|
|
|
|
if(dir.empty()) {
|
|
|
|
return strconcat(A2STR::DOT_C, A2STR::SLASH_C, relPath);
|
|
|
|
} else if(dir == A2STR::SLASH_C) {
|
|
|
|
return strconcat(A2STR::SLASH_C, relPath);
|
|
|
|
} else {
|
|
|
|
return strconcat(dir, A2STR::SLASH_C, relPath);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-11 14:32:20 +00:00
|
|
|
std::string fixTaintedBasename(const std::string& src)
|
|
|
|
{
|
2010-10-02 08:20:10 +00:00
|
|
|
static std::string SLASH_REP = "%2F";
|
|
|
|
return escapePath(replace(src, A2STR::SLASH_C, SLASH_REP));
|
2010-01-11 14:32:20 +00:00
|
|
|
}
|
|
|
|
|
2010-01-17 10:05:53 +00:00
|
|
|
void generateRandomKey(unsigned char* key)
|
|
|
|
{
|
2010-01-23 10:02:56 +00:00
|
|
|
#ifdef ENABLE_MESSAGE_DIGEST
|
2010-01-17 10:05:53 +00:00
|
|
|
unsigned char bytes[40];
|
|
|
|
generateRandomData(bytes, sizeof(bytes));
|
2011-02-05 14:38:51 +00:00
|
|
|
message_digest::digest(key, 20, MessageDigest::sha1(), bytes, sizeof(bytes));
|
2010-01-23 10:02:56 +00:00
|
|
|
#else // !ENABLE_MESSAGE_DIGEST
|
|
|
|
generateRandomData(key, 20);
|
|
|
|
#endif // !ENABLE_MESSAGE_DIGEST
|
2010-01-17 10:05:53 +00:00
|
|
|
}
|
|
|
|
|
2010-02-20 14:23:25 +00:00
|
|
|
// Returns true is given numeric ipv4addr is in Private Address Space.
|
|
|
|
//
|
|
|
|
// From Section.3 RFC1918
|
|
|
|
// 10.0.0.0 - 10.255.255.255 (10/8 prefix)
|
|
|
|
// 172.16.0.0 - 172.31.255.255 (172.16/12 prefix)
|
|
|
|
// 192.168.0.0 - 192.168.255.255 (192.168/16 prefix)
|
|
|
|
bool inPrivateAddress(const std::string& ipv4addr)
|
|
|
|
{
|
|
|
|
if(util::startsWith(ipv4addr, "10.") ||
|
|
|
|
util::startsWith(ipv4addr, "192.168.")) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if(util::startsWith(ipv4addr, "172.")) {
|
|
|
|
for(int i = 16; i <= 31; ++i) {
|
|
|
|
if(util::startsWith(ipv4addr, "172."+util::itos(i)+".")) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-02-25 14:40:18 +00:00
|
|
|
bool detectDirTraversal(const std::string& s)
|
|
|
|
{
|
2010-02-28 16:04:52 +00:00
|
|
|
for(std::string::const_iterator i = s.begin(), eoi = s.end(); i != eoi; ++i) {
|
2010-10-02 08:20:10 +00:00
|
|
|
unsigned char c = *i;
|
2010-10-09 14:22:49 +00:00
|
|
|
if(in(c, 0x00u, 0x1fu) || c == 0x7fu) {
|
2010-02-27 10:06:40 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2010-10-02 08:29:15 +00:00
|
|
|
|
2010-11-14 08:19:53 +00:00
|
|
|
static std::string A2_DS = "./";
|
|
|
|
static std::string A2_DDS = "../";
|
|
|
|
static std::string A2_SD = "/.";
|
|
|
|
static std::string A2_SDD = "/..";
|
|
|
|
static std::string A2_SDDS = "/../";
|
|
|
|
static std::string A2_SDS = "/./";
|
|
|
|
static std::string A2_DD = "..";
|
2010-10-02 08:29:15 +00:00
|
|
|
|
2010-02-25 14:40:18 +00:00
|
|
|
return s == A2STR::DOT_C ||
|
2010-11-14 08:19:53 +00:00
|
|
|
s == A2_DD ||
|
2010-02-25 14:40:18 +00:00
|
|
|
util::startsWith(s, A2STR::SLASH_C) ||
|
2010-11-14 08:19:53 +00:00
|
|
|
util::startsWith(s, A2_DS) ||
|
|
|
|
util::startsWith(s, A2_DDS) ||
|
|
|
|
s.find(A2_SDDS) != std::string::npos ||
|
|
|
|
s.find(A2_SDS) != std::string::npos ||
|
2010-10-02 08:29:15 +00:00
|
|
|
util::endsWith(s, A2STR::SLASH_C) ||
|
2010-11-14 08:19:53 +00:00
|
|
|
util::endsWith(s, A2_SD) ||
|
|
|
|
util::endsWith(s, A2_SDD);
|
2010-02-25 14:40:18 +00:00
|
|
|
}
|
|
|
|
|
2010-10-02 08:20:10 +00:00
|
|
|
std::string escapePath(const std::string& s)
|
|
|
|
{
|
|
|
|
// We don't escape '/' because we use it as a path separator.
|
2010-02-27 10:06:40 +00:00
|
|
|
#ifdef __MINGW32__
|
2010-10-02 08:20:10 +00:00
|
|
|
static const char WIN_INVALID_PATH_CHARS[] =
|
|
|
|
{ '"', '*', ':', '<', '>', '?', '\\', '|' };
|
2010-02-27 10:06:40 +00:00
|
|
|
#endif // __MINGW32__
|
2010-10-02 08:20:10 +00:00
|
|
|
std::string d;
|
|
|
|
for(std::string::const_iterator i = s.begin(), eoi = s.end(); i != eoi; ++i) {
|
|
|
|
unsigned char c = *i;
|
2010-10-09 14:22:49 +00:00
|
|
|
if(in(c, 0x00u, 0x1fu) || c == 0x7fu
|
2010-10-02 08:20:10 +00:00
|
|
|
#ifdef __MINGW32__
|
|
|
|
|| std::find(vbegin(WIN_INVALID_PATH_CHARS),
|
|
|
|
vend(WIN_INVALID_PATH_CHARS),
|
|
|
|
c) != vend(WIN_INVALID_PATH_CHARS)
|
2010-11-26 13:07:28 +00:00
|
|
|
// Since Windows does not understand UTF-8 correctly, we
|
|
|
|
// percent-encode character other than ASCII.
|
|
|
|
|| c > 0x7fu
|
2010-10-02 08:20:10 +00:00
|
|
|
#endif // __MINGW32__
|
|
|
|
){
|
2010-11-20 09:36:14 +00:00
|
|
|
d += fmt("%%%02X", c);
|
2010-10-02 08:20:10 +00:00
|
|
|
} else {
|
|
|
|
d += *i;
|
|
|
|
}
|
|
|
|
}
|
2010-02-27 10:06:40 +00:00
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
2010-03-19 08:56:17 +00:00
|
|
|
bool getCidrPrefix(struct in_addr& in, const std::string& ip, int bits)
|
|
|
|
{
|
|
|
|
struct in_addr t;
|
|
|
|
if(inet_aton(ip.c_str(), &t) == 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
int lastindex = bits/8;
|
|
|
|
if(lastindex < 4) {
|
|
|
|
char* p = reinterpret_cast<char*>(&t.s_addr);
|
|
|
|
const char* last = p+4;
|
|
|
|
p += lastindex;
|
|
|
|
if(bits%8 != 0) {
|
|
|
|
*p &= bitfield::lastByteMask(bits);
|
|
|
|
++p;
|
|
|
|
}
|
|
|
|
for(; p != last; ++p) {
|
|
|
|
*p &= 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
in = t;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool inSameCidrBlock(const std::string& ip1, const std::string& ip2, int bits)
|
|
|
|
{
|
|
|
|
struct in_addr in1;
|
|
|
|
struct in_addr in2;
|
|
|
|
if(!getCidrPrefix(in1, ip1, bits) || !getCidrPrefix(in2, ip2, bits)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return in1.s_addr == in2.s_addr;
|
|
|
|
}
|
|
|
|
|
2010-04-01 15:41:53 +00:00
|
|
|
void removeMetalinkContentTypes(const SharedHandle<RequestGroup>& group)
|
|
|
|
{
|
|
|
|
for(std::vector<std::string>::const_iterator i =
|
|
|
|
DownloadHandlerConstants::getMetalinkContentTypes().begin(),
|
|
|
|
eoi = DownloadHandlerConstants::getMetalinkContentTypes().end();
|
|
|
|
i != eoi; ++i) {
|
|
|
|
group->removeAcceptType(*i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-12-04 09:14:27 +00:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
void executeHook
|
|
|
|
(const std::string& command,
|
2010-12-04 10:00:48 +00:00
|
|
|
gid_t gid,
|
|
|
|
size_t numFiles,
|
2010-12-04 09:14:27 +00:00
|
|
|
const std::string& firstFilename)
|
2010-07-16 14:22:57 +00:00
|
|
|
{
|
2010-12-04 10:00:48 +00:00
|
|
|
const std::string gidStr = util::itos(gid);
|
|
|
|
const std::string numFilesStr = util::uitos(numFiles);
|
|
|
|
A2_LOG_INFO(fmt("Executing user command: %s %s %s %s",
|
2010-11-20 08:21:36 +00:00
|
|
|
command.c_str(),
|
2010-12-04 10:00:48 +00:00
|
|
|
gidStr.c_str(),
|
|
|
|
numFilesStr.c_str(),
|
2010-12-04 09:14:27 +00:00
|
|
|
firstFilename.c_str()));
|
2010-07-16 14:22:57 +00:00
|
|
|
#ifndef __MINGW32__
|
|
|
|
pid_t cpid = fork();
|
|
|
|
if(cpid == -1) {
|
2010-11-20 08:21:36 +00:00
|
|
|
A2_LOG_ERROR("fork() failed. Cannot execute user command.");
|
2010-07-16 14:22:57 +00:00
|
|
|
} else if(cpid == 0) {
|
2010-12-04 10:00:48 +00:00
|
|
|
execl(command.c_str(),
|
|
|
|
command.c_str(),
|
|
|
|
gidStr.c_str(),
|
|
|
|
numFilesStr.c_str(),
|
|
|
|
firstFilename.c_str(),
|
2010-07-16 14:22:57 +00:00
|
|
|
reinterpret_cast<char*>(0));
|
|
|
|
perror(("Could not execute user command: "+command).c_str());
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
PROCESS_INFORMATION pi;
|
|
|
|
STARTUPINFO si;
|
|
|
|
|
|
|
|
memset(&si, 0, sizeof (si));
|
|
|
|
si.cb = sizeof(STARTUPINFO);
|
|
|
|
|
|
|
|
memset(&pi, 0, sizeof (pi));
|
|
|
|
|
|
|
|
std::string cmdline = command;
|
2010-12-04 10:00:48 +00:00
|
|
|
strappend(cmdline, " ", gidStr, " ", numFilesStr, " \"", firstFilename, "\"");
|
2010-07-16 14:22:57 +00:00
|
|
|
|
|
|
|
DWORD rc = CreateProcess(
|
|
|
|
NULL,
|
|
|
|
(LPSTR)cmdline.c_str(),
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
true,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
&si,
|
|
|
|
&pi);
|
|
|
|
|
2010-11-20 08:21:36 +00:00
|
|
|
if(!rc) {
|
|
|
|
A2_LOG_ERROR("CreateProcess() failed. Cannot execute user command.");
|
|
|
|
}
|
2010-07-16 14:22:57 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2010-12-04 09:14:27 +00:00
|
|
|
} // namespace
|
|
|
|
|
2010-07-16 14:22:57 +00:00
|
|
|
void executeHookByOptName
|
|
|
|
(const SharedHandle<RequestGroup>& group, const Option* option,
|
|
|
|
const std::string& opt)
|
2010-07-16 15:00:35 +00:00
|
|
|
{
|
|
|
|
executeHookByOptName(group.get(), option, opt);
|
|
|
|
}
|
|
|
|
|
|
|
|
void executeHookByOptName
|
|
|
|
(const RequestGroup* group, const Option* option, const std::string& opt)
|
2010-07-16 14:22:57 +00:00
|
|
|
{
|
|
|
|
if(!option->blank(opt)) {
|
2010-12-04 09:14:27 +00:00
|
|
|
const SharedHandle<DownloadContext> dctx = group->getDownloadContext();
|
|
|
|
std::string firstFilename;
|
2010-12-04 10:00:48 +00:00
|
|
|
size_t numFiles = 0;
|
|
|
|
if(!group->inMemoryDownload()) {
|
|
|
|
SharedHandle<FileEntry> file = dctx->getFirstRequestedFileEntry();
|
|
|
|
if(file) {
|
|
|
|
firstFilename = file->getPath();
|
|
|
|
}
|
|
|
|
numFiles = dctx->countRequestedFileEntry();
|
2010-12-04 09:14:27 +00:00
|
|
|
}
|
2010-12-04 10:00:48 +00:00
|
|
|
executeHook(option->get(opt), group->getGID(), numFiles, firstFilename);
|
2010-07-16 14:22:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-02 07:54:43 +00:00
|
|
|
std::string createSafePath
|
|
|
|
(const std::string& dir, const std::string& filename)
|
|
|
|
{
|
|
|
|
return util::applyDir
|
|
|
|
(dir,
|
|
|
|
util::isUtf8(filename)?
|
|
|
|
util::fixTaintedBasename(filename):
|
|
|
|
util::escapePath(util::percentEncode(filename)));
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string encodeNonUtf8(const std::string& s)
|
|
|
|
{
|
|
|
|
return util::isUtf8(s)?s:util::percentEncode(s);
|
|
|
|
}
|
|
|
|
|
2010-11-09 14:43:47 +00:00
|
|
|
std::string makeString(const char* str)
|
|
|
|
{
|
|
|
|
if(str) {
|
|
|
|
return str;
|
|
|
|
} else {
|
|
|
|
return A2STR::NIL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string safeStrerror(int errNum)
|
|
|
|
{
|
|
|
|
return makeString(strerror(errNum));
|
|
|
|
}
|
|
|
|
|
2009-10-22 14:43:42 +00:00
|
|
|
} // namespace util
|
|
|
|
|
2008-02-08 15:53:45 +00:00
|
|
|
} // namespace aria2
|