upgrade to JUCE 5.4.3. Remove (probably) unused JUCE modules. Remove VST2 target (it's been end-of-life'd by Steinberg and by JUCE)
This commit is contained in:
		@ -23,7 +23,20 @@
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
IPAddress::IPAddress (bool IPv6) noexcept : isIPv6 (IPv6)
 | 
			
		||||
/** Union used to split a 16-bit unsigned integer into 2 8-bit unsigned integers or vice-versa */
 | 
			
		||||
union IPAddressByteUnion
 | 
			
		||||
{
 | 
			
		||||
    uint16 combined;
 | 
			
		||||
    uint8 split[2];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void zeroUnusedBytes (uint8* address) noexcept
 | 
			
		||||
{
 | 
			
		||||
    for (int i = 4; i < 16; ++i)
 | 
			
		||||
        address[i] = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
IPAddress::IPAddress() noexcept
 | 
			
		||||
{
 | 
			
		||||
    for (int i = 0; i < 16; ++i)
 | 
			
		||||
        address[i] = 0;
 | 
			
		||||
@ -35,12 +48,12 @@ IPAddress::IPAddress (const uint8 bytes[], bool IPv6) noexcept : isIPv6 (IPv6)
 | 
			
		||||
        address[i] = bytes[i];
 | 
			
		||||
 | 
			
		||||
    if (! isIPv6)
 | 
			
		||||
        zeroUnusedBytes();
 | 
			
		||||
        zeroUnusedBytes (address);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
IPAddress::IPAddress (const uint16 bytes[8]) noexcept : isIPv6 (true)
 | 
			
		||||
{
 | 
			
		||||
    ByteUnion temp;
 | 
			
		||||
    IPAddressByteUnion temp;
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < 8; ++i)
 | 
			
		||||
    {
 | 
			
		||||
@ -56,7 +69,7 @@ IPAddress::IPAddress (uint8 a0, uint8 a1, uint8 a2, uint8 a3) noexcept : isIPv6
 | 
			
		||||
    address[0] = a0;  address[1] = a1;
 | 
			
		||||
    address[2] = a2;  address[3] = a3;
 | 
			
		||||
 | 
			
		||||
    zeroUnusedBytes();
 | 
			
		||||
    zeroUnusedBytes (address);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
IPAddress::IPAddress (uint16 a1, uint16 a2, uint16 a3, uint16 a4,
 | 
			
		||||
@ -65,7 +78,7 @@ IPAddress::IPAddress (uint16 a1, uint16 a2, uint16 a3, uint16 a4,
 | 
			
		||||
{
 | 
			
		||||
    uint16 array[8] = { a1, a2, a3, a4, a5, a6, a7, a8 };
 | 
			
		||||
 | 
			
		||||
    ByteUnion temp;
 | 
			
		||||
    IPAddressByteUnion temp;
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < 8; ++i)
 | 
			
		||||
    {
 | 
			
		||||
@ -82,30 +95,57 @@ IPAddress::IPAddress (uint32 n) noexcept : isIPv6 (false)
 | 
			
		||||
    address[2] = (n >> 8) & 255;
 | 
			
		||||
    address[3] = (n & 255);
 | 
			
		||||
 | 
			
		||||
    zeroUnusedBytes();
 | 
			
		||||
    zeroUnusedBytes (address);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool IPAddress::isNull() const
 | 
			
		||||
{
 | 
			
		||||
    for (int i = 0; i < 16; ++i)
 | 
			
		||||
        if (address[i] != 0)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static String removePort (const String& adr)
 | 
			
		||||
{
 | 
			
		||||
    if (adr.containsAnyOf ("[]"))
 | 
			
		||||
        return adr.fromFirstOccurrenceOf ("[", false, true).upToLastOccurrenceOf ("]", false, true);
 | 
			
		||||
 | 
			
		||||
    if (adr.indexOf (":") == adr.lastIndexOf (":"))
 | 
			
		||||
        return adr.upToLastOccurrenceOf (":", false, true);
 | 
			
		||||
 | 
			
		||||
    return adr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
IPAddress::IPAddress (const String& adr)
 | 
			
		||||
{
 | 
			
		||||
    isIPv6 = adr.contains (":");
 | 
			
		||||
    auto ipAddress = removePort (adr);
 | 
			
		||||
 | 
			
		||||
    isIPv6 = ipAddress.contains (":");
 | 
			
		||||
 | 
			
		||||
    if (! isIPv6)
 | 
			
		||||
    {
 | 
			
		||||
        StringArray tokens;
 | 
			
		||||
        tokens.addTokens (adr, ".", String());
 | 
			
		||||
        auto tokens = StringArray::fromTokens (ipAddress, ".", {});
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < 4; ++i)
 | 
			
		||||
            address[i] = (uint8) tokens[i].getIntValue();
 | 
			
		||||
 | 
			
		||||
        zeroUnusedBytes (address);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        StringArray tokens;
 | 
			
		||||
        tokens.addTokens (adr.removeCharacters ("[]"), ":", String());
 | 
			
		||||
        auto tokens = StringArray::fromTokens (ipAddress, ":", {});
 | 
			
		||||
 | 
			
		||||
        if (tokens.contains (StringRef())) // if :: shorthand has been used
 | 
			
		||||
        if (tokens.contains ({})) // if :: shorthand has been used
 | 
			
		||||
        {
 | 
			
		||||
            int idx = tokens.indexOf (StringRef());
 | 
			
		||||
            auto idx = tokens.indexOf ({});
 | 
			
		||||
            tokens.set (idx, "0");
 | 
			
		||||
            tokens.removeEmptyStrings();
 | 
			
		||||
 | 
			
		||||
            // mapped IPv4 address will be treated as a single token, so pad the end of the StringArray
 | 
			
		||||
            if (tokens[tokens.size() - 1].containsChar ('.'))
 | 
			
		||||
                tokens.add ({});
 | 
			
		||||
 | 
			
		||||
            while (tokens.size() < 8)
 | 
			
		||||
                tokens.insert (idx, "0");
 | 
			
		||||
@ -113,7 +153,19 @@ IPAddress::IPAddress (const String& adr)
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < 8; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            ByteUnion temp;
 | 
			
		||||
            if (i == 6 && isIPv4MappedAddress (IPAddress (address, true)))
 | 
			
		||||
            {
 | 
			
		||||
                IPAddress v4Address (tokens[i]);
 | 
			
		||||
 | 
			
		||||
                address[12] = v4Address.address[0];
 | 
			
		||||
                address[13] = v4Address.address[1];
 | 
			
		||||
                address[14] = v4Address.address[2];
 | 
			
		||||
                address[15] = v4Address.address[3];
 | 
			
		||||
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            IPAddressByteUnion temp;
 | 
			
		||||
            temp.combined = (uint16) CharacterFunctions::HexParser<int>::parse (tokens[i].getCharPointer());
 | 
			
		||||
 | 
			
		||||
            address[i * 2]     = temp.split[0];
 | 
			
		||||
@ -134,29 +186,62 @@ String IPAddress::toString() const
 | 
			
		||||
        return s;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    String addressString;
 | 
			
		||||
    ByteUnion temp;
 | 
			
		||||
    IPAddressByteUnion temp;
 | 
			
		||||
 | 
			
		||||
    temp.split[0] = address[0];
 | 
			
		||||
    temp.split[1] = address[1];
 | 
			
		||||
 | 
			
		||||
    addressString = String (String::toHexString (temp.combined));
 | 
			
		||||
    auto addressString = String::toHexString (temp.combined);
 | 
			
		||||
 | 
			
		||||
    for (int i = 1; i < 8; ++i)
 | 
			
		||||
    {
 | 
			
		||||
        temp.split[0] = address[i * 2];
 | 
			
		||||
        temp.split[1] = address[i * 2 + 1];
 | 
			
		||||
 | 
			
		||||
        addressString << ':' << String (String::toHexString (temp.combined));
 | 
			
		||||
        addressString << ':' << String::toHexString (temp.combined);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return getFormattedAddress (addressString);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
IPAddress IPAddress::any (bool IPv6) noexcept           { return IPAddress (IPv6); }
 | 
			
		||||
IPAddress IPAddress::broadcast() noexcept               { return IPAddress (255, 255, 255, 255); }
 | 
			
		||||
IPAddress IPAddress::local (bool IPv6) noexcept         { return IPv6 ? IPAddress (0, 0, 0, 0, 0, 0, 0, 1)
 | 
			
		||||
                                                                      : IPAddress (127, 0, 0, 1); }
 | 
			
		||||
bool IPAddress::operator== (const IPAddress& other) const noexcept    { return compare (other) == 0; }
 | 
			
		||||
bool IPAddress::operator!= (const IPAddress& other) const noexcept    { return compare (other) != 0; }
 | 
			
		||||
bool IPAddress::operator<  (const IPAddress& other) const noexcept    { return compare (other) <  0; }
 | 
			
		||||
bool IPAddress::operator<= (const IPAddress& other) const noexcept    { return compare (other) <= 0; }
 | 
			
		||||
bool IPAddress::operator>  (const IPAddress& other) const noexcept    { return compare (other) >  0; }
 | 
			
		||||
bool IPAddress::operator>= (const IPAddress& other) const noexcept    { return compare (other) >= 0; }
 | 
			
		||||
 | 
			
		||||
int IPAddress::compare (const IPAddress& other) const noexcept
 | 
			
		||||
{
 | 
			
		||||
    if (isIPv6 != other.isIPv6)
 | 
			
		||||
    {
 | 
			
		||||
        if (isIPv6)
 | 
			
		||||
        {
 | 
			
		||||
            if (isIPv4MappedAddress (*this))
 | 
			
		||||
                return convertIPv4MappedAddressToIPv4 (*this).compare (other);
 | 
			
		||||
 | 
			
		||||
            return 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (isIPv4MappedAddress (other))
 | 
			
		||||
            return compare (convertIPv4MappedAddressToIPv4 (other));
 | 
			
		||||
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < (isIPv6 ? 16 : 4); ++i)
 | 
			
		||||
    {
 | 
			
		||||
        if (address[i] > other.address[i])  return 1;
 | 
			
		||||
        if (address[i] < other.address[i])  return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
IPAddress IPAddress::any() noexcept               { return IPAddress(); }
 | 
			
		||||
IPAddress IPAddress::broadcast() noexcept         { return IPAddress (255, 255, 255, 255); }
 | 
			
		||||
IPAddress IPAddress::local (bool IPv6) noexcept   { return IPv6 ? IPAddress (0, 0, 0, 0, 0, 0, 0, 1)
 | 
			
		||||
                                                                : IPAddress (127, 0, 0, 1); }
 | 
			
		||||
 | 
			
		||||
String IPAddress::getFormattedAddress (const String& unformattedAddress)
 | 
			
		||||
{
 | 
			
		||||
@ -174,7 +259,7 @@ String IPAddress::getFormattedAddress (const String& unformattedAddress)
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < tokens.size(); ++i)
 | 
			
		||||
    {
 | 
			
		||||
        const auto& t = tokens.getReference (i);
 | 
			
		||||
        auto& t = tokens.getReference (i);
 | 
			
		||||
 | 
			
		||||
        if (t.getHexValue32() == 0x0000)
 | 
			
		||||
        {
 | 
			
		||||
@ -232,73 +317,149 @@ String IPAddress::getFormattedAddress (const String& unformattedAddress)
 | 
			
		||||
    return addressString;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool IPAddress::operator== (const IPAddress& other) const noexcept
 | 
			
		||||
bool IPAddress::isIPv4MappedAddress (const IPAddress& mappedAddress)
 | 
			
		||||
{
 | 
			
		||||
    for (int i = 0; i < (isIPv6 ? 16 : 4); ++i)
 | 
			
		||||
        if (address[i] != other.address[i])
 | 
			
		||||
    if (! mappedAddress.isIPv6)
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < 10; ++i)
 | 
			
		||||
        if (mappedAddress.address[i] != 0)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
    if (mappedAddress.address[10] != 255 || mappedAddress.address[11] != 255)
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool IPAddress::operator!= (const IPAddress& other) const noexcept
 | 
			
		||||
IPAddress IPAddress::convertIPv4MappedAddressToIPv4 (const IPAddress& mappedAddress)
 | 
			
		||||
{
 | 
			
		||||
    return ! operator== (other);
 | 
			
		||||
    // The address that you're converting needs to be IPv6!
 | 
			
		||||
    jassert (mappedAddress.isIPv6);
 | 
			
		||||
 | 
			
		||||
    if (isIPv4MappedAddress (mappedAddress))
 | 
			
		||||
        return { mappedAddress.address[12], mappedAddress.address[13],
 | 
			
		||||
                 mappedAddress.address[14], mappedAddress.address[15] };
 | 
			
		||||
 | 
			
		||||
    return {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if (! JUCE_WINDOWS) && (! JUCE_ANDROID)
 | 
			
		||||
static void addAddress (const sockaddr_in* addr_in, Array<IPAddress>& result)
 | 
			
		||||
IPAddress IPAddress::convertIPv4AddressToIPv4Mapped (const IPAddress& addressToMap)
 | 
			
		||||
{
 | 
			
		||||
    auto addr = addr_in->sin_addr.s_addr;
 | 
			
		||||
    // The address that you're converting needs to be IPv4!
 | 
			
		||||
    jassert (! addressToMap.isIPv6);
 | 
			
		||||
 | 
			
		||||
    if (addr != INADDR_NONE)
 | 
			
		||||
        result.addIfNotAlreadyThere (IPAddress (ntohl (addr)));
 | 
			
		||||
    return { 0x0, 0x0, 0x0, 0x0, 0x0, 0xffff,
 | 
			
		||||
            static_cast<uint16> ((addressToMap.address[0] << 8) | addressToMap.address[1]),
 | 
			
		||||
            static_cast<uint16> ((addressToMap.address[2] << 8) | addressToMap.address[3]) };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void addAddress (const sockaddr_in6* addr_in, Array<IPAddress>& result)
 | 
			
		||||
IPAddress IPAddress::getLocalAddress (bool includeIPv6)
 | 
			
		||||
{
 | 
			
		||||
    in6_addr addr = addr_in->sin6_addr;
 | 
			
		||||
    auto addresses = getAllAddresses (includeIPv6);
 | 
			
		||||
 | 
			
		||||
    typedef union
 | 
			
		||||
    for (auto& a : addresses)
 | 
			
		||||
        if (a != local())
 | 
			
		||||
            return a;
 | 
			
		||||
 | 
			
		||||
    return local();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Array<IPAddress> IPAddress::getAllAddresses (bool includeIPv6)
 | 
			
		||||
{
 | 
			
		||||
    Array<IPAddress> addresses;
 | 
			
		||||
    findAllAddresses (addresses, includeIPv6);
 | 
			
		||||
    return addresses;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
#if JUCE_UNIT_TESTS
 | 
			
		||||
 | 
			
		||||
struct IPAddressTests : public UnitTest
 | 
			
		||||
{
 | 
			
		||||
    IPAddressTests()
 | 
			
		||||
        : UnitTest ("IPAddress", "Networking")
 | 
			
		||||
    {
 | 
			
		||||
        uint16 combined;
 | 
			
		||||
        uint8 split[2];
 | 
			
		||||
    } ByteUnion;
 | 
			
		||||
 | 
			
		||||
    ByteUnion temp;
 | 
			
		||||
    uint16 arr[8];
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < 8; ++i) // Swap bytes from network to host order
 | 
			
		||||
    {
 | 
			
		||||
        temp.split[0] = addr.s6_addr[i * 2 + 1];
 | 
			
		||||
        temp.split[1] = addr.s6_addr[i * 2];
 | 
			
		||||
 | 
			
		||||
        arr[i] = temp.combined;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    IPAddress ip (arr);
 | 
			
		||||
    result.addIfNotAlreadyThere (ip);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void IPAddress::findAllAddresses (Array<IPAddress>& result, bool includeIPv6)
 | 
			
		||||
{
 | 
			
		||||
    struct ifaddrs *ifaddr, *ifa;
 | 
			
		||||
 | 
			
		||||
    if (getifaddrs (&ifaddr) == -1)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next)
 | 
			
		||||
    void runTest() override
 | 
			
		||||
    {
 | 
			
		||||
        if (ifa->ifa_addr == nullptr)
 | 
			
		||||
            continue;
 | 
			
		||||
 | 
			
		||||
        if      (ifa->ifa_addr->sa_family == AF_INET)                 addAddress ((const sockaddr_in*)  ifa->ifa_addr, result);
 | 
			
		||||
        else if (ifa->ifa_addr->sa_family == AF_INET6 && includeIPv6) addAddress ((const sockaddr_in6*) ifa->ifa_addr, result);
 | 
			
		||||
        testConstructors();
 | 
			
		||||
        testFindAllAddresses();
 | 
			
		||||
        testFindBroadcastAddress();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    freeifaddrs (ifaddr);
 | 
			
		||||
}
 | 
			
		||||
    void testConstructors()
 | 
			
		||||
    {
 | 
			
		||||
        beginTest ("constructors");
 | 
			
		||||
 | 
			
		||||
        // Default IPAdress should be null
 | 
			
		||||
        IPAddress defaultConstructed;
 | 
			
		||||
        expect (defaultConstructed.isNull());
 | 
			
		||||
 | 
			
		||||
        auto local = IPAddress::local();
 | 
			
		||||
        expect (! local.isNull());
 | 
			
		||||
 | 
			
		||||
        IPAddress ipv4{1, 2, 3, 4};
 | 
			
		||||
        expect (! ipv4.isNull());
 | 
			
		||||
        expect (! ipv4.isIPv6);
 | 
			
		||||
        expect (ipv4.toString() == "1.2.3.4");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void testFindAllAddresses()
 | 
			
		||||
    {
 | 
			
		||||
        beginTest ("find all addresses");
 | 
			
		||||
 | 
			
		||||
        Array<IPAddress> ipv4Addresses;
 | 
			
		||||
        Array<IPAddress> allAddresses;
 | 
			
		||||
 | 
			
		||||
        IPAddress::findAllAddresses (ipv4Addresses, false);
 | 
			
		||||
        IPAddress::findAllAddresses (allAddresses, true);
 | 
			
		||||
 | 
			
		||||
        expect (allAddresses.size() >= ipv4Addresses.size());
 | 
			
		||||
 | 
			
		||||
        for (auto& a : ipv4Addresses)
 | 
			
		||||
        {
 | 
			
		||||
            expect (! a.isNull());
 | 
			
		||||
            expect (! a.isIPv6);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (auto& a : allAddresses)
 | 
			
		||||
        {
 | 
			
		||||
            expect (! a.isNull());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void testFindBroadcastAddress()
 | 
			
		||||
    {
 | 
			
		||||
        beginTest ("broadcast addresses");
 | 
			
		||||
 | 
			
		||||
        Array<IPAddress> addresses;
 | 
			
		||||
 | 
			
		||||
        // Only IPv4 interfaces have broadcast
 | 
			
		||||
        IPAddress::findAllAddresses (addresses, false);
 | 
			
		||||
 | 
			
		||||
        for (auto& a : addresses)
 | 
			
		||||
        {
 | 
			
		||||
            expect (! a.isNull());
 | 
			
		||||
 | 
			
		||||
            auto broadcastAddress = IPAddress::getInterfaceBroadcastAddress (a);
 | 
			
		||||
 | 
			
		||||
            // If we retrieve an address, it should be an IPv4 address
 | 
			
		||||
            if (! broadcastAddress.isNull())
 | 
			
		||||
            {
 | 
			
		||||
                expect (! a.isIPv6);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Expect to fail to find a broadcast for this address
 | 
			
		||||
        IPAddress address{1, 2, 3, 4};
 | 
			
		||||
        expect (IPAddress::getInterfaceBroadcastAddress (address).isNull());
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static IPAddressTests iPAddressTests;
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 | 
			
		||||
@ -32,26 +32,45 @@ namespace juce
 | 
			
		||||
class JUCE_API  IPAddress  final
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns an IP address meaning "any", equivalent to 0.0.0.0 (IPv4) or ::, (IPv6)  */
 | 
			
		||||
    static IPAddress any() noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns an IPv4 address meaning "broadcast" (255.255.255.255) */
 | 
			
		||||
    static IPAddress broadcast() noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns an IPv4 or IPv6 address meaning "localhost", equivalent to 127.0.0.1 (IPv4) or ::1 (IPv6) */
 | 
			
		||||
    static IPAddress local (bool IPv6 = false) noexcept;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Populates a list of all the IP addresses that this machine is using. */
 | 
			
		||||
    static void findAllAddresses (Array<IPAddress>& results, bool includeIPv6 = false);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates a null address - 0.0.0.0 (IPv4) or ::, (IPv6)
 | 
			
		||||
        @param IPv6 if true indicates that this is an IPv6 address
 | 
			
		||||
    /** Populates a list of all the IP addresses that this machine is using. */
 | 
			
		||||
    static Array<IPAddress> getAllAddresses (bool includeIPv6 = false);
 | 
			
		||||
 | 
			
		||||
    /** Returns the first 'real' address for the local machine.
 | 
			
		||||
        Unlike local(), this will attempt to find the machine's actual assigned
 | 
			
		||||
        address rather than "127.0.0.1". If there are multiple network cards, this
 | 
			
		||||
        may return any of their addresses. If it doesn't find any, then it'll return
 | 
			
		||||
        local() as a fallback.
 | 
			
		||||
    */
 | 
			
		||||
    IPAddress (bool IPv6 = false) noexcept;
 | 
			
		||||
    static IPAddress getLocalAddress (bool includeIPv6 = false);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates a null address - 0.0.0.0 (IPv4) or ::, (IPv6) */
 | 
			
		||||
    IPAddress() noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Creates an IPv4 or IPv6 address by reading 4 or 16 bytes from an array.
 | 
			
		||||
        @param bytes The array containing the bytes to read.
 | 
			
		||||
        @param IPv6 if true indicates that 16 bytes should be read instead of 4.
 | 
			
		||||
    */
 | 
			
		||||
    explicit IPAddress (const uint8 bytes[], bool IPv6 = false) noexcept;
 | 
			
		||||
    explicit IPAddress (const uint8* bytes, bool IPv6 = false) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Creates an IPv6 address from an array of 8 16-bit integers
 | 
			
		||||
        @param bytes The array containing the bytes to read.
 | 
			
		||||
    */
 | 
			
		||||
    explicit IPAddress (const uint16 bytes[8]) noexcept;
 | 
			
		||||
    explicit IPAddress (const uint16* bytes) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Creates an IPv4 address from 4 bytes. */
 | 
			
		||||
    IPAddress (uint8 address1, uint8 address2, uint8 address3, uint8 address4) noexcept;
 | 
			
		||||
@ -68,47 +87,56 @@ public:
 | 
			
		||||
    /** Parses a string IP address of the form "1.2.3.4" (IPv4) or "1:2:3:4:5:6:7:8" (IPv6). */
 | 
			
		||||
    explicit IPAddress (const String& address);
 | 
			
		||||
 | 
			
		||||
    /** Returns whether the address contains the null address (e.g. 0.0.0.0). */
 | 
			
		||||
    bool isNull() const;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns a dot- or colon-separated string in the form "1.2.3.4" (IPv4) or "1:2:3:4:5:6:7:8" (IPv6). */
 | 
			
		||||
    String toString() const;
 | 
			
		||||
 | 
			
		||||
    /** Returns an IPv4 or IPv6 address meaning "any", equivalent to 0.0.0.0 (IPv4) or ::, (IPv6)  */
 | 
			
		||||
    static IPAddress any (bool IPv6 = false) noexcept;
 | 
			
		||||
    /** Compares this IPAddress with another.
 | 
			
		||||
 | 
			
		||||
    /** Returns an IPv4 address meaning "broadcast" (255.255.255.255) */
 | 
			
		||||
    static IPAddress broadcast() noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns an IPv4 or IPv6 address meaning "localhost", equivalent to 127.0.0.1 (IPv4) or ::1 (IPv6) */
 | 
			
		||||
    static IPAddress local (bool IPv6 = false) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns a formatted version of the provided IPv6 address conforming to RFC 5952 with leading zeros suppressed,
 | 
			
		||||
        lower case characters, and double-colon notation used to represent contiguous 16-bit fields of zeros.
 | 
			
		||||
 | 
			
		||||
        @param unformattedAddress the IPv6 address to be formatted
 | 
			
		||||
        @returns 0 if the two addresses are identical, negative if this address is smaller than
 | 
			
		||||
                 the other one, or positive if is greater.
 | 
			
		||||
    */
 | 
			
		||||
    static String getFormattedAddress (const String& unformattedAddress);
 | 
			
		||||
    int compare (const IPAddress&) const noexcept;
 | 
			
		||||
 | 
			
		||||
    bool operator== (const IPAddress& other) const noexcept;
 | 
			
		||||
    bool operator!= (const IPAddress& other) const noexcept;
 | 
			
		||||
    bool operator== (const IPAddress&) const noexcept;
 | 
			
		||||
    bool operator!= (const IPAddress&) const noexcept;
 | 
			
		||||
    bool operator<  (const IPAddress&) const noexcept;
 | 
			
		||||
    bool operator>  (const IPAddress&) const noexcept;
 | 
			
		||||
    bool operator<= (const IPAddress&) const noexcept;
 | 
			
		||||
    bool operator>= (const IPAddress&) const noexcept;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** The elements of the IP address. */
 | 
			
		||||
    uint8 address[16];
 | 
			
		||||
 | 
			
		||||
    bool isIPv6;
 | 
			
		||||
    bool isIPv6 = false;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    /** Union used to split a 16-bit unsigned integer into 2 8-bit unsigned integers or vice-versa */
 | 
			
		||||
    typedef union
 | 
			
		||||
    {
 | 
			
		||||
        uint16 combined;
 | 
			
		||||
        uint8 split[2];
 | 
			
		||||
    } ByteUnion;
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns a formatted version of the provided IPv6 address conforming to RFC 5952 with leading zeros suppressed,
 | 
			
		||||
        lower case characters, and double-colon notation used to represent contiguous 16-bit fields of zeros.
 | 
			
		||||
 | 
			
		||||
    /** Method used to zero the remaining bytes of the address array when creating IPv4 addresses */
 | 
			
		||||
    void zeroUnusedBytes()
 | 
			
		||||
    {
 | 
			
		||||
        for (int i = 4; i < 16; ++i)
 | 
			
		||||
            address[i] = 0;
 | 
			
		||||
    }
 | 
			
		||||
        @param unformattedAddress    the IPv6 address to be formatted
 | 
			
		||||
    */
 | 
			
		||||
    static String getFormattedAddress (const String& unformattedAddress);
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the given IP address is an IPv4-mapped IPv6 address. */
 | 
			
		||||
    static bool isIPv4MappedAddress (const IPAddress& mappedAddress);
 | 
			
		||||
 | 
			
		||||
    /** Converts an IPv4-mapped IPv6 address to an IPv4 address.
 | 
			
		||||
        If the address is not IPv4-mapped, this will return a null address.
 | 
			
		||||
    */
 | 
			
		||||
    static IPAddress convertIPv4MappedAddressToIPv4 (const IPAddress& mappedAddress);
 | 
			
		||||
 | 
			
		||||
    /** Converts an IPv4 address to an IPv4-mapped IPv6 address. */
 | 
			
		||||
    static IPAddress convertIPv4AddressToIPv4Mapped (const IPAddress& addressToMap);
 | 
			
		||||
 | 
			
		||||
    /** If the IPAdress is the address of an interface on the machine, returns the associated broadcast address.
 | 
			
		||||
        If the address is not an interface, it will return a null address.
 | 
			
		||||
    */
 | 
			
		||||
    static IPAddress getInterfaceBroadcastAddress (const IPAddress& interfaceAddress);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 | 
			
		||||
@ -85,6 +85,13 @@ int64 MACAddress::toInt64() const noexcept
 | 
			
		||||
    return n;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Array<MACAddress> MACAddress::getAllAddresses()
 | 
			
		||||
{
 | 
			
		||||
    Array<MACAddress> addresses;
 | 
			
		||||
    findAllAddresses (addresses);
 | 
			
		||||
    return addresses;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool MACAddress::isNull() const noexcept                                { return toInt64() == 0; }
 | 
			
		||||
 | 
			
		||||
bool MACAddress::operator== (const MACAddress& other) const noexcept    { return memcmp (address, other.address, sizeof (address)) == 0; }
 | 
			
		||||
 | 
			
		||||
@ -33,6 +33,9 @@ class JUCE_API  MACAddress  final
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns a list of the MAC addresses of all the available network cards. */
 | 
			
		||||
    static Array<MACAddress> getAllAddresses();
 | 
			
		||||
 | 
			
		||||
    /** Populates a list of the MAC addresses of all the available network cards. */
 | 
			
		||||
    static void findAllAddresses (Array<MACAddress>& results);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -60,4 +60,198 @@ String NamedPipe::getName() const
 | 
			
		||||
 | 
			
		||||
// other methods for this class are implemented in the platform-specific files
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
 | 
			
		||||
#if JUCE_UNIT_TESTS
 | 
			
		||||
 | 
			
		||||
class NamedPipeTests  : public UnitTest
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    NamedPipeTests()
 | 
			
		||||
        : UnitTest ("NamedPipe", "Networking")
 | 
			
		||||
    {}
 | 
			
		||||
 | 
			
		||||
    void runTest() override
 | 
			
		||||
    {
 | 
			
		||||
        const String pipeName ("TestPipe");
 | 
			
		||||
 | 
			
		||||
        beginTest ("Pre test cleanup");
 | 
			
		||||
        {
 | 
			
		||||
            NamedPipe pipe;
 | 
			
		||||
            expect (pipe.createNewPipe (pipeName, false));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        beginTest ("Create pipe");
 | 
			
		||||
        {
 | 
			
		||||
            NamedPipe pipe;
 | 
			
		||||
            expect (! pipe.isOpen());
 | 
			
		||||
 | 
			
		||||
            expect (pipe.createNewPipe (pipeName, true));
 | 
			
		||||
            expect (pipe.isOpen());
 | 
			
		||||
 | 
			
		||||
            expect (pipe.createNewPipe (pipeName, false));
 | 
			
		||||
            expect (pipe.isOpen());
 | 
			
		||||
 | 
			
		||||
            NamedPipe otherPipe;
 | 
			
		||||
            expect (! otherPipe.createNewPipe (pipeName, true));
 | 
			
		||||
            expect (! otherPipe.isOpen());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        beginTest ("Existing pipe");
 | 
			
		||||
        {
 | 
			
		||||
            NamedPipe pipe;
 | 
			
		||||
 | 
			
		||||
            expect (! pipe.openExisting (pipeName));
 | 
			
		||||
            expect (! pipe.isOpen());
 | 
			
		||||
 | 
			
		||||
            expect (pipe.createNewPipe (pipeName, true));
 | 
			
		||||
 | 
			
		||||
            NamedPipe otherPipe;
 | 
			
		||||
            expect (otherPipe.openExisting (pipeName));
 | 
			
		||||
            expect (otherPipe.isOpen());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        int sendData = 4684682;
 | 
			
		||||
 | 
			
		||||
        beginTest ("Receive message created pipe");
 | 
			
		||||
        {
 | 
			
		||||
            NamedPipe pipe;
 | 
			
		||||
            expect (pipe.createNewPipe (pipeName, true));
 | 
			
		||||
 | 
			
		||||
            WaitableEvent senderFinished;
 | 
			
		||||
            SenderThread sender (pipeName, false, senderFinished, sendData);
 | 
			
		||||
 | 
			
		||||
            sender.startThread();
 | 
			
		||||
 | 
			
		||||
            int recvData = -1;
 | 
			
		||||
            auto bytesRead = pipe.read (&recvData, sizeof (recvData), 2000);
 | 
			
		||||
 | 
			
		||||
            expect (senderFinished.wait (4000));
 | 
			
		||||
 | 
			
		||||
            expectEquals (bytesRead, (int) sizeof (recvData));
 | 
			
		||||
            expectEquals (sender.result, (int) sizeof (sendData));
 | 
			
		||||
            expectEquals (recvData, sendData);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        beginTest ("Receive message existing pipe");
 | 
			
		||||
        {
 | 
			
		||||
            WaitableEvent senderFinished;
 | 
			
		||||
            SenderThread sender (pipeName, true, senderFinished, sendData);
 | 
			
		||||
 | 
			
		||||
            NamedPipe pipe;
 | 
			
		||||
            expect (pipe.openExisting (pipeName));
 | 
			
		||||
 | 
			
		||||
            sender.startThread();
 | 
			
		||||
 | 
			
		||||
            int recvData = -1;
 | 
			
		||||
            auto bytesRead = pipe.read (&recvData, sizeof (recvData), 2000);
 | 
			
		||||
 | 
			
		||||
            expect (senderFinished.wait (4000));
 | 
			
		||||
 | 
			
		||||
            expectEquals (bytesRead, (int) sizeof (recvData));
 | 
			
		||||
            expectEquals (sender.result, (int) sizeof (sendData));
 | 
			
		||||
            expectEquals (recvData, sendData);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        beginTest ("Send message created pipe");
 | 
			
		||||
        {
 | 
			
		||||
            NamedPipe pipe;
 | 
			
		||||
            expect (pipe.createNewPipe (pipeName, true));
 | 
			
		||||
 | 
			
		||||
            WaitableEvent receiverFinished;
 | 
			
		||||
            ReceiverThread receiver (pipeName, false, receiverFinished);
 | 
			
		||||
 | 
			
		||||
            receiver.startThread();
 | 
			
		||||
 | 
			
		||||
            auto bytesWritten = pipe.write (&sendData, sizeof (sendData), 2000);
 | 
			
		||||
 | 
			
		||||
            expect (receiverFinished.wait (4000));
 | 
			
		||||
 | 
			
		||||
            expectEquals (bytesWritten, (int) sizeof (sendData));
 | 
			
		||||
            expectEquals (receiver.result, (int) sizeof (receiver.recvData));
 | 
			
		||||
            expectEquals (receiver.recvData, sendData);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        beginTest ("Send message existing pipe");
 | 
			
		||||
        {
 | 
			
		||||
            WaitableEvent receiverFinished;
 | 
			
		||||
            ReceiverThread receiver (pipeName, true, receiverFinished);
 | 
			
		||||
 | 
			
		||||
            NamedPipe pipe;
 | 
			
		||||
            expect (pipe.openExisting (pipeName));
 | 
			
		||||
 | 
			
		||||
            receiver.startThread();
 | 
			
		||||
 | 
			
		||||
            auto bytesWritten = pipe.write (&sendData, sizeof (sendData), 2000);
 | 
			
		||||
 | 
			
		||||
            expect (receiverFinished.wait (4000));
 | 
			
		||||
 | 
			
		||||
            expectEquals (bytesWritten, (int) sizeof (sendData));
 | 
			
		||||
            expectEquals (receiver.result, (int) sizeof (receiver.recvData));
 | 
			
		||||
            expectEquals (receiver.recvData, sendData);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    struct NamedPipeThread   : public Thread
 | 
			
		||||
    {
 | 
			
		||||
        NamedPipeThread (const String& threadName, const String& pName,
 | 
			
		||||
                         bool shouldCreatePipe, WaitableEvent& completed)
 | 
			
		||||
            : Thread (threadName), pipeName (pName), workCompleted (completed)
 | 
			
		||||
        {
 | 
			
		||||
            if (shouldCreatePipe)
 | 
			
		||||
                pipe.createNewPipe (pipeName);
 | 
			
		||||
            else
 | 
			
		||||
                pipe.openExisting (pipeName);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        NamedPipe pipe;
 | 
			
		||||
        const String& pipeName;
 | 
			
		||||
        WaitableEvent& workCompleted;
 | 
			
		||||
 | 
			
		||||
        int result = -2;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    struct SenderThread   : public NamedPipeThread
 | 
			
		||||
    {
 | 
			
		||||
        SenderThread (const String& pName, bool shouldCreatePipe,
 | 
			
		||||
                      WaitableEvent& completed, int sData)
 | 
			
		||||
            : NamedPipeThread ("NamePipeSender", pName, shouldCreatePipe, completed),
 | 
			
		||||
              sendData (sData)
 | 
			
		||||
        {}
 | 
			
		||||
 | 
			
		||||
        void run() override
 | 
			
		||||
        {
 | 
			
		||||
            result = pipe.write (&sendData, sizeof (sendData), 2000);
 | 
			
		||||
            workCompleted.signal();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const int sendData;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    struct ReceiverThread   : public NamedPipeThread
 | 
			
		||||
    {
 | 
			
		||||
        ReceiverThread (const String& pName, bool shouldCreatePipe,
 | 
			
		||||
                        WaitableEvent& completed)
 | 
			
		||||
            : NamedPipeThread ("NamePipeSender", pName, shouldCreatePipe, completed)
 | 
			
		||||
        {}
 | 
			
		||||
 | 
			
		||||
        void run() override
 | 
			
		||||
        {
 | 
			
		||||
            result = pipe.read (&recvData, sizeof (recvData), 2000);
 | 
			
		||||
            workCompleted.signal();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        int recvData = -2;
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static NamedPipeTests namedPipeTests;
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 | 
			
		||||
@ -264,7 +264,7 @@ namespace SocketHelpers
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            timeoutp = 0;
 | 
			
		||||
            timeoutp = nullptr;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fd_set rset, wset;
 | 
			
		||||
@ -282,7 +282,8 @@ namespace SocketHelpers
 | 
			
		||||
       #else
 | 
			
		||||
        {
 | 
			
		||||
            int result;
 | 
			
		||||
            while ((result = select (h + 1, prset, pwset, 0, timeoutp)) < 0
 | 
			
		||||
 | 
			
		||||
            while ((result = select (h + 1, prset, pwset, nullptr, timeoutp)) < 0
 | 
			
		||||
                    && errno == EINTR)
 | 
			
		||||
            {
 | 
			
		||||
            }
 | 
			
		||||
@ -590,11 +591,9 @@ bool StreamingSocket::isLocal() const noexcept
 | 
			
		||||
    if (! isConnected())
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    Array<IPAddress> localAddresses;
 | 
			
		||||
    IPAddress::findAllAddresses (localAddresses);
 | 
			
		||||
    IPAddress currentIP (SocketHelpers::getConnectedAddress (handle));
 | 
			
		||||
 | 
			
		||||
    for (auto& a : localAddresses)
 | 
			
		||||
    for (auto& a : IPAddress::getAllAddresses())
 | 
			
		||||
        if (a == currentIP)
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -68,7 +68,7 @@ public:
 | 
			
		||||
        network address otherwise this function will fail.
 | 
			
		||||
        @returns    true on success; false may indicate that another socket is already bound
 | 
			
		||||
                    on the same port
 | 
			
		||||
        @see bindToPort(int localPortNumber), IPAddress::findAllAddresses
 | 
			
		||||
        @see bindToPort(int localPortNumber), IPAddress::getAllAddresses
 | 
			
		||||
    */
 | 
			
		||||
    bool bindToPort (int localPortNumber, const String& localAddress);
 | 
			
		||||
 | 
			
		||||
@ -236,7 +236,7 @@ public:
 | 
			
		||||
        network address otherwise this function will fail.
 | 
			
		||||
        @returns    true on success; false may indicate that another socket is already bound
 | 
			
		||||
                    on the same port
 | 
			
		||||
        @see bindToPort(int localPortNumber), IPAddress::findAllAddresses
 | 
			
		||||
        @see bindToPort(int localPortNumber), IPAddress::getAllAddresses
 | 
			
		||||
    */
 | 
			
		||||
    bool bindToPort (int localPortNumber, const String& localAddress);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -40,13 +40,14 @@ struct FallbackDownloadTask  : public URL::DownloadTask,
 | 
			
		||||
        jassert (fileStream != nullptr);
 | 
			
		||||
        jassert (stream != nullptr);
 | 
			
		||||
 | 
			
		||||
        contentLength = stream->getTotalLength();
 | 
			
		||||
        httpCode      = stream->getStatusCode();
 | 
			
		||||
        targetLocation = fileStream->getFile();
 | 
			
		||||
        contentLength  = stream->getTotalLength();
 | 
			
		||||
        httpCode       = stream->getStatusCode();
 | 
			
		||||
 | 
			
		||||
        startThread();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~FallbackDownloadTask()
 | 
			
		||||
    ~FallbackDownloadTask() override
 | 
			
		||||
    {
 | 
			
		||||
        signalThreadShouldExit();
 | 
			
		||||
        stream->cancel();
 | 
			
		||||
@ -61,10 +62,10 @@ struct FallbackDownloadTask  : public URL::DownloadTask,
 | 
			
		||||
            if (listener != nullptr)
 | 
			
		||||
                listener->progress (this, downloaded, contentLength);
 | 
			
		||||
 | 
			
		||||
            const int max = jmin ((int) bufferSize, contentLength < 0 ? std::numeric_limits<int>::max()
 | 
			
		||||
                                                                      : static_cast<int> (contentLength - downloaded));
 | 
			
		||||
            auto max = jmin ((int) bufferSize, contentLength < 0 ? std::numeric_limits<int>::max()
 | 
			
		||||
                                                                 : static_cast<int> (contentLength - downloaded));
 | 
			
		||||
 | 
			
		||||
            const int actual = stream->read (buffer.get(), max);
 | 
			
		||||
            auto actual = stream->read (buffer.get(), max);
 | 
			
		||||
 | 
			
		||||
            if (actual < 0 || threadShouldExit() || stream->isError())
 | 
			
		||||
                break;
 | 
			
		||||
@ -118,9 +119,7 @@ URL::DownloadTask* URL::DownloadTask::createFallbackDownloader (const URL& urlTo
 | 
			
		||||
    const size_t bufferSize = 0x8000;
 | 
			
		||||
    targetFileToUse.deleteFile();
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr<FileOutputStream> outputStream (targetFileToUse.createOutputStream (bufferSize));
 | 
			
		||||
 | 
			
		||||
    if (outputStream != nullptr)
 | 
			
		||||
    if (auto outputStream = std::unique_ptr<FileOutputStream> (targetFileToUse.createOutputStream (bufferSize)))
 | 
			
		||||
    {
 | 
			
		||||
        std::unique_ptr<WebInputStream> stream (new WebInputStream (urlToUse, usePostRequest));
 | 
			
		||||
        stream->withExtraHeaders (extraHeadersToUse);
 | 
			
		||||
@ -186,8 +185,8 @@ void URL::init()
 | 
			
		||||
    {
 | 
			
		||||
        do
 | 
			
		||||
        {
 | 
			
		||||
            const int nextAmp   = url.indexOfChar (i + 1, '&');
 | 
			
		||||
            const int equalsPos = url.indexOfChar (i + 1, '=');
 | 
			
		||||
            auto nextAmp   = url.indexOfChar (i + 1, '&');
 | 
			
		||||
            auto equalsPos = url.indexOfChar (i + 1, '=');
 | 
			
		||||
 | 
			
		||||
            if (nextAmp < 0)
 | 
			
		||||
            {
 | 
			
		||||
@ -211,26 +210,26 @@ void URL::init()
 | 
			
		||||
URL::URL (const String& u, int)  : url (u) {}
 | 
			
		||||
 | 
			
		||||
URL::URL (URL&& other)
 | 
			
		||||
    : url             (static_cast<String&&> (other.url)),
 | 
			
		||||
      postData        (static_cast<MemoryBlock&&> (other.postData)),
 | 
			
		||||
      parameterNames  (static_cast<StringArray&&> (other.parameterNames)),
 | 
			
		||||
      parameterValues (static_cast<StringArray&&> (other.parameterValues)),
 | 
			
		||||
      filesToUpload   (static_cast<ReferenceCountedArray<Upload>&&> (other.filesToUpload))
 | 
			
		||||
    : url             (std::move (other.url)),
 | 
			
		||||
      postData        (std::move (other.postData)),
 | 
			
		||||
      parameterNames  (std::move (other.parameterNames)),
 | 
			
		||||
      parameterValues (std::move (other.parameterValues)),
 | 
			
		||||
      filesToUpload   (std::move (other.filesToUpload))
 | 
			
		||||
   #if JUCE_IOS
 | 
			
		||||
    , bookmark        (static_cast<Bookmark::Ptr&&> (other.bookmark))
 | 
			
		||||
    , bookmark        (std::move (other.bookmark))
 | 
			
		||||
   #endif
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
URL& URL::operator= (URL&& other)
 | 
			
		||||
{
 | 
			
		||||
    url             = static_cast<String&&> (other.url);
 | 
			
		||||
    postData        = static_cast<MemoryBlock&&> (other.postData);
 | 
			
		||||
    parameterNames  = static_cast<StringArray&&> (other.parameterNames);
 | 
			
		||||
    parameterValues = static_cast<StringArray&&> (other.parameterValues);
 | 
			
		||||
    filesToUpload   = static_cast<ReferenceCountedArray<Upload>&&> (other.filesToUpload);
 | 
			
		||||
    url             = std::move (other.url);
 | 
			
		||||
    postData        = std::move (other.postData);
 | 
			
		||||
    parameterNames  = std::move (other.parameterNames);
 | 
			
		||||
    parameterValues = std::move (other.parameterValues);
 | 
			
		||||
    filesToUpload   = std::move (other.filesToUpload);
 | 
			
		||||
   #if JUCE_IOS
 | 
			
		||||
    bookmark        = static_cast<Bookmark::Ptr&&> (other.bookmark);
 | 
			
		||||
    bookmark        = std::move (other.bookmark);
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
    return *this;
 | 
			
		||||
@ -324,7 +323,7 @@ void URL::addParameter (const String& name, const String& value)
 | 
			
		||||
    parameterValues.add (value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
String URL::toString (const bool includeGetParameters) const
 | 
			
		||||
String URL::toString (bool includeGetParameters) const
 | 
			
		||||
{
 | 
			
		||||
    if (includeGetParameters && parameterNames.size() > 0)
 | 
			
		||||
        return url + "?" + URLHelpers::getMangledParameters (*this);
 | 
			
		||||
@ -345,14 +344,7 @@ bool URL::isWellFormed() const
 | 
			
		||||
 | 
			
		||||
String URL::getDomain() const
 | 
			
		||||
{
 | 
			
		||||
    auto start = URLHelpers::findStartOfNetLocation (url);
 | 
			
		||||
    auto end1 = url.indexOfChar (start, '/');
 | 
			
		||||
    auto end2 = url.indexOfChar (start, ':');
 | 
			
		||||
 | 
			
		||||
    auto end = (end1 < 0 && end2 < 0) ? std::numeric_limits<int>::max()
 | 
			
		||||
                                      : ((end1 < 0 || end2 < 0) ? jmax (end1, end2)
 | 
			
		||||
                                                                : jmin (end1, end2));
 | 
			
		||||
    return url.substring (start, end);
 | 
			
		||||
    return getDomainInternal (false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
String URL::getSubPath() const
 | 
			
		||||
@ -393,7 +385,7 @@ File URL::fileFromFileSchemeURL (const URL& fileURL)
 | 
			
		||||
        return {};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    auto path = removeEscapeChars (fileURL.getDomain()).replace ("+", "%2B");
 | 
			
		||||
    auto path = removeEscapeChars (fileURL.getDomainInternal (true)).replace ("+", "%2B");
 | 
			
		||||
 | 
			
		||||
   #ifdef JUCE_WINDOWS
 | 
			
		||||
    bool isUncPath = (! fileURL.url.startsWith ("file:///"));
 | 
			
		||||
@ -531,6 +523,18 @@ bool URL::isProbablyAnEmailAddress (const String& possibleEmailAddress)
 | 
			
		||||
        && ! possibleEmailAddress.endsWithChar ('.');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
String URL::getDomainInternal (bool ignorePort) const
 | 
			
		||||
{
 | 
			
		||||
    auto start = URLHelpers::findStartOfNetLocation (url);
 | 
			
		||||
    auto end1 = url.indexOfChar (start, '/');
 | 
			
		||||
    auto end2 = ignorePort ? -1 : url.indexOfChar (start, ':');
 | 
			
		||||
 | 
			
		||||
    auto end = (end1 < 0 && end2 < 0) ? std::numeric_limits<int>::max()
 | 
			
		||||
                                      : ((end1 < 0 || end2 < 0) ? jmax (end1, end2)
 | 
			
		||||
                                                                : jmin (end1, end2));
 | 
			
		||||
    return url.substring (start, end);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if JUCE_IOS
 | 
			
		||||
URL::Bookmark::Bookmark (void* bookmarkToUse)
 | 
			
		||||
    : data (bookmarkToUse)
 | 
			
		||||
@ -576,11 +580,11 @@ public:
 | 
			
		||||
            BOOL isBookmarkStale = false;
 | 
			
		||||
            NSError* error = nil;
 | 
			
		||||
 | 
			
		||||
            auto* nsURL = [NSURL URLByResolvingBookmarkData: bookmark
 | 
			
		||||
                                                    options: 0
 | 
			
		||||
                                              relativeToURL: nil
 | 
			
		||||
                                        bookmarkDataIsStale: &isBookmarkStale
 | 
			
		||||
                                                      error: &error];
 | 
			
		||||
            auto nsURL = [NSURL URLByResolvingBookmarkData: bookmark
 | 
			
		||||
                                                   options: 0
 | 
			
		||||
                                             relativeToURL: nil
 | 
			
		||||
                                       bookmarkDataIsStale: &isBookmarkStale
 | 
			
		||||
                                                     error: &error];
 | 
			
		||||
 | 
			
		||||
            if (error == nil)
 | 
			
		||||
            {
 | 
			
		||||
@ -591,7 +595,7 @@ public:
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                auto* desc = [error localizedDescription];
 | 
			
		||||
                auto desc = [error localizedDescription];
 | 
			
		||||
                ignoreUnused (desc);
 | 
			
		||||
                jassertfalse;
 | 
			
		||||
            }
 | 
			
		||||
@ -609,10 +613,10 @@ private:
 | 
			
		||||
            BOOL isBookmarkStale = false;
 | 
			
		||||
            NSError* error = nil;
 | 
			
		||||
 | 
			
		||||
            auto* nsURL = [NSURL URLByResolvingBookmarkData: bookmark
 | 
			
		||||
                                                    options: 0
 | 
			
		||||
                                              relativeToURL: nil
 | 
			
		||||
                                        bookmarkDataIsStale: &isBookmarkStale
 | 
			
		||||
            auto nsURL = [NSURL URLByResolvingBookmarkData: bookmark
 | 
			
		||||
                                                   options: 0
 | 
			
		||||
                                             relativeToURL: nil
 | 
			
		||||
                                       bookmarkDataIsStale: &isBookmarkStale
 | 
			
		||||
                                                      error: &error];
 | 
			
		||||
 | 
			
		||||
            if (error == nil)
 | 
			
		||||
@ -626,7 +630,7 @@ private:
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                auto* desc = [error localizedDescription];
 | 
			
		||||
                auto desc = [error localizedDescription];
 | 
			
		||||
                ignoreUnused (desc);
 | 
			
		||||
                jassertfalse;
 | 
			
		||||
            }
 | 
			
		||||
@ -653,14 +657,14 @@ private:
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
InputStream* URL::createInputStream (const bool usePostCommand,
 | 
			
		||||
                                     OpenStreamProgressCallback* const progressCallback,
 | 
			
		||||
                                     void* const progressCallbackContext,
 | 
			
		||||
InputStream* URL::createInputStream (bool usePostCommand,
 | 
			
		||||
                                     OpenStreamProgressCallback* progressCallback,
 | 
			
		||||
                                     void* progressCallbackContext,
 | 
			
		||||
                                     String headers,
 | 
			
		||||
                                     const int timeOutMs,
 | 
			
		||||
                                     StringPairArray* const responseHeaders,
 | 
			
		||||
                                     int timeOutMs,
 | 
			
		||||
                                     StringPairArray* responseHeaders,
 | 
			
		||||
                                     int* statusCode,
 | 
			
		||||
                                     const int numRedirectsToFollow,
 | 
			
		||||
                                     int numRedirectsToFollow,
 | 
			
		||||
                                     String httpRequestCmd) const
 | 
			
		||||
{
 | 
			
		||||
    if (isLocalFile())
 | 
			
		||||
@ -684,10 +688,10 @@ InputStream* URL::createInputStream (const bool usePostCommand,
 | 
			
		||||
 | 
			
		||||
        bool postDataSendProgress (WebInputStream&, int bytesSent, int totalBytes) override
 | 
			
		||||
        {
 | 
			
		||||
            return callback(data, bytesSent, totalBytes);
 | 
			
		||||
            return callback (data, bytesSent, totalBytes);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        OpenStreamProgressCallback* const callback;
 | 
			
		||||
        OpenStreamProgressCallback* callback;
 | 
			
		||||
        void* const data;
 | 
			
		||||
 | 
			
		||||
        // workaround a MSVC 2013 compiler warning
 | 
			
		||||
@ -858,8 +862,8 @@ String URL::removeEscapeChars (const String& s)
 | 
			
		||||
    {
 | 
			
		||||
        if (utf8.getUnchecked(i) == '%')
 | 
			
		||||
        {
 | 
			
		||||
            const int hexDigit1 = CharacterFunctions::getHexDigitValue ((juce_wchar) (uint8) utf8 [i + 1]);
 | 
			
		||||
            const int hexDigit2 = CharacterFunctions::getHexDigitValue ((juce_wchar) (uint8) utf8 [i + 2]);
 | 
			
		||||
            auto hexDigit1 = CharacterFunctions::getHexDigitValue ((juce_wchar) (uint8) utf8 [i + 1]);
 | 
			
		||||
            auto hexDigit2 = CharacterFunctions::getHexDigitValue ((juce_wchar) (uint8) utf8 [i + 2]);
 | 
			
		||||
 | 
			
		||||
            if (hexDigit1 >= 0 && hexDigit2 >= 0)
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
@ -284,7 +284,7 @@ public:
 | 
			
		||||
        It allows your app to receive progress updates during a lengthy POST operation. If you
 | 
			
		||||
        want to continue the operation, this should return true, or false to abort.
 | 
			
		||||
    */
 | 
			
		||||
    typedef bool (OpenStreamProgressCallback) (void* context, int bytesSent, int totalBytes);
 | 
			
		||||
    using OpenStreamProgressCallback = bool (void* context, int bytesSent, int totalBytes);
 | 
			
		||||
 | 
			
		||||
    /** Attempts to open a stream that can read from this URL.
 | 
			
		||||
 | 
			
		||||
@ -347,27 +347,26 @@ public:
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Represents a download task.
 | 
			
		||||
        Returned by downloadToFile to allow querying and controling the download task.
 | 
			
		||||
        Returned by downloadToFile to allow querying and controlling the download task.
 | 
			
		||||
    */
 | 
			
		||||
    class DownloadTask
 | 
			
		||||
    class JUCE_API  DownloadTask
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        /** Used to receive callbacks for download progress */
 | 
			
		||||
        struct Listener
 | 
			
		||||
        struct JUCE_API  Listener
 | 
			
		||||
        {
 | 
			
		||||
            virtual ~Listener();
 | 
			
		||||
 | 
			
		||||
            /** Called when the download has finished. Be aware that this callback may
 | 
			
		||||
                come on an arbitrary thread. */
 | 
			
		||||
            virtual void finished (DownloadTask* task, bool success) = 0;
 | 
			
		||||
            virtual void finished (URL::DownloadTask* task, bool success) = 0;
 | 
			
		||||
 | 
			
		||||
            /** Called periodically by the OS to indicate download progress.
 | 
			
		||||
                Beware that this callback may come on an arbitrary thread.
 | 
			
		||||
            */
 | 
			
		||||
            virtual void progress (DownloadTask* task, int64 bytesDownloaded, int64 totalLength);
 | 
			
		||||
            virtual void progress (URL::DownloadTask* task, int64 bytesDownloaded, int64 totalLength);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        /** Releases the resources of the download task, unregisters the listener
 | 
			
		||||
            and cancels the download if necessary. */
 | 
			
		||||
        virtual ~DownloadTask();
 | 
			
		||||
@ -391,10 +390,14 @@ public:
 | 
			
		||||
        /** Returns true if there was an error. */
 | 
			
		||||
        inline bool hadError() const                      { return error; }
 | 
			
		||||
 | 
			
		||||
        /** Returns the target file location that was provided in URL::downloadToFile. */
 | 
			
		||||
        File getTargetLocation() const                    { return targetLocation; }
 | 
			
		||||
 | 
			
		||||
    protected:
 | 
			
		||||
        int64 contentLength = -1, downloaded = 0;
 | 
			
		||||
        bool finished = false, error = false;
 | 
			
		||||
        int httpCode = -1;
 | 
			
		||||
        File targetLocation;
 | 
			
		||||
 | 
			
		||||
        DownloadTask();
 | 
			
		||||
 | 
			
		||||
@ -464,7 +467,7 @@ public:
 | 
			
		||||
        If it fails, or if the text that it reads can't be parsed as XML, this will
 | 
			
		||||
        return nullptr.
 | 
			
		||||
 | 
			
		||||
        When it returns a valid XmlElement object, the caller is responsibile for deleting
 | 
			
		||||
        When it returns a valid XmlElement object, the caller is responsible for deleting
 | 
			
		||||
        this object when no longer needed.
 | 
			
		||||
 | 
			
		||||
        Note that on some platforms (Android, for example) it's not permitted to do any network
 | 
			
		||||
@ -526,6 +529,7 @@ private:
 | 
			
		||||
    StringArray parameterNames, parameterValues;
 | 
			
		||||
 | 
			
		||||
    static File fileFromFileSchemeURL (const URL&);
 | 
			
		||||
    String getDomainInternal (bool) const;
 | 
			
		||||
 | 
			
		||||
    struct Upload  : public ReferenceCountedObject
 | 
			
		||||
    {
 | 
			
		||||
@ -537,7 +541,6 @@ private:
 | 
			
		||||
        JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Upload)
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    friend struct ContainerDeletePolicy<Upload>;
 | 
			
		||||
    ReferenceCountedArray<Upload> filesToUpload;
 | 
			
		||||
 | 
			
		||||
  #if JUCE_IOS
 | 
			
		||||
 | 
			
		||||
@ -36,7 +36,7 @@ class JUCE_API WebInputStream : public InputStream
 | 
			
		||||
    class JUCE_API Listener
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        virtual ~Listener() {}
 | 
			
		||||
        virtual ~Listener() = default;
 | 
			
		||||
 | 
			
		||||
        virtual bool postDataSendProgress (WebInputStream& /*request*/, int /*bytesSent*/, int /*totalBytes*/)    { return true; }
 | 
			
		||||
    };
 | 
			
		||||
@ -50,7 +50,7 @@ class JUCE_API WebInputStream : public InputStream
 | 
			
		||||
    */
 | 
			
		||||
    WebInputStream (const URL& url, const bool usePost);
 | 
			
		||||
 | 
			
		||||
    ~WebInputStream();
 | 
			
		||||
    ~WebInputStream() override;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /** Add extra headers to http request
 | 
			
		||||
@ -101,7 +101,7 @@ class JUCE_API WebInputStream : public InputStream
 | 
			
		||||
 | 
			
		||||
        If getResponseHeaders is called without an established connection, then
 | 
			
		||||
        getResponseHeaders will call connect internally and block until connect
 | 
			
		||||
        returns - either due to a succesful connection or a connection
 | 
			
		||||
        returns - either due to a successful connection or a connection
 | 
			
		||||
        error.
 | 
			
		||||
 | 
			
		||||
        @see connect
 | 
			
		||||
@ -112,7 +112,7 @@ class JUCE_API WebInputStream : public InputStream
 | 
			
		||||
 | 
			
		||||
        If getStatusCode is called without an established connection, then
 | 
			
		||||
        getStatusCode will call connect internally and block until connect
 | 
			
		||||
        returns - either due to a succesful connection or a connection
 | 
			
		||||
        returns - either due to a successful connection or a connection
 | 
			
		||||
        error.
 | 
			
		||||
 | 
			
		||||
        @see connect
 | 
			
		||||
@ -153,7 +153,7 @@ class JUCE_API WebInputStream : public InputStream
 | 
			
		||||
 | 
			
		||||
        If getTotalLength is called without an established connection, then
 | 
			
		||||
        getTotalLength will call connect internally and block until connect
 | 
			
		||||
        returns - either due to a succesful connection or a connection
 | 
			
		||||
        returns - either due to a successful connection or a connection
 | 
			
		||||
        error.
 | 
			
		||||
 | 
			
		||||
        If the size of the stream isn't actually known, this will return -1.
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user