mirror of https://github.com/aria2/aria2
891 lines
24 KiB
C++
891 lines
24 KiB
C++
/* <!-- copyright */
|
|
/*
|
|
* aria2 - The high speed download utility
|
|
*
|
|
* 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
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
* 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.
|
|
*/
|
|
/* copyright --> */
|
|
#include "Util.h"
|
|
#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"
|
|
#include "StringFormat.h"
|
|
#include "A2STR.h"
|
|
#include <signal.h>
|
|
#include <limits.h>
|
|
#include <stdint.h>
|
|
#include <cerrno>
|
|
#include <cassert>
|
|
#include <cstring>
|
|
#include <cstdlib>
|
|
#include <iomanip>
|
|
#include <sstream>
|
|
#include <algorithm>
|
|
#ifndef HAVE_SLEEP
|
|
# ifdef HAVE_WINSOCK_H
|
|
# define WIN32_LEAN_AND_MEAN
|
|
# include <windows.h>
|
|
# endif // HAVE_WINSOCK_H
|
|
#endif // HAVE_SLEEP
|
|
|
|
namespace aria2 {
|
|
|
|
const std::string Util::DEFAULT_TRIM_CHARSET("\r\n\t ");
|
|
|
|
std::string Util::trim(const std::string& src, const std::string& trimCharset)
|
|
{
|
|
std::string temp(src);
|
|
trimSelf(temp, trimCharset);
|
|
return temp;
|
|
}
|
|
|
|
void Util::trimSelf(std::string& str, const std::string& trimCharset)
|
|
{
|
|
std::string::size_type first = str.find_first_not_of(trimCharset);
|
|
if(first == std::string::npos) {
|
|
str.clear();
|
|
} else {
|
|
std::string::size_type last = str.find_last_not_of(trimCharset)+1;
|
|
str.erase(last);
|
|
str.erase(0, first);
|
|
}
|
|
}
|
|
|
|
void Util::split(std::pair<std::string, std::string>& hp, const std::string& src, char delim)
|
|
{
|
|
hp.first = A2STR::NIL;
|
|
hp.second = A2STR::NIL;
|
|
std::string::size_type p = src.find(delim);
|
|
if(p == std::string::npos) {
|
|
hp.first = src;
|
|
hp.second = A2STR::NIL;
|
|
} else {
|
|
hp.first = trim(src.substr(0, p));
|
|
hp.second = trim(src.substr(p+1));
|
|
}
|
|
}
|
|
|
|
std::pair<std::string, std::string> Util::split(const std::string& src, const std::string& delims)
|
|
{
|
|
std::pair<std::string, std::string> hp;
|
|
hp.first = A2STR::NIL;
|
|
hp.second = A2STR::NIL;
|
|
std::string::size_type p = src.find_first_of(delims);
|
|
if(p == std::string::npos) {
|
|
hp.first = src;
|
|
hp.second = A2STR::NIL;
|
|
} else {
|
|
hp.first = trim(src.substr(0, p));
|
|
hp.second = trim(src.substr(p+1));
|
|
}
|
|
return hp;
|
|
}
|
|
|
|
int64_t Util::difftv(struct timeval tv1, struct timeval tv2) {
|
|
if((tv1.tv_sec < tv2.tv_sec) ||
|
|
((tv1.tv_sec == tv2.tv_sec) && (tv1.tv_usec < tv2.tv_usec))) {
|
|
return 0;
|
|
}
|
|
return ((int64_t)(tv1.tv_sec-tv2.tv_sec)*1000000+
|
|
tv1.tv_usec-tv2.tv_usec);
|
|
}
|
|
|
|
int32_t Util::difftvsec(struct timeval tv1, struct timeval tv2) {
|
|
if(tv1.tv_sec < tv2.tv_sec) {
|
|
return 0;
|
|
}
|
|
return tv1.tv_sec-tv2.tv_sec;
|
|
}
|
|
|
|
void Util::slice(std::deque<std::string>& result, const std::string& src, char delim, bool doTrim) {
|
|
std::string::size_type p = 0;
|
|
while(1) {
|
|
std::string::size_type np = src.find(delim, p);
|
|
if(np == std::string::npos) {
|
|
std::string term = src.substr(p);
|
|
if(doTrim) {
|
|
term = trim(term);
|
|
}
|
|
if(term.size()) {
|
|
result.push_back(term);
|
|
}
|
|
break;
|
|
}
|
|
std::string term = src.substr(p, np-p);
|
|
if(doTrim) {
|
|
term = trim(term);
|
|
}
|
|
p = np+1;
|
|
if(term.size()) {
|
|
result.push_back(term);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool Util::startsWith(const std::string& target, const std::string& part) {
|
|
if(target.size() < part.size()) {
|
|
return false;
|
|
}
|
|
if(part.empty()) {
|
|
return true;
|
|
}
|
|
if(target.find(part) == 0) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool Util::endsWith(const std::string& target, const std::string& part) {
|
|
if(target.size() < part.size()) {
|
|
return false;
|
|
}
|
|
if(part.empty()) {
|
|
return true;
|
|
}
|
|
if(target.rfind(part) == target.size()-part.size()) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
std::string Util::replace(const std::string& target, const std::string& oldstr, const std::string& newstr) {
|
|
if(target.empty() || oldstr.empty()) {
|
|
return target;
|
|
}
|
|
std::string result;
|
|
std::string::size_type p = 0;
|
|
std::string::size_type np = target.find(oldstr);
|
|
while(np != std::string::npos) {
|
|
result += target.substr(p, np-p)+newstr;
|
|
p = np+oldstr.size();
|
|
np = target.find(oldstr, p);
|
|
}
|
|
result += target.substr(p);
|
|
|
|
return result;
|
|
}
|
|
|
|
bool Util::shouldUrlencode(const char c)
|
|
{
|
|
return !(// ALPHA
|
|
('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z') ||
|
|
// DIGIT
|
|
('0' <= c && c <= '9') ||
|
|
// safe
|
|
'$' == c || '-' == c || '_' == c || '.' == c ||
|
|
// extra
|
|
'!' == c || '*' == c || '\'' == c ||'(' == c ||
|
|
')' == c || ',' == c ||
|
|
// reserved
|
|
';' == c || '/' == c || '?' == c || ':' == c ||
|
|
'@' == c || '&' == c || '=' == c || '+' == c);
|
|
}
|
|
|
|
std::string Util::urlencode(const unsigned char* target, size_t len) {
|
|
std::string dest;
|
|
for(size_t i = 0; i < len; i++) {
|
|
if(shouldUrlencode(target[i])) {
|
|
dest.append(StringFormat("%%%02x", target[i]).str());
|
|
} else {
|
|
dest += target[i];
|
|
}
|
|
}
|
|
return dest;
|
|
}
|
|
|
|
std::string Util::torrentUrlencode(const unsigned char* target, size_t len) {
|
|
std::string dest;
|
|
for(size_t i = 0; i < len; i++) {
|
|
if(('0' <= target[i] && target[i] <= '9') ||
|
|
('A' <= target[i] && target[i] <= 'Z') ||
|
|
('a' <= target[i] && target[i] <= 'z')) {
|
|
dest += target[i];
|
|
} else {
|
|
dest.append(StringFormat("%%%02x", target[i]).str());
|
|
}
|
|
}
|
|
return dest;
|
|
}
|
|
|
|
std::string Util::urldecode(const std::string& target) {
|
|
std::string result;
|
|
for(std::string::const_iterator itr = target.begin();
|
|
itr != target.end(); itr++) {
|
|
if(*itr == '%') {
|
|
if(itr+1 != target.end() && itr+2 != target.end() &&
|
|
isxdigit(*(itr+1)) && isxdigit(*(itr+2))) {
|
|
result += Util::parseInt(std::string(itr+1, itr+3), 16);
|
|
itr += 2;
|
|
} else {
|
|
result += *itr;
|
|
}
|
|
} else {
|
|
result += *itr;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
std::string Util::toHex(const unsigned char* src, size_t len) {
|
|
char* temp = new char[len*2+1];
|
|
for(size_t i = 0; i < len; i++) {
|
|
sprintf(temp+i*2, "%02x", src[i]);
|
|
}
|
|
temp[len*2] = '\0';
|
|
std::string hex = temp;
|
|
delete [] temp;
|
|
return hex;
|
|
}
|
|
|
|
FILE* Util::openFile(const std::string& filename, const std::string& mode) {
|
|
FILE* file = fopen(filename.c_str(), mode.c_str());
|
|
return file;
|
|
}
|
|
|
|
void Util::fileCopy(const std::string& dest, const std::string& src) {
|
|
File file(src);
|
|
rangedFileCopy(dest, src, 0, file.size());
|
|
}
|
|
|
|
void Util::rangedFileCopy(const std::string& dest, const std::string& src, off_t srcOffset, uint64_t length)
|
|
{
|
|
size_t bufSize = 4096;
|
|
unsigned char buf[bufSize];
|
|
DefaultDiskWriter srcdw;
|
|
DefaultDiskWriter destdw;
|
|
|
|
srcdw.openExistingFile(src);
|
|
destdw.initAndOpenFile(dest);
|
|
|
|
lldiv_t res = lldiv(length, bufSize);
|
|
unsigned int x = res.quot;
|
|
unsigned int r = res.rem;
|
|
|
|
off_t initialOffset = srcOffset;
|
|
for(unsigned int i = 0; i < x; ++i) {
|
|
size_t readLength = 0;
|
|
while(readLength < bufSize) {
|
|
ssize_t ret = srcdw.readData(buf, bufSize-readLength, srcOffset);
|
|
destdw.writeData(buf, ret, srcOffset-initialOffset);
|
|
srcOffset += ret;
|
|
readLength += ret;
|
|
}
|
|
}
|
|
if(r > 0) {
|
|
size_t readLength = 0;
|
|
while(readLength < r) {
|
|
ssize_t ret = srcdw.readData(buf, r-readLength, srcOffset);
|
|
destdw.writeData(buf, ret, srcOffset-initialOffset);
|
|
srcOffset += ret;
|
|
readLength += ret;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool Util::isPowerOf(int num, int base) {
|
|
if(base <= 0) { return false; }
|
|
if(base == 1) { return true; }
|
|
|
|
while(num%base == 0) {
|
|
num /= base;
|
|
if(num == 1) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
std::string Util::secfmt(time_t sec) {
|
|
std::string str;
|
|
if(sec >= 3600) {
|
|
str = itos(sec/3600)+"h";
|
|
sec %= 3600;
|
|
}
|
|
if(sec >= 60) {
|
|
int min = sec/60;
|
|
if(min < 10) {
|
|
str += "0";
|
|
}
|
|
str += itos(min)+"m";
|
|
sec %= 60;
|
|
}
|
|
if(sec < 10) {
|
|
str += "0";
|
|
}
|
|
str += itos(sec)+"s";
|
|
return str;
|
|
}
|
|
|
|
size_t Util::expandBuffer(char** pbuf, size_t curLength, size_t newLength) {
|
|
char* newbuf = new char[newLength];
|
|
memcpy(newbuf, *pbuf, curLength);
|
|
delete [] *pbuf;
|
|
*pbuf = newbuf;
|
|
return newLength;
|
|
}
|
|
|
|
int getNum(const char* buf, int offset, size_t length) {
|
|
char* temp = new char[length+1];
|
|
memcpy(temp, buf+offset, length);
|
|
temp[length] = '\0';
|
|
int x = strtol(temp, 0, 10);
|
|
delete [] temp;
|
|
return x;
|
|
}
|
|
|
|
void unfoldSubRange(const std::string& src, std::deque<int>& range) {
|
|
if(src.empty()) {
|
|
return;
|
|
}
|
|
std::string::size_type p = src.find_first_of(",-");
|
|
if(p == 0) {
|
|
return;
|
|
} else if(p == std::string::npos) {
|
|
range.push_back(atoi(src.c_str()));
|
|
} else {
|
|
if(src.at(p) == ',') {
|
|
int num = getNum(src.c_str(), 0, p);
|
|
range.push_back(num);
|
|
unfoldSubRange(src.substr(p+1), range);
|
|
} else if(src.at(p) == '-') {
|
|
std::string::size_type rightNumBegin = p+1;
|
|
std::string::size_type nextDelim = src.find_first_of(",", rightNumBegin);
|
|
if(nextDelim == std::string::npos) {
|
|
nextDelim = src.size();
|
|
}
|
|
int left = getNum(src.c_str(), 0, p);
|
|
int right = getNum(src.c_str(), rightNumBegin, nextDelim-rightNumBegin);
|
|
for(int i = left; i <= right; i++) {
|
|
range.push_back(i);
|
|
}
|
|
if(src.size() > nextDelim) {
|
|
unfoldSubRange(src.substr(nextDelim+1), range);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Util::unfoldRange(const std::string& src, std::deque<int>& range) {
|
|
unfoldSubRange(src, range);
|
|
std::sort(range.begin(), range.end());
|
|
range.erase(std::unique(range.begin(), range.end()), range.end());
|
|
}
|
|
|
|
int32_t Util::parseInt(const std::string& s, int32_t base)
|
|
{
|
|
std::string trimed = Util::trim(s);
|
|
if(trimed.empty()) {
|
|
throw DlAbortEx(StringFormat(MSG_STRING_INTEGER_CONVERSION_FAILURE,
|
|
"empty string").str());
|
|
}
|
|
char* stop;
|
|
errno = 0;
|
|
long int v = strtol(trimed.c_str(), &stop, base);
|
|
if(*stop != '\0') {
|
|
throw DlAbortEx(StringFormat(MSG_STRING_INTEGER_CONVERSION_FAILURE,
|
|
trimed.c_str()).str());
|
|
} else if((((v == LONG_MIN) || (v == LONG_MAX)) && (errno == ERANGE)) ||
|
|
(v > INT32_MAX) ||
|
|
(v < INT32_MIN)) {
|
|
throw DlAbortEx(StringFormat(MSG_STRING_INTEGER_CONVERSION_FAILURE,
|
|
trimed.c_str()).str());
|
|
}
|
|
return v;
|
|
}
|
|
|
|
uint32_t Util::parseUInt(const std::string& s, int base)
|
|
{
|
|
std::string trimed = Util::trim(s);
|
|
if(trimed.empty()) {
|
|
throw DlAbortEx(StringFormat(MSG_STRING_INTEGER_CONVERSION_FAILURE,
|
|
"empty string").str());
|
|
}
|
|
// We don't allow negative number.
|
|
if(trimed[0] == '-') {
|
|
throw DlAbortEx(StringFormat(MSG_STRING_INTEGER_CONVERSION_FAILURE,
|
|
trimed.c_str()).str());
|
|
}
|
|
char* stop;
|
|
errno = 0;
|
|
unsigned long int v = strtoul(trimed.c_str(), &stop, base);
|
|
if(*stop != '\0') {
|
|
throw DlAbortEx(StringFormat(MSG_STRING_INTEGER_CONVERSION_FAILURE,
|
|
trimed.c_str()).str());
|
|
} else if(((v == ULONG_MAX) && (errno == ERANGE)) || (v > UINT32_MAX)) {
|
|
throw DlAbortEx(StringFormat(MSG_STRING_INTEGER_CONVERSION_FAILURE,
|
|
trimed.c_str()).str());
|
|
}
|
|
return v;
|
|
}
|
|
|
|
int64_t Util::parseLLInt(const std::string& s, int32_t base)
|
|
{
|
|
std::string trimed = Util::trim(s);
|
|
if(trimed.empty()) {
|
|
throw DlAbortEx(StringFormat(MSG_STRING_INTEGER_CONVERSION_FAILURE,
|
|
"empty string").str());
|
|
}
|
|
char* stop;
|
|
errno = 0;
|
|
int64_t v = strtoll(trimed.c_str(), &stop, base);
|
|
if(*stop != '\0') {
|
|
throw DlAbortEx(StringFormat(MSG_STRING_INTEGER_CONVERSION_FAILURE,
|
|
trimed.c_str()).str());
|
|
} else if(((v == INT64_MIN) || (v == INT64_MAX)) && (errno == ERANGE)) {
|
|
throw DlAbortEx(StringFormat(MSG_STRING_INTEGER_CONVERSION_FAILURE,
|
|
trimed.c_str()).str());
|
|
}
|
|
return v;
|
|
}
|
|
|
|
uint64_t Util::parseULLInt(const std::string& s, int base)
|
|
{
|
|
std::string trimed = Util::trim(s);
|
|
if(trimed.empty()) {
|
|
throw DlAbortEx(StringFormat(MSG_STRING_INTEGER_CONVERSION_FAILURE,
|
|
"empty string").str());
|
|
}
|
|
// We don't allow negative number.
|
|
if(trimed[0] == '-') {
|
|
throw DlAbortEx(StringFormat(MSG_STRING_INTEGER_CONVERSION_FAILURE,
|
|
trimed.c_str()).str());
|
|
}
|
|
char* stop;
|
|
errno = 0;
|
|
uint64_t v = strtoull(trimed.c_str(), &stop, base);
|
|
if(*stop != '\0') {
|
|
throw DlAbortEx(StringFormat(MSG_STRING_INTEGER_CONVERSION_FAILURE,
|
|
trimed.c_str()).str());
|
|
} else if((v == ULLONG_MAX) && (errno == ERANGE)) {
|
|
throw DlAbortEx(StringFormat(MSG_STRING_INTEGER_CONVERSION_FAILURE,
|
|
trimed.c_str()).str());
|
|
}
|
|
return v;
|
|
}
|
|
|
|
IntSequence Util::parseIntRange(const std::string& src)
|
|
{
|
|
IntSequence::Values values;
|
|
std::string temp = src;
|
|
while(temp.size()) {
|
|
std::pair<std::string, std::string> p = Util::split(temp, ",");
|
|
temp = p.second;
|
|
if(p.first.empty()) {
|
|
continue;
|
|
}
|
|
if(p.first.find("-") == std::string::npos) {
|
|
int32_t v = Util::parseInt(p.first.c_str());
|
|
values.push_back(IntSequence::Value(v, v+1));
|
|
} else {
|
|
std::pair<std::string, std::string> vp = Util::split(p.first.c_str(), "-");
|
|
if(vp.first.empty() || vp.second.empty()) {
|
|
throw DlAbortEx
|
|
(StringFormat(MSG_INCOMPLETE_RANGE, p.first.c_str()).str());
|
|
}
|
|
int32_t v1 = Util::parseInt(vp.first.c_str());
|
|
int32_t v2 = Util::parseInt(vp.second.c_str());
|
|
values.push_back(IntSequence::Value(v1, v2+1));
|
|
}
|
|
}
|
|
return values;
|
|
}
|
|
|
|
std::string Util::getContentDispositionFilename(const std::string& header) {
|
|
static const std::string keyName = "filename=";
|
|
std::string::size_type attributesp = header.find(keyName);
|
|
if(attributesp == std::string::npos) {
|
|
return A2STR::NIL;
|
|
}
|
|
std::string::size_type filenamesp = attributesp+keyName.size();
|
|
std::string::size_type filenameep;
|
|
if(filenamesp == header.size()) {
|
|
return A2STR::NIL;
|
|
}
|
|
|
|
if(header[filenamesp] == '\'' || header[filenamesp] == '"') {
|
|
char quoteChar = header[filenamesp];
|
|
filenameep = header.find(quoteChar, filenamesp+1);
|
|
} else {
|
|
filenameep = header.find(';', filenamesp);
|
|
}
|
|
if(filenameep == std::string::npos) {
|
|
filenameep = header.size();
|
|
}
|
|
static const std::string TRIMMED("\r\n '\"");
|
|
return trim(header.substr(filenamesp, filenameep-filenamesp), TRIMMED);
|
|
}
|
|
|
|
static int nbits[] = {
|
|
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
|
|
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
|
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
|
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
|
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
|
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
|
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
|
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
|
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
|
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
|
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
|
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
|
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
|
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
|
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
|
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8,
|
|
};
|
|
|
|
unsigned int Util::countBit(uint32_t n) {
|
|
return
|
|
nbits[n&0xffu]+
|
|
nbits[(n >> 8)&0xffu]+
|
|
nbits[(n >> 16)&0xffu]+
|
|
nbits[(n >> 24)&0xffu];
|
|
}
|
|
|
|
std::string Util::randomAlpha(size_t length, const RandomizerHandle& randomizer) {
|
|
static const char *random_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
std::string str;
|
|
for(size_t i = 0; i < length; i++) {
|
|
size_t index = randomizer->getRandomNumber(strlen(random_chars));
|
|
str += random_chars[index];
|
|
}
|
|
return str;
|
|
}
|
|
|
|
std::string Util::toUpper(const std::string& src) {
|
|
std::string temp = src;
|
|
std::transform(temp.begin(), temp.end(), temp.begin(), ::toupper);
|
|
return temp;
|
|
}
|
|
|
|
std::string Util::toLower(const std::string& src) {
|
|
std::string temp = src;
|
|
std::transform(temp.begin(), temp.end(), temp.begin(), ::tolower);
|
|
return temp;
|
|
}
|
|
|
|
bool Util::isNumbersAndDotsNotation(const std::string& name) {
|
|
struct sockaddr_in sockaddr;
|
|
if(inet_aton(name.c_str(), &sockaddr.sin_addr)) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void Util::setGlobalSignalHandler(int sig, void (*handler)(int), int flags) {
|
|
#ifdef HAVE_SIGACTION
|
|
struct sigaction sigact;
|
|
sigact.sa_handler = handler;
|
|
sigact.sa_flags = flags;
|
|
sigemptyset(&sigact.sa_mask);
|
|
sigaction(sig, &sigact, NULL);
|
|
#else
|
|
signal(sig, handler);
|
|
#endif // HAVE_SIGACTION
|
|
}
|
|
|
|
void Util::indexRange(size_t& startIndex, size_t& endIndex,
|
|
off_t offset, size_t srcLength, size_t destLength)
|
|
{
|
|
int64_t _startIndex = offset/destLength;
|
|
int64_t _endIndex = (offset+srcLength-1)/destLength;
|
|
assert(_startIndex <= INT32_MAX);
|
|
assert(_endIndex <= INT32_MAX);
|
|
startIndex = _startIndex;
|
|
endIndex = _endIndex;
|
|
}
|
|
|
|
std::string Util::getHomeDir()
|
|
{
|
|
const char* p = getenv("HOME");
|
|
if(p) {
|
|
return p;
|
|
} else {
|
|
return A2STR::NIL;
|
|
}
|
|
}
|
|
|
|
int64_t Util::getRealSize(const std::string& sizeWithUnit)
|
|
{
|
|
std::string::size_type p = sizeWithUnit.find_first_of("KM");
|
|
std::string size;
|
|
int32_t mult = 1;
|
|
if(p == std::string::npos) {
|
|
size = sizeWithUnit;
|
|
} else {
|
|
if(sizeWithUnit[p] == 'K') {
|
|
mult = 1024;
|
|
} else if(sizeWithUnit[p] == 'M') {
|
|
mult = 1024*1024;
|
|
}
|
|
size = sizeWithUnit.substr(0, p);
|
|
}
|
|
int64_t v = Util::parseLLInt(size);
|
|
|
|
if(v < 0) {
|
|
throw DlAbortEx
|
|
(StringFormat("Negative value detected: %s", sizeWithUnit.c_str()).str());
|
|
} else if(INT64_MAX/mult < v) {
|
|
throw DlAbortEx(StringFormat(MSG_STRING_INTEGER_CONVERSION_FAILURE,
|
|
"overflow/underflow").str());
|
|
}
|
|
return v*mult;
|
|
}
|
|
|
|
std::string Util::abbrevSize(int64_t size)
|
|
{
|
|
if(size < 1024) {
|
|
return Util::itos(size, true);
|
|
}
|
|
char units[] = { 'K', 'M' };
|
|
size_t numUnit = sizeof(units)/sizeof(char);
|
|
size_t i = 0;
|
|
int r = size&0x3ff;
|
|
size >>= 10;
|
|
for(; i < numUnit-1 && size >= 1024; ++i) {
|
|
r = size&0x3ff;
|
|
size >>= 10;
|
|
}
|
|
return Util::itos(size, true)+"."+Util::itos(r*10/1024)+units[i]+"i";
|
|
}
|
|
|
|
time_t Util::httpGMT(const std::string& httpStdTime)
|
|
{
|
|
struct tm tm;
|
|
memset(&tm, 0, sizeof(tm));
|
|
strptime(httpStdTime.c_str(), "%a, %Y-%m-%d %H:%M:%S GMT", &tm);
|
|
time_t thetime = timegm(&tm);
|
|
return thetime;
|
|
}
|
|
|
|
void Util::toStream(std::ostream& os, const FileEntries& fileEntries)
|
|
{
|
|
os << _("Files:") << "\n";
|
|
os << "idx|path/length" << "\n";
|
|
os << "===+===========================================================================" << "\n";
|
|
int32_t count = 1;
|
|
for(FileEntries::const_iterator itr = fileEntries.begin();
|
|
itr != fileEntries.end(); count++, itr++) {
|
|
os << std::setw(3) << count << "|" << (*itr)->getPath() << "\n";
|
|
os << " |" << Util::abbrevSize((*itr)->getLength()) << "B" << "\n";
|
|
os << "---+---------------------------------------------------------------------------" << "\n";
|
|
}
|
|
}
|
|
|
|
void Util::sleep(long seconds) {
|
|
#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
|
|
}
|
|
|
|
void Util::usleep(long microseconds) {
|
|
#ifdef HAVE_USLEEP
|
|
::usleep(microseconds);
|
|
#elif defined(HAVE_WINSOCK2_H)
|
|
|
|
LARGE_INTEGER current, freq, end;
|
|
|
|
static enum {GET_FREQUENCY, GET_MICROSECONDS, SKIP_MICROSECONDS} state = GET_FREQUENCY;
|
|
|
|
if (state == GET_FREQUENCY) {
|
|
if (QueryPerformanceFrequency(&freq))
|
|
state = GET_MICROSECONDS;
|
|
else
|
|
state = SKIP_MICROSECONDS;
|
|
}
|
|
|
|
long msec = microseconds / 1000;
|
|
microseconds %= 1000;
|
|
|
|
if (state == GET_MICROSECONDS && microseconds) {
|
|
QueryPerformanceCounter(&end);
|
|
|
|
end.QuadPart += (freq.QuadPart * microseconds) / 1000000;
|
|
|
|
while (QueryPerformanceCounter(¤t) && (current.QuadPart <= end.QuadPart))
|
|
/* noop */ ;
|
|
}
|
|
|
|
if (msec)
|
|
Sleep(msec);
|
|
#else
|
|
#error no usleep function is available (nanosleep?)
|
|
#endif
|
|
}
|
|
|
|
bool Util::isNumber(const std::string& what)
|
|
{
|
|
if(what.empty()) {
|
|
return false;
|
|
}
|
|
for(uint32_t i = 0; i < what.size(); ++i) {
|
|
if(!isdigit(what[i])) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool Util::isLowercase(const std::string& what)
|
|
{
|
|
if(what.empty()) {
|
|
return false;
|
|
}
|
|
for(uint32_t i = 0; i < what.size(); ++i) {
|
|
if(!('a' <= what[i] && what[i] <= 'z')) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool Util::isUppercase(const std::string& what)
|
|
{
|
|
if(what.empty()) {
|
|
return false;
|
|
}
|
|
for(uint32_t i = 0; i < what.size(); ++i) {
|
|
if(!('A' <= what[i] && what[i] <= 'Z')) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
unsigned int Util::alphaToNum(const std::string& alphabets)
|
|
{
|
|
if(alphabets.empty()) {
|
|
return 0;
|
|
}
|
|
char base;
|
|
if(islower(alphabets[0])) {
|
|
base = 'a';
|
|
} else {
|
|
base = 'A';
|
|
}
|
|
uint64_t num = 0;
|
|
for(size_t i = 0; i < alphabets.size(); ++i) {
|
|
unsigned int v = alphabets[i]-base;
|
|
num = num*26+v;
|
|
if(num > UINT32_MAX) {
|
|
return 0;
|
|
}
|
|
}
|
|
return num;
|
|
}
|
|
|
|
void Util::mkdirs(const std::string& dirpath)
|
|
{
|
|
File dir(dirpath);
|
|
if(dir.isDir()) {
|
|
// do nothing
|
|
} else if(dir.exists()) {
|
|
throw DlAbortEx
|
|
(StringFormat(EX_MAKE_DIR, dir.getPath().c_str(),
|
|
"File already exists.").str());
|
|
} else if(!dir.mkdirs()) {
|
|
throw DlAbortEx
|
|
(StringFormat(EX_MAKE_DIR, dir.getPath().c_str(),
|
|
strerror(errno)).str());
|
|
}
|
|
}
|
|
|
|
void Util::convertBitfield(BitfieldMan* dest, const BitfieldMan* src)
|
|
{
|
|
size_t numBlock = dest->countBlock();
|
|
for(size_t index = 0; index < numBlock; ++index) {
|
|
if(src->isBitSetOffsetRange((uint64_t)index*dest->getBlockLength(),
|
|
dest->getBlockLength())) {
|
|
dest->setBit(index);
|
|
}
|
|
}
|
|
}
|
|
|
|
std::string Util::toString(const BinaryStreamHandle& binaryStream)
|
|
{
|
|
std::stringstream strm;
|
|
char data[2048];
|
|
while(1) {
|
|
int32_t dataLength = binaryStream->readData((unsigned char*)data, sizeof(data), strm.tellp());
|
|
strm.write(data, dataLength);
|
|
if(dataLength == 0) {
|
|
break;
|
|
}
|
|
}
|
|
return strm.str();
|
|
}
|
|
|
|
#ifdef HAVE_POSIX_MEMALIGN
|
|
/**
|
|
* In linux 2.6, alignment and size should be a multiple of 512.
|
|
*/
|
|
void* Util::allocateAlignedMemory(size_t alignment, size_t size)
|
|
{
|
|
void* buffer;
|
|
int res;
|
|
if((res = posix_memalign(&buffer, alignment, size)) != 0) {
|
|
throw FatalException
|
|
(StringFormat("Error in posix_memalign: %s", strerror(res)).str());
|
|
}
|
|
return buffer;
|
|
}
|
|
#endif // HAVE_POSIX_MEMALIGN
|
|
|
|
std::pair<std::string, uint16_t>
|
|
Util::getNumericNameInfo(const struct sockaddr* sockaddr, socklen_t len)
|
|
{
|
|
char host[NI_MAXHOST];
|
|
char service[NI_MAXSERV];
|
|
int s = getnameinfo(sockaddr, len, host, NI_MAXHOST, service, NI_MAXSERV,
|
|
NI_NUMERICHOST|NI_NUMERICSERV);
|
|
if(s != 0) {
|
|
throw DlAbortEx(StringFormat("Failed to get hostname and port. cause: %s",
|
|
gai_strerror(s)).str());
|
|
}
|
|
return std::pair<std::string, uint16_t>(host, atoi(service)); // TODO
|
|
}
|
|
|
|
} // namespace aria2
|