| 
							- /*
 -   ==============================================================================
 - 
 -    This file is part of the JUCE library.
 -    Copyright (c) 2015 - ROLI Ltd.
 - 
 -    Permission is granted to use this software under the terms of either:
 -    a) the GPL v2 (or any later version)
 -    b) the Affero GPL v3
 - 
 -    Details of these licenses can be found at: www.gnu.org/licenses
 - 
 -    JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
 -    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 -    A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 - 
 -    ------------------------------------------------------------------------------
 - 
 -    To release a closed-source product which uses JUCE, commercial licenses are
 -    available: visit www.juce.com for more information.
 - 
 -   ==============================================================================
 - */
 - 
 - namespace
 - {
 -     //==============================================================================
 -     /** Writes OSC data to an internal memory buffer, which grows as required.
 - 
 -         The data that was written into the stream can then be accessed later as
 -         a contiguous block of memory.
 - 
 -         This class implements the Open Sound Control 1.0 Specification for
 -         the format in which the OSC data will be written into the buffer.
 -      */
 -     struct OSCOutputStream
 -     {
 -         OSCOutputStream() noexcept {}
 - 
 -         /** Returns a pointer to the data that has been written to the stream. */
 -         const void* getData() const noexcept    { return output.getData(); }
 - 
 -         /** Returns the number of bytes of data that have been written to the stream. */
 -         size_t getDataSize() const noexcept     { return output.getDataSize(); }
 - 
 -         //==============================================================================
 -         bool writeInt32 (int32 value)
 -         {
 -             return output.writeIntBigEndian (value);
 -         }
 - 
 -         bool writeUint64 (uint64 value)
 -         {
 -             return output.writeInt64BigEndian (int64 (value));
 -         }
 - 
 -         bool writeFloat32 (float value)
 -         {
 -             return output.writeFloatBigEndian (value);
 -         }
 - 
 -         bool writeString (const String& value)
 -         {
 -             if (! output.writeString (value))
 -                 return false;
 - 
 -             const size_t numPaddingZeros = ~value.length() & 3;
 - 
 -             return output.writeRepeatedByte ('\0', numPaddingZeros);
 -         }
 - 
 -         bool writeBlob (const MemoryBlock& blob)
 -         {
 -             if (! (output.writeIntBigEndian ((int) blob.getSize())
 -                     && output.write (blob.getData(), blob.getSize())))
 -                 return false;
 - 
 -             const size_t numPaddingZeros = ~(blob.getSize() - 1) & 3;
 - 
 -             return output.writeRepeatedByte (0, numPaddingZeros);
 -         }
 - 
 -         bool writeTimeTag (OSCTimeTag timeTag)
 -         {
 -             return output.writeInt64BigEndian (int64 (timeTag.getRawTimeTag()));
 -         }
 - 
 -         bool writeAddress (const OSCAddress& address)
 -         {
 -             return writeString (address.toString());
 -         }
 - 
 -         bool writeAddressPattern (const OSCAddressPattern& ap)
 -         {
 -             return writeString (ap.toString());
 -         }
 - 
 -         bool writeTypeTagString (const OSCTypeList& typeList)
 -         {
 -             output.writeByte (',');
 - 
 -             if (typeList.size() > 0)
 -                 output.write (typeList.begin(), (size_t) typeList.size());
 - 
 -             output.writeByte ('\0');
 - 
 -             size_t bytesWritten = (size_t) typeList.size() + 1;
 -             size_t numPaddingZeros = ~bytesWritten & 0x03;
 - 
 -             return output.writeRepeatedByte ('\0', numPaddingZeros);
 -         }
 - 
 -         bool writeArgument (const OSCArgument& arg)
 -         {
 -             switch (arg.getType())
 -             {
 -                 case OSCTypes::int32:       return writeInt32 (arg.getInt32());
 -                 case OSCTypes::float32:     return writeFloat32 (arg.getFloat32());
 -                 case OSCTypes::string:      return writeString (arg.getString());
 -                 case OSCTypes::blob:        return writeBlob (arg.getBlob());
 - 
 -                 default:
 -                     // In this very unlikely case you supplied an invalid OSCType!
 -                     jassertfalse;
 -                     return false;
 -             }
 -         }
 - 
 -         //==============================================================================
 -         bool writeMessage (const OSCMessage& msg)
 -         {
 -             if (! writeAddressPattern (msg.getAddressPattern()))
 -                 return false;
 - 
 -             OSCTypeList typeList;
 - 
 -             for (OSCArgument* arg = msg.begin(); arg != msg.end(); ++arg)
 -                 typeList.add (arg->getType());
 - 
 -             if (! writeTypeTagString (typeList))
 -                 return false;
 - 
 -             for (OSCArgument* arg = msg.begin(); arg != msg.end(); ++arg)
 -                 if (! writeArgument (*arg))
 -                     return false;
 - 
 -             return true;
 -         }
 - 
 -         bool writeBundle (const OSCBundle& bundle)
 -         {
 -             if (! writeString ("#bundle"))
 -                 return false;
 - 
 -             if (! writeTimeTag (bundle.getTimeTag()))
 -                 return false;
 - 
 -             for (OSCBundle::Element* element = bundle.begin(); element != bundle.end(); ++element)
 -                 if (! writeBundleElement (*element))
 -                     return false;
 - 
 -             return true;
 -         }
 - 
 -         //==============================================================================
 -         bool writeBundleElement (const OSCBundle::Element& element)
 -         {
 -             const int64 startPos = output.getPosition();
 - 
 -             if (! writeInt32 (0))   // writing dummy value for element size
 -                 return false;
 - 
 -             if (element.isBundle())
 -             {
 -                 if (! writeBundle (element.getBundle()))
 -                     return false;
 -             }
 -             else
 -             {
 -                 if (! writeMessage (element.getMessage()))
 -                     return false;
 -             }
 - 
 -             const int64 endPos = output.getPosition();
 -             const int64 elementSize = endPos - (startPos + 4);
 - 
 -             return output.setPosition (startPos)
 -                      && writeInt32 ((int32) elementSize)
 -                      && output.setPosition (endPos);
 -         }
 - 
 -     private:
 -         MemoryOutputStream output;
 - 
 -         JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OSCOutputStream)
 -     };
 - 
 - } // namespace
 - 
 - 
 - //==============================================================================
 - struct OSCSender::Pimpl
 - {
 -     Pimpl() noexcept : targetPortNumber (0) {}
 -     ~Pimpl() noexcept { disconnect(); }
 - 
 -     //==============================================================================
 -     bool connect (const String& newTargetHost, int newTargetPort)
 -     {
 -         if (! disconnect())
 -             return false;
 - 
 -         socket = new DatagramSocket (true);
 -         targetHostName = newTargetHost;
 -         targetPortNumber = newTargetPort;
 - 
 -         if (socket->bindToPort (0)) // 0 = use any local port assigned by the OS.
 -             return true;
 - 
 -         socket = nullptr;
 -         return false;
 -     }
 - 
 -     bool disconnect()
 -     {
 -         socket = nullptr;
 -         return true;
 -     }
 - 
 -     //==============================================================================
 -     bool send (const OSCMessage& message, const String& hostName, int portNumber)
 -     {
 -         OSCOutputStream outStream;
 -         outStream.writeMessage (message);
 -         return sendOutputStream (outStream, hostName, portNumber);
 -     }
 - 
 -     bool send (const OSCBundle& bundle, const String& hostName, int portNumber)
 -     {
 -         OSCOutputStream outStream;
 -         outStream.writeBundle (bundle);
 -         return sendOutputStream (outStream, hostName, portNumber);
 -     }
 - 
 -     bool send (const OSCMessage& message)   { return send (message, targetHostName, targetPortNumber); }
 -     bool send (const OSCBundle& bundle)     { return send (bundle,  targetHostName, targetPortNumber); }
 - 
 - private:
 -     //==============================================================================
 -     bool sendOutputStream (OSCOutputStream& outStream, const String& hostName, int portNumber)
 -     {
 -         if (socket != nullptr)
 -         {
 -             const int streamSize = (int) outStream.getDataSize();
 - 
 -             const int bytesWritten = socket->write (hostName, portNumber,
 -                                                     outStream.getData(), streamSize);
 -             return bytesWritten == streamSize;
 -         }
 - 
 -         // if you hit this, you tried to send some OSC data without being
 -         // connected to a port! You should call OSCSender::connect() first.
 -         jassertfalse;
 - 
 -         return false;
 -     }
 - 
 -     //==============================================================================
 -     ScopedPointer<DatagramSocket> socket;
 -     String targetHostName;
 -     int targetPortNumber;
 - 
 -     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
 - };
 - 
 - 
 - //==============================================================================
 - OSCSender::OSCSender()   : pimpl (new Pimpl())
 - {
 - }
 - 
 - OSCSender::~OSCSender()
 - {
 -     pimpl->disconnect();
 -     pimpl = nullptr;
 - }
 - 
 - //==============================================================================
 - bool OSCSender::connect (const String& targetHostName, int targetPortNumber)
 - {
 -     return pimpl->connect (targetHostName, targetPortNumber);
 - }
 - 
 - bool OSCSender::disconnect()
 - {
 -     return pimpl->disconnect();
 - }
 - 
 - //==============================================================================
 - bool OSCSender::send (const OSCMessage& message)    { return pimpl->send (message); }
 - bool OSCSender::send (const OSCBundle& bundle)      { return pimpl->send (bundle); }
 - 
 - bool OSCSender::sendToIPAddress (const String& host, int port, const OSCMessage& message) { return pimpl->send (message, host, port); }
 - bool OSCSender::sendToIPAddress (const String& host, int port, const OSCBundle& bundle)   { return pimpl->send (bundle,  host, port); }
 - 
 - //==============================================================================
 - //==============================================================================
 - #if JUCE_UNIT_TESTS
 - 
 - class OSCBinaryWriterTests  : public UnitTest
 - {
 - public:
 -     OSCBinaryWriterTests() : UnitTest ("OSCBinaryWriter class") {}
 - 
 -     void runTest()
 -     {
 -         beginTest ("writing OSC addresses");
 -         {
 -             OSCOutputStream outStream;
 -             const char check[16] = { '/', 't', 'e', 's', 't', '/', 'f', 'a', 'd', 'e', 'r', '7', '\0', '\0', '\0', '\0' };
 - 
 -             OSCAddress address ("/test/fader7");
 -             expect (outStream.writeAddress (address));
 - 
 -             expect (outStream.getDataSize() == sizeof (check));
 -             expect (std::memcmp (outStream.getData(), check, sizeof (check)) == 0);
 -         }
 - 
 -         beginTest ("writing OSC address patterns");
 -         {
 -             OSCOutputStream outStream;
 -             const char check[20] = { '/', '*', '/', '*', 'p', 'u', 't', '/', 'f', 'a', 'd', 'e', 'r', '[', '0', '-', '9', ']', '\0', '\0' };
 - 
 -             OSCAddressPattern ap ("/*/*put/fader[0-9]");
 -             expect (outStream.writeAddressPattern (ap));
 - 
 -             expect (outStream.getDataSize() == sizeof (check));
 -             expect (std::memcmp (outStream.getData(), check, sizeof (check)) == 0);
 -         }
 - 
 -         beginTest ("writing OSC time tags");
 -         {
 -             OSCOutputStream outStream;
 -             const char check[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 };
 -             OSCTimeTag tag;
 - 
 -             expect (outStream.writeTimeTag (tag));
 -             expect (outStream.getDataSize() == 8);
 -             expect (std::memcmp (outStream.getData(), check, sizeof (check)) == 0);
 -         }
 - 
 -         beginTest ("writing OSC type tag strings");
 -         {
 -             {
 -                 OSCOutputStream outStream;
 - 
 -                 OSCTypeList list;
 - 
 -                 const char check[4] = { ',', '\0', '\0', '\0' };
 -                 expect (outStream.writeTypeTagString (list));
 -                 expect (outStream.getDataSize() == 4);
 -                 expect (std::memcmp (outStream.getData(), check, sizeof (check)) == 0);
 -             }
 - 
 -             {
 -                 OSCOutputStream outStream;
 - 
 -                 OSCTypeList list;
 -                 list.add (OSCTypes::int32);
 -                 list.add (OSCTypes::float32);
 - 
 -                 const char check[4] = { ',', 'i', 'f', '\0' };
 -                 expect (outStream.writeTypeTagString (list));
 -                 expect (outStream.getDataSize() == sizeof (check));
 -                 expect (std::memcmp (outStream.getData(), check, sizeof (check)) == 0);
 -             }
 - 
 -             {
 -                 OSCOutputStream outStream;
 - 
 -                 OSCTypeList list;
 -                 list.add (OSCTypes::blob);
 -                 list.add (OSCTypes::blob);
 -                 list.add (OSCTypes::string);
 - 
 -                 const char check[8] = { ',', 'b', 'b', 's', '\0', '\0', '\0', '\0' };
 -                 expect (outStream.writeTypeTagString (list));
 -                 expect (outStream.getDataSize() == sizeof (check));
 -                 expect (std::memcmp (outStream.getData(), check, sizeof (check)) == 0);
 -             }
 -         }
 - 
 -         beginTest ("writing OSC arguments");
 -         {
 -             // test data:
 -             int testInt = -2015;
 -             const uint8 testIntRepresentation[] =  { 0xFF, 0xFF, 0xF8, 0x21 }; // big endian two's complement
 - 
 -             float testFloat = 345.6125f;
 -             const uint8 testFloatRepresentation[] = { 0x43, 0xAC, 0xCE, 0x66 }; // big endian IEEE 754
 - 
 -             String testString = "Hello, World!";
 -             const char testStringRepresentation[] = { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!', '\0', '\0', '\0' }; // padded to size % 4 == 0
 - 
 -             const uint8 testBlobData[] = { 0xBB, 0xCC, 0xDD, 0xEE, 0xFF };
 -             const MemoryBlock testBlob (testBlobData, sizeof (testBlobData));
 -             const uint8 testBlobRepresentation[] = { 0x00, 0x00, 0x00, 0x05, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00, 0x00, 0x00 }; // padded to size % 4 == 0
 - 
 -             // write:
 - 
 -             {
 -                 // int32:
 -                 OSCArgument arg (testInt);
 -                 OSCOutputStream outStream;
 - 
 -                 expect (outStream.writeArgument (arg));
 -                 expect (outStream.getDataSize() == 4);
 -                 expect (std::memcmp (outStream.getData(), testIntRepresentation, sizeof (testIntRepresentation)) == 0);
 -             }
 -             {
 -                 // float32:
 -                 OSCArgument arg (testFloat);
 -                 OSCOutputStream outStream;
 - 
 -                 expect (outStream.writeArgument (arg));
 -                 expect (outStream.getDataSize() == 4);
 -                 expect (std::memcmp (outStream.getData(), testFloatRepresentation, sizeof (testFloatRepresentation)) == 0);
 - 
 -             }
 -             {
 -                 // string:
 -                 expect (testString.length() % 4 != 0); // check whether we actually cover padding
 -                 expect (sizeof (testStringRepresentation) % 4 == 0);
 - 
 -                 OSCArgument arg (testString);
 -                 OSCOutputStream outStream;
 - 
 -                 expect (outStream.writeArgument (arg));
 -                 expect (outStream.getDataSize() == sizeof (testStringRepresentation));
 -                 expect (std::memcmp (outStream.getData(), testStringRepresentation, sizeof (testStringRepresentation)) == 0);
 - 
 -             }
 -             {
 -                 // blob:
 -                 expect (testBlob.getSize() % 4 != 0);  // check whether we actually cover padding
 -                 expect (sizeof (testBlobRepresentation) % 4 == 0);
 - 
 -                 OSCArgument arg (testBlob);
 -                 OSCOutputStream outStream;
 - 
 -                 expect (outStream.writeArgument (arg));
 -                 expect (outStream.getDataSize() == sizeof (testBlobRepresentation));
 -                 expect (std::memcmp (outStream.getData(), testBlobRepresentation, sizeof (testBlobRepresentation)) == 0);
 - 
 -             }
 -         }
 - 
 -         beginTest ("Writing strings with correct padding");
 -         {
 -             // the only OSC-specific thing to check is the correct number of padding zeros
 - 
 -             {
 -                 OSCArgument with15Chars ("123456789012345");
 -                 OSCOutputStream outStream;
 -                 expect (outStream.writeArgument (with15Chars));
 -                 expect (outStream.getDataSize() == 16);
 -             }
 -             {
 -                 OSCArgument with16Chars ("1234567890123456");
 -                 OSCOutputStream outStream;
 -                 expect (outStream.writeArgument (with16Chars));
 -                 expect (outStream.getDataSize() == 20);
 -             }
 -             {
 -                 OSCArgument with17Chars ("12345678901234567");
 -                 OSCOutputStream outStream;
 -                 expect (outStream.writeArgument (with17Chars));
 -                 expect (outStream.getDataSize() == 20);
 -             }
 -             {
 - 
 -                 OSCArgument with18Chars ("123456789012345678");
 -                 OSCOutputStream outStream;
 -                 expect (outStream.writeArgument (with18Chars));
 -                 expect (outStream.getDataSize() == 20);
 -             }
 -             {
 - 
 -                 OSCArgument with19Chars ("1234567890123456789");
 -                 OSCOutputStream outStream;
 -                 expect (outStream.writeArgument (with19Chars));
 -                 expect (outStream.getDataSize() == 20);
 -             }
 -             {
 - 
 -                 OSCArgument with20Chars ("12345678901234567890");
 -                 OSCOutputStream outStream;
 -                 expect (outStream.writeArgument (with20Chars));
 -                 expect (outStream.getDataSize() == 24);
 -             }
 -         }
 -         beginTest ("Writing blobs with correct padding");
 -         {
 -             const char buffer[20] = {};
 -             {
 -                 OSCArgument with15Bytes (MemoryBlock (buffer, 15));
 -                 OSCOutputStream outStream;
 -                 expect (outStream.writeArgument (with15Bytes));
 -                 expect (outStream.getDataSize() == 20);
 -             }
 -             {
 -                 OSCArgument with16Bytes (MemoryBlock (buffer, 16));
 -                 OSCOutputStream outStream;
 -                 expect (outStream.writeArgument (with16Bytes));
 -                 expect (outStream.getDataSize() == 20);
 -             }
 -             {
 -                 OSCArgument with17Bytes (MemoryBlock (buffer, 17));
 -                 OSCOutputStream outStream;
 -                 expect (outStream.writeArgument (with17Bytes));
 -                 expect (outStream.getDataSize() == 24);
 -             }
 -             {
 -                 OSCArgument with18Bytes (MemoryBlock (buffer, 18));
 -                 OSCOutputStream outStream;
 -                 expect (outStream.writeArgument (with18Bytes));
 -                 expect (outStream.getDataSize() == 24);
 -             }
 -             {
 -                 OSCArgument with19Bytes (MemoryBlock (buffer, 19));
 -                 OSCOutputStream outStream;
 -                 expect (outStream.writeArgument (with19Bytes));
 -                 expect (outStream.getDataSize() == 24);
 -             }
 -             {
 -                 OSCArgument with20Bytes (MemoryBlock (buffer, 20));
 -                 OSCOutputStream outStream;
 -                 expect (outStream.writeArgument (with20Bytes));
 -                 expect (outStream.getDataSize() == 24);
 -             }
 -         }
 - 
 -         beginTest ("Writing OSC messages.");
 -         {
 -             {
 -                 int32 testInt = -2015;
 -                 float testFloat = 345.6125f;
 -                 String testString = "Hello, World!";
 - 
 -                 const uint8 testBlobData[] = { 0xBB, 0xCC, 0xDD, 0xEE, 0xFF };
 -                 const MemoryBlock testBlob (testBlobData, sizeof (testBlobData));
 - 
 -                 uint8 check[52] = { '/', 't', 'e', 's', 't', '\0', '\0', '\0',
 -                                     ',', 'i', 'f', 's', 'b', '\0', '\0', '\0',
 -                                     0xFF, 0xFF, 0xF8, 0x21,
 -                                     0x43, 0xAC, 0xCE, 0x66,
 -                                     'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!', '\0', '\0', '\0',
 -                                     0x00, 0x00, 0x00, 0x05, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00, 0x00, 0x00
 -                 };
 - 
 -                 OSCOutputStream outStream;
 - 
 -                 OSCMessage msg ("/test");
 - 
 -                 msg.addInt32 (testInt);
 -                 msg.addFloat32 (testFloat);
 -                 msg.addString (testString);
 -                 msg.addBlob (testBlob);
 - 
 -                 expect (outStream.writeMessage (msg));
 -                 expect (outStream.getDataSize() == sizeof (check));
 -                 expect (std::memcmp (outStream.getData(), check, sizeof (check)) == 0);
 -             }
 -         }
 - 
 -         beginTest ("Writing OSC bundle.");
 -         {
 -             {
 -                 int32 testInt = -2015;
 -                 float testFloat = 345.6125f;
 -                 String testString = "Hello, World!";
 -                 const uint8 testBlobData[] = { 0xBB, 0xCC, 0xDD, 0xEE, 0xFF };
 -                 const MemoryBlock testBlob (testBlobData, sizeof (testBlobData));
 - 
 -                 uint8 check[] = {
 -                     '#', 'b', 'u', 'n', 'd', 'l', 'e', '\0',
 -                     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
 - 
 -                     0x00, 0x00, 0x00, 0x34,
 - 
 -                     '/', 't', 'e', 's', 't', '/', '1', '\0',
 -                     ',', 'i', 'f', 's', 'b', '\0', '\0', '\0',
 -                     0xFF, 0xFF, 0xF8, 0x21,
 -                     0x43, 0xAC, 0xCE, 0x66,
 -                     'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!', '\0', '\0', '\0',
 -                     0x00, 0x00, 0x00, 0x05, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00, 0x00, 0x00,
 - 
 -                     0x00, 0x00, 0x00, 0x0C,
 - 
 -                     '/', 't', 'e', 's', 't', '/', '2', '\0',
 -                     ',', '\0', '\0', '\0',
 - 
 -                     0x00, 0x00, 0x00, 0x10,
 - 
 -                     '#', 'b', 'u', 'n', 'd', 'l', 'e', '\0',
 -                     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
 -                 };
 - 
 -                 OSCOutputStream outStream;
 - 
 -                 OSCBundle bundle;
 - 
 -                 OSCMessage msg1 ("/test/1");
 -                 msg1.addInt32 (testInt);
 -                 msg1.addFloat32 (testFloat);
 -                 msg1.addString (testString);
 -                 msg1.addBlob (testBlob);
 -                 bundle.addElement (msg1);
 - 
 -                 OSCMessage msg2 ("/test/2");
 -                 bundle.addElement (msg2);
 - 
 -                 OSCBundle subBundle;
 -                 bundle.addElement (subBundle);
 - 
 -                 expect (outStream.writeBundle (bundle));
 -                 expect (outStream.getDataSize() == sizeof (check));
 -                 expect (std::memcmp (outStream.getData(), check, sizeof (check)) == 0);
 -             }
 -         }
 -     }
 - };
 - 
 - static OSCBinaryWriterTests OSCBinaryWriterUnitTests;
 - 
 - #endif // JUCE_UNIT_TESTS
 
 
  |