From de39ce6ec44647cee92853e2928cf5475af992e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Remko=20Tron=C3=A7on?= Date: Wed, 15 May 2013 21:44:37 +0200 Subject: Fixed unicode path handling. - Use boost::filesystem::path consistently for referring to files. - Use boost::filesystem streams for I/O, such that paths are always handled correctly. - Use stringToPath and pathToString for conversion between strings and boost::filesystem::path, to ensure we have consistent unicode handling across platforms and environments. The default constructor and string conversion uses platform-dependent encoding, depending on the global locale set in the application, which causes problems. So, unless you are in platform dependent code, the default constructor and string() function should not be used. When constructing paths from other paths (e.g. using operator/), also use stringToPath (instead of string arguments) if the path can contain unicode characters. Change-Id: If286bd9e71c8414afc0b24ba67e26ab7608ef6ea diff --git a/SwifTools/Application/UnitTest/ApplicationPathProviderTest.cpp b/SwifTools/Application/UnitTest/ApplicationPathProviderTest.cpp index 5eb0e16..e7a47a7 100644 --- a/SwifTools/Application/UnitTest/ApplicationPathProviderTest.cpp +++ b/SwifTools/Application/UnitTest/ApplicationPathProviderTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -9,6 +9,7 @@ #include #include +#include #include using namespace Swift; @@ -40,7 +41,7 @@ class ApplicationPathProviderTest : public CppUnit::TestFixture { void testGetExecutableDir() { boost::filesystem::path dir = testling_->getExecutableDir(); CPPUNIT_ASSERT(boost::filesystem::is_directory(dir)); - CPPUNIT_ASSERT(boost::ends_with(dir.string(), "UnitTest")); + CPPUNIT_ASSERT(boost::ends_with(pathToString(dir), "UnitTest")); } private: diff --git a/SwifTools/Application/WindowsApplicationPathProvider.cpp b/SwifTools/Application/WindowsApplicationPathProvider.cpp index 730a57a..2c61208 100644 --- a/SwifTools/Application/WindowsApplicationPathProvider.cpp +++ b/SwifTools/Application/WindowsApplicationPathProvider.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -8,6 +8,7 @@ #include #include +#include namespace Swift { @@ -17,16 +18,17 @@ WindowsApplicationPathProvider::WindowsApplicationPathProvider(const std::string } boost::filesystem::path WindowsApplicationPathProvider::getDataDir() const { - char* appDirRaw = getenv("APPDATA"); + wchar_t* appDirRaw = _wgetenv(L"APPDATA"); assert(appDirRaw); - boost::filesystem::path result(boost::filesystem::path(appDirRaw) / getApplicationName()); + boost::filesystem::path result( + boost::filesystem::path(appDirRaw) / getApplicationName()); boost::filesystem::create_directory(result); return result; } boost::filesystem::path WindowsApplicationPathProvider::getHomeDir() const { //FIXME: This should be My Documents - char* homeDirRaw = getenv("USERPROFILE"); + wchar_t* homeDirRaw = _wgetenv(L"USERPROFILE"); assert(homeDirRaw); return boost::filesystem::path(homeDirRaw); } diff --git a/SwifTools/CrashReporter.cpp b/SwifTools/CrashReporter.cpp index 67377f2..f47ab33 100644 --- a/SwifTools/CrashReporter.cpp +++ b/SwifTools/CrashReporter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Remko Tronçon + * Copyright (c) 2012-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -7,6 +7,7 @@ #include #include +#include #if defined(HAVE_BREAKPAD) @@ -51,7 +52,7 @@ CrashReporter::CrashReporter(const boost::filesystem::path& path) { p = boost::make_shared(); #if defined(SWIFTEN_PLATFORM_WINDOWS) // FIXME: Need UTF8 conversion from string to wstring - std::string pathString = path.string(); + std::string pathString = pathToString(path); p->handler = boost::shared_ptr( // Not using make_shared, because 'handleDump' seems to have problems with VC2010 new google_breakpad::ExceptionHandler( @@ -62,7 +63,7 @@ CrashReporter::CrashReporter(const boost::filesystem::path& path) { google_breakpad::ExceptionHandler::HANDLER_ALL)); // Turning it off for Mac, because it doesn't really help us //#elif defined(SWIFTEN_PLATFORM_MACOSX) -// p->handler = boost::make_shared(path.string(), (google_breakpad::ExceptionHandler::FilterCallback) 0, handleDump, (void*) 0, true, (const char*) 0); +// p->handler = boost::make_shared(pathToString(path), (google_breakpad::ExceptionHandler::FilterCallback) 0, handleDump, (void*) 0, true, (const char*) 0); #endif } diff --git a/SwifTools/Notifier/GNTPNotifier.cpp b/SwifTools/Notifier/GNTPNotifier.cpp index 9bc05bd..757594f 100644 --- a/SwifTools/Notifier/GNTPNotifier.cpp +++ b/SwifTools/Notifier/GNTPNotifier.cpp @@ -14,6 +14,7 @@ #include #include +#include #include namespace Swift { @@ -23,7 +24,7 @@ GNTPNotifier::GNTPNotifier(const std::string& name, const boost::filesystem::pat std::ostringstream message; message << "GNTP/1.0 REGISTER NONE\r\n"; message << "Application-Name: " << name << "\r\n"; - message << "Application-Icon: file://" << icon.string() << "\r\n"; + message << "Application-Icon: file://" << pathToString(icon) << "\r\n"; message << "Notifications-Count: " << getAllTypes().size() << "\r\n"; std::vector defaultTypes = getDefaultTypes(); std::vector allTypes = getAllTypes(); @@ -59,7 +60,7 @@ void GNTPNotifier::showMessage(Type type, const std::string& subject, const std: message << "Notification-Name: " << typeToString(type) << "\r\n"; message << "Notification-Title: " << subject << "\r\n"; message << "Notification-Text: " << description << "\r\n"; - message << "Notification-Icon: " << picture.string() << "\r\n"; + message << "Notification-Icon: " << pathToString(picture) << "\r\n"; message << "\r\n"; send(message.str()); } diff --git a/SwifTools/Notifier/GrowlNotifier.mm b/SwifTools/Notifier/GrowlNotifier.mm index c1996d9..2ababf4 100644 --- a/SwifTools/Notifier/GrowlNotifier.mm +++ b/SwifTools/Notifier/GrowlNotifier.mm @@ -65,7 +65,7 @@ GrowlNotifier::~GrowlNotifier() { void GrowlNotifier::showMessage(Type type, const std::string& subject, const std::string& description, const boost::filesystem::path& picturePath, boost::function callback) { ByteArray picture; - readByteArrayFromFile(picture, picturePath.string()); + readByteArrayFromFile(picture, picturePath); Context* context = new Context(callback); // Growl sometimes sends timeout notifications twice for the same message. We therefore need diff --git a/Swift/Controllers/Chat/ChatController.cpp b/Swift/Controllers/Chat/ChatController.cpp index 1fb45a9..f5c690c 100644 --- a/Swift/Controllers/Chat/ChatController.cpp +++ b/Swift/Controllers/Chat/ChatController.cpp @@ -285,7 +285,7 @@ void ChatController::postSendMessage(const std::string& body, boost::shared_ptr< eraseIf(unackedStanzas_, PairSecondEquals, std::string>(myLastMessageUIID_)); replaceMessage(body, myLastMessageUIID_, boost::posix_time::microsec_clock::universal_time(), HighlightAction()); } else { - myLastMessageUIID_ = addMessage(body, QT_TRANSLATE_NOOP("", "me"), true, labelsEnabled_ ? chatWindow_->getSelectedSecurityLabel().getLabel() : boost::shared_ptr(), std::string(avatarManager_->getAvatarPath(selfJID_).string()), boost::posix_time::microsec_clock::universal_time(), HighlightAction()); + myLastMessageUIID_ = addMessage(body, QT_TRANSLATE_NOOP("", "me"), true, labelsEnabled_ ? chatWindow_->getSelectedSecurityLabel().getLabel() : boost::shared_ptr(), avatarManager_->getAvatarPath(selfJID_), boost::posix_time::microsec_clock::universal_time(), HighlightAction()); } if (stanzaChannel_->getStreamManagementEnabled() && !myLastMessageUIID_.empty() ) { diff --git a/Swift/Controllers/Chat/ChatControllerBase.cpp b/Swift/Controllers/Chat/ChatControllerBase.cpp index e469637..621fd2d 100644 --- a/Swift/Controllers/Chat/ChatControllerBase.cpp +++ b/Swift/Controllers/Chat/ChatControllerBase.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -179,11 +180,11 @@ void ChatControllerBase::activateChatWindow() { chatWindow_->activate(); } -std::string ChatControllerBase::addMessage(const std::string& message, const std::string& senderName, bool senderIsSelf, const boost::shared_ptr label, const std::string& avatarPath, const boost::posix_time::ptime& time, const HighlightAction& highlight) { +std::string ChatControllerBase::addMessage(const std::string& message, const std::string& senderName, bool senderIsSelf, const boost::shared_ptr label, const boost::filesystem::path& avatarPath, const boost::posix_time::ptime& time, const HighlightAction& highlight) { if (boost::starts_with(message, "/me ")) { - return chatWindow_->addAction(String::getSplittedAtFirst(message, ' ').second, senderName, senderIsSelf, label, avatarPath, time, highlight); + return chatWindow_->addAction(String::getSplittedAtFirst(message, ' ').second, senderName, senderIsSelf, label, pathToString(avatarPath), time, highlight); } else { - return chatWindow_->addMessage(message, senderName, senderIsSelf, label, avatarPath, time, highlight); + return chatWindow_->addMessage(message, senderName, senderIsSelf, label, pathToString(avatarPath), time, highlight); } } @@ -266,7 +267,7 @@ void ChatControllerBase::handleIncomingMessage(boost::shared_ptr m } } else { - lastMessagesUIID_[from] = addMessage(body, senderDisplayNameFromMessage(from), isIncomingMessageFromMe(message), label, std::string(avatarManager_->getAvatarPath(from).string()), timeStamp, highlight); + lastMessagesUIID_[from] = addMessage(body, senderDisplayNameFromMessage(from), isIncomingMessageFromMe(message), label, avatarManager_->getAvatarPath(from), timeStamp, highlight); } logMessage(body, from, selfJID_, timeStamp, true); diff --git a/Swift/Controllers/Chat/ChatControllerBase.h b/Swift/Controllers/Chat/ChatControllerBase.h index 84bd06a..0199142 100644 --- a/Swift/Controllers/Chat/ChatControllerBase.h +++ b/Swift/Controllers/Chat/ChatControllerBase.h @@ -10,7 +10,7 @@ #include #include #include "Swiften/Base/boost_bsignals.h" -#include +#include #include #include @@ -50,7 +50,7 @@ namespace Swift { void activateChatWindow(); virtual void setAvailableServerFeatures(boost::shared_ptr info); void handleIncomingMessage(boost::shared_ptr message); - std::string addMessage(const std::string& message, const std::string& senderName, bool senderIsSelf, boost::shared_ptr label, const std::string& avatarPath, const boost::posix_time::ptime& time, const HighlightAction& highlight); + std::string addMessage(const std::string& message, const std::string& senderName, bool senderIsSelf, boost::shared_ptr label, const boost::filesystem::path& avatarPath, const boost::posix_time::ptime& time, const HighlightAction& highlight); void replaceMessage(const std::string& message, const std::string& id, const boost::posix_time::ptime& time, const HighlightAction& highlight); virtual void setOnline(bool online); virtual void setEnabled(bool enabled); diff --git a/Swift/Controllers/Chat/MUCController.cpp b/Swift/Controllers/Chat/MUCController.cpp index b964bad..6bf3e5f 100644 --- a/Swift/Controllers/Chat/MUCController.cpp +++ b/Swift/Controllers/Chat/MUCController.cpp @@ -312,8 +312,7 @@ void MUCController::handleAvatarChanged(const JID& jid) { if (parting_ || !jid.equals(toJID_, JID::WithoutResource)) { return; } - std::string path = avatarManager_->getAvatarPath(jid).string(); - roster_->applyOnItems(SetAvatar(jid, path, JID::WithResource)); + roster_->applyOnItems(SetAvatar(jid, avatarManager_->getAvatarPath(jid), JID::WithResource)); } void MUCController::handleWindowClosed() { @@ -337,7 +336,7 @@ void MUCController::handleOccupantJoined(const MUCOccupant& occupant) { NickJoinPart event(occupant.getNick(), Join); appendToJoinParts(joinParts_, event); std::string groupName(roleToGroupName(occupant.getRole())); - roster_->addContact(jid, realJID, occupant.getNick(), groupName, avatarManager_->getAvatarPath(jid).string()); + roster_->addContact(jid, realJID, occupant.getNick(), groupName, avatarManager_->getAvatarPath(jid)); roster_->getGroup(groupName)->setManualSort(roleToSortName(occupant.getRole())); if (joined_) { std::string joinString; @@ -483,7 +482,7 @@ void MUCController::handleOccupantRoleChanged(const std::string& nick, const MUC realJID = occupant.getRealJID().get(); } std::string group(roleToGroupName(occupant.getRole())); - roster_->addContact(jid, realJID, nick, group, avatarManager_->getAvatarPath(jid).string()); + roster_->addContact(jid, realJID, nick, group, avatarManager_->getAvatarPath(jid)); roster_->getGroup(group)->setManualSort(roleToSortName(occupant.getRole())); chatWindow_->addSystemMessage(str(format(QT_TRANSLATE_NOOP("", "%1% is now a %2%")) % nick % roleToFriendlyName(occupant.getRole())), ChatWindow::DefaultDirection); if (nick == nick_) { @@ -830,7 +829,7 @@ void MUCController::addRecentLogs() { bool senderIsSelf = nick_ == message.getFromJID().getResource(); // the chatWindow uses utc timestamps - addMessage(message.getMessage(), senderDisplayNameFromMessage(message.getFromJID()), senderIsSelf, boost::shared_ptr(new SecurityLabel()), std::string(avatarManager_->getAvatarPath(message.getFromJID()).string()), message.getTime() - boost::posix_time::hours(message.getOffset()), HighlightAction()); + addMessage(message.getMessage(), senderDisplayNameFromMessage(message.getFromJID()), senderIsSelf, boost::shared_ptr(new SecurityLabel()), avatarManager_->getAvatarPath(message.getFromJID()), message.getTime() - boost::posix_time::hours(message.getOffset()), HighlightAction()); } } diff --git a/Swift/Controllers/HistoryViewController.cpp b/Swift/Controllers/HistoryViewController.cpp index 9343017..cfa2482 100644 --- a/Swift/Controllers/HistoryViewController.cpp +++ b/Swift/Controllers/HistoryViewController.cpp @@ -4,6 +4,12 @@ * See Documentation/Licenses/BSD-simplified.txt for more information. */ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + #include #include @@ -15,6 +21,7 @@ #include #include #include +#include namespace Swift { static const std::string category[] = { "Contacts", "MUC", "Contacts" }; @@ -146,7 +153,7 @@ void HistoryViewController::handleNewMessage(const HistoryMessage& message) { // update contacts if (!contacts_[message.getType()].count(displayJID)) { - roster_->addContact(displayJID, displayJID, nickResolver_->jidToNick(displayJID), category[message.getType()], avatarManager_->getAvatarPath(displayJID).string()); + roster_->addContact(displayJID, displayJID, nickResolver_->jidToNick(displayJID), category[message.getType()], avatarManager_->getAvatarPath(displayJID)); } contacts_[message.getType()][displayJID].insert(message.getTime().date()); @@ -154,7 +161,7 @@ void HistoryViewController::handleNewMessage(const HistoryMessage& message) { void HistoryViewController::addNewMessage(const HistoryMessage& message, bool addAtTheTop) { bool senderIsSelf = message.getFromJID().toBare() == selfJID_; - std::string avatarPath = avatarManager_->getAvatarPath(message.getFromJID()).string(); + std::string avatarPath = pathToString(avatarManager_->getAvatarPath(message.getFromJID())); std::string nick = message.getType() != HistoryMessage::Groupchat ? nickResolver_->jidToNick(message.getFromJID()) : message.getFromJID().getResource(); historyWindow_->addMessage(message.getMessage(), nick, senderIsSelf, avatarPath, message.getTime(), addAtTheTop); @@ -177,7 +184,7 @@ void HistoryViewController::handleReturnPressed(const std::string& keyword) { else { nick = nickResolver_->jidToNick(jid); } - roster_->addContact(jid, jid, nick, category[type], avatarManager_->getAvatarPath(jid).string()); + roster_->addContact(jid, jid, nick, category[type], avatarManager_->getAvatarPath(jid)); Presence::ref presence = getPresence(jid, type == HistoryMessage::Groupchat); @@ -323,8 +330,7 @@ void HistoryViewController::handlePresenceChanged(Presence::ref presence) { } void HistoryViewController::handleAvatarChanged(const JID& jid) { - std::string path = avatarManager_->getAvatarPath(jid).string(); - roster_->applyOnItems(SetAvatar(jid, path)); + roster_->applyOnItems(SetAvatar(jid, avatarManager_->getAvatarPath(jid))); } Presence::ref HistoryViewController::getPresence(const JID& jid, bool isMUC) { diff --git a/Swift/Controllers/Roster/ContactRosterItem.cpp b/Swift/Controllers/Roster/ContactRosterItem.cpp index bf85167..70b4a1b 100644 --- a/Swift/Controllers/Roster/ContactRosterItem.cpp +++ b/Swift/Controllers/Roster/ContactRosterItem.cpp @@ -52,11 +52,11 @@ std::string ContactRosterItem::getIdleText() const { } } -void ContactRosterItem::setAvatarPath(const std::string& path) { +void ContactRosterItem::setAvatarPath(const boost::filesystem::path& path) { avatarPath_ = path; onDataChanged(); } -const std::string& ContactRosterItem::getAvatarPath() const { +const boost::filesystem::path& ContactRosterItem::getAvatarPath() const { return avatarPath_; } diff --git a/Swift/Controllers/Roster/ContactRosterItem.h b/Swift/Controllers/Roster/ContactRosterItem.h index fc65d6d..67a9722 100644 --- a/Swift/Controllers/Roster/ContactRosterItem.h +++ b/Swift/Controllers/Roster/ContactRosterItem.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Kevin Smith + * Copyright (c) 2010-2013 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -18,6 +18,7 @@ #include "Swiften/Base/boost_bsignals.h" #include #include +#include namespace Swift { @@ -43,8 +44,8 @@ class ContactRosterItem : public RosterItem { StatusShow::Type getSimplifiedStatusShow() const; std::string getStatusText() const; std::string getIdleText() const; - void setAvatarPath(const std::string& path); - const std::string& getAvatarPath() const; + void setAvatarPath(const boost::filesystem::path& path); + const boost::filesystem::path& getAvatarPath() const; const JID& getJID() const; void setDisplayJID(const JID& jid); const JID& getDisplayJID() const; @@ -66,7 +67,7 @@ class ContactRosterItem : public RosterItem { JID jid_; JID displayJID_; boost::posix_time::ptime lastAvailableTime_; - std::string avatarPath_; + boost::filesystem::path avatarPath_; std::map > presences_; boost::shared_ptr offlinePresence_; boost::shared_ptr shownPresence_; diff --git a/Swift/Controllers/Roster/Roster.cpp b/Swift/Controllers/Roster/Roster.cpp index 3d0ca2e..9b45b63 100644 --- a/Swift/Controllers/Roster/Roster.cpp +++ b/Swift/Controllers/Roster/Roster.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -105,7 +105,7 @@ void Roster::handleChildrenChanged(GroupRosterItem* item) { onChildrenChanged(item); } -void Roster::addContact(const JID& jid, const JID& displayJID, const std::string& name, const std::string& groupName, const std::string& avatarPath) { +void Roster::addContact(const JID& jid, const JID& displayJID, const std::string& name, const std::string& groupName, const boost::filesystem::path& avatarPath) { GroupRosterItem* group(getGroup(groupName)); ContactRosterItem *item = new ContactRosterItem(jid, displayJID, name, group); item->setAvatarPath(avatarPath); diff --git a/Swift/Controllers/Roster/Roster.h b/Swift/Controllers/Roster/Roster.h index 91a152f..a4c8b99 100644 --- a/Swift/Controllers/Roster/Roster.h +++ b/Swift/Controllers/Roster/Roster.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -28,7 +28,7 @@ class Roster { Roster(bool sortByStatus = true, bool fullJIDMapping = false); ~Roster(); - void addContact(const JID& jid, const JID& displayJID, const std::string& name, const std::string& group, const std::string& avatarPath); + void addContact(const JID& jid, const JID& displayJID, const std::string& name, const std::string& group, const boost::filesystem::path& avatarPath); void removeContact(const JID& jid); void removeContactFromGroup(const JID& jid, const std::string& group); void removeGroup(const std::string& group); diff --git a/Swift/Controllers/Roster/RosterController.cpp b/Swift/Controllers/Roster/RosterController.cpp index d09ef4c..d277799 100644 --- a/Swift/Controllers/Roster/RosterController.cpp +++ b/Swift/Controllers/Roster/RosterController.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2012 Kevin Smith + * Copyright (c) 2010-2013 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -73,7 +74,7 @@ RosterController::RosterController(const JID& jid, XMPPRoster* xmppRoster, Avata uiEventConnection_ = uiEventStream->onUIEvent.connect(boost::bind(&RosterController::handleUIEvent, this, _1)); avatarManager_ = avatarManager; avatarManager_->onAvatarChanged.connect(boost::bind(&RosterController::handleAvatarChanged, this, _1)); - mainWindow_->setMyAvatarPath(avatarManager_->getAvatarPath(myJID_).string()); + mainWindow_->setMyAvatarPath(pathToString(avatarManager_->getAvatarPath(myJID_))); nickManager_->onOwnNickChanged.connect(boost::bind(&MainWindow::setMyNick, mainWindow_, _1)); mainWindow_->setMyJID(jid); @@ -125,11 +126,11 @@ void RosterController::handleOnJIDAdded(const JID& jid) { std::string name = nickResolver_->jidToNick(jid); if (!groups.empty()) { foreach(const std::string& group, groups) { - roster_->addContact(jid, jid, name, group, avatarManager_->getAvatarPath(jid).string()); + roster_->addContact(jid, jid, name, group, avatarManager_->getAvatarPath(jid)); } } else { - roster_->addContact(jid, jid, name, QT_TRANSLATE_NOOP("", "Contacts"), avatarManager_->getAvatarPath(jid).string()); + roster_->addContact(jid, jid, name, QT_TRANSLATE_NOOP("", "Contacts"), avatarManager_->getAvatarPath(jid)); } applyAllPresenceTo(jid); } @@ -164,7 +165,7 @@ void RosterController::handleOnJIDUpdated(const JID& jid, const std::string& old } foreach(const std::string& group, groups) { if (std::find(oldGroups.begin(), oldGroups.end(), group) == oldGroups.end()) { - roster_->addContact(jid, jid, name, group, avatarManager_->getAvatarPath(jid).string()); + roster_->addContact(jid, jid, name, group, avatarManager_->getAvatarPath(jid)); } } foreach(const std::string& group, oldGroups) { @@ -326,10 +327,10 @@ void RosterController::handleSubscriptionRequestDeclined(SubscriptionRequestEven } void RosterController::handleAvatarChanged(const JID& jid) { - std::string path = avatarManager_->getAvatarPath(jid).string(); + boost::filesystem::path path = avatarManager_->getAvatarPath(jid); roster_->applyOnItems(SetAvatar(jid, path)); if (jid.equals(myJID_, JID::WithoutResource)) { - mainWindow_->setMyAvatarPath(path); + mainWindow_->setMyAvatarPath(pathToString(path)); } } diff --git a/Swift/Controllers/Roster/SetAvatar.h b/Swift/Controllers/Roster/SetAvatar.h index 241b741..424f0b3 100644 --- a/Swift/Controllers/Roster/SetAvatar.h +++ b/Swift/Controllers/Roster/SetAvatar.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -10,6 +10,7 @@ #include "Swiften/JID/JID.h" #include "Swift/Controllers/Roster/RosterItemOperation.h" #include "Swift/Controllers/Roster/ContactRosterItem.h" +#include namespace Swift { @@ -17,7 +18,7 @@ class RosterItem; class SetAvatar : public RosterItemOperation { public: - SetAvatar(const JID& jid, const std::string& path, JID::CompareType compareType = JID::WithoutResource) : RosterItemOperation(true, jid), jid_(jid), path_(path), compareType_(compareType) { + SetAvatar(const JID& jid, const boost::filesystem::path& path, JID::CompareType compareType = JID::WithoutResource) : RosterItemOperation(true, jid), jid_(jid), path_(path), compareType_(compareType) { } virtual void operator() (RosterItem* item) const { @@ -29,7 +30,7 @@ class SetAvatar : public RosterItemOperation { private: JID jid_; - std::string path_; + boost::filesystem::path path_; JID::CompareType compareType_; }; diff --git a/Swift/Controllers/Roster/TableRoster.h b/Swift/Controllers/Roster/TableRoster.h index d4612ed..f447760 100644 --- a/Swift/Controllers/Roster/TableRoster.h +++ b/Swift/Controllers/Roster/TableRoster.h @@ -12,6 +12,7 @@ #include #include +#include namespace Swift { class Roster; @@ -21,13 +22,13 @@ namespace Swift { class TableRoster { public: struct Item { - Item(const std::string& name, const std::string& description, const JID& jid, StatusShow::Type status, const std::string& avatarPath) : name(name), description(description), jid(jid), status(status), avatarPath(avatarPath) { + Item(const std::string& name, const std::string& description, const JID& jid, StatusShow::Type status, const boost::filesystem::path& avatarPath) : name(name), description(description), jid(jid), status(status), avatarPath(avatarPath) { } std::string name; std::string description; JID jid; StatusShow::Type status; - std::string avatarPath; + boost::filesystem::path avatarPath; }; struct Index { diff --git a/Swift/Controllers/StatusCache.cpp b/Swift/Controllers/StatusCache.cpp index 1569e26..3444189 100644 --- a/Swift/Controllers/StatusCache.cpp +++ b/Swift/Controllers/StatusCache.cpp @@ -61,7 +61,7 @@ void StatusCache::loadRecents() { try { if (boost::filesystem::exists(path_)) { ByteArray data; - readByteArrayFromFile(data, path_.string()); + readByteArrayFromFile(data, path_); std::string stringData = byteArrayToString(data); std::vector lines; boost::split(lines, stringData, boost::is_any_of("\n")); diff --git a/Swift/Controllers/Storages/AvatarFileStorage.cpp b/Swift/Controllers/Storages/AvatarFileStorage.cpp index 792b77b..671e0cb 100644 --- a/Swift/Controllers/Storages/AvatarFileStorage.cpp +++ b/Swift/Controllers/Storages/AvatarFileStorage.cpp @@ -69,7 +69,7 @@ boost::filesystem::path AvatarFileStorage::getAvatarPath(const std::string& hash ByteArray AvatarFileStorage::getAvatar(const std::string& hash) const { ByteArray data; - readByteArrayFromFile(data, getAvatarPath(hash).string()); + readByteArrayFromFile(data, getAvatarPath(hash)); return data; } diff --git a/Swift/Controllers/Storages/CertificateFileStorage.cpp b/Swift/Controllers/Storages/CertificateFileStorage.cpp index b5e85d2..34d1f76 100644 --- a/Swift/Controllers/Storages/CertificateFileStorage.cpp +++ b/Swift/Controllers/Storages/CertificateFileStorage.cpp @@ -24,7 +24,7 @@ bool CertificateFileStorage::hasCertificate(Certificate::ref certificate) const boost::filesystem::path certificatePath = getCertificatePath(certificate); if (boost::filesystem::exists(certificatePath)) { ByteArray data; - readByteArrayFromFile(data, certificatePath.string()); + readByteArrayFromFile(data, certificatePath); Certificate::ref storedCertificate = certificateFactory->createCertificateFromDER(data); if (storedCertificate && storedCertificate->toDER() == certificate->toDER()) { return true; diff --git a/Swift/Controllers/Storages/FileStorages.cpp b/Swift/Controllers/Storages/FileStorages.cpp index 357c213..52a5e00 100644 --- a/Swift/Controllers/Storages/FileStorages.cpp +++ b/Swift/Controllers/Storages/FileStorages.cpp @@ -10,17 +10,18 @@ #include "Swift/Controllers/Storages/CapsFileStorage.h" #include "Swift/Controllers/Storages/RosterFileStorage.h" #include +#include namespace Swift { FileStorages::FileStorages(const boost::filesystem::path& baseDir, const JID& jid, CryptoProvider* crypto) { - std::string profile = jid.toBare(); + boost::filesystem::path profile = stringToPath(jid.toBare()); vcardStorage = new VCardFileStorage(baseDir / profile / "vcards", crypto); capsStorage = new CapsFileStorage(baseDir / "caps"); avatarStorage = new AvatarFileStorage(baseDir / "avatars", baseDir / profile / "avatars", crypto); rosterStorage = new RosterFileStorage(baseDir / profile / "roster.xml"); #ifdef SWIFT_EXPERIMENTAL_HISTORY - historyStorage = new SQLiteHistoryStorage((baseDir / "history.db").string()); + historyStorage = new SQLiteHistoryStorage(baseDir / "history.db"); #endif } diff --git a/Swift/Controllers/Storages/VCardFileStorage.cpp b/Swift/Controllers/Storages/VCardFileStorage.cpp index 633ed58..b22e235 100644 --- a/Swift/Controllers/Storages/VCardFileStorage.cpp +++ b/Swift/Controllers/Storages/VCardFileStorage.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include "Swiften/JID/JID.h" #include "Swiften/Elements/VCard.h" @@ -66,7 +67,7 @@ boost::filesystem::path VCardFileStorage::getVCardPath(const JID& jid) const { try { std::string file(jid.toString()); String::replaceAll(file, '/', "%2f"); - return boost::filesystem::path(vcardsPath / (file + ".xml")); + return boost::filesystem::path(vcardsPath / stringToPath(file + ".xml")); } catch (const boost::filesystem::filesystem_error& e) { std::cerr << "ERROR: " << e.what() << std::endl; diff --git a/Swift/QtUI/ChatList/ChatListRecentItem.cpp b/Swift/QtUI/ChatList/ChatListRecentItem.cpp index 6c9807f..5a4d1e1 100644 --- a/Swift/QtUI/ChatList/ChatListRecentItem.cpp +++ b/Swift/QtUI/ChatList/ChatListRecentItem.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 Kevin Smith + * Copyright (c) 2011-2013 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -7,6 +7,7 @@ #include #include +#include namespace Swift { ChatListRecentItem::ChatListRecentItem(const ChatListWindow::Chat& chat, ChatListGroupItem* parent) : ChatListItem(parent), chat_(chat) { @@ -25,7 +26,7 @@ QVariant ChatListRecentItem::data(int role) const { case Qt::BackgroundColorRole: return backgroundColor_; case Qt::ToolTipRole: return isContact() ? toolTipString() : QVariant(); case StatusTextRole: return statusText_;*/ - case AvatarRole: return QVariant(QString(chat_.avatarPath.string().c_str())); + case AvatarRole: return QVariant(P2QSTRING(pathToString(chat_.avatarPath))); case PresenceIconRole: return getPresenceIcon(); default: return QVariant(); } diff --git a/Swift/QtUI/ChatList/ChatListWhiteboardItem.cpp b/Swift/QtUI/ChatList/ChatListWhiteboardItem.cpp index 41648b6..6791aa5 100644 --- a/Swift/QtUI/ChatList/ChatListWhiteboardItem.cpp +++ b/Swift/QtUI/ChatList/ChatListWhiteboardItem.cpp @@ -4,9 +4,16 @@ * See Documentation/Licenses/BSD-simplified.txt for more information. */ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + #include #include +#include namespace Swift { ChatListWhiteboardItem::ChatListWhiteboardItem(const ChatListWindow::Chat& chat, ChatListGroupItem* parent) : ChatListItem(parent), chat_(chat) { @@ -25,7 +32,7 @@ namespace Swift { case Qt::BackgroundColorRole: return backgroundColor_; case Qt::ToolTipRole: return isContact() ? toolTipString() : QVariant(); case StatusTextRole: return statusText_;*/ - case AvatarRole: return QVariant(QString(chat_.avatarPath.string().c_str())); + case AvatarRole: return QVariant(P2QSTRING(pathToString(chat_.avatarPath))); case PresenceIconRole: return getPresenceIcon(); default: return QVariant(); } diff --git a/Swift/QtUI/FreeDesktopNotifier.cpp b/Swift/QtUI/FreeDesktopNotifier.cpp index 2393340..a51e482 100644 --- a/Swift/QtUI/FreeDesktopNotifier.cpp +++ b/Swift/QtUI/FreeDesktopNotifier.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -13,6 +13,7 @@ #include #include #include +#include namespace Swift { @@ -43,7 +44,7 @@ void FreeDesktopNotifier::showMessage(Type type, const std::string& subject, con hints["x-canonical-append"] = QString("allowed"); msg << applicationName.c_str(); msg << quint32(0); // ID of previous notification to replace - msg << imageScaler.getScaledImage(picture, 48).string().c_str(); // Icon to display + msg << pathToString(imageScaler.getScaledImage(picture, 48)); // Icon to display msg << subject.c_str(); // Summary / Header of the message to display msg << body; // Body of the message to display msg << actions; // Actions from which the user may choose diff --git a/Swift/QtUI/QtCachedImageScaler.cpp b/Swift/QtUI/QtCachedImageScaler.cpp index 7307577..9b1709b 100644 --- a/Swift/QtUI/QtCachedImageScaler.cpp +++ b/Swift/QtUI/QtCachedImageScaler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -8,6 +8,8 @@ #include #include +#include +#include namespace Swift { @@ -15,16 +17,17 @@ QtCachedImageScaler::QtCachedImageScaler() { } boost::filesystem::path QtCachedImageScaler::getScaledImage(const boost::filesystem::path& imagePath, int size) { - boost::filesystem::path scaledImagePath(imagePath.string() + "." + boost::lexical_cast(size)); + boost::filesystem::path scaledImagePath(imagePath); + scaledImagePath += "." + boost::lexical_cast(size); if (!boost::filesystem::exists(scaledImagePath)) { - QImage image(imagePath.string().c_str()); + QImage image(P2QSTRING(pathToString(imagePath))); if (!image.isNull()) { if (image.width() > size || image.height() > size) { QImage scaledImage = image.scaled(size, size, Qt::KeepAspectRatio, Qt::SmoothTransformation); - scaledImage.save(QString::fromUtf8(scaledImagePath.string().c_str()), "PNG"); + scaledImage.save(P2QSTRING(pathToString(scaledImagePath)), "PNG"); } else { - image.save(QString::fromUtf8(scaledImagePath.string().c_str()), "PNG"); + image.save(P2QSTRING(pathToString(scaledImagePath)), "PNG"); } } else { diff --git a/Swift/QtUI/QtSoundPlayer.cpp b/Swift/QtUI/QtSoundPlayer.cpp index 63f76f0..3f3782d 100644 --- a/Swift/QtUI/QtSoundPlayer.cpp +++ b/Swift/QtUI/QtSoundPlayer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Kevin Smith + * Copyright (c) 2010-2013 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -9,7 +9,9 @@ #include #include -#include "SwifTools/Application/ApplicationPathProvider.h" +#include +#include +#include namespace Swift { @@ -28,10 +30,10 @@ void QtSoundPlayer::playSound(SoundEffect sound, const std::string& soundResourc void QtSoundPlayer::playSound(const std::string& soundResource) { boost::filesystem::path resourcePath = applicationPathProvider->getResourcePath(soundResource); if (boost::filesystem::exists(resourcePath)) { - QSound::play(resourcePath.string().c_str()); + QSound::play(P2QSTRING(pathToString(resourcePath))); } else if (boost::filesystem::exists(soundResource)) { - QSound::play(soundResource.c_str()); + QSound::play(P2QSTRING(soundResource)); } else { std::cerr << "Unable to find sound: " << soundResource << std::endl; diff --git a/Swift/QtUI/QtSwift.cpp b/Swift/QtUI/QtSwift.cpp index 839d079..b563c53 100644 --- a/Swift/QtUI/QtSwift.cpp +++ b/Swift/QtUI/QtSwift.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2012 Kevin Smith + * Copyright (c) 2010-2013 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -129,14 +130,14 @@ QtSwift::QtSwift(const po::variables_map& options) : networkFactories_(&clientMa QCoreApplication::setApplicationVersion(buildVersion); qtSettings_ = new QtSettingsProvider(); - xmlSettings_ = loadSettingsFile(P2QSTRING((Paths::getExecutablePath() / "system-settings.xml").string())); + xmlSettings_ = loadSettingsFile(P2QSTRING(pathToString(Paths::getExecutablePath() / "system-settings.xml"))); settingsHierachy_ = new SettingsProviderHierachy(); settingsHierachy_->addProviderToTopOfStack(xmlSettings_); settingsHierachy_->addProviderToTopOfStack(qtSettings_); QMap emoticons; loadEmoticonsFile(":/emoticons/emoticons.txt", emoticons); - loadEmoticonsFile(P2QSTRING((Paths::getExecutablePath() / "emoticons.txt").string()), emoticons); + loadEmoticonsFile(P2QSTRING(pathToString(Paths::getExecutablePath() / "emoticons.txt")), emoticons); if (options.count("netbook-mode")) { splitter_ = new QtSingleWindow(qtSettings_); diff --git a/Swift/QtUI/Roster/RosterModel.cpp b/Swift/QtUI/Roster/RosterModel.cpp index 8f39f35..1b93047 100644 --- a/Swift/QtUI/Roster/RosterModel.cpp +++ b/Swift/QtUI/Roster/RosterModel.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Kevin Smith + * Copyright (c) 2010-2013 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -16,6 +16,7 @@ #include "Swift/Controllers/Roster/ContactRosterItem.h" #include "Swift/Controllers/Roster/GroupRosterItem.h" #include +#include #include "QtSwiftUtil.h" #include "Swift/QtUI/Roster/QtTreeWidget.h" @@ -150,7 +151,7 @@ QString RosterModel::getAvatar(RosterItem* item) const { if (!contact) { return ""; } - return QString(contact->getAvatarPath().c_str()); + return P2QSTRING(pathToString(contact->getAvatarPath())); } QString RosterModel::getStatusText(RosterItem* item) const { diff --git a/Swift/QtUI/main.cpp b/Swift/QtUI/main.cpp index 70947f5..d734713 100644 --- a/Swift/QtUI/main.cpp +++ b/Swift/QtUI/main.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include "QtSwift.h" #include "QtTranslator.h" @@ -73,14 +74,14 @@ int main(int argc, char* argv[]) { if (!someTranslationPath.empty()) { #if QT_VERSION >= 0x040800 if (vm.count("language") > 0) { - qtTranslator.load(QString(SWIFT_APPLICATION_NAME).toLower() + "_" + P2QSTRING(vm["language"].as()), someTranslationPath.parent_path().string().c_str()); + qtTranslator.load(QString(SWIFT_APPLICATION_NAME).toLower() + "_" + P2QSTRING(vm["language"].as()), P2QSTRING(Swift::pathToString(someTranslationPath.parent_path()))); } else { - qtTranslator.load(QLocale::system(), QString(SWIFT_APPLICATION_NAME).toLower(), "_", someTranslationPath.parent_path().string().c_str()); + qtTranslator.load(QLocale::system(), QString(SWIFT_APPLICATION_NAME).toLower(), "_", P2QSTRING(Swift::pathToString(someTranslationPath))); } #else //std::cout << "Loading " << std::string(QLocale::system().name().toUtf8()) << std::endl; - qtTranslator.load(QString(SWIFT_APPLICATION_NAME).toLower() + "_" + QLocale::system().name(), someTranslationPath.parent_path().string().c_str()); + qtTranslator.load(QString(SWIFT_APPLICATION_NAME).toLower() + "_" + QLocale::system().name(), P2QSTRING(Swift::pathToString(someTranslationPath))); #endif } app.installTranslator(&qtTranslator); diff --git a/Swiften/Base/ByteArray.cpp b/Swiften/Base/ByteArray.cpp index d6b5c97..466db5f 100644 --- a/Swiften/Base/ByteArray.cpp +++ b/Swiften/Base/ByteArray.cpp @@ -7,14 +7,14 @@ #include #include -#include +#include namespace Swift { static const int BUFFER_SIZE = 4096; -void readByteArrayFromFile(ByteArray& data, const std::string& file) { - std::ifstream input(file.c_str(), std::ios_base::in|std::ios_base::binary); +void readByteArrayFromFile(ByteArray& data, const boost::filesystem::path& file) { + boost::filesystem::ifstream input(file, std::ios_base::in|std::ios_base::binary); while (input.good()) { size_t oldSize = data.size(); data.resize(oldSize + BUFFER_SIZE); diff --git a/Swiften/Base/ByteArray.h b/Swiften/Base/ByteArray.h index 8688aab..133b75f 100644 --- a/Swiften/Base/ByteArray.h +++ b/Swiften/Base/ByteArray.h @@ -10,6 +10,7 @@ #include #include +#include namespace Swift { typedef std::vector ByteArray; @@ -41,6 +42,6 @@ namespace Swift { SWIFTEN_API std::string byteArrayToString(const ByteArray& b); - SWIFTEN_API void readByteArrayFromFile(ByteArray&, const std::string& file); + SWIFTEN_API void readByteArrayFromFile(ByteArray&, const boost::filesystem::path& file); } diff --git a/Swiften/Base/Path.cpp b/Swiften/Base/Path.cpp new file mode 100644 index 0000000..2a49676 --- /dev/null +++ b/Swiften/Base/Path.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include + +#include +#include + +using namespace Swift; + +boost::filesystem::path Swift::stringToPath(const std::string& path) { +#ifdef SWIFTEN_PLATFORM_WINDOWS + return boost::filesystem::path(convertStringToWString(path)); +#else + return boost::filesystem::path(path); +#endif +} + +std::string Swift::pathToString(const boost::filesystem::path& path) { +#ifdef SWIFTEN_PLATFORM_WINDOWS + return convertWStringToString(path.native()); +#else + return path.native(); +#endif +} diff --git a/Swiften/Base/Path.h b/Swiften/Base/Path.h new file mode 100644 index 0000000..ea99be9 --- /dev/null +++ b/Swiften/Base/Path.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#pragma once + +#include +#include +#include + +namespace Swift { + /** + * Creates a path for the given UTF-8 encoded string. + * This works independently of global locale settings. + */ + SWIFTEN_API boost::filesystem::path stringToPath(const std::string&); + + /** + * Returns the UTF-8 representation of the given path + * This works independently of global locale settings. + */ + SWIFTEN_API std::string pathToString(const boost::filesystem::path&); +} + + diff --git a/Swiften/Base/Paths.cpp b/Swiften/Base/Paths.cpp index d434cc1..8ad1159 100644 --- a/Swiften/Base/Paths.cpp +++ b/Swiften/Base/Paths.cpp @@ -36,10 +36,11 @@ boost::filesystem::path Paths::getExecutablePath() { return boost::filesystem::path(std::string(reinterpret_cast(vecptr(path)), path.size()).c_str()).parent_path(); } #elif defined(SWIFTEN_PLATFORM_WINDOWS) - ByteArray data; + std::vector data; data.resize(2048); - GetModuleFileName(NULL, reinterpret_cast(vecptr(data)), data.size()); - return boost::filesystem::path(std::string(reinterpret_cast(vecptr(data)), data.size()).c_str()).parent_path(); + GetModuleFileNameW(NULL, vecptr(data), data.size()); + return boost::filesystem::path( + std::wstring(vecptr(data), data.size())).parent_path(); #endif return boost::filesystem::path(); } diff --git a/Swiften/Base/SConscript b/Swiften/Base/SConscript index b56db8c..4956fba 100644 --- a/Swiften/Base/SConscript +++ b/Swiften/Base/SConscript @@ -7,6 +7,7 @@ objects = swiften_env.SwiftenObject([ "SafeAllocator.cpp", "Error.cpp", "Log.cpp", + "Path.cpp", "Paths.cpp", "String.cpp", "IDGenerator.cpp", diff --git a/Swiften/Base/String.cpp b/Swiften/Base/String.cpp index 242b8e5..40ea2e1 100644 --- a/Swiften/Base/String.cpp +++ b/Swiften/Base/String.cpp @@ -1,15 +1,21 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ +#include + #include #include #include #include +#ifdef SWIFTEN_PLATFORM_WINDOWS +#include +#endif #include +#include namespace Swift { @@ -113,4 +119,35 @@ int String::convertHexStringToInt(const std::string& s) { return h; } + +#ifdef SWIFTEN_PLATFORM_WINDOWS +std::string convertWStringToString(const std::wstring& s) { + int utf8Size = WideCharToMultiByte(CP_UTF8, 0, s.c_str(), -1, NULL, 0, NULL, NULL); + if (utf8Size < 0) { + throw std::runtime_error("Conversion error"); + } + std::vector utf8Data(utf8Size); + int result = WideCharToMultiByte( + CP_UTF8, 0, s.c_str(), -1, vecptr(utf8Data), utf8Data.size(), NULL, NULL); + if (result < 0) { + throw std::runtime_error("Conversion error"); + } + return std::string(vecptr(utf8Data), utf8Size-1 /* trailing 0 character */); +} + +std::wstring convertStringToWString(const std::string& s) { + int utf16Size = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, NULL, 0); + if (utf16Size < 0) { + throw std::runtime_error("Conversion error"); + } + std::vector utf16Data(utf16Size); + int result = MultiByteToWideChar( + CP_UTF8, 0, s.c_str(), -1, vecptr(utf16Data), utf16Data.size()); + if (result < 0) { + throw std::runtime_error("Conversion error"); + } + return std::wstring(vecptr(utf16Data), utf16Size-1 /* trailing 0 character */); +} +#endif + } diff --git a/Swiften/Base/String.h b/Swiften/Base/String.h index 5ce6c3d..5a5642e 100644 --- a/Swiften/Base/String.h +++ b/Swiften/Base/String.h @@ -11,6 +11,7 @@ #include #include +#include #define SWIFTEN_STRING_TO_CFSTRING(a) \ CFStringCreateWithBytes(NULL, reinterpret_cast(a.c_str()), a.size(), kCFStringEncodingUTF8, false) @@ -32,8 +33,14 @@ namespace Swift { std::string convertIntToHexString(int h); int convertHexStringToInt(const std::string& s); + } +#ifdef SWIFTEN_PLATFORM_WINDOWS + SWIFTEN_API std::string convertWStringToString(const std::wstring& s); + SWIFTEN_API std::wstring convertStringToWString(const std::string& s); +#endif + class SWIFTEN_API makeString { public: template makeString& operator<<(T const& v) { diff --git a/Swiften/Base/UnitTest/PathTest.cpp b/Swiften/Base/UnitTest/PathTest.cpp new file mode 100644 index 0000000..f5f99e7 --- /dev/null +++ b/Swiften/Base/UnitTest/PathTest.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include +#include + +#include +#include + +using namespace Swift; + +class PathTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(PathTest); + CPPUNIT_TEST(testStringToPath); + CPPUNIT_TEST(testPathToString); + CPPUNIT_TEST_SUITE_END(); + + public: + void testStringToPath() { +#ifdef SWIFTEN_PLATFORM_WINDOWS + CPPUNIT_ASSERT(std::wstring(L"tron\xe7on") == stringToPath("tron\xc3\xa7on").native()); +#else + CPPUNIT_ASSERT_EQUAL(std::string("tron\xc3\xa7on"), stringToPath("tron\xc3\xa7on").native()); +#endif + } + + void testPathToString() { + CPPUNIT_ASSERT_EQUAL(std::string("tron\xc3\xa7on"), pathToString(stringToPath("tron\xc3\xa7on"))); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(PathTest); + diff --git a/Swiften/Base/UnitTest/StringTest.cpp b/Swiften/Base/UnitTest/StringTest.cpp index b29f331..ffca98a 100644 --- a/Swiften/Base/UnitTest/StringTest.cpp +++ b/Swiften/Base/UnitTest/StringTest.cpp @@ -9,6 +9,7 @@ #include #include +#include using namespace Swift; @@ -24,6 +25,10 @@ class StringTest : public CppUnit::TestFixture { CPPUNIT_TEST(testReplaceAll_ConsecutiveChars); CPPUNIT_TEST(testReplaceAll_MatchingReplace); CPPUNIT_TEST(testSplit); +#ifdef SWIFTEN_PLATFORM_WINDOWS + CPPUNIT_TEST(testConvertWStringToString); + CPPUNIT_TEST(testConvertStringToWString); +#endif CPPUNIT_TEST_SUITE_END(); public: @@ -109,6 +114,16 @@ class StringTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(std::string("def"), result[1]); CPPUNIT_ASSERT_EQUAL(std::string("ghi"), result[2]); } + +#ifdef SWIFTEN_PLATFORM_WINDOWS + void testConvertWStringToString() { + CPPUNIT_ASSERT_EQUAL(std::string("tron\xc3\xa7on"), convertWStringToString(std::wstring(L"tron\xe7on"))); + } + + void testConvertStringToWString() { + CPPUNIT_ASSERT(std::wstring(L"tron\xe7on") == convertStringToWString(std::string("tron\xc3\xa7on"))); + } +#endif }; CPPUNIT_TEST_SUITE_REGISTRATION(StringTest); diff --git a/Swiften/Config/SConscript b/Swiften/Config/SConscript index 27dfc2e..837884b 100644 --- a/Swiften/Config/SConscript +++ b/Swiften/Config/SConscript @@ -37,12 +37,18 @@ config_flags += cStringVariable(swiften_env, "LIBFLAGS", libflags) config_env = env.Clone() # Create a local copy of Paths.cpp to avoid a Swiften dependency -config_env.Install(".", "#/Swiften/Base/Paths.cpp") +config_env.Install(".", [ + "#/Swiften/Base/Paths.cpp", + "#/Swiften/Base/Path.cpp", + "#/Swiften/Base/String.cpp", +]) config_env.UseFlags(config_env["BOOST_FLAGS"]) config_env.UseFlags(config_env["PLATFORM_FLAGS"]) config_env.WriteVal("swiften-config.h", config_env.Value(config_flags)) swiften_config = config_env.Program("swiften-config", [ "Paths.cpp", + "Path.cpp", + "String.cpp", "swiften-config.cpp" ]) diff --git a/Swiften/Config/swiften-config.cpp b/Swiften/Config/swiften-config.cpp index 89df9cd..778134d 100644 --- a/Swiften/Config/swiften-config.cpp +++ b/Swiften/Config/swiften-config.cpp @@ -16,6 +16,7 @@ #include #include +#include #include #include "swiften-config.h" @@ -90,12 +91,12 @@ int main(int argc, char* argv[]) { for(size_t i = 0; i < libs.size(); ++i) { if (inPlace) { std::string lib = libs[i]; - boost::replace_all(lib, "#", topSourcePath.string()); + boost::replace_all(lib, "#", pathToString(topSourcePath)); libs[i] = lib; } else { std::string lib = libs[i]; - boost::replace_all(lib, "#", (topInstallPath / "lib").string()); + boost::replace_all(lib, "#", pathToString(topInstallPath / "lib")); boost::erase_all(lib, "/Swiften"); libs[i] = lib; } @@ -103,12 +104,12 @@ int main(int argc, char* argv[]) { for(size_t i = 0; i < cflags.size(); ++i) { if (inPlace) { std::string cflag = cflags[i]; - boost::replace_all(cflag, "#", topSourcePath.string()); + boost::replace_all(cflag, "#", pathToString(topSourcePath)); cflags[i] = cflag; } else { std::string cflag = cflags[i]; - boost::replace_all(cflag, "#", (topInstallPath / "include").string()); + boost::replace_all(cflag, "#", pathToString(topInstallPath / "include")); cflags[i] = cflag; } } diff --git a/Swiften/Entity/PayloadPersister.cpp b/Swiften/Entity/PayloadPersister.cpp index 729d36a..ace7b4a 100644 --- a/Swiften/Entity/PayloadPersister.cpp +++ b/Swiften/Entity/PayloadPersister.cpp @@ -42,7 +42,7 @@ boost::shared_ptr PayloadPersister::loadPayload(const boost::filesystem try { if (boost::filesystem::exists(path)) { ByteArray data; - readByteArrayFromFile(data, path.string()); + readByteArrayFromFile(data, path); boost::shared_ptr parser(createParser()); PayloadParserTester tester(parser.get()); tester.parse(byteArrayToString(data)); diff --git a/Swiften/Examples/SendFile/SendFile.cpp b/Swiften/Examples/SendFile/SendFile.cpp index ff49149..b056842 100644 --- a/Swiften/Examples/SendFile/SendFile.cpp +++ b/Swiften/Examples/SendFile/SendFile.cpp @@ -64,7 +64,7 @@ class FileSender { client->sendPresence(Presence::create()); //ByteArray fileData; - //readByteArrayFromFile(fileData, file.string()); + //readByteArrayFromFile(fileData, file); // gather file information /*StreamInitiationFileInfo fileInfo; diff --git a/Swiften/FileTransfer/FileTransferManagerImpl.cpp b/Swiften/FileTransfer/FileTransferManagerImpl.cpp index e6c4796..b832d7e 100644 --- a/Swiften/FileTransfer/FileTransferManagerImpl.cpp +++ b/Swiften/FileTransfer/FileTransferManagerImpl.cpp @@ -18,6 +18,7 @@ #include #include +#include #include "Swiften/Disco/EntityCapsProvider.h" #include #include @@ -130,7 +131,7 @@ OutgoingFileTransfer::ref FileTransferManagerImpl::createOutgoingFileTransfer( #if BOOST_FILESYSTEM_VERSION == 2 // TODO: Delete this when boost 1.44 becomes a minimum requirement, and we no longer need v2 std::string filename = filepath.filename(); #else - std::string filename = filepath.filename().string(); + std::string filename = pathToString(filepath.filename()); #endif boost::uintmax_t sizeInBytes = boost::filesystem::file_size(filepath); diff --git a/Swiften/History/SQLiteHistoryStorage.cpp b/Swiften/History/SQLiteHistoryStorage.cpp index 2da389a..dda8766 100644 --- a/Swiften/History/SQLiteHistoryStorage.cpp +++ b/Swiften/History/SQLiteHistoryStorage.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -11,6 +11,7 @@ #include #include #include +#include inline std::string getEscapedString(const std::string& s) { std::string result(s); @@ -25,12 +26,12 @@ inline std::string getEscapedString(const std::string& s) { namespace Swift { -SQLiteHistoryStorage::SQLiteHistoryStorage(const std::string& file) : db_(0) { +SQLiteHistoryStorage::SQLiteHistoryStorage(const boost::filesystem::path& file) : db_(0) { thread_ = new boost::thread(boost::bind(&SQLiteHistoryStorage::run, this)); - sqlite3_open(file.c_str(), &db_); + sqlite3_open(pathToString(file).c_str(), &db_); if (!db_) { - std::cerr << "Error opening database " << file << std::endl; + std::cerr << "Error opening database " << pathToString(file) << std::endl; } char* errorMessage; diff --git a/Swiften/History/SQLiteHistoryStorage.h b/Swiften/History/SQLiteHistoryStorage.h index 524247d..2c1ba7a 100644 --- a/Swiften/History/SQLiteHistoryStorage.h +++ b/Swiften/History/SQLiteHistoryStorage.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2013 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -11,13 +11,14 @@ #include #include #include +#include struct sqlite3; namespace Swift { class SWIFTEN_API SQLiteHistoryStorage : public HistoryStorage { public: - SQLiteHistoryStorage(const std::string& file); + SQLiteHistoryStorage(const boost::filesystem::path& file); ~SQLiteHistoryStorage(); void addMessage(const HistoryMessage& message); diff --git a/Swiften/QA/StorageTest/VCardFileStorageTest.cpp b/Swiften/QA/StorageTest/VCardFileStorageTest.cpp index 7667176..4145696 100644 --- a/Swiften/QA/StorageTest/VCardFileStorageTest.cpp +++ b/Swiften/QA/StorageTest/VCardFileStorageTest.cpp @@ -49,7 +49,7 @@ class VCardFileStorageTest : public CppUnit::TestFixture { boost::filesystem::path vcardFile(vcardsPath / "alice@wonderland.lit%2fTeaRoom.xml"); CPPUNIT_ASSERT(boost::filesystem::exists(vcardFile)); ByteArray data; - data.readFromFile(vcardFile.string()); + data.readFromFile(vcardFile); CPPUNIT_ASSERT(boost::starts_with(data.toString(), "")); } diff --git a/Swiften/QA/TLSTest/CertificateTest.cpp b/Swiften/QA/TLSTest/CertificateTest.cpp index 6932881..2fa4c04 100644 --- a/Swiften/QA/TLSTest/CertificateTest.cpp +++ b/Swiften/QA/TLSTest/CertificateTest.cpp @@ -32,7 +32,7 @@ class CertificateTest : public CppUnit::TestFixture { public: void setUp() { pathProvider = new PlatformApplicationPathProvider("FileReadBytestreamTest"); - readByteArrayFromFile(certificateData, (pathProvider->getExecutableDir() / "jabber_org.crt").string()); + readByteArrayFromFile(certificateData, (pathProvider->getExecutableDir() / "jabber_org.crt")); certificateFactory = new CERTIFICATE_FACTORY(); } diff --git a/Swiften/SConscript b/Swiften/SConscript index 1cb3543..aab9984 100644 --- a/Swiften/SConscript +++ b/Swiften/SConscript @@ -308,6 +308,7 @@ if env["SCONS_STAGE"] == "build" : File("Base/UnitTest/DateTimeTest.cpp"), File("Base/UnitTest/ByteArrayTest.cpp"), File("Base/UnitTest/URLTest.cpp"), + File("Base/UnitTest/PathTest.cpp"), File("Chat/UnitTest/ChatStateNotifierTest.cpp"), # File("Chat/UnitTest/ChatStateTrackerTest.cpp"), File("Client/UnitTest/ClientSessionTest.cpp"), diff --git a/Swiften/TLS/PKCS12Certificate.h b/Swiften/TLS/PKCS12Certificate.h index 2f70456..2d4c2e5 100644 --- a/Swiften/TLS/PKCS12Certificate.h +++ b/Swiften/TLS/PKCS12Certificate.h @@ -8,13 +8,14 @@ #include #include +#include namespace Swift { class PKCS12Certificate : public Swift::CertificateWithKey { public: PKCS12Certificate() {} - PKCS12Certificate(const std::string& filename, const SafeByteArray& password) : password_(password) { + PKCS12Certificate(const boost::filesystem::path& filename, const SafeByteArray& password) : password_(password) { readByteArrayFromFile(data_, filename); } diff --git a/Swiftob/LuaCommands.cpp b/Swiftob/LuaCommands.cpp index d27c131..c2478cd 100644 --- a/Swiftob/LuaCommands.cpp +++ b/Swiftob/LuaCommands.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include @@ -414,7 +415,7 @@ void LuaCommands::loadScript(boost::filesystem::path filePath) { std::string filename = filePath.filename().string(); #endif filename += ".storage"; - boost::filesystem::path storagePath(boost::filesystem::path(path_) / filename); + boost::filesystem::path storagePath(boost::filesystem::path(path_) / stringToPath(filename)); Storage* storage = new Storage(storagePath); lua_pushlightuserdata(lua, storage); lua_setfield(lua, LUA_REGISTRYINDEX, STORAGE); diff --git a/Swiftob/Storage.cpp b/Swiftob/Storage.cpp index 141be9f..5311d82 100644 --- a/Swiftob/Storage.cpp +++ b/Swiftob/Storage.cpp @@ -25,7 +25,7 @@ Storage::Storage(const boost::filesystem::path& path) : settingsPath_(path) { void Storage::load() { if (boost::filesystem::exists(settingsPath_)) { Swift::ByteArray data; - Swift::readByteArrayFromFile(data, settingsPath_.string()); + Swift::readByteArrayFromFile(data, settingsPath_); foreach (std::string line, Swift::String::split(Swift::byteArrayToString(data), '\n')) { std::pair pair = Swift::String::getSplittedAtFirst(line, '\t'); settings_[pair.first] = pair.second; -- cgit v0.10.2-6-g49f6