/* */ #include "Util.h" #include "DlAbortEx.h" #include "File.h" #include "message.h" #include #include #include #include #include #include #include #include #include #include #include template string uint2str(T value, bool comma) { string str; if(value == 0) { str = "0"; return str; } int count = 0; while(value) { ++count; char digit = value%10+'0'; str.insert(str.begin(), digit); value /= 10; if(comma && count > 3 && count%3 == 1) { str.insert(str.begin()+1, ','); } } return str; } template string int2str(T value, bool comma) { bool flag = false; if(value < 0) { flag = true; value = -value; } string str = uint2str(value, comma); if(flag) { str.insert(str.begin(), '-'); } return str; } string Util::uitos(uint16_t value, bool comma) { return uint2str(value, comma); } string Util::itos(int16_t value, bool comma) { return int2str(value, comma); } string Util::uitos(uint32_t value, bool comma) { return uint2str(value, comma); } string Util::itos(int32_t value, bool comma) { return int2str(value, comma); } string Util::ullitos(uint64_t value, bool comma) { return uint2str(value, comma); } string Util::llitos(int64_t value, bool comma) { return int2str(value, comma); } string Util::trim(const string& src) { string::size_type sp = src.find_first_not_of("\r\n\t "); string::size_type ep = src.find_last_not_of("\r\n\t "); if(sp == string::npos || ep == string::npos) { return ""; } else { return src.substr(sp, ep-sp+1); } } void Util::split(pair& hp, const string& src, char delim) { hp.first = ""; hp.second = ""; string::size_type p = src.find(delim); if(p == string::npos) { hp.first = src; hp.second = ""; } else { hp.first = trim(src.substr(0, p)); hp.second = trim(src.substr(p+1)); } } pair Util::split(const string& src, const string& delims) { pair hp; hp.first = ""; hp.second = ""; string::size_type p = src.find_first_of(delims); if(p == string::npos) { hp.first = src; hp.second = ""; } else { hp.first = trim(src.substr(0, p)); hp.second = trim(src.substr(p+1)); } return hp; } long long int 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 ((long long int)(tv1.tv_sec-tv2.tv_sec)*1000000+ tv1.tv_usec-tv2.tv_usec); } int 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(Strings& result, const string& src, char delim, bool doTrim) { string::size_type p = 0; while(1) { string::size_type np = src.find(delim, p); if(np == string::npos) { string term = src.substr(p); if(doTrim) { term = trim(term); } if(term.size()) { result.push_back(term); } break; } 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 string& target, const string& part) { if(target.size() < part.size()) { return false; } if(part == "") { return true; } if(target.find(part) == 0) { return true; } else { return false; } } bool Util::endsWith(const string& target, const string& part) { if(target.size() < part.size()) { return false; } if(part == "") { return true; } if(target.rfind(part) == target.size()-part.size()) { return true; } else { return false; } } string Util::replace(const string& target, const string& oldstr, const string& newstr) { if(target == "" || oldstr == "" ) { return target; } string result; string::size_type p = 0; string::size_type np = target.find(oldstr); while(np != string::npos) { result += target.substr(p, np-p)+newstr; p = np+oldstr.size(); np = target.find(oldstr, p); } result += target.substr(p); return result; } string Util::urlencode(const unsigned char* target, int len) { string dest; for(int i = 0; i < len; i++) { if(!('0' <= target[i] && target[i] <= '9' || 'A' <= target[i] && target[i] <= 'Z' || 'a' <= target[i] && target[i] <= 'z' || '$' == target[i] || '-' == target[i] || '_' == target[i] || '.' == target[i] || '+' == target[i] || '!' == target[i] || '*' == target[i] || '\'' == target[i] || '(' == target[i] || ')' == target[i] || ',' == target[i])) { char temp[4]; sprintf(temp, "%%%02x", target[i]); temp[sizeof(temp)-1] = '\0'; dest.append(temp); } else { dest += target[i]; } } return dest; } string Util::torrentUrlencode(const unsigned char* target, int len) { string dest; for(int 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 { char temp[4]; sprintf(temp, "%%%02x", target[i]); temp[sizeof(temp)-1] = '\0'; dest.append(temp); } } return dest; } string Util::urldecode(const string& target) { string result; for(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))) { char temp[3]; temp[0] = *(itr+1); temp[1] = *(itr+2); temp[2] = '\0'; result += strtol(temp, 0, 16); itr += 2; } else { result += *itr; } } else { result += *itr; } } return result; } string Util::toHex(const unsigned char* src, int len) { char* temp = new char[len*2+1]; for(int i = 0; i < len; i++) { sprintf(temp+i*2, "%02x", src[i]); } temp[len*2] = '\0'; string hex = temp; delete [] temp; return hex; } FILE* Util::openFile(const string& filename, const string& mode) { FILE* file = fopen(filename.c_str(), mode.c_str()); return file; } void Util::fileCopy(const string& dest, const string& src) { File file(src); rangedFileCopy(dest, src, 0, file.size()); } void Util::rangedFileCopy(const string& dest, const string& src, long long int srcOffset, long long int length) { int bufSize = 4096; char buf[bufSize]; int destFd = -1; int srcFd = -1; try { if((destFd = open(dest.c_str(), O_CREAT|O_WRONLY|O_TRUNC, OPEN_MODE)) == -1) { throw new DlAbortEx(EX_FILE_OPEN, dest.c_str(), strerror(errno)); } if((srcFd = open(src.c_str(), O_RDONLY, OPEN_MODE)) == -1) { throw new DlAbortEx(EX_FILE_OPEN, src.c_str(), strerror(errno)); } if(lseek(srcFd, srcOffset, SEEK_SET) != srcOffset) { throw new DlAbortEx(EX_FILE_SEEK, src.c_str(), strerror(errno)); } int x = length/bufSize; int r = length%bufSize; for(int i = 0; i < x; i++) { int readLength; if((readLength = read(srcFd, buf, bufSize)) == -1 || readLength != bufSize) { throw new DlAbortEx(EX_FILE_READ, src.c_str(), strerror(errno)); } if(write(destFd, buf, readLength) == -1) { throw new DlAbortEx(EX_FILE_WRITE, dest.c_str(), strerror(errno)); } } if(r > 0) { int readLength; if((readLength = read(srcFd, buf, r)) == -1 || readLength != r) { throw new DlAbortEx(EX_FILE_READ, src.c_str(), strerror(errno)); } if(write(destFd, buf, r) == -1) { throw new DlAbortEx(EX_FILE_WRITE, dest.c_str(), strerror(errno)); } } close(srcFd); close(destFd); srcFd = -1; destFd = -1; } catch(RecoverableException* e) { if(srcFd != -1) { close(srcFd); } if(destFd != -1) { close(destFd); } throw; } } 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; } string Util::secfmt(int sec) { 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; } int Util::expandBuffer(char** pbuf, int curLength, int newLength) { char* newbuf = new char[newLength]; memcpy(newbuf, *pbuf, curLength); delete [] *pbuf; *pbuf = newbuf; return newLength; } int getNum(const char* buf, int offset, int length) { char* temp = new char[length+1]; memcpy(temp, buf+offset, length); temp[length] = '\0'; int x = strtol(temp, NULL, 10); delete [] temp; return x; } void unfoldSubRange(const string& src, Integers& range) { if(src.empty()) { return; } string::size_type p = src.find_first_of(",-"); if(p == 0) { return; } else if(p == 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) == '-') { int rightNumBegin = p+1; string::size_type nextDelim = src.find_first_of(",", rightNumBegin); if(nextDelim == 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 string& src, Integers& range) { unfoldSubRange(src, range); sort(range.begin(), range.end()); range.erase(unique(range.begin(), range.end()), range.end()); } string Util::getContentDispositionFilename(const string& header) { string::size_type attributesp = header.find("filename=\""); if(attributesp == string::npos) { return ""; } string::size_type filenamesp = attributesp+strlen("filename=\""); string::size_type filenameep = header.find("\"", filenamesp); if(filenameep == string::npos) { return ""; } return trim(header.substr(filenamesp, filenameep-filenamesp)); } #ifdef ENABLE_MESSAGE_DIGEST void Util::sha1Sum(unsigned char* digest, const void* data, int dataLength) { MessageDigestContext ctx(DIGEST_ALGO_SHA1); ctx.digestInit(); ctx.digestUpdate(data, dataLength); ctx.digestFinal(digest); } string Util::simpleMessageDigest(const string& data) { unsigned char checksum[20]; sha1Sum(checksum, data.c_str(), data.size()); return Util::toHex(checksum, sizeof(checksum)); } #endif // ENABLE_MESSAGE_DIGEST #ifdef ENABLE_MESSAGE_DIGEST void Util::fileChecksum(const string& filename, unsigned char* digest, MessageDigestContext::DigestAlgo algo) { MessageDigestContext ctx(algo); ctx.digestInit(); int BUFLEN = 4096; char buf[BUFLEN]; int fd; if((fd = open(filename.c_str(), O_RDWR, OPEN_MODE)) < 0) { throw new DlAbortEx(EX_FILE_OPEN, filename.c_str(), strerror(errno)); } while(1) { int size = read(fd, buf, BUFLEN); if(size == -1) { if(errno == EINTR) { continue; } else { close(fd); throw new DlAbortEx(EX_FILE_READ, filename.c_str(), strerror(errno)); } } else if(size > 0) { ctx.digestUpdate(buf, size); } if(size < BUFLEN) { break; } } ctx.digestFinal(digest); } #endif // ENABLE_MESSAGE_DIGEST #ifdef ENABLE_BITTORRENT Integers Util::computeFastSet(string ipaddr, const unsigned char* infoHash, int pieces, int fastSetSize) { Integers fastSet; struct in_addr saddr; if(inet_aton(ipaddr.c_str(), &saddr) == 0) { abort(); } unsigned char tx[24]; memcpy(tx, (void*)&saddr.s_addr, 4); if((tx[0] & 0x80) == 0 || (tx[0] & 0x40) == 0) { tx[2] = 0x00; tx[3] = 0x00; } else { tx[3] = 0x00; } memcpy(tx+4, infoHash, 20); unsigned char x[20]; sha1Sum(x, tx, 24); while((int)fastSet.size() < fastSetSize) { for(int i = 0; i < 5 && (int)fastSet.size() < fastSetSize; i++) { int j = i*4; unsigned int ny; memcpy(&ny, x+j, 4); unsigned int y = ntohl(ny); int index = y%pieces; if(find(fastSet.begin(), fastSet.end(), index) == fastSet.end()) { fastSet.push_back(index); } } unsigned char temp[20]; sha1Sum(temp, x, 20); memcpy(x, temp, sizeof(x)); } return fastSet; } #endif // ENABLE_BITTORRENT /* int Util::countBit(unsigned int n) { int count = 0; while(n > 0) { count++; n &= (n-1); } return count; } */ 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, }; int32_t Util::countBit(uint32_t n) { return nbits[n&0xffu]+ nbits[(n >> 8)&0xffu]+ nbits[(n >> 16)&0xffu]+ nbits[(n >> 24)&0xffu]; } string Util::randomAlpha(int length) { string str; for(int i = 0; i < length; i++) { int index = (int)(((double)52)*random()/(RAND_MAX+1.0)); char ch; if(index < 26) { ch = (char)('A'+index); } else { ch = (char)('a'+index-26); } str += ch; } return str; } class UpperCase { public: void operator()(char& ch) { ch = toupper(ch); } }; string Util::toUpper(const string& src) { string temp = src; for_each(temp.begin(), temp.end(), UpperCase()); return temp; } class LowerCase { public: void operator()(char& ch) { ch = tolower(ch); } }; string Util::toLower(const string& src) { string temp = src; for_each(temp.begin(), temp.end(), LowerCase()); return temp; } bool Util::isNumbersAndDotsNotation(const string& name) { struct sockaddr_in sockaddr; if(inet_aton(name.c_str(), &sockaddr.sin_addr)) { return true; } else { return false; } } void Util::setGlobalSignalHandler(int signal, void (*handler)(int), int flags) { struct sigaction sigact; sigact.sa_handler = handler; sigact.sa_flags = flags; sigemptyset(&sigact.sa_mask); sigaction(signal, &sigact, NULL); } void Util::indexRange(int32_t& startIndex, int32_t& endIndex, int64_t offset, int32_t srcLength, int32_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; } string Util::getHomeDir() { const char* p = getenv("HOME"); if(p) { return p; } else { return ""; } } int64_t Util::getRealSize(const string& sizeWithUnit) { string::size_type p = sizeWithUnit.find_first_of("KM"); string size; int mult = 1; if(p == string::npos) { size = sizeWithUnit; } else { if(sizeWithUnit[p] == 'K') { mult = 1024; } else if(sizeWithUnit[p] == 'M') { mult = 1024*1024; } size = sizeWithUnit.substr(0, p); } return strtoll(size.c_str(), 0, 10)*mult; } string Util::abbrevSize(int64_t size) { if(size < 1024) { return Util::llitos(size, true); } char units[] = { 'K', 'M' }; int32_t numUnit = sizeof(units)/sizeof(char); int32_t i = 0; int32_t r = size%1024; size >>= 10; for(; i < numUnit-1 && size >= 1024; ++i) { r = size%1024; size >>= 10; } return Util::llitos(size, true)+"."+Util::itos(r*10/1024)+units[i]; } time_t Util::httpGMT(const 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; }