diff --git a/src/AbstractDiskWriter.cc b/src/AbstractDiskWriter.cc index ae5c1b5a..cfa29171 100644 --- a/src/AbstractDiskWriter.cc +++ b/src/AbstractDiskWriter.cc @@ -95,15 +95,15 @@ void AbstractDiskWriter::openExistingFile(uint64_t totalLength) } else { flags |= O_RDWR; } - - while((fd_ = open(filename_.c_str(), flags, OPEN_MODE)) == -1 && + while((fd_ = a2open(utf8ToWChar(filename_).c_str(), + flags, OPEN_MODE)) == -1 && errno == EINTR); if(fd_ < 0) { int errNum = errno; throw DL_ABORT_EX3 (errNum, fmt(EX_FILE_OPEN, - filename_.c_str(), + utf8ToNative(filename_).c_str(), util::safeStrerror(errNum).c_str()), error_code::FILE_OPEN_ERROR); } @@ -114,14 +114,15 @@ void AbstractDiskWriter::createFile(int addFlags) assert(!filename_.empty()); util::mkdirs(File(filename_).getDirname()); - while((fd_ = open(filename_.c_str(), O_CREAT|O_RDWR|O_TRUNC|O_BINARY|addFlags, - OPEN_MODE)) == -1 && errno == EINTR); + while((fd_ = a2open(utf8ToWChar(filename_).c_str(), + O_CREAT|O_RDWR|O_TRUNC|O_BINARY|addFlags, + OPEN_MODE)) == -1 && errno == EINTR); if(fd_ < 0) { int errNum = errno; throw DL_ABORT_EX3 (errNum, fmt(EX_FILE_OPEN, - filename_.c_str(), + utf8ToNative(filename_).c_str(), util::safeStrerror(errNum).c_str()), error_code::FILE_CREATE_ERROR); } @@ -153,7 +154,7 @@ void AbstractDiskWriter::seek(off_t offset) if(a2lseek(fd_, offset, SEEK_SET) == (off_t)-1) { int errNum = errno; throw DL_ABORT_EX2(fmt(EX_FILE_SEEK, - filename_.c_str(), + utf8ToNative(filename_).c_str(), util::safeStrerror(errNum).c_str()), error_code::FILE_IO_ERROR); } @@ -170,14 +171,14 @@ void AbstractDiskWriter::writeData(const unsigned char* data, size_t len, off_t throw DOWNLOAD_FAILURE_EXCEPTION3 (errNum, fmt(EX_FILE_WRITE, - filename_.c_str(), + utf8ToNative(filename_).c_str(), util::safeStrerror(errNum).c_str()), error_code::NOT_ENOUGH_DISK_SPACE); } else { throw DL_ABORT_EX3 (errNum, fmt(EX_FILE_WRITE, - filename_.c_str(), + utf8ToNative(filename_).c_str(), util::safeStrerror(errNum).c_str()), error_code::FILE_IO_ERROR); } @@ -193,7 +194,7 @@ ssize_t AbstractDiskWriter::readData(unsigned char* data, size_t len, off_t offs throw DL_ABORT_EX3 (errNum, fmt(EX_FILE_READ, - filename_.c_str(), + utf8ToNative(filename_).c_str(), util::safeStrerror(errNum).c_str()), error_code::FILE_IO_ERROR); } diff --git a/src/BtDependency.cc b/src/BtDependency.cc index 9b7c156c..92bd6755 100644 --- a/src/BtDependency.cc +++ b/src/BtDependency.cc @@ -135,7 +135,7 @@ bool BtDependency::resolve() if(d == ctxFilesEnd) { throw DL_ABORT_EX (fmt("No entry %s in torrent file", - (*s)->getOriginalName().c_str())); + utf8ToNative((*s)->getOriginalName()).c_str())); } copyValues(*d, *s); } diff --git a/src/BtPostDownloadHandler.cc b/src/BtPostDownloadHandler.cc index 00ecea28..2cca80e6 100644 --- a/src/BtPostDownloadHandler.cc +++ b/src/BtPostDownloadHandler.cc @@ -69,7 +69,7 @@ void BtPostDownloadHandler::getNextRequestGroups RequestGroup* requestGroup) { A2_LOG_INFO(fmt("Generating RequestGroups for Torrent file %s", - requestGroup->getFirstFilePath().c_str())); + utf8ToNative(requestGroup->getFirstFilePath()).c_str())); std::string content; try { requestGroup->getPieceStorage()->getDiskAdaptor()->openExistingFile(); diff --git a/src/CheckIntegrityCommand.cc b/src/CheckIntegrityCommand.cc index c4284211..60521e14 100644 --- a/src/CheckIntegrityCommand.cc +++ b/src/CheckIntegrityCommand.cc @@ -73,7 +73,8 @@ bool CheckIntegrityCommand::executeInternal() if(getRequestGroup()->downloadFinished()) { A2_LOG_NOTICE (fmt(MSG_VERIFICATION_SUCCESSFUL, - getRequestGroup()->getDownloadContext()->getBasePath().c_str())); + utf8ToNative(getRequestGroup()->getDownloadContext() + ->getBasePath()).c_str())); std::vector* commands = new std::vector(); auto_delete_container > commandsDel(commands); entry_->onDownloadFinished(*commands, getDownloadEngine()); @@ -82,7 +83,8 @@ bool CheckIntegrityCommand::executeInternal() } else { A2_LOG_ERROR (fmt(MSG_VERIFICATION_FAILED, - getRequestGroup()->getDownloadContext()->getBasePath().c_str())); + utf8ToNative(getRequestGroup()->getDownloadContext() + ->getBasePath()).c_str())); std::vector* commands = new std::vector(); auto_delete_container > commandsDel(commands); entry_->onDownloadIncomplete(*commands, getDownloadEngine()); @@ -106,7 +108,8 @@ bool CheckIntegrityCommand::handleException(Exception& e) A2_LOG_ERROR (fmt(MSG_DOWNLOAD_NOT_COMPLETE, getCuid(), - getRequestGroup()->getDownloadContext()->getBasePath().c_str())); + utf8ToNative(getRequestGroup()->getDownloadContext() + ->getBasePath()).c_str())); return true; } diff --git a/src/File.cc b/src/File.cc index ce8e4200..9a998cd4 100644 --- a/src/File.cc +++ b/src/File.cc @@ -72,7 +72,7 @@ File& File::operator=(const File& c) } int File::fillStat(a2_struct_stat& fstat) { - return a2stat(name_.c_str(), &fstat); + return a2stat(utf8ToWChar(name_).c_str(), &fstat); } bool File::exists() { @@ -98,9 +98,9 @@ bool File::isDir() { bool File::remove() { if(isFile()) { - return unlink(name_.c_str()) == 0; + return a2unlink(utf8ToWChar(name_).c_str()) == 0; } else if(isDir()) { - return rmdir(name_.c_str()) == 0; + return a2rmdir(utf8ToWChar(name_).c_str()) == 0; } else { return false; } @@ -148,13 +148,14 @@ bool File::mkdirs() { } #endif // __MINGW32__ std::string dir = std::string(begin, j); - A2_LOG_DEBUG(fmt("Making directory %s", dir.c_str())); + A2_LOG_DEBUG(fmt("Making directory %s", utf8ToNative(dir).c_str())); if(File(dir).isDir()) { - A2_LOG_DEBUG(fmt("%s exists and is a directory.", dir.c_str())); + A2_LOG_DEBUG(fmt("%s exists and is a directory.", + utf8ToNative(dir).c_str())); continue; } - if(a2mkdir(dir.c_str(), DIR_OPEN_MODE) == -1) { - A2_LOG_DEBUG(fmt("Failed to create %s", dir.c_str())); + if(a2mkdir(utf8ToWChar(dir).c_str(), DIR_OPEN_MODE) == -1) { + A2_LOG_DEBUG(fmt("Failed to create %s", utf8ToNative(dir).c_str())); return false; } } @@ -205,13 +206,13 @@ bool File::renameTo(const std::string& dest) { #ifdef __MINGW32__ /* MinGW's rename() doesn't delete an existing destination */ - if (_access(dest.c_str(), 0) == 0) { - if (_unlink(dest.c_str()) != 0) { + if (_waccess(utf8ToWChar(dest).c_str(), 0) == 0) { + if (a2unlink(utf8ToWChar(dest).c_str()) != 0) { return false; } } #endif // __MINGW32__ - if(rename(name_.c_str(), dest.c_str()) == 0) { + if(a2rename(utf8ToWChar(name_).c_str(), utf8ToWChar(dest).c_str()) == 0) { name_ = dest; return true; } else { @@ -221,10 +222,10 @@ bool File::renameTo(const std::string& dest) bool File::utime(const Time& actime, const Time& modtime) const { - struct utimbuf ub; + a2utimbuf ub; ub.actime = actime.getTime(); ub.modtime = modtime.getTime(); - return ::utime(name_.c_str(), &ub) == 0; + return a2utime(utf8ToWChar(name_).c_str(), &ub) == 0; } Time File::getModifiedTime() @@ -238,6 +239,15 @@ Time File::getModifiedTime() std::string File::getCurrentDir() { +#ifdef __MINGW32__ + const size_t buflen = 2048; + wchar_t buf[buflen]; + if(_wgetcwd(buf, buflen)) { + return wCharToUtf8(buf); + } else { + return A2STR::DOT_C; + } +#else // !__MINGW32__ const size_t buflen = 2048; char buf[buflen]; if(getcwd(buf, buflen)) { @@ -245,6 +255,7 @@ std::string File::getCurrentDir() } else { return A2STR::DOT_C; } +#endif // !__MINGW32__ } } // namespace aria2 diff --git a/src/FileAllocationCommand.cc b/src/FileAllocationCommand.cc index 84e28e06..e0b16e6a 100644 --- a/src/FileAllocationCommand.cc +++ b/src/FileAllocationCommand.cc @@ -96,7 +96,8 @@ bool FileAllocationCommand::handleException(Exception& e) A2_LOG_ERROR (fmt(MSG_DOWNLOAD_NOT_COMPLETE, getCuid(), - getRequestGroup()->getDownloadContext()->getBasePath().c_str())); + utf8ToNative(getRequestGroup()->getDownloadContext() + ->getBasePath()).c_str())); return true; } diff --git a/src/FileEntry.cc b/src/FileEntry.cc index 355883f5..3fa5a900 100644 --- a/src/FileEntry.cc +++ b/src/FileEntry.cc @@ -355,7 +355,7 @@ void FileEntry::removeURIWhoseHostnameIs(const std::string& hostname) } A2_LOG_DEBUG(fmt("Removed %lu duplicate hostname URIs for path=%s", static_cast(uris_.size()-newURIs.size()), - getPath().c_str())); + utf8ToNative(getPath()).c_str())); uris_.swap(newURIs); } diff --git a/src/FileEntry.h b/src/FileEntry.h index 1a321683..ce202d57 100644 --- a/src/FileEntry.h +++ b/src/FileEntry.h @@ -49,6 +49,7 @@ #include "error_code.h" #include "A2STR.h" #include "TimerA2.h" +#include "util.h" namespace aria2 { @@ -316,9 +317,9 @@ void writeFilePath } } else { if(memory) { - o << "[MEMORY]" << File(e->getPath()).getBasename(); + o << "[MEMORY]" << utf8ToNative(File(e->getPath()).getBasename()); } else { - o << e->getPath(); + o << utf8ToNative(e->getPath()); } size_t count = countRequestedFileEntry(first, last); if(count > 1) { diff --git a/src/FtpNegotiationCommand.cc b/src/FtpNegotiationCommand.cc index 96c09476..8d25b6e6 100644 --- a/src/FtpNegotiationCommand.cc +++ b/src/FtpNegotiationCommand.cc @@ -376,7 +376,7 @@ bool FtpNegotiationCommand::onFileSizeDetermined(uint64_t totalLength) isSameFileBeingDownloaded(getRequestGroup())) { throw DOWNLOAD_FAILURE_EXCEPTION2 (fmt(EX_DUPLICATE_FILE_DOWNLOAD, - getRequestGroup()->getFirstFilePath().c_str()), + utf8ToNative(getRequestGroup()->getFirstFilePath()).c_str()), error_code::DUPLICATE_DOWNLOAD); } if(totalLength == 0) { @@ -404,9 +404,10 @@ bool FtpNegotiationCommand::onFileSizeDetermined(uint64_t totalLength) getPieceStorage()->markAllPiecesDone(); getDownloadContext()->setChecksumVerified(true); sequence_ = SEQ_DOWNLOAD_ALREADY_COMPLETED; - A2_LOG_NOTICE(fmt(MSG_DOWNLOAD_ALREADY_COMPLETED, - util::itos(getRequestGroup()->getGID()).c_str(), - getRequestGroup()->getFirstFilePath().c_str())); + A2_LOG_NOTICE + (fmt(MSG_DOWNLOAD_ALREADY_COMPLETED, + util::itos(getRequestGroup()->getGID()).c_str(), + utf8ToNative(getRequestGroup()->getFirstFilePath()).c_str())); poolConnection(); return false; diff --git a/src/HttpResponseCommand.cc b/src/HttpResponseCommand.cc index 0f25f757..2610d0e3 100644 --- a/src/HttpResponseCommand.cc +++ b/src/HttpResponseCommand.cc @@ -186,9 +186,10 @@ bool HttpResponseCommand::executeInternal() getPieceStorage()->markAllPiecesDone(); // Just set checksum verification done. getDownloadContext()->setChecksumVerified(true); - A2_LOG_NOTICE(fmt(MSG_DOWNLOAD_ALREADY_COMPLETED, - util::itos(getRequestGroup()->getGID()).c_str(), - getRequestGroup()->getFirstFilePath().c_str())); + A2_LOG_NOTICE + (fmt(MSG_DOWNLOAD_ALREADY_COMPLETED, + util::itos(getRequestGroup()->getGID()).c_str(), + utf8ToNative(getRequestGroup()->getFirstFilePath()).c_str())); poolConnection(); getFileEntry()->poolRequest(getRequest()); return true; @@ -257,7 +258,7 @@ bool HttpResponseCommand::executeInternal() isSameFileBeingDownloaded(getRequestGroup())) { throw DOWNLOAD_FAILURE_EXCEPTION2 (fmt(EX_DUPLICATE_FILE_DOWNLOAD, - getRequestGroup()->getFirstFilePath().c_str()), + utf8ToNative(getRequestGroup()->getFirstFilePath()).c_str()), error_code::DUPLICATE_DOWNLOAD); } // update last modified time @@ -438,9 +439,10 @@ bool HttpResponseCommand::handleOtherEncoding getRequestGroup()->initPieceStorage(); getPieceStorage()->markAllPiecesDone(); getDownloadContext()->setChecksumVerified(true); - A2_LOG_NOTICE(fmt(MSG_DOWNLOAD_ALREADY_COMPLETED, - util::itos(getRequestGroup()->getGID()).c_str(), - getRequestGroup()->getFirstFilePath().c_str())); + A2_LOG_NOTICE + (fmt(MSG_DOWNLOAD_ALREADY_COMPLETED, + util::itos(getRequestGroup()->getGID()).c_str(), + utf8ToNative(getRequestGroup()->getFirstFilePath()).c_str())); poolConnection(); return true; } diff --git a/src/IteratableChunkChecksumValidator.cc b/src/IteratableChunkChecksumValidator.cc index 475e3b06..18f20893 100644 --- a/src/IteratableChunkChecksumValidator.cc +++ b/src/IteratableChunkChecksumValidator.cc @@ -143,7 +143,7 @@ std::string IteratableChunkChecksumValidator::digest(off_t offset, size_t length curoffset); if(r == 0 || r < static_cast(woffset)) { throw DL_ABORT_EX - (fmt(EX_FILE_READ, dctx_->getBasePath().c_str(), + (fmt(EX_FILE_READ, utf8ToNative(dctx_->getBasePath()).c_str(), "data is too short")); } size_t wlength; diff --git a/src/Metalink2RequestGroup.cc b/src/Metalink2RequestGroup.cc index 07291dda..7d29b38b 100644 --- a/src/Metalink2RequestGroup.cc +++ b/src/Metalink2RequestGroup.cc @@ -233,7 +233,8 @@ Metalink2RequestGroup::createRequestGroup SharedHandle dctx; if(mes.size() == 1) { SharedHandle entry = mes[0]; - A2_LOG_INFO(fmt(MSG_METALINK_QUEUEING, entry->getPath().c_str())); + A2_LOG_INFO(fmt(MSG_METALINK_QUEUEING, + utf8ToNative(entry->getPath()).c_str())); entry->reorderResourcesByPriority(); std::vector uris; std::for_each(entry->resources.begin(), entry->resources.end(), @@ -287,7 +288,7 @@ Metalink2RequestGroup::createRequestGroup for(std::vector >::const_iterator i = mes.begin(), eoi = mes.end(); i != eoi; ++i) { A2_LOG_INFO(fmt("Metalink: Queueing %s for download as a member.", - (*i)->getPath().c_str())); + utf8ToNative((*i)->getPath()).c_str())); A2_LOG_DEBUG(fmt("originalName = %s", (*i)->metaurls[0]->name.c_str())); (*i)->reorderResourcesByPriority(); std::vector uris; diff --git a/src/MetalinkPostDownloadHandler.cc b/src/MetalinkPostDownloadHandler.cc index c611bc62..07a1e5ba 100644 --- a/src/MetalinkPostDownloadHandler.cc +++ b/src/MetalinkPostDownloadHandler.cc @@ -97,7 +97,7 @@ void MetalinkPostDownloadHandler::getNextRequestGroups RequestGroup* requestGroup) { A2_LOG_DEBUG(fmt("Generating RequestGroups for Metalink file %s", - requestGroup->getFirstFilePath().c_str())); + utf8ToNative(requestGroup->getFirstFilePath()).c_str())); SharedHandle diskAdaptor = requestGroup->getPieceStorage()->getDiskAdaptor(); try { diff --git a/src/MultiDiskAdaptor.cc b/src/MultiDiskAdaptor.cc index f3672836..c69b20d1 100644 --- a/src/MultiDiskAdaptor.cc +++ b/src/MultiDiskAdaptor.cc @@ -187,7 +187,7 @@ void MultiDiskAdaptor::resetDiskWriterEntries() pieceLength_*pieceLength_; A2_LOG_DEBUG(fmt("Checking adjacent backward file to %s" " whose lastPieceStartOffset+pieceLength_=%lld", - fileEntry->getPath().c_str(), + utf8ToNative(fileEntry->getPath()).c_str(), static_cast (lastPieceStartOffset+pieceLength_))); ++itr; @@ -196,14 +196,16 @@ void MultiDiskAdaptor::resetDiskWriterEntries() for(; itr != eoi && (!(*itr)->getFileEntry()->isRequested() || (*itr)->getFileEntry()->getLength() == 0); ++itr) { - A2_LOG_DEBUG(fmt("file=%s, offset=%lld", - (*itr)->getFileEntry()->getPath().c_str(), - static_cast - ((*itr)->getFileEntry()->getOffset()))); + A2_LOG_DEBUG + (fmt("file=%s, offset=%lld", + utf8ToNative((*itr)->getFileEntry()->getPath()).c_str(), + static_cast + ((*itr)->getFileEntry()->getOffset()))); if((*itr)->getFileEntry()->getOffset() < static_cast(lastPieceStartOffset+pieceLength_)) { - A2_LOG_DEBUG(fmt("%s needs diskwriter", - (*itr)->getFileEntry()->getPath().c_str())); + A2_LOG_DEBUG + (fmt("%s needs diskwriter", + utf8ToNative((*itr)->getFileEntry()->getPath()).c_str())); dwreq[(*itr)->getFileEntry()->getPath()] = true; } else { break; @@ -224,7 +226,7 @@ void MultiDiskAdaptor::resetDiskWriterEntries() dwreq.find((*i)->getFileEntry()->getPath()) != dwreq.end() || (*i)->fileExists()) { A2_LOG_DEBUG(fmt("Creating DiskWriter for filename=%s", - (*i)->getFilePath().c_str())); + utf8ToNative((*i)->getFilePath()).c_str())); (*i)->setDiskWriter(dwFactory.newDiskWriter((*i)->getFilePath())); if(readOnly_) { (*i)->getDiskWriter()->enableReadOnly(); diff --git a/src/Option.cc b/src/Option.cc index 579d7e73..305fd4eb 100644 --- a/src/Option.cc +++ b/src/Option.cc @@ -122,4 +122,14 @@ std::map::const_iterator Option::end() const return table_.end(); } +std::map::iterator Option::begin() +{ + return table_.begin(); +} + +std::map::iterator Option::end() +{ + return table_.end(); +} + } // namespace aria2 diff --git a/src/Option.h b/src/Option.h index 7770859f..17ea69a8 100644 --- a/src/Option.h +++ b/src/Option.h @@ -68,6 +68,10 @@ public: std::map::const_iterator begin() const; std::map::const_iterator end() const; + + std::map::iterator begin(); + + std::map::iterator end(); }; } // namespace aria2 diff --git a/src/RequestGroup.cc b/src/RequestGroup.cc index b48528e3..d7de3612 100644 --- a/src/RequestGroup.cc +++ b/src/RequestGroup.cc @@ -246,9 +246,10 @@ SharedHandle RequestGroup::createCheckIntegrityEntry() #endif // ENABLE_MESSAGE_DIGEST { downloadContext_->setChecksumVerified(true); - A2_LOG_NOTICE(fmt(MSG_DOWNLOAD_ALREADY_COMPLETED, - util::itos(gid_).c_str(), - downloadContext_->getBasePath().c_str())); + A2_LOG_NOTICE + (fmt(MSG_DOWNLOAD_ALREADY_COMPLETED, + util::itos(gid_).c_str(), + utf8ToNative(downloadContext_->getBasePath()).c_str())); } } else { checkEntry.reset(new StreamCheckIntegrityEntry(this)); @@ -267,9 +268,10 @@ SharedHandle RequestGroup::createCheckIntegrityEntry() #endif // ENABLE_MESSAGE_DIGEST { downloadContext_->setChecksumVerified(true); - A2_LOG_NOTICE(fmt(MSG_DOWNLOAD_ALREADY_COMPLETED, - util::itos(gid_).c_str(), - downloadContext_->getBasePath().c_str())); + A2_LOG_NOTICE + (fmt(MSG_DOWNLOAD_ALREADY_COMPLETED, + util::itos(gid_).c_str(), + utf8ToNative(downloadContext_->getBasePath()).c_str())); } } else { loadAndOpenFile(infoFile); @@ -312,7 +314,7 @@ void RequestGroup::createInitialCommand if(e->getRequestGroupMan()->isSameFileBeingDownloaded(this)) { throw DOWNLOAD_FAILURE_EXCEPTION2 (fmt(EX_DUPLICATE_FILE_DOWNLOAD, - downloadContext_->getBasePath().c_str()), + utf8ToNative(downloadContext_->getBasePath()).c_str()), error_code::DUPLICATE_DOWNLOAD); } initPieceStorage(); @@ -419,7 +421,7 @@ void RequestGroup::createInitialCommand // TODO we need this->haltRequested = true? throw DOWNLOAD_FAILURE_EXCEPTION2 (fmt(MSG_FILE_ALREADY_EXISTS, - downloadContext_->getBasePath().c_str()), + utf8ToNative(downloadContext_->getBasePath()).c_str()), error_code::FILE_ALREADY_EXISTS); } else { pieceStorage_->getDiskAdaptor()->openFile(); @@ -484,7 +486,7 @@ void RequestGroup::createInitialCommand if(e->getRequestGroupMan()->isSameFileBeingDownloaded(this)) { throw DOWNLOAD_FAILURE_EXCEPTION2 (fmt(EX_DUPLICATE_FILE_DOWNLOAD, - downloadContext_->getBasePath().c_str()), + utf8ToNative(downloadContext_->getBasePath()).c_str()), error_code::DUPLICATE_DOWNLOAD); } SharedHandle progressInfoFile @@ -511,7 +513,7 @@ void RequestGroup::createInitialCommand if(e->getRequestGroupMan()->isSameFileBeingDownloaded(this)) { throw DOWNLOAD_FAILURE_EXCEPTION2 (fmt(EX_DUPLICATE_FILE_DOWNLOAD, - downloadContext_->getBasePath().c_str()), + utf8ToNative(downloadContext_->getBasePath()).c_str()), error_code::DUPLICATE_DOWNLOAD); } initPieceStorage(); @@ -535,7 +537,7 @@ void RequestGroup::createInitialCommand // TODO we need this->haltRequested = true? throw DOWNLOAD_FAILURE_EXCEPTION2 (fmt(MSG_FILE_ALREADY_EXISTS, - downloadContext_->getBasePath().c_str()), + utf8ToNative(downloadContext_->getBasePath()).c_str()), error_code::FILE_ALREADY_EXISTS); } else { pieceStorage_->getDiskAdaptor()->openFile(); @@ -720,7 +722,7 @@ void RequestGroup::removeDefunctControlFile progressInfoFile->removeFile(); A2_LOG_NOTICE(fmt(MSG_REMOVED_DEFUNCT_CONTROL_FILE, progressInfoFile->getFilename().c_str(), - downloadContext_->getBasePath().c_str())); + utf8ToNative(downloadContext_->getBasePath()).c_str())); } } @@ -769,17 +771,18 @@ void RequestGroup::shouldCancelDownloadForSafety() if(outfile.exists()) { if(option_->getAsBool(PREF_AUTO_FILE_RENAMING)) { if(tryAutoFileRenaming()) { - A2_LOG_NOTICE(fmt(MSG_FILE_RENAMED, getFirstFilePath().c_str())); + A2_LOG_NOTICE(fmt(MSG_FILE_RENAMED, + utf8ToNative(getFirstFilePath()).c_str())); } else { throw DOWNLOAD_FAILURE_EXCEPTION2 (fmt("File renaming failed: %s", - getFirstFilePath().c_str()), + utf8ToNative(getFirstFilePath()).c_str()), error_code::FILE_RENAMING_FAILED); } } else { throw DOWNLOAD_FAILURE_EXCEPTION2 (fmt(MSG_FILE_ALREADY_EXISTS, - getFirstFilePath().c_str()), + utf8ToNative(getFirstFilePath()).c_str()), error_code::FILE_ALREADY_EXISTS); } } @@ -1036,7 +1039,7 @@ void RequestGroup::releaseRuntimeResource(DownloadEngine* e) void RequestGroup::preDownloadProcessing() { A2_LOG_DEBUG(fmt("Finding PreDownloadHandler for path %s.", - getFirstFilePath().c_str())); + utf8ToNative(getFirstFilePath()).c_str())); try { for(std::vector >::const_iterator itr = preDownloadHandlers_.begin(), eoi = preDownloadHandlers_.end(); @@ -1058,7 +1061,7 @@ void RequestGroup::postDownloadProcessing (std::vector >& groups) { A2_LOG_DEBUG(fmt("Finding PostDownloadHandler for path %s.", - getFirstFilePath().c_str())); + utf8ToNative(getFirstFilePath()).c_str())); try { for(std::vector >::const_iterator itr = postDownloadHandlers_.begin(), eoi = postDownloadHandlers_.end(); @@ -1200,7 +1203,7 @@ DownloadResultHandle RequestGroup::createDownloadResult() const void RequestGroup::reportDownloadFinished() { A2_LOG_NOTICE(fmt(MSG_FILE_DOWNLOAD_COMPLETED, - downloadContext_->getBasePath().c_str())); + utf8ToNative(downloadContext_->getBasePath()).c_str())); uriSelector_->resetCounters(); #ifdef ENABLE_BITTORRENT if(downloadContext_->hasAttribute(bittorrent::BITTORRENT)) { diff --git a/src/RequestGroupMan.cc b/src/RequestGroupMan.cc index 5c8ab05c..dccd655b 100644 --- a/src/RequestGroupMan.cc +++ b/src/RequestGroupMan.cc @@ -344,7 +344,8 @@ public: A2_LOG_NOTICE (fmt("Download GID#%s not complete: %s", util::itos(group->getGID()).c_str(), - group->getDownloadContext()->getBasePath().c_str())); + utf8ToNative(group->getDownloadContext() + ->getBasePath()).c_str())); group->saveControlFile(); } } catch(RecoverableException& ex) { diff --git a/src/SegmentMan.cc b/src/SegmentMan.cc index 7fb65b38..fb3137ee 100644 --- a/src/SegmentMan.cc +++ b/src/SegmentMan.cc @@ -471,7 +471,7 @@ size_t SegmentMan::countFreePieceFrom(size_t index) const void SegmentMan::ignoreSegmentFor(const SharedHandle& fileEntry) { A2_LOG_DEBUG(fmt("ignoring segment for path=%s, offset=%s, length=%s", - fileEntry->getPath().c_str(), + utf8ToNative(fileEntry->getPath()).c_str(), util::itos(fileEntry->getOffset()).c_str(), util::uitos(fileEntry->getLength()).c_str())); ignoreBitfield_.addFilter(fileEntry->getOffset(), fileEntry->getLength()); diff --git a/src/a2io.h b/src/a2io.h index 8b50f02b..19cb81a5 100644 --- a/src/a2io.h +++ b/src/a2io.h @@ -124,9 +124,15 @@ # undef stat # endif // stat # define a2_struct_stat struct _stati64 -# define a2stat(path, buf) _stati64(path, buf) +# define a2stat(path, buf) _wstati64(path, buf) # define a2tell(handle) _telli64(handle) -# define a2mkdir(path, openMode) mkdir(path) +# define a2mkdir(path, openMode) _wmkdir(path) +# define a2utimbuf _utimbuf +# define a2utime(path, times) _wutime(path, times) +# define a2unlink(path) _wunlink(path) +# define a2rmdir(path) _wrmdir(path) +# define a2rename(src, dest) _wrename(src, dest) +# define a2open(path, flags, mode) _wopen(path, flags, mode) #else // !__MINGW32__ # define a2lseek(fd, offset, origin) lseek(fd, offset, origin) # define a2fseek(fp, offset, origin) fseek(fp, offset, origin) @@ -135,6 +141,12 @@ # define a2_struct_stat struct stat # define a2stat(path, buf) stat(path, buf) # define a2mkdir(path, openMode) mkdir(path, openMode) +# define a2utimbuf utimbuf +# define a2utime(path, times) ::utime(path, times) +# define a2unlink(path) unlink(path) +# define a2rmdir(path) rmdir(path) +# define a2rename(src, dest) rename(src, dest) +# define a2open(path, flags, mode) open(path, flags, mode) #endif // !__MINGW32__ #define OPEN_MODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH diff --git a/src/option_processing.cc b/src/option_processing.cc index 4fad4465..f4894f80 100644 --- a/src/option_processing.cc +++ b/src/option_processing.cc @@ -170,6 +170,14 @@ void option_processing(Option& op, std::vector& uris, cmdstream.seekg(0, std::ios::beg); // finaly let's parse and store command-iine options. oparser.parse(op, cmdstream); +#ifdef __MINGW32__ + for(std::map::iterator i = op.begin(); + i != op.end(); ++i) { + if(!util::isUtf8((*i).second)) { + (*i).second = nativeToUtf8((*i).second); + } + } +#endif // __MINGW32__ } catch(OptionHandlerException& e) { std::cerr << e.stackTrace() << "\n"; SharedHandle h = oparser.findByName(e.getOptionName()); diff --git a/src/util.cc b/src/util.cc index 16e4d5e9..ff819238 100644 --- a/src/util.cc +++ b/src/util.cc @@ -94,6 +94,101 @@ namespace aria2 { +#ifdef __MINGW32__ +namespace { +int utf8ToWChar(wchar_t* out, size_t outLength, const std::string& src) +{ + return MultiByteToWideChar(CP_UTF8, 0, src.c_str(), -1, + out, outLength); +} +} // namespace + +namespace { +int ansiToWChar(wchar_t* out, size_t outLength, const std::string& src) +{ + return MultiByteToWideChar(CP_ACP, 0, src.c_str(), -1, + out, outLength); +} +} // namespace + +namespace { +int wCharToUtf8(char* out, size_t outLength, const std::wstring& src) +{ + return WideCharToMultiByte(CP_UTF8, 0, src.c_str(), -1, + out, outLength, 0, 0); +} +} // namespace + +namespace { +int wCharToAnsi(char* out, size_t outLength, const std::wstring& src) +{ + return WideCharToMultiByte(CP_ACP, 0, src.c_str(), -1, + out, outLength, 0, 0); +} +} // namespace + +std::wstring utf8ToWChar(const std::string& src) +{ + int len = utf8ToWChar(0, 0, src); + if(len == 0) { + abort(); + } + wchar_t* buf = new wchar_t[len]; + len = utf8ToWChar(buf, len, src); + if(len == 0) { + abort(); + } else { + return buf; + } +} + +std::string utf8ToNative(const std::string& src) +{ + std::wstring wsrc = utf8ToWChar(src); + int len = wCharToAnsi(0, 0, wsrc); + if(len == 0) { + abort(); + } + char* buf = new char[len]; + len = wCharToAnsi(buf, len, wsrc); + if(len == 0) { + abort(); + } else { + return buf; + } +} + +std::string wCharToUtf8(const std::wstring& wsrc) +{ + int len = wCharToUtf8(0, 0, wsrc); + if(len == 0) { + abort(); + } + char* buf = new char[len]; + len = wCharToUtf8(buf, len, wsrc); + if(len == 0) { + abort(); + } else { + return buf; + } +} + +std::string nativeToUtf8(const std::string& src) +{ + int len = ansiToWChar(0, 0, src); + if(len == 0) { + abort(); + } + wchar_t* buf = new wchar_t[len]; + len = ansiToWChar(buf, len, src); + if(len == 0) { + abort(); + } else { + return wCharToUtf8(buf); + } +} +#endif // __MINGW32__ + namespace util { const std::string DEFAULT_STRIP_CHARSET("\r\n\t "); @@ -1171,7 +1266,7 @@ void mkdirs(const std::string& dirpath) if(!dir.isDir()) { throw DL_ABORT_EX3 (errNum, - fmt(EX_MAKE_DIR, dir.getPath().c_str(), + fmt(EX_MAKE_DIR, utf8ToNative(dir.getPath()).c_str(), safeStrerror(errNum).c_str()), error_code::DIR_CREATE_ERROR); } @@ -1412,9 +1507,6 @@ std::string escapePath(const std::string& s) || std::find(vbegin(WIN_INVALID_PATH_CHARS), vend(WIN_INVALID_PATH_CHARS), c) != vend(WIN_INVALID_PATH_CHARS) - // Since Windows does not understand UTF-8 correctly, we - // percent-encode character other than ASCII. - || c > 0x7fu #endif // __MINGW32__ ){ d += fmt("%%%02X", c); diff --git a/src/util.h b/src/util.h index db8a9aba..09e8e63f 100644 --- a/src/util.h +++ b/src/util.h @@ -86,6 +86,19 @@ inline uint64_t ntoh64(uint64_t x) { return byteswap64(x); } inline uint64_t hton64(uint64_t x) { return byteswap64(x); } #endif // !WORDS_BIGENDIAN +#ifdef __MINGW32__ +std::wstring utf8ToWChar(const std::string& src); + +std::string utf8ToNative(const std::string& src); + +std::string wCharToUtf8(const std::wstring& wsrc); + +std::string nativeToUtf8(const std::string& src); +#else // !__MINGW32__ +# define utf8ToWChar(src) src +# define utf8ToNative(src) src +#endif // !__MINGW32__ + namespace util { void divide @@ -255,7 +268,8 @@ void toStream os << "===+===========================================================================" << "\n"; int32_t count = 1; for(; first != last; ++first, ++count) { - os << std::setw(3) << count << "|" << (*first)->getPath() << "\n"; + os << std::setw(3) << count << "|" + << utf8ToNative((*first)->getPath()) << "\n"; os << " |" << util::abbrevSize((*first)->getLength()) << "B (" << util::uitos((*first)->getLength(), true) << ")\n"; os << "---+---------------------------------------------------------------------------" << "\n"; diff --git a/test/FileTest.cc b/test/FileTest.cc index bb03012e..7055ec2f 100644 --- a/test/FileTest.cc +++ b/test/FileTest.cc @@ -7,6 +7,8 @@ #include #include +#include "util.h" + namespace aria2 { class FileTest:public CppUnit::TestFixture { @@ -241,7 +243,7 @@ void FileTest::testUtime() CPPUNIT_ASSERT(f.utime(Time(atime), Time(mtime))); a2_struct_stat buf; - CPPUNIT_ASSERT(0 == a2stat(f.getPath().c_str(), &buf)); + CPPUNIT_ASSERT(0 == a2stat(utf8ToWChar(f.getPath()).c_str(), &buf)); CPPUNIT_ASSERT_EQUAL((time_t)atime, (time_t)buf.st_atime); CPPUNIT_ASSERT_EQUAL((time_t)mtime, f.getModifiedTime().getTime());