/* * Copyright (c) 2010-2012 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #include #if defined(HAVE_ICU) #pragma GCC diagnostic ignored "-Wold-style-cast" #include #include #include #elif defined(HAVE_LIBIDN) extern "C" { #include } #endif #include #include #include #include using namespace Swift; #if defined(HAVE_ICU) namespace { static UStringPrepProfileType getICUProfileType(StringPrep::Profile profile) { switch(profile) { case StringPrep::NamePrep: return USPREP_RFC3491_NAMEPREP; case StringPrep::XMPPNodePrep: return USPREP_RFC3920_NODEPREP; case StringPrep::XMPPResourcePrep: return USPREP_RFC3920_RESOURCEPREP; case StringPrep::SASLPrep: return USPREP_RFC4013_SASLPREP; } assert(false); return USPREP_RFC3491_NAMEPREP; } template std::vector > getStringPrepared(const StringType& s, StringPrep::Profile profile) { UErrorCode status = U_ZERO_ERROR; ICUConverter converter; boost::shared_ptr icuProfile(usprep_openByType(getICUProfileType(profile), &status), usprep_close); assert(U_SUCCESS(status)); ICUConverter::ICUString icuInput = converter.convertToICUString(s); ICUConverter::ICUString icuResult; UParseError parseError; icuResult.resize(icuInput.size()); int icuResultLength = usprep_prepare(icuProfile.get(), vecptr(icuInput), icuInput.size(), vecptr(icuResult), icuResult.size(), USPREP_ALLOW_UNASSIGNED, &parseError, &status); icuResult.resize(icuResultLength); if (status == U_BUFFER_OVERFLOW_ERROR) { status = U_ZERO_ERROR; icuResult.resize(icuResultLength); icuResultLength = usprep_prepare(icuProfile.get(), vecptr(icuInput), icuInput.size(), vecptr(icuResult), icuResult.size(), USPREP_ALLOW_UNASSIGNED, &parseError, &status); icuResult.resize(icuResultLength); } if (U_FAILURE(status)) { return std::vector >(); } icuResult.resize(icuResultLength); return converter.convertToArray(icuResult); } } namespace Swift { std::string StringPrep::getPrepared(const std::string& s, Profile profile) { if (s.empty()) { return ""; } std::vector > preparedData = getStringPrepared(s, profile); if (preparedData.empty()) { throw std::exception(); } return std::string(vecptr(preparedData)); } SafeByteArray StringPrep::getPrepared(const SafeByteArray& s, Profile profile) { if (s.empty()) { return SafeByteArray(); } std::vector > preparedData = getStringPrepared(s, profile); if (preparedData.empty()) { throw std::exception(); } return createSafeByteArray(reinterpret_cast(vecptr(preparedData))); } } //////////////////////////////////////////////////////////////////////////////// #elif defined(HAVE_LIBIDN) namespace { static const int MAX_STRINGPREP_SIZE = 1024; const Stringprep_profile* getLibIDNProfile(StringPrep::Profile profile) { switch(profile) { case StringPrep::NamePrep: return stringprep_nameprep; case StringPrep::XMPPNodePrep: return stringprep_xmpp_nodeprep; case StringPrep::XMPPResourcePrep: return stringprep_xmpp_resourceprep; case StringPrep::SASLPrep: return stringprep_saslprep; } assert(false); return 0; } template ContainerType getStringPrepared(const StringType& s, StringPrep::Profile profile) { ContainerType input(s.begin(), s.end()); input.resize(MAX_STRINGPREP_SIZE); if (stringprep(&input[0], MAX_STRINGPREP_SIZE, static_cast(0), getLibIDNProfile(profile)) == 0) { return input; } else { return ContainerType(); } } } namespace Swift { std::string StringPrep::getPrepared(const std::string& s, Profile profile) { std::vector preparedData = getStringPrepared< std::string, std::vector >(s, profile); if (preparedData.empty()) { throw std::exception(); } return std::string(vecptr(preparedData)); } SafeByteArray StringPrep::getPrepared(const SafeByteArray& s, Profile profile) { std::vector > preparedData = getStringPrepared > >(s, profile); if (preparedData.empty()) { throw std::exception(); } return createSafeByteArray(reinterpret_cast(vecptr(preparedData))); } } #endif