Reorganize source file hierarchy:

* Rename unity files
* Move some modules to new subdirectories
* Remove obsolete Visual Studio project files
* Remove obsolete coding style and TODO list
This commit is contained in:
Vinnie Falco
2014-06-03 14:48:34 -07:00
parent dda5fd7390
commit 558b914c64
213 changed files with 304 additions and 3704 deletions

0
beast/module/README.md Normal file
View File

77
beast/module/asio/asio.h Normal file
View File

@@ -0,0 +1,77 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_MODULE_H_INCLUDED
#define BEAST_ASIO_MODULE_H_INCLUDED
// Must come before boost includes to fix the bost placeholders.
#include <beast/module/core/core.h>
// This module requires boost and possibly OpenSSL
#include <beast/module/asio/system/BoostIncludes.h>
#include <beast/http/URL.h>
#include <beast/http/ParsedURL.h>
#include <beast/asio/IPAddressConversion.h>
// Order matters
#include <beast/module/asio/async/AsyncObject.h>
#include <beast/module/asio/basics/FixedInputBuffer.h>
#include <beast/module/asio/basics/PeerRole.h>
#include <beast/module/asio/basics/SSLContext.h>
#include <beast/module/asio/basics/SharedArg.h>
#include <beast/module/asio/http/HTTPVersion.h>
#include <beast/module/asio/http/HTTPField.h>
#include <beast/module/asio/http/HTTPHeaders.h>
#include <beast/module/asio/http/HTTPMessage.h>
#include <beast/module/asio/http/HTTPRequest.h>
#include <beast/module/asio/http/HTTPResponse.h>
#include <beast/module/asio/http/HTTPParser.h>
#include <beast/module/asio/http/HTTPRequestParser.h>
#include <beast/module/asio/http/HTTPResponseParser.h>
#include <beast/module/asio/http/HTTPClientType.h>
#include <beast/module/asio/protocol/InputParser.h>
#include <beast/module/asio/protocol/HandshakeDetectLogic.h>
#include <beast/module/asio/protocol/HandshakeDetectLogicPROXY.h>
#include <beast/module/asio/protocol/HandshakeDetectLogicSSL2.h>
#include <beast/module/asio/protocol/HandshakeDetectLogicSSL3.h>
#include <beast/module/asio/protocol/HandshakeDetector.h>
#include <beast/module/asio/protocol/PrefilledReadStream.h>
#include <beast/module/asio/tests/TestPeerBasics.h>
#include <beast/module/asio/tests/TestPeer.h>
#include <beast/module/asio/tests/TestPeerDetails.h>
#include <beast/module/asio/tests/TestPeerLogic.h>
#include <beast/module/asio/tests/TestPeerLogicSyncServer.h>
#include <beast/module/asio/tests/TestPeerLogicSyncClient.h>
#include <beast/module/asio/tests/TestPeerLogicProxyClient.h>
#include <beast/module/asio/tests/TestPeerLogicAsyncServer.h>
#include <beast/module/asio/tests/TestPeerLogicAsyncClient.h>
#include <beast/module/asio/tests/TestPeerType.h>
#include <beast/module/asio/tests/TestPeerDetailsTcp.h>
#include <beast/module/asio/tests/PeerTest.h>
#endif

View File

@@ -0,0 +1,56 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#if BEAST_INCLUDE_BEASTCONFIG
#include <BeastConfig.h>
#endif
#include <beast/module/asio/system/OpenSSLIncludes.h>
#include <beast/module/asio/asio.h>
#include <beast/http/impl/joyent_parser.h>
#include <beast/module/asio/basics/PeerRole.cpp>
#include <beast/module/asio/basics/SSLContext.cpp>
#include <beast/module/asio/protocol/HandshakeDetectLogicPROXY.cpp>
#include <beast/module/asio/http/HTTPParserImpl.h>
#include <beast/module/asio/http/HTTPClientType.cpp>
#include <beast/module/asio/http/HTTPField.cpp>
#include <beast/module/asio/http/HTTPHeaders.cpp>
#include <beast/module/asio/http/HTTPMessage.cpp>
#include <beast/module/asio/http/HTTPRequest.cpp>
#include <beast/module/asio/http/HTTPResponse.cpp>
#include <beast/module/asio/http/HTTPVersion.cpp>
#include <beast/module/asio/tests/PeerTest.cpp>
#include <beast/module/asio/tests/TestPeerBasics.cpp>
#include <beast/module/asio/tests/TestPeerLogic.cpp>
#include <beast/module/asio/tests/TestPeerLogicProxyClient.cpp>
#include <beast/module/asio/tests/TestPeerLogicSyncServer.cpp>
#include <beast/module/asio/tests/TestPeerLogicSyncClient.cpp>
#include <beast/module/asio/tests/TestPeerLogicAsyncServer.cpp>
#include <beast/module/asio/tests/TestPeerLogicAsyncClient.cpp>
#include <beast/module/asio/tests/TestPeerUnitTests.cpp>
#include <beast/module/asio/http/HTTPParser.cpp>
#include <beast/module/asio/http/HTTPRequestParser.cpp>
#include <beast/module/asio/http/HTTPResponseParser.cpp>

View File

@@ -0,0 +1,89 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_ASYNCOBJECT_H_INCLUDED
#define BEAST_ASIO_ASYNCOBJECT_H_INCLUDED
namespace beast {
namespace asio {
/** Mix-in to track when all pending I/O is complete.
Derived classes must be callable with this signature:
void asyncHandlersComplete()
*/
template <class Derived>
class AsyncObject
{
public:
~AsyncObject ()
{
// Destroying the object with I/O pending? Not a clean exit!
bassert (m_pending.get() == 0);
}
/** RAII container that maintains the count of pending I/O.
Bind this into the argument list of every handler passed
to an initiating function.
*/
class CompletionCounter
{
public:
explicit CompletionCounter (Derived* owner)
: m_owner (owner)
{
++m_owner->m_pending;
}
CompletionCounter (CompletionCounter const& other)
: m_owner (other.m_owner)
{
++m_owner->m_pending;
}
~CompletionCounter ()
{
if (--m_owner->m_pending == 0)
m_owner->asyncHandlersComplete ();
}
private:
CompletionCounter& operator= (CompletionCounter const&);
Derived* m_owner;
};
void addReference ()
{
++m_pending;
}
void removeReference ()
{
if (--m_pending)
(static_cast <Derived *> (this))->asyncHandlersComplete ();
}
private:
// The number of handlers pending.
beast::Atomic <int> m_pending;
};
}
}
#endif

View File

@@ -0,0 +1,101 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
ContentBodyBuffer::ContentBodyBuffer (size_type blocksize)
: m_blocksize (blocksize)
, m_size (0)
{
}
ContentBodyBuffer::~ContentBodyBuffer ()
{
for (Handles::iterator iter (m_handles.begin());
iter != m_handles.end(); ++iter)
{
void* const buffer (*iter);
std::free (buffer);
}
}
void ContentBodyBuffer::swapWith (ContentBodyBuffer& other)
{
std::swap (m_blocksize, other.m_blocksize);
std::swap (m_size, other.m_size);
m_handles.swap (other.m_handles);
}
void ContentBodyBuffer::commit (size_type n)
{
m_size += n;
bassert (m_size <= m_handles.size () * m_blocksize);
}
ConstBuffers ContentBodyBuffer::data () const
{
size_type n (m_size);
std::vector <ConstBuffer> v;
v.reserve ((m_size + m_blocksize - 1) / m_blocksize);
for (Handles::const_iterator iter (m_handles.begin());
iter != m_handles.end() && n > 0; ++iter)
{
size_type const amount (std::min (n, m_blocksize));
v.push_back (MutableBuffer (*iter, amount));
n -= amount;
}
return ConstBuffers (v);
}
ContentBodyBuffer::size_type ContentBodyBuffer::size () const
{
return m_size;
}
MutableBuffers ContentBodyBuffer::prepare (size_type n)
{
reserve (n);
std::vector <MutableBuffer> v;
size_type offset (m_size % m_blocksize);
for (Handles::iterator iter = m_handles.begin () + (m_size / m_blocksize);
iter != m_handles.end () && n > 0; ++iter)
{
size_type const amount (std::min (n, m_blocksize - offset));
v.push_back (MutableBuffer (*iter, amount));
n -= amount;
offset = 0;
}
return MutableBuffers (v);
}
void ContentBodyBuffer::reserve (size_type n)
{
size_type count ((m_size + n + m_blocksize - 1) / m_blocksize);
if (count > m_handles.size ())
for (count -= m_handles.size (); count-- > 0;)
m_handles.push_back (std::malloc (m_blocksize));
}
void ContentBodyBuffer::shrink_to_fit ()
{
size_type const count ((m_size + m_blocksize - 1) / m_blocksize);
while (m_handles.size () > count)
{
std::free (m_handles.back ());
m_handles.erase (m_handles.end () - 1);
}
}

View File

@@ -0,0 +1,78 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_BASICS_CONTENTBODYBUFFER_H_INCLUDED
#define BEAST_ASIO_BASICS_CONTENTBODYBUFFER_H_INCLUDED
/** Dynamic storage optimized for a large Content-Body of unknown size.
This comes at the expense of discontiguous storage of the segments.
We derive from SharedObject to make transfer of ownership inexpensive.
*/
class ContentBodyBuffer
{
public:
enum
{
defaultBlocksize = 32 * 1024
};
typedef std::size_t size_type;
typedef ConstBuffers const_buffers_tyoe;
typedef MutableBuffers mutable_buffers_type;
explicit ContentBodyBuffer (size_type blocksize = defaultBlocksize);
~ContentBodyBuffer ();
/** Swap the contents of this buffer with another.
This is the preferred way to transfer ownership.
*/
void swapWith (ContentBodyBuffer& other);
/** Move bytes from the output to the input sequence.
This will invalidate references to buffers.
*/
void commit (size_type n);
/** Returns a buffer to the input sequence. */
ConstBuffers data () const;
/** Returns the size of the input sequence. */
size_type size () const;
/** Reserve space in the output sequence.
This also returns a buffer suitable for writing.
*/
MutableBuffers prepare (size_type n);
/** Reserve space in the output sequence. */
void reserve (size_type n);
/** Release memory while preserving the input sequence. */
void shrink_to_fit ();
private:
typedef std::vector <void*> Handles;
size_type m_blocksize;
size_type m_size;
Handles m_handles;
};
#endif

View File

@@ -0,0 +1,202 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_BASICS_FIXEDINPUTBUFFER_H_INCLUDED
#define BEAST_ASIO_BASICS_FIXEDINPUTBUFFER_H_INCLUDED
#include <beast/asio/buffer_sequence.h>
#include <array>
namespace beast {
namespace asio {
/** Represents a small, fixed size buffer.
This provides a convenient interface for doing a bytewise
verification/reject test on a handshake protocol.
*/
/** @{ */
class FixedInputBuffer
{
protected:
struct CtorParams
{
CtorParams (std::uint8_t const* begin_, std::size_t bytes_)
: begin (begin_)
, bytes (bytes_)
{
}
std::uint8_t const* begin;
std::size_t bytes;
};
FixedInputBuffer (CtorParams const& params)
: m_begin (params.begin)
, m_iter (m_begin)
, m_end (m_begin + params.bytes)
{
}
public:
FixedInputBuffer (FixedInputBuffer const& other)
: m_begin (other.m_begin)
, m_iter (other.m_iter)
, m_end (other.m_end)
{
}
FixedInputBuffer& operator= (FixedInputBuffer const& other)
{
m_begin = other.m_begin;
m_iter = other.m_iter;
m_end = other.m_end;
return *this;
}
// Returns the number of bytes consumed
std::size_t used () const noexcept
{
return m_iter - m_begin;
}
// Returns the size of what's remaining
std::size_t size () const noexcept
{
return m_end - m_iter;
}
void const* peek (std::size_t bytes)
{
return peek_impl (bytes, nullptr);
}
template <typename T>
bool peek (T* t) const noexcept
{
return peek_impl (sizeof (T), t) != nullptr;
}
bool consume (std::size_t bytes) noexcept
{
return read_impl (bytes, nullptr) != nullptr;
}
bool read (std::size_t bytes) noexcept
{
return read_impl (bytes, nullptr) != nullptr;
}
template <typename T>
bool read (T* t) noexcept
{
return read_impl (sizeof (T), t) != nullptr;
}
std::uint8_t operator[] (std::size_t index) const noexcept
{
bassert (index >= 0 && index < size ());
return m_iter [index];
}
// Reads an integraltype in network byte order
template <typename IntegerType>
bool readNetworkInteger (IntegerType* value)
{
// Must be an integral type!
// not available in all versions of std:: unfortunately
//static_bassert (std::is_integral <IntegerType>::value);
IntegerType networkValue;
if (! read (&networkValue))
return false;
*value = fromNetworkByteOrder (networkValue);
return true;
}
protected:
void const* peek_impl (std::size_t bytes, void* buffer) const noexcept
{
if (size () >= bytes)
{
if (buffer != nullptr)
memcpy (buffer, m_iter, bytes);
return m_iter;
}
return nullptr;
}
void const* read_impl (std::size_t bytes, void* buffer) noexcept
{
if (size () >= bytes)
{
if (buffer != nullptr)
memcpy (buffer, m_iter, bytes);
void const* data = m_iter;
m_iter += bytes;
return data;
}
return nullptr;
}
private:
std::uint8_t const* m_begin;
std::uint8_t const* m_iter;
std::uint8_t const* m_end;
};
//------------------------------------------------------------------------------
template <int Bytes>
class FixedInputBufferSize : public FixedInputBuffer
{
protected:
struct SizedCtorParams
{
template <typename ConstBufferSequence, typename Storage>
SizedCtorParams (ConstBufferSequence const& buffers, Storage& storage)
{
boost::asio::mutable_buffer buffer (boost::asio::buffer (storage));
data = boost::asio::buffer_cast <std::uint8_t const*> (buffer);
bytes = boost::asio::buffer_copy (buffer, buffers);
}
operator CtorParams () const noexcept
{
return CtorParams (data, bytes);
}
std::uint8_t const* data;
std::size_t bytes;
};
public:
template <typename ConstBufferSequence>
explicit FixedInputBufferSize (ConstBufferSequence const& buffers)
: FixedInputBuffer (SizedCtorParams (buffers, m_storage))
{
}
private:
std::array <std::uint8_t, Bytes> m_storage;
boost::asio::mutable_buffer m_buffer;
};
}
}
#endif

View File

@@ -0,0 +1,50 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast {
namespace asio {
PeerRole::PeerRole (role_t role)
: m_role (role)
{
}
String PeerRole::name () const noexcept
{
if (m_role == server)
return "server";
return "client";
}
bool PeerRole::operator== (role_t role) const noexcept
{
return m_role == role;
}
#if 0
PeerRole::operator abstract_socket::handshake_type () const noexcept
{
if (m_role == server)
return abstract_socket::server;
return abstract_socket::client;
}
#endif
}
}

View File

@@ -0,0 +1,46 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_BASICS_PEERROLE_H_INCLUDED
#define BEAST_ASIO_BASICS_PEERROLE_H_INCLUDED
namespace beast {
namespace asio {
/** Identifies if the peer is a client or a server. */
struct PeerRole
{
enum role_t
{
client,
server
};
PeerRole (role_t role);
String name () const noexcept;
bool operator== (role_t role) const noexcept;
private:
role_t m_role;
};
}
}
#endif

View File

@@ -0,0 +1,33 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast {
namespace asio {
SSLContext::SSLContext (ContextType& context)
: m_context (context)
{
}
SSLContext::~SSLContext ()
{
}
}
}

View File

@@ -0,0 +1,69 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_BASICS_SSLCONTEXT_H_INCLUDED
#define BEAST_ASIO_BASICS_SSLCONTEXT_H_INCLUDED
#include <boost/asio/ssl/context.hpp>
namespace beast {
namespace asio {
/** Simple base class for passing a context around.
This lets derived classes hide their implementation from the headers.
*/
class SSLContext : public Uncopyable
{
public:
virtual ~SSLContext ();
// Saves typing
typedef boost::asio::ssl::context ContextType;
inline ContextType& get () noexcept
{
return m_context;
}
inline ContextType const& get () const noexcept
{
return m_context;
}
// implicit conversion
inline operator ContextType& () noexcept
{
return get ();
}
inline operator ContextType const& () const noexcept
{
return get ();
}
protected:
explicit SSLContext (ContextType& context);
ContextType& m_context;
};
}
}
#endif

View File

@@ -0,0 +1,167 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_SHAREDARG_H_INCLUDED
#define BEAST_ASIO_SHAREDARG_H_INCLUDED
namespace beast {
namespace asio {
/** A container that turns T into a SharedObject.
We use this to manage the lifetime of objects passed to handlers.
*/
template <typename T>
struct SharedArg
{
private:
struct Arg : SharedObject
{
Arg ()
{
}
explicit Arg (BEAST_MOVE_ARG(T) t)
: value (BEAST_MOVE_CAST(T)(t))
{
}
template <class P1>
explicit Arg (P1 p1)
: value (p1)
{
}
template <class P1, class P2>
Arg (P1 p1, P2 p2)
: value (p1, p2)
{
}
template <class P1, class P2, class P3>
Arg (P1 p1, P2 p2, P3 p3)
: value (p1, p2, p3)
{
}
template <class P1, class P2, class P3, class P4>
Arg (P1 p1, P2 p2, P3 p3, P4 p4)
: value (p1, p2, p3, p4)
{
}
~Arg ()
{
}
T value;
};
public:
SharedArg ()
{
}
explicit SharedArg (BEAST_MOVE_ARG(T) t)
: m_arg (new Arg (BEAST_MOVE_CAST(T)(t)))
{
}
template <class P1>
explicit SharedArg (P1 p1)
: m_arg (new Arg (p1))
{
}
template <class P1, class P2>
SharedArg (P1 p1, P2 p2)
: m_arg (new Arg (p1, p2))
{
}
template <class P1, class P2, class P3>
SharedArg (P1 p1, P2 p2, P3 p3)
: m_arg (new Arg (p1, p2, p3))
{
}
template <class P1, class P2, class P3, class P4>
SharedArg (P1 p1, P2 p2, P3 p3, P4 p4)
: m_arg (new Arg (p1, p2, p3, p4))
{
}
SharedArg (SharedArg const& other)
: m_arg (other.m_arg)
{
}
SharedArg& operator= (SharedArg const& other)
{
m_arg = other.m_arg;
return *this;
}
T& get ()
{
return m_arg->value;
}
T const& get () const
{
return m_arg->value;
}
T& operator* ()
{
return get();
}
T const& operator* () const
{
return get();
}
T* operator-> ()
{
return &get();
}
T const* operator-> () const
{
return &get();
}
operator T& ()
{
return m_arg->value;
}
operator T const& () const
{
return m_arg->value;
}
private:
SharedPtr <Arg> m_arg;
};
}
}
#endif

View File

@@ -0,0 +1,689 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <beast/asio/wrap_handler.h>
#include <beast/asio/placeholders.h>
#include <beast/unit_test/suite.h>
#include <beast/cxx14/memory.h> // <memory>
namespace beast {
namespace asio {
class HTTPClientType : public HTTPClientBase, public Uncopyable
{
public:
class Session;
struct State
{
List <Session> list;
};
typedef SharedData <State> SharedState;
SharedState m_state;
Journal m_journal;
double m_timeoutSeconds;
std::size_t m_messageLimitBytes;
std::size_t m_bufferSize;
boost::asio::io_service m_io_service;
WaitableEvent m_stopped;
//--------------------------------------------------------------------------
HTTPClientType (
Journal journal,
double timeoutSeconds,
std::size_t messageLimitBytes,
std::size_t bufferSize)
: m_journal (journal)
, m_timeoutSeconds (timeoutSeconds)
, m_messageLimitBytes (messageLimitBytes)
, m_bufferSize (bufferSize)
, m_stopped (true, true) // manual reset, initially signaled
{
}
~HTTPClientType ()
{
cancel();
wait();
}
result_type get (URL const& url)
{
result_type result;
boost::asio::io_service io_service;
async_get (io_service, url, beast::bind (
&HTTPClientType::handle_get, beast::placeholders::_1, &result));
io_service.run ();
return result;
}
void async_get (boost::asio::io_service& io_service, URL const& url,
asio::shared_handler <void (result_type)> handler)
{
new Session (*this, io_service, url,
handler, m_timeoutSeconds, m_messageLimitBytes, m_bufferSize);
}
void cancel ()
{
SharedState::Access state (m_state);
for (List <Session>::iterator iter (state->list.begin());
iter != state->list.end(); ++iter)
iter->cancel();
}
void wait()
{
m_stopped.wait();
}
//--------------------------------------------------------------------------
void add (Session& session)
{
SharedState::Access state (m_state);
if (state->list.empty())
m_stopped.reset();
state->list.push_back (session);
}
void remove (Session& session)
{
SharedState::Access state (m_state);
state->list.erase (state->list.iterator_to (session));
if (state->list.empty())
m_stopped.signal();
}
static void handle_get (result_type const& result, result_type* dest)
{
*dest = result;
}
Journal journal() const
{
return m_journal;
}
boost::asio::io_service& get_io_service()
{
return m_io_service;
}
//--------------------------------------------------------------------------
/** Helper function to get a const_buffer from a String. */
static boost::asio::const_buffers_1 stringBuffer (String const& s)
{
return boost::asio::const_buffers_1 (s.getCharPointer (), s.length ());
}
/** Helper function to fill out a Query from a URL. */
template <typename Query>
static Query queryFromURL (URL const& url)
{
if (url.port () != 0)
{
return Query (
url.host().toStdString(),
url.port_string().toStdString(),
Query::numeric_service);
}
return Query (
url.host().toStdString(),
url.scheme().toStdString());
}
//--------------------------------------------------------------------------
class Session
: public SharedObject
, public List <Session>::Node
{
public:
typedef SharedPtr <Session> Ptr;
typedef boost::asio::ip::tcp Protocol;
typedef boost::system::error_code error_code;
typedef HTTPClientBase::error_type error_type;
typedef HTTPClientBase::value_type value_type;
typedef HTTPClientBase::result_type result_type;
typedef Protocol::resolver resolver;
typedef Protocol::socket socket;
typedef resolver::query query;
typedef resolver::iterator iterator;
typedef iterator::value_type resolver_entry;
HTTPClientType& m_owner;
boost::asio::io_service& m_io_service;
boost::asio::io_service::strand m_strand;
boost::asio::deadline_timer m_timer;
resolver m_resolver;
socket m_socket;
asio::shared_handler <void (result_type)> m_handler;
URL m_url;
boost::asio::ssl::context m_context;
MemoryBlock m_buffer;
HTTPResponseParser m_parser;
std::size_t m_messageLimitBytes;
std::size_t m_bytesReceived;
String m_get_string;
WaitableEvent m_done;
std::unique_ptr <abstract_socket> m_stream;
struct State
{
State () : complete (false)
{
}
bool complete;
error_code error;
SharedPtr <HTTPResponse> response;
};
typedef SharedData <State> SharedState;
SharedState m_state;
//----------------------------------------------------------------------
Session (HTTPClientType& owner,
boost::asio::io_service& io_service,
URL const& url,
asio::shared_handler <void (result_type)> const& handler,
double timeoutSeconds,
std::size_t messageLimitBytes,
std::size_t bufferSize)
: m_owner (owner)
, m_io_service (io_service)
, m_strand (io_service)
, m_timer (io_service)
, m_resolver (io_service)
, m_socket (io_service)
, m_handler (handler)
, m_url (url)
, m_context (boost::asio::ssl::context::sslv23)
, m_buffer (bufferSize)
, m_messageLimitBytes (messageLimitBytes)
, m_bytesReceived (0)
{
m_owner.add (*this);
// Configure the SSL context for certificate verification
m_context.set_default_verify_paths ();
m_context.set_options (
boost::asio::ssl::context::no_sslv2 |
boost::asio::ssl::context::single_dh_use |
boost::asio::ssl::context::default_workarounds);
//m_context.set_verify_mode (boost::asio::ssl::verify_peer);
// Set the timer if a timeout is requested
if (timeoutSeconds > 0)
{
m_timer.expires_from_now (
boost::posix_time::milliseconds (
long (timeoutSeconds * 1000)));
m_timer.async_wait (m_strand.wrap (asio::wrap_handler (
std::bind (&Session::handle_timer, Ptr(this),
asio::placeholders::error), m_handler)));
}
// Start the operation on an io_service thread
io_service.dispatch (m_strand.wrap (asio::wrap_handler (
std::bind (&Session::handle_start, Ptr(this)), m_handler)));
}
~Session ()
{
State result;
{
SharedState::ConstAccess state (m_state);
result = *state;
}
m_io_service.post (bind_handler (m_handler,
std::make_pair (result.error, result.response)));
m_owner.remove (*this);
}
//----------------------------------------------------------------------
// Called by the owner to cancel pending i/o.
void cancel ()
{
{
SharedState::Access state (m_state);
if (! state->complete)
{
state->complete = true;
state->error = boost::asio::error::operation_aborted;
}
}
cancel_all();
}
// Cancel all pending I/O
void cancel_all ()
{
error_code ec;
m_timer.cancel (ec);
m_resolver.cancel ();
m_socket.cancel (ec);
m_socket.shutdown (socket::shutdown_both, ec);
}
// Called by a completion handler when error is not eof or aborted.
void failed (error_code ec)
{
{
SharedState::Access state (m_state);
if (! state->complete)
{
state->complete = true;
state->error = ec;
state->response = nullptr;
}
}
cancel_all();
}
void async_read_some ()
{
boost::asio::mutable_buffers_1 buf (
m_buffer.getData (), m_buffer.getSize ());
m_stream->async_read_some (buf, m_strand.wrap (
asio::wrap_handler (std::bind (&Session::handle_read,
Ptr(this), asio::placeholders::error,
asio::placeholders::bytes_transferred), m_handler)));
}
//----------------------------------------------------------------------
//
// Completion handlers
//
// Called when the operation starts
void handle_start ()
{
query q (queryFromURL <query> (m_url));
m_resolver.async_resolve (q, m_strand.wrap (
asio::wrap_handler (std::bind (&Session::handle_resolve,
Ptr(this), asio::placeholders::error,
asio::placeholders::iterator), m_handler)));
}
// Called when the timer completes
void handle_timer (error_code ec)
{
if (ec == boost::asio::error::operation_aborted)
return;
if (ec != 0)
{
failed (ec);
return;
}
failed (boost::system::errc::make_error_code (
boost::system::errc::timed_out));
}
// Called when the resolver completes
void handle_resolve (error_code ec, iterator iter)
{
if (ec == boost::asio::error::operation_aborted)
return;
if (ec != 0)
{
failed (ec);
return;
}
resolver_entry const entry (*iter);
m_socket.async_connect (entry.endpoint (), m_strand.wrap (
asio::wrap_handler (std::bind (&Session::handle_connect,
Ptr(this), asio::placeholders::error), m_handler)));
}
// Called when the connection attempt completes
void handle_connect (error_code ec)
{
if (ec == boost::asio::error::operation_aborted)
return;
if (ec != 0)
{
failed (ec);
return;
}
if (m_url.scheme () == "https")
{
typedef boost::asio::ssl::stream <socket&> ssl_stream;
m_stream = std::make_unique <
socket_wrapper <ssl_stream>> (m_socket, m_context);
/*
m_stream->set_verify_mode (
boost::asio::ssl::verify_peer |
boost::asio::ssl::verify_fail_if_no_peer_cert);
*/
m_stream->async_handshake (abstract_socket::client, m_strand.wrap (
asio::wrap_handler (std::bind (&Session::handle_handshake,
Ptr(this), asio::placeholders::error), m_handler)));
return;
}
m_stream = std::make_unique <socket_wrapper <socket&>> (m_socket);
handle_handshake (ec);
}
// Called when the SSL handshake completes
void handle_handshake (error_code ec)
{
if (ec == boost::asio::error::operation_aborted)
return;
if (ec != 0)
{
failed (ec);
return;
}
m_get_string =
"GET " + m_url.path() + " HTTP/1.1\r\n" +
"Host: " + m_url.host() + "\r\n" +
"Accept: */*\r\n" +
"Connection: close\r\n\r\n";
boost::asio::async_write (*m_stream, stringBuffer (
m_get_string), m_strand.wrap (asio::wrap_handler (
std::bind (&Session::handle_write, Ptr(this),
asio::placeholders::error,
asio::placeholders::bytes_transferred), m_handler)));
async_read_some ();
}
// Called when the write operation completes
void handle_write (error_code ec, std::size_t)
{
if (ec == boost::asio::error::operation_aborted)
return;
if (ec != 0)
{
failed (ec);
return;
}
if (! m_stream->needs_handshake ())
m_socket.shutdown (socket::shutdown_send, ec);
}
void handle_read (error_code ec,
std::size_t bytes_transferred)
{
if (ec == boost::asio::error::operation_aborted)
return;
if (ec != 0)
{
failed (ec);
return;
}
m_bytesReceived += bytes_transferred;
if (m_bytesReceived > m_messageLimitBytes)
{
failed (error_code (
boost::system::errc::invalid_argument,
boost::system::system_category ()));
return;
}
std::size_t const bytes_parsed (m_parser.process (
m_buffer.getData (), bytes_transferred));
if (m_parser.error ())
{
failed (error_code (
boost::system::errc::invalid_argument,
boost::system::system_category ()));
return;
}
if (bytes_parsed != bytes_transferred)
{
failed (error_code (
boost::system::errc::invalid_argument,
boost::system::system_category ()));
return;
}
if (ec == boost::asio::error::eof)
m_parser.process_eof ();
if (m_parser.finished ())
{
if (m_stream->needs_handshake ())
{
m_stream->async_shutdown (m_strand.wrap (asio::wrap_handler (
std::bind (&Session::handle_shutdown,
Ptr(this), asio::placeholders::error), m_handler)));
}
else
{
handle_shutdown (error_code ());
}
return;
}
async_read_some ();
}
void handle_shutdown (error_code ec)
{
if (ec == boost::asio::error::operation_aborted)
return;
if (ec == boost::asio::error::eof)
ec = error_code();
if (ec != 0)
{
failed (ec);
return;
}
{
SharedState::Access state (m_state);
if (! state->complete)
{
state->complete = true;
state->response = m_parser.response();
}
}
cancel_all();
}
};
};
//------------------------------------------------------------------------------
HTTPClientBase* HTTPClientBase::New (Journal journal,
double timeoutSeconds, std::size_t messageLimitBytes, std::size_t bufferSize)
{
return new HTTPClientType (
journal, timeoutSeconds, messageLimitBytes, bufferSize);
}
//------------------------------------------------------------------------------
class HTTPClient_test : public unit_test::suite
{
public:
typedef boost::system::error_code error_code;
//--------------------------------------------------------------------------
class IoServiceThread : protected Thread
{
public:
explicit IoServiceThread (String name = "io_service")
: Thread (name)
{
}
~IoServiceThread ()
{
join ();
}
boost::asio::io_service& get_io_service ()
{
return m_service;
}
void start ()
{
startThread ();
}
void join ()
{
this->waitForThreadToExit ();
}
private:
void run ()
{
m_service.run ();
}
private:
boost::asio::io_service m_service;
};
//--------------------------------------------------------------------------
void print (HTTPMessage const& m)
{
for (int i = 0; i < m.headers().size(); ++i)
{
HTTPField const f (m.headers()[i]);
std::stringstream ss;
log <<
"[ '" << f.name() <<
"' , '" << f.value() + "' ]";
}
}
void print (HTTPClientBase::error_type error,
HTTPClientBase::value_type const& response)
{
if (error != 0)
{
log <<
"HTTPClient error: '" + error.message() << "'";
}
else if (! response.empty ())
{
log <<
"Status: " <<
String::fromNumber (response->status()).toStdString();
print (*response);
}
else
{
log <<
"HTTPClient: no response";
}
}
//--------------------------------------------------------------------------
void handle_get (HTTPClientBase::result_type result)
{
print (result.first, result.second);
}
void testSync (String const& s, double timeoutSeconds)
{
std::unique_ptr <HTTPClientBase> client (
HTTPClientBase::New (Journal(), timeoutSeconds));
HTTPClientBase::result_type const& result (
client->get (ParsedURL (s).url ()));
print (result.first, result.second);
}
void testAsync (String const& s, double timeoutSeconds)
{
IoServiceThread t;
std::unique_ptr <HTTPClientBase> client (
HTTPClientBase::New (Journal(), timeoutSeconds));
client->async_get (t.get_io_service (), ParsedURL (s).url (),
beast::bind (&HTTPClient_test::handle_get, this,
beast::_1));
t.start ();
t.join ();
}
//--------------------------------------------------------------------------
void run ()
{
testSync (
"http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference.html",
5);
testAsync (
"http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference.html",
5);
testAsync (
"https://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference.html",
5);
pass ();
}
};
BEAST_DEFINE_TESTSUITE_MANUAL(HTTPClient,beast_asio,beast);
}
}

View File

@@ -0,0 +1,68 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_HTTPCLIENTTYPE_H_INCLUDED
#define BEAST_ASIO_HTTPCLIENTTYPE_H_INCLUDED
#include <beast/asio/shared_handler.h>
#include <utility>
namespace beast {
namespace asio {
class HTTPClientBase
{
public:
typedef boost::system::error_code error_type;
typedef SharedPtr <HTTPResponse> value_type;
typedef std::pair <error_type, value_type> result_type;
static HTTPClientBase* New (
Journal journal = Journal(),
double timeoutSeconds = 30,
std::size_t messageLimitBytes = 256 * 1024,
std::size_t bufferSize = 16 * 1024);
/** Destroy the client.
This will cancel any pending i/o and block until all completion
handlers have been called.
*/
virtual ~HTTPClientBase () { }
virtual result_type get (URL const& url) = 0;
/** Perform an asynchronous get on the specified URL.
Handler will be called with this signature:
void (result_type)
*/
virtual void async_get (boost::asio::io_service& io_service,
URL const& url, asio::shared_handler <void (result_type)> handler) = 0;
/** Cancel all pending asynchronous operations. */
virtual void cancel() = 0;
/** Block until all asynchronous i/o completes. */
virtual void wait() = 0;
};
}
}
#endif

View File

@@ -0,0 +1,55 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast {
HTTPField::HTTPField ()
{
}
HTTPField::HTTPField (String name_, String value_)
: m_name (name_)
, m_value (value_)
{
}
HTTPField::HTTPField (HTTPField const& other)
: m_name (other.m_name)
, m_value (other.m_value)
{
}
HTTPField& HTTPField::operator= (HTTPField const& other)
{
m_name = other.m_name;
m_value = other.m_value;
return *this;
}
String HTTPField::name () const
{
return m_name;
}
String HTTPField::value () const
{
return m_value;
}
}

View File

@@ -0,0 +1,48 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_HTTPFIELD_H_INCLUDED
#define BEAST_ASIO_HTTPFIELD_H_INCLUDED
#include <beast/strings/String.h>
namespace beast {
/** A single header.
The header is a field/value pair.
Time complexity of copies is constant.
*/
class HTTPField
{
public:
HTTPField ();
HTTPField (String name_, String value_);
HTTPField (HTTPField const& other);
HTTPField& operator= (HTTPField const& other);
String name () const;
String value () const;
private:
String m_name;
String m_value;
};
}
#endif

View File

@@ -0,0 +1,89 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast {
HTTPHeaders::HTTPHeaders ()
{
}
HTTPHeaders::HTTPHeaders (StringPairArray& fields)
{
m_fields.swapWith (fields);
}
HTTPHeaders::HTTPHeaders (StringPairArray const& fields)
: m_fields (fields)
{
}
HTTPHeaders::HTTPHeaders (HTTPHeaders const& other)
: m_fields (other.m_fields)
{
}
HTTPHeaders& HTTPHeaders::operator= (HTTPHeaders const& other)
{
m_fields = other.m_fields;
return *this;
}
bool HTTPHeaders::empty () const
{
return m_fields.size () == 0;
}
std::size_t HTTPHeaders::size () const
{
return m_fields.size ();
}
HTTPField HTTPHeaders::at (int index) const
{
return HTTPField (m_fields.getAllKeys () [index],
m_fields.getAllValues () [index]);
}
HTTPField HTTPHeaders::operator[] (int index) const
{
return at (index);
}
String HTTPHeaders::get (String const& field) const
{
return m_fields [field];
}
String HTTPHeaders::operator[] (String const& field) const
{
return get (field);
}
String HTTPHeaders::toString () const
{
String s;
for (int i = 0; i < m_fields.size (); ++i)
{
HTTPField const field (at(i));
s << field.name() << ": " << field.value() << newLine;
}
return s;
}
}

View File

@@ -0,0 +1,79 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_HTTPHEADERS_H_INCLUDED
#define BEAST_ASIO_HTTPHEADERS_H_INCLUDED
#include <beast/module/asio/http/HTTPField.h>
#include <beast/module/core/text/StringPairArray.h>
namespace beast {
/** A set of HTTP headers. */
class HTTPHeaders
{
public:
/** Construct an empty set of headers. */
HTTPHeaders ();
/** Construct headers taking ownership of a field array.
The callers value is overwritten.
*/
HTTPHeaders (StringPairArray& fields);
/** Construct a copy of headers from an array.*/
HTTPHeaders (StringPairArray const& fields);
/** Construct a copy of headers. */
HTTPHeaders (HTTPHeaders const& other);
/** Assign a copy of headers. */
HTTPHeaders& operator= (HTTPHeaders const& other);
/** Returns `true` if the container is empty. */
bool empty () const;
/** Returns the number of fields in the container. */
std::size_t size () const;
/** Random access to fields by index. */
/** @{ */
HTTPField at (int index) const;
HTTPField operator[] (int index) const;
/** @} */
/** Associative access to fields by name.
If the field is not present, an empty string is returned.
*/
/** @{ */
String get (String const& field) const;
String operator[] (String const& field) const;
/** @} */
/** Outputs all the headers into one string. */
String toString () const;
private:
StringPairArray m_fields;
};
}
#endif

View File

@@ -0,0 +1,54 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast {
HTTPMessage::HTTPMessage (HTTPVersion const& version_,
StringPairArray& fields,
DynamicBuffer& body)
: m_version (version_)
, m_headers (fields)
{
m_body.swapWith (body);
}
HTTPVersion const& HTTPMessage::version () const
{
return m_version;
}
HTTPHeaders const& HTTPMessage::headers () const
{
return m_headers;
}
DynamicBuffer const& HTTPMessage::body () const
{
return m_body;
}
String HTTPMessage::toString () const
{
String s;
s << "HTTP " << version().toString() << newLine;
s << m_headers.toString ();
return s;
}
}

View File

@@ -0,0 +1,74 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_HTTPMESSAGE_H_INCLUDED
#define BEAST_ASIO_HTTPMESSAGE_H_INCLUDED
#include <beast/module/asio/http/HTTPHeaders.h>
#include <beast/module/asio/http/HTTPVersion.h>
#include <beast/smart_ptr/SharedObject.h>
#include <beast/net/DynamicBuffer.h>
#include <beast/module/core/text/StringPairArray.h>
namespace beast {
/** A complete HTTP message.
This provides the information common to all HTTP messages, including
the version, content body, and headers.
Derived classes provide the request or response specific data.
Because a single HTTP message can be a fairly expensive object to
make copies of, this is a SharedObject.
@see HTTPRequest, HTTPResponse
*/
class HTTPMessage : public SharedObject
{
public:
/** Construct the common HTTP message parts from values.
Ownership of the fields and body parameters are
transferred from the caller.
*/
HTTPMessage (HTTPVersion const& version_,
StringPairArray& fields,
DynamicBuffer& body);
/** Returns the HTTP version of this message. */
HTTPVersion const& version () const;
/** Returns the set of HTTP headers associated with this message. */
HTTPHeaders const& headers () const;
/** Returns the content-body. */
DynamicBuffer const& body () const;
/** Outputs all the HTTPMessage data excluding the body into a string. */
String toString () const;
private:
HTTPVersion m_version;
HTTPHeaders m_headers;
DynamicBuffer m_body;
};
}
#endif

View File

@@ -0,0 +1,108 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast {
HTTPParser::HTTPParser (Type type)
: m_type (type)
, m_impl (new HTTPParserImpl (
(type == typeResponse) ? joyent::HTTP_RESPONSE : joyent::HTTP_REQUEST))
{
}
HTTPParser::~HTTPParser ()
{
}
unsigned char HTTPParser::error () const
{
return m_impl->http_errno ();
}
String HTTPParser::message () const
{
return m_impl->http_errno_message ();
}
std::size_t HTTPParser::process (void const* buf, std::size_t bytes)
{
std::size_t const bytes_used (m_impl->process (buf, bytes));
if (m_impl->finished ())
{
if (m_type == typeRequest)
{
m_request = new HTTPRequest (
m_impl->version (),
m_impl->fields (),
m_impl->body (),
m_impl->method ());
}
else if (m_type == typeResponse)
{
m_response = new HTTPResponse (
m_impl->version (),
m_impl->fields (),
m_impl->body (),
m_impl->status_code ());
}
else
{
bassertfalse;
}
}
return bytes_used;
}
void HTTPParser::process_eof ()
{
m_impl->process_eof ();
}
bool HTTPParser::finished () const
{
return m_impl->finished();
}
StringPairArray const& HTTPParser::fields () const
{
return m_impl->fields();
}
bool HTTPParser::headersComplete () const
{
return m_impl->headers_complete();
}
SharedPtr <HTTPRequest> const& HTTPParser::request ()
{
bassert (m_type == typeRequest);
return m_request;
}
SharedPtr <HTTPResponse> const& HTTPParser::response ()
{
bassert (m_type == typeResponse);
return m_response;
}
}

View File

@@ -0,0 +1,92 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_HTTPPARSER_H_INCLUDED
#define BEAST_ASIO_HTTPPARSER_H_INCLUDED
#include <beast/module/asio/http/HTTPRequest.h>
#include <beast/module/asio/http/HTTPResponse.h>
namespace beast {
class HTTPParserImpl;
/** A parser for HTTPRequest and HTTPResponse objects. */
class HTTPParser
{
public:
enum Type
{
typeRequest,
typeResponse
};
/** Construct a new parser for the specified HTTPMessage type. */
explicit HTTPParser (Type type);
/** Destroy the parser. */
~HTTPParser ();
/** Returns a non zero error code if parsing fails. */
unsigned char error () const;
/** Returns the error message text when error is non zero. */
String message () const;
/** Parse the buffer and return the amount used.
Typically it is an error when this returns less than
the amount passed in.
*/
std::size_t process (void const* buf, std::size_t bytes);
/** Notify the parser that eof was received.
*/
void process_eof ();
/** Returns `true` when parsing is successful and complete. */
bool finished () const;
/** Peek at the header fields as they are being built.
Only complete pairs will show up, never partial strings.
*/
StringPairArray const& fields () const;
/** Returns `true` if all the HTTP headers have been received. */
bool headersComplete () const;
/** Return the HTTPRequest object produced from the parsiing.
Only valid after finished returns `true`.
*/
SharedPtr <HTTPRequest> const& request ();
/** Return the HTTPResponse object produced from the parsing.
Only valid after finished returns `true`.
*/
SharedPtr <HTTPResponse> const& response ();
protected:
Type m_type;
std::unique_ptr <HTTPParserImpl> m_impl;
SharedPtr <HTTPRequest> m_request;
SharedPtr <HTTPResponse> m_response;
};
}
#endif

View File

@@ -0,0 +1,273 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_HTTPPARSERIMPL_H_INCLUDED
#define BEAST_HTTPPARSERIMPL_H_INCLUDED
namespace beast {
class HTTPParserImpl
{
public:
enum
{
stringReservation = 256
};
explicit HTTPParserImpl (enum joyent::http_parser_type type)
: m_finished (false)
, m_was_value (false)
, m_headersComplete (false)
{
m_settings.on_message_begin = &HTTPParserImpl::on_message_begin;
m_settings.on_url = &HTTPParserImpl::on_url;
m_settings.on_status = &HTTPParserImpl::on_status;
m_settings.on_header_field = &HTTPParserImpl::on_header_field;
m_settings.on_header_value = &HTTPParserImpl::on_header_value;
m_settings.on_headers_complete = &HTTPParserImpl::on_headers_complete;
m_settings.on_body = &HTTPParserImpl::on_body;
m_settings.on_message_complete = &HTTPParserImpl::on_message_complete;
m_field.reserve (stringReservation);
m_value.reserve (stringReservation);
joyent::http_parser_init (&m_parser, type);
m_parser.data = this;
}
~HTTPParserImpl ()
{
}
unsigned char error () const
{
return m_parser.http_errno;
}
String message () const
{
return String (joyent::http_errno_name (static_cast <
enum joyent::http_errno> (m_parser.http_errno)));
}
std::size_t process (void const* buf, std::size_t bytes)
{
return joyent::http_parser_execute (&m_parser,
&m_settings, static_cast <char const*> (buf), bytes);
}
void process_eof ()
{
joyent::http_parser_execute (&m_parser, &m_settings, nullptr, 0);
}
bool finished () const
{
return m_finished;
}
HTTPVersion version () const
{
return HTTPVersion (
m_parser.http_major, m_parser.http_minor);
}
// Only for HTTPResponse!
unsigned short status_code () const
{
return m_parser.status_code;
}
// Only for HTTPRequest!
unsigned char method () const
{
return m_parser.method;
}
unsigned char http_errno () const
{
return m_parser.http_errno;
}
String http_errno_message () const
{
return String (joyent::http_errno_name (
static_cast <enum joyent::http_errno> (
m_parser.http_errno)));
}
bool upgrade () const
{
return m_parser.upgrade != 0;
}
StringPairArray& fields ()
{
return m_fields;
}
bool headers_complete () const
{
return m_headersComplete;
}
DynamicBuffer& body ()
{
return m_body;
}
private:
void addFieldValue ()
{
if (m_field.size () > 0 && m_value.size () > 0)
m_fields.set (m_field, m_value);
m_field.resize (0);
m_value.resize (0);
}
int onMessageBegin ()
{
int ec (0);
return ec;
}
int onUrl (char const*, std::size_t)
{
int ec (0);
// This is for HTTP Request
return ec;
}
int onStatus ()
{
int ec (0);
return ec;
}
int onHeaderField (char const* at, std::size_t length)
{
int ec (0);
if (m_was_value)
{
addFieldValue ();
m_was_value = false;
}
m_field.append (at, length);
return ec;
}
int onHeaderValue (char const* at, std::size_t length)
{
int ec (0);
m_value.append (at, length);
m_was_value = true;
return ec;
}
int onHeadersComplete ()
{
m_headersComplete = true;
int ec (0);
addFieldValue ();
return ec;
}
int onBody (char const* at, std::size_t length)
{
m_body.commit (boost::asio::buffer_copy (
m_body.prepare <boost::asio::mutable_buffer> (length),
boost::asio::buffer (at, length)));
return 0;
}
int onMessageComplete ()
{
int ec (0);
m_finished = true;
return ec;
}
private:
static int on_message_begin (joyent::http_parser* parser)
{
return static_cast <HTTPParserImpl*> (parser->data)->
onMessageBegin ();
}
static int on_url (joyent::http_parser* parser, const char *at, size_t length)
{
return static_cast <HTTPParserImpl*> (parser->data)->
onUrl (at, length);
}
static int on_status (joyent::http_parser* parser,
char const* /*at*/, size_t /*length*/)
{
return static_cast <HTTPParserImpl*> (parser->data)->
onStatus ();
}
static int on_header_field (joyent::http_parser* parser,
const char *at, size_t length)
{
return static_cast <HTTPParserImpl*> (parser->data)->
onHeaderField (at, length);
}
static int on_header_value (joyent::http_parser* parser,
const char *at, size_t length)
{
return static_cast <HTTPParserImpl*> (parser->data)->
onHeaderValue (at, length);
}
static int on_headers_complete (joyent::http_parser* parser)
{
return static_cast <HTTPParserImpl*> (parser->data)->
onHeadersComplete ();
}
static int on_body (joyent::http_parser* parser,
const char *at, size_t length)
{
return static_cast <HTTPParserImpl*> (parser->data)->
onBody (at, length);
}
static int on_message_complete (joyent::http_parser* parser)
{
return static_cast <HTTPParserImpl*> (parser->data)->
onMessageComplete ();
}
private:
bool m_finished;
joyent::http_parser_settings m_settings;
joyent::http_parser m_parser;
StringPairArray m_fields;
bool m_was_value;
std::string m_field;
std::string m_value;
bool m_headersComplete;
DynamicBuffer m_body;
};
}
#endif

View File

@@ -0,0 +1,45 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast {
HTTPRequest::HTTPRequest (
HTTPVersion const& version_,
StringPairArray& fields,
DynamicBuffer& body,
unsigned short method_)
: HTTPMessage (version_, fields, body)
, m_method (method_)
{
}
unsigned short HTTPRequest::method () const
{
return m_method;
}
String HTTPRequest::toString () const
{
String s;
s << "Method: " << String::fromNumber (method ()) << newLine;
s << this->HTTPMessage::toString ();
return s;
}
}

View File

@@ -0,0 +1,51 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_HTTPREQUEST_H_INCLUDED
#define BEAST_ASIO_HTTPREQUEST_H_INCLUDED
#include <beast/module/asio/http/HTTPMessage.h>
namespace beast {
class HTTPRequest : public HTTPMessage
{
public:
/** Construct a complete response from values.
Ownership of the fields and body parameters are
transferred from the caller.
*/
HTTPRequest (
HTTPVersion const& version_,
StringPairArray& fields,
DynamicBuffer& body,
unsigned short method_);
unsigned short method () const;
/** Convert the request into a string, excluding the body. */
String toString () const;
private:
unsigned short m_method;
};
}
#endif

View File

@@ -0,0 +1,38 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
//#include "HTTPRequestParser.h"
namespace beast {
HTTPRequestParser::HTTPRequestParser ()
: HTTPParser (typeRequest)
{
}
HTTPRequestParser::~HTTPRequestParser ()
{
}
SharedPtr <HTTPRequest> const& HTTPRequestParser::request ()
{
return m_request;
}
}

View File

@@ -0,0 +1,46 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_HTTP_REQUESTPARSER_H_INCLUDED
#define BEAST_HTTP_REQUESTPARSER_H_INCLUDED
#include <beast/module/asio/http/HTTPParser.h>
namespace beast {
/** A parser for HTTPRequest objects. */
class HTTPRequestParser : public HTTPParser
{
public:
/** Construct a new parser for the specified HTTPMessage type. */
HTTPRequestParser ();
/** Destroy the parser. */
~HTTPRequestParser ();
/** Return the HTTPRequest object produced from the parsing. */
SharedPtr <HTTPRequest> const& request ();
private:
//SharedPtr <HTTPRequest> m_request;
};
}
#endif

View File

@@ -0,0 +1,45 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast {
HTTPResponse::HTTPResponse (
HTTPVersion const& version_,
StringPairArray& fields,
DynamicBuffer& body,
unsigned short status_)
: HTTPMessage (version_, fields, body)
, m_status (status_)
{
}
unsigned short HTTPResponse::status () const
{
return m_status;
}
String HTTPResponse::toString () const
{
String s;
s << "Status: " << String::fromNumber (status ()) << newLine;
s << this->HTTPMessage::toString ();
return s;
}
}

View File

@@ -0,0 +1,49 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_HTTPRESPONSE_H_INCLUDED
#define BEAST_ASIO_HTTPRESPONSE_H_INCLUDED
namespace beast {
class HTTPResponse : public HTTPMessage
{
public:
/** Construct a complete response from values.
Ownership of the fields and body parameters are
transferred from the caller.
*/
HTTPResponse (
HTTPVersion const& version_,
StringPairArray& fields,
DynamicBuffer& body,
unsigned short status_);
unsigned short status () const;
/** Convert the response into a string, excluding the body. */
String toString () const;
private:
unsigned short m_status;
};
}
#endif

View File

@@ -0,0 +1,38 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
//#include "HTTPResponseParser.h"
namespace beast {
HTTPResponseParser::HTTPResponseParser ()
: HTTPParser (typeResponse)
{
}
HTTPResponseParser::~HTTPResponseParser ()
{
}
SharedPtr <HTTPResponse> const& HTTPResponseParser::response ()
{
return m_response;
}
}

View File

@@ -0,0 +1,46 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_HTTP_RESPONSEPARSER_H_INCLUDED
#define BEAST_HTTP_RESPONSEPARSER_H_INCLUDED
#include <beast/module/asio/http/HTTPParser.h>
namespace beast {
/** A parser for HTTPResponse objects. */
class HTTPResponseParser : public HTTPParser
{
public:
/** Construct a new parser for the specified HTTPMessage type. */
HTTPResponseParser ();
/** Destroy the parser. */
~HTTPResponseParser ();
/** Return the HTTPResponse object produced from the parsing. */
SharedPtr <HTTPResponse> const& response ();
private:
//SharedPtr <HTTPResponse> m_response;
};
}
#endif

View File

@@ -0,0 +1,97 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast {
HTTPVersion::HTTPVersion ()
: m_major (0)
, m_minor (0)
{
}
HTTPVersion::HTTPVersion (unsigned short major_, unsigned short minor_)
: m_major (major_)
, m_minor (minor_)
{
}
HTTPVersion::HTTPVersion (HTTPVersion const& other)
: m_major (other.m_major)
, m_minor (other.m_minor)
{
}
HTTPVersion& HTTPVersion::operator= (HTTPVersion const& other)
{
m_major = other.m_major;
m_minor = other.m_minor;
return *this;
}
String HTTPVersion::toString () const
{
return String::fromNumber (vmajor ()) + "." +
String::fromNumber (vminor ());
}
unsigned short HTTPVersion::vmajor () const
{
return m_major;
}
unsigned short HTTPVersion::vminor () const
{
return m_minor;
}
bool HTTPVersion::operator== (HTTPVersion const& rhs) const
{
return (m_major == rhs.m_major) && (m_minor == rhs.m_minor);
}
bool HTTPVersion::operator!= (HTTPVersion const& rhs) const
{
return (m_major != rhs.m_major) || (m_minor != rhs.m_minor);
}
bool HTTPVersion::operator> (HTTPVersion const& rhs) const
{
return (m_major > rhs.m_major) ||
((m_major == rhs.m_major) && (m_minor > rhs.m_minor));
}
bool HTTPVersion::operator>= (HTTPVersion const& rhs) const
{
return (m_major > rhs.m_major) ||
((m_major == rhs.m_major) && (m_minor >= rhs.m_minor));
}
bool HTTPVersion::operator< (HTTPVersion const& rhs) const
{
return (m_major < rhs.m_major) ||
((m_major == rhs.m_major) && (m_minor < rhs.m_minor));
}
bool HTTPVersion::operator<= (HTTPVersion const& rhs) const
{
return (m_major < rhs.m_major) ||
((m_major == rhs.m_major) && (m_minor <= rhs.m_minor));
}
}

View File

@@ -0,0 +1,50 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_HTTPVERSION_H_INCLUDED
#define BEAST_ASIO_HTTPVERSION_H_INCLUDED
namespace beast {
/** The HTTP version. This is the major.minor version number. */
class HTTPVersion
{
public:
HTTPVersion ();
HTTPVersion (unsigned short major_, unsigned short minor_);
HTTPVersion (HTTPVersion const& other);
HTTPVersion& operator= (HTTPVersion const& other);
String toString () const;
unsigned short vmajor () const;
unsigned short vminor () const;
bool operator== (HTTPVersion const& rhs) const;
bool operator!= (HTTPVersion const& rhs) const;
bool operator> (HTTPVersion const& rhs) const;
bool operator>= (HTTPVersion const& rhs) const;
bool operator< (HTTPVersion const& rhs) const;
bool operator<= (HTTPVersion const& rhs) const;
private:
unsigned short m_major;
unsigned short m_minor;
};
}
#endif

View File

@@ -0,0 +1,147 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_HANDSHAKE_HANDSHAKEDETECTLOGIC_H_INCLUDED
#define BEAST_ASIO_HANDSHAKE_HANDSHAKEDETECTLOGIC_H_INCLUDED
namespace beast {
namespace asio {
class HandshakeDetectLogic
{
public:
HandshakeDetectLogic ()
: m_finished (false)
, m_success (false)
{
}
/** How many bytes maximum we might need.
This is the largest number of bytes that the detector
might need in order to come to a conclusion about
whether or not the handshake is a match. Depending
on the data, it could come to that conclusion sooner
though.
Use read_some instead of read so that the detect logic
can reject the handshake sooner if possible.
*/
virtual std::size_t max_needed () = 0;
/** How many bytes the handshake consumes.
If the detector processes the entire handshake this will
be non zero. The SSL detector would return 0, since we
want all the existing bytes to be passed on.
*/
virtual std::size_t bytes_consumed () = 0;
/** Return true if we have enough data to form a conclusion.
*/
bool finished () const noexcept
{
return m_finished;
}
/** Return true if we came to a conclusion and the data matched.
*/
bool success () const noexcept
{
return m_finished && m_success;
}
protected:
void conclude (bool success = true)
{
m_finished = true;
m_success = success;
}
void fail ()
{
conclude (false);
}
private:
bool m_finished;
bool m_success;
};
//------------------------------------------------------------------------------
/** Wraps the logic and exports it as an abstract interface.
*/
template <typename Logic>
class HandshakeDetectLogicType
{
public:
typedef Logic LogicType;
typedef typename Logic::arg_type arg_type;
explicit HandshakeDetectLogicType (arg_type const& arg = arg_type ())
: m_logic (arg)
{
}
LogicType& get ()
{
return m_logic;
}
std::size_t max_needed ()
{
return m_logic.max_needed ();
}
std::size_t bytes_consumed ()
{
return m_logic.bytes_consumed ();
}
bool finished ()
{
return m_logic.finished ();
}
/** If finished is true, this tells us if the handshake was detected.
*/
bool success ()
{
return m_logic.success ();
}
/** Analyze the buffer to match the Handshake.
Returns `true` if the analysis is complete.
*/
template <typename ConstBufferSequence>
bool analyze (ConstBufferSequence const& buffer)
{
bassert (! m_logic.finished ());
m_logic.analyze (buffer);
return m_logic.finished ();
}
private:
Logic m_logic;
};
}
}
#endif

View File

@@ -0,0 +1,24 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast {
namespace asio {
}
}

View File

@@ -0,0 +1,168 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_HANDSHAKE_HANDSHAKEDETECTLOGICPROXY_H_INCLUDED
#define BEAST_ASIO_HANDSHAKE_HANDSHAKEDETECTLOGICPROXY_H_INCLUDED
#include <beast/module/asio/protocol/HandshakeDetectLogic.h>
#include <beast/module/asio/protocol/InputParser.h>
namespace beast {
namespace asio {
/** Handshake detector for the PROXY protcol
http://haproxy.1wt.eu/download/1.5/doc/proxy-protocol.txt
*/
class HandshakeDetectLogicPROXY : public HandshakeDetectLogic
{
public:
typedef int arg_type;
enum
{
// This is for version 1. The largest number of bytes
// that we could possibly need to parse a valid handshake.
// We will reject it much sooner if there's an illegal value.
//
maxBytesNeeded = 107 // including CRLF, no null term
};
struct ProxyInfo
{
typedef InputParser::IPv4Address IPv4Address;
String protocol; // "TCP4", "TCP6", "UNKNOWN"
IPv4Address sourceAddress;
IPv4Address destAddress;
std::uint16_t sourcePort;
std::uint16_t destPort;
};
explicit HandshakeDetectLogicPROXY (arg_type const&)
: m_consumed (0)
{
}
ProxyInfo const& getInfo () const noexcept
{
return m_info;
}
std::size_t max_needed ()
{
return maxBytesNeeded;
}
std::size_t bytes_consumed ()
{
return m_consumed;
}
template <typename ConstBufferSequence>
void analyze (ConstBufferSequence const& buffer)
{
FixedInputBufferSize <maxBytesNeeded> in (buffer);
InputParser::State state;
analyze_input (in, state);
if (state.passed ())
{
m_consumed = in.used ();
conclude (true);
}
else if (state.failed ())
{
conclude (false);
}
}
void analyze_input (FixedInputBuffer& in, InputParser::State& state)
{
using namespace InputParser;
if (! match (in, "PROXY ", state))
return;
if (match (in, "TCP4 "))
{
m_info.protocol = "TCP4";
if (! read (in, m_info.sourceAddress, state))
return;
if (! match (in, " ", state))
return;
if (! read (in, m_info.destAddress, state))
return;
if (! match (in, " ", state))
return;
UInt16Str sourcePort;
if (! read (in, sourcePort, state))
return;
m_info.sourcePort = sourcePort.value;
if (! match (in, " ", state))
return;
UInt16Str destPort;
if (! read (in, destPort, state))
return;
m_info.destPort = destPort.value;
if (! match (in, "\r\n", state))
return;
state = State::pass;
return;
}
else if (match (in, "TCP6 "))
{
m_info.protocol = "TCP6";
state = State::fail;
return;
}
else if (match (in, "UNKNOWN "))
{
m_info.protocol = "UNKNOWN";
state = State::fail;
return;
}
state = State::fail;
}
private:
std::size_t m_consumed;
ProxyInfo m_info;
};
}
}
#endif

View File

@@ -0,0 +1,114 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_HANDSHAKE_HANDSHAKEDETECTLOGICSSL2_H_INCLUDED
#define BEAST_ASIO_HANDSHAKE_HANDSHAKEDETECTLOGICSSL2_H_INCLUDED
namespace beast {
namespace asio {
// Handshake for SSL 2
//
// http://tools.ietf.org/html/rfc5246#appendix-E.2
//
// std::uint8_t V2CipherSpec[3];
// struct {
// std::uint16_t msg_length;
// std::uint8_t msg_type;
// Version version; Should be 'ProtocolVersion'?
// std::uint16_t cipher_spec_length;
// std::uint16_t session_id_length;
// std::uint16_t challenge_length;
// ...
//
class HandshakeDetectLogicSSL2 : public HandshakeDetectLogic
{
public:
typedef int arg_type;
explicit HandshakeDetectLogicSSL2 (arg_type const&)
{
}
enum
{
bytesNeeded = 3
};
std::size_t max_needed ()
{
return bytesNeeded;
}
std::size_t bytes_consumed ()
{
return 0;
}
template <typename ConstBufferSequence>
void analyze (ConstBufferSequence const& buffer)
{
FixedInputBufferSize <bytesNeeded> in (buffer);
{
std::uint8_t byte;
if (! in.peek (&byte))
return;
// First byte must have the high bit set
//
if((byte & 0x80) != 0x80)
return fail ();
}
// The remaining bits contain the
// length of the following data in bytes.
//
std::uint16_t msg_length;
if (! in.readNetworkInteger(&msg_length))
return;
// sizeof (msg_type +
// Version (ProtcolVersion?) +
// cipher_spec_length +
// session_id_length +
// challenge_length)
//
// Should be 9 or greater.
//
if (msg_length < 9)
return fail ();
std::uint8_t msg_type;
if (! in.read (&msg_type))
return;
// The msg_type must be 0x01 for a version 2 ClientHello
//
if (msg_type != 0x01)
return fail ();
conclude ();
}
};
}
}
#endif

View File

@@ -0,0 +1,88 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_HANDSHAKE_HANDSHAKEDETECTLOGICSSL3_H_INCLUDED
#define BEAST_ASIO_HANDSHAKE_HANDSHAKEDETECTLOGICSSL3_H_INCLUDED
namespace beast {
namespace asio {
// Handshake for SSL 3 (Also TLS 1.0 and 1.1)
//
// http://www.ietf.org/rfc/rfc2246.txt
//
// Section 7.4. Handshake protocol
//
class HandshakeDetectLogicSSL3 : public HandshakeDetectLogic
{
public:
typedef int arg_type; // dummy
explicit HandshakeDetectLogicSSL3 (arg_type const&)
{
}
enum
{
bytesNeeded = 6
};
std::size_t max_needed ()
{
return bytesNeeded;
}
std::size_t bytes_consumed ()
{
return 0;
}
template <typename ConstBufferSequence>
void analyze (ConstBufferSequence const& buffer)
{
std::uint16_t version;
FixedInputBufferSize <bytesNeeded> in (buffer);
std::uint8_t msg_type;
if (! in.read (&msg_type))
return;
// msg_type must be 0x16 = "SSL Handshake"
//
if (msg_type != 0x16)
return fail ();
if (! in.read (&version))
return;
version = fromNetworkByteOrder (version);
std::uint16_t length;
if (! in.read (&length))
return;
length = fromNetworkByteOrder (length);
conclude ();
}
};
}
}
#endif

View File

@@ -0,0 +1,219 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_HANDSHAKE_HANDSHAKEDETECTOR_H_INCLUDED
#define BEAST_ASIO_HANDSHAKE_HANDSHAKEDETECTOR_H_INCLUDED
#include <beast/boost/get_pointer.h>
#include <beast/asio/bind_handler.h>
#include <beast/asio/wrap_handler.h>
#include <beast/asio/placeholders.h>
#include <beast/asio/shared_handler.h>
#include <boost/asio/detail/handler_cont_helpers.hpp>
namespace beast {
namespace asio {
/** A wrapper to decode the handshake data on a Stream.
Stream must meet these requirements
For detect:
SyncReadStream
For async_detect:
AsyncReadStream
Logic must meet this requirement:
HandshakeDetectLogic
*/
template <typename Stream, typename Logic>
class HandshakeDetectorType
{
protected:
typedef boost::system::error_code error_code;
public:
Logic& getLogic ()
{
return m_logic.get ();
}
//--------------------------------------------------------------------------
/** Synchronous handshake detect.
The bytes from the input sequence in the specified buffer
are used first.
*/
template <typename Allocator>
error_code detect (Stream& stream,
boost::asio::basic_streambuf <Allocator>& buffer)
{
typedef boost::asio::basic_streambuf <Allocator> BuffersType;
error_code ec;
do
{
m_logic.analyze (buffer.data ());
if (m_logic.finished ())
{
// consume what we used (for SSL its 0)
std::size_t const consumed = m_logic.bytes_consumed ();
bassert (consumed <= buffer.size ());
buffer.consume (consumed);
break;
}
std::size_t const available = buffer.size ();
std::size_t const needed = m_logic.max_needed ();
// If postcondition fails, loop will never end
if (meets_postcondition (available < needed))
{
typename BuffersType::mutable_buffers_type buffers (
buffer.prepare (needed - available));
buffer.commit (stream.read_some (buffers, ec));
}
}
while (! ec);
return ec;
}
//--------------------------------------------------------------------------
/** Asynchronous handshake detect.
The bytes from the input sequence in the specified buffer
are used first.
DetectHandler must have this signature:
void(error_code)
*/
template <typename Allocator>
void async_detect (Stream& stream,
boost::asio::basic_streambuf <Allocator>& buffer,
asio::shared_handler <void(error_code)> handler)
{
typedef AsyncOp <Allocator> Op;
auto const op (std::make_shared <Op> (std::ref (m_logic),
std::ref (stream), std::ref (buffer), std::cref (handler)));
//op->start();
stream.get_io_service().post (asio::wrap_handler (std::bind (
&Op::start, op), handler));
}
private:
template <typename Allocator>
class AsyncOp
: public std::enable_shared_from_this <AsyncOp <Allocator>>
{
public:
typedef boost::asio::basic_streambuf <Allocator> BuffersType;
AsyncOp (HandshakeDetectLogicType <Logic>& logic, Stream& stream,
BuffersType& buffer, asio::shared_handler <
void(error_code)> const& handler)
: m_logic (logic)
, m_stream (stream)
, m_buffer (buffer)
, m_handler (handler)
, m_continuation (false)
{
}
// Set breakpoint to prove it gets destroyed
~AsyncOp ()
{
}
void start()
{
async_read_some (error_code(), 0);
}
void on_read (error_code ec, size_t bytes_transferred)
{
m_continuation = true;
async_read_some (ec, bytes_transferred);
}
void async_read_some (error_code ec, size_t bytes_transferred)
{
if (! ec)
{
m_buffer.commit (bytes_transferred);
m_logic.analyze (m_buffer.data ());
if (!m_logic.finished ())
{
std::size_t const available = m_buffer.size ();
std::size_t const needed = m_logic.max_needed ();
// If postcondition fails, loop will never end
if (meets_postcondition (available < needed))
{
typename BuffersType::mutable_buffers_type buffers (
m_buffer.prepare (needed - available));
m_stream.async_read_some (buffers, asio::wrap_handler (
std::bind (&AsyncOp <Allocator>::on_read,
this->shared_from_this(), asio::placeholders::error,
asio::placeholders::bytes_transferred),
m_handler, m_continuation));
}
return;
}
std::size_t const consumed = m_logic.bytes_consumed ();
m_buffer.consume (consumed);
}
// Finalize with a call to the original handler.
if (m_continuation)
{
m_handler (ec);
return;
}
// Post, otherwise we would call the
// handler from the initiating function.
m_stream.get_io_service ().post (asio::bind_handler (
m_handler, ec));
}
private:
HandshakeDetectLogicType <Logic>& m_logic;
Stream& m_stream;
BuffersType& m_buffer;
asio::shared_handler <void(error_code)> m_handler;
bool m_continuation;
};
private:
HandshakeDetectLogicType <Logic> m_logic;
};
}
}
#endif

View File

@@ -0,0 +1,392 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_HANDSHAKE_INPUTPARSER_H_INCLUDED
#define BEAST_ASIO_HANDSHAKE_INPUTPARSER_H_INCLUDED
#include <beast/module/asio/basics/FixedInputBuffer.h>
namespace beast {
namespace asio {
namespace InputParser {
/** Tri-valued parsing state.
This is convertible to bool which means continue.
Or you can use stop() to decide if you should return.
After a stop you can use failed () to determine if parsing failed.
*/
struct State
{
enum State_t
{
pass, // passed the parse
fail, // failed the parse
more // didn't fail but need more bytes
};
State () : m_state (more) { }
State (State_t state) : m_state (state) { }
/** Implicit construction from bool.
If condition is true then the parse passes, else need more.
*/
State (bool condition) : m_state (condition ? pass : more) { }
State& operator= (State_t state) { m_state = state; return *this; }
bool eof () const noexcept { return m_state == more; }
bool stop () const noexcept { return m_state != pass; }
bool passed () const noexcept { return m_state == pass; }
bool failed () const noexcept { return m_state == fail; }
explicit operator bool() const noexcept { return m_state == pass; }
private:
State_t m_state;
};
//------------------------------------------------------------------------------
// Shortcut to save typing.
typedef FixedInputBuffer& Input;
/** Specializations implement the get() function. */
template <class T>
struct Get;
/** Specializations implement the match() function.
Default implementation of match tries to read it into a local.
*/
template <class T>
struct Match
{
static State func (Input in, T other)
{
T t;
State state = Get <T>::func (in, t);
if (state.passed ())
{
if (t == other)
return State::pass;
return State::fail;
}
return state;
}
};
/** Specializations implement the peek() function.
Default implementation of peek reads and rewinds.
*/
template <class T>
struct Peek
{
static State func (Input in, T& t)
{
Input dup (in);
return Get <T>::func (dup, t);
}
};
//------------------------------------------------------------------------------
//
// Free Functions
//
//------------------------------------------------------------------------------
// match a block of data in memory
//
static State match_buffer (Input in, void const* buffer, std::size_t bytes)
{
bassert (bytes > 0);
if (in.size () <= 0)
return State::more;
std::size_t const have = std::min (in.size (), bytes);
void const* data = in.peek (have);
bassert (data != nullptr);
int const compare = memcmp (data, buffer, have);
if (compare != 0)
return State::fail;
in.consume (have);
return have == bytes;
}
//------------------------------------------------------------------------------
//
// match
//
// Returns the state
template <class T>
State match (Input in, T t)
{
return Match <T>::func (in, t);
}
// Stores the state in the argument and returns true if its a pass
template <class T>
bool match (Input in, T t, State& state)
{
return (state = match (in, t)).passed ();
}
//------------------------------------------------------------------------------
//
// peek
//
// Returns the state
template <class T>
State peek (Input in, T& t)
{
return Peek <T>::func (in, t);
}
// Stores the state in the argument and returns true if its a pass
template <class T>
bool peek (Input in, T& t, State& state)
{
return (state = peek (in, t)).passed ();
}
//------------------------------------------------------------------------------
//
// read
//
// Returns the state
template <class T>
State read (Input in, T& t)
{
return Get <T>::func (in, t);
}
// Stores the state in the argument and returns true if its a pass
template <class T>
bool read (Input in, T& t, State& state)
{
return (state = read (in, t)).passed ();
}
//------------------------------------------------------------------------------
//
// Specializations for basic types
//
template <>
struct Match <char const*>
{
static State func (Input in, char const* text)
{
return InputParser::match_buffer (in, text, strlen (text));
}
};
//------------------------------------------------------------------------------
//
// Special types and their specializations
//
struct Digit
{
int value;
};
template <>
struct Get <Digit>
{
static State func (Input in, Digit& t)
{
char c;
if (! in.peek (&c))
return State::more;
if (! std::isdigit (c))
return State::fail;
in.consume (1);
t.value = c - '0';
return State::pass;
}
};
//------------------------------------------------------------------------------
// An unsigned 32 bit number expressed as a string
struct UInt32Str
{
std::uint32_t value;
};
template <>
struct Get <UInt32Str>
{
static State func (Input in, UInt32Str& t)
{
State state;
std::uint32_t value (0);
Digit digit;
// have to have at least one digit
if (! read (in, digit, state))
return state;
value = digit.value;
for (;;)
{
state = peek (in, digit);
if (state.failed ())
{
t.value = value;
return State::pass;
}
else if (state.eof ())
{
t.value = value;
return state;
}
// can't have a digit following a zero
if (value == 0)
return State::fail;
std::uint32_t newValue = (value * 10) + digit.value;
// overflow
if (newValue < value)
return State::fail;
value = newValue;
}
return State::fail;
}
};
//------------------------------------------------------------------------------
// An unsigned 16 bit number expressed as a string
struct UInt16Str
{
std::uint16_t value;
};
template <>
struct Get <UInt16Str>
{
static State func (Input in, UInt16Str& t)
{
UInt32Str v;
State state = read (in, v);
if (state.passed ())
{
if (v.value <= 65535)
{
t.value = std::uint16_t(v.value);
return State::pass;
}
return State::fail;
}
return state;
}
};
//------------------------------------------------------------------------------
// An unsigned 8 bit number expressed as a string
struct UInt8Str
{
std::uint8_t value;
};
template <>
struct Get <UInt8Str>
{
static State func (Input in, UInt8Str& t)
{
UInt32Str v;
State state = read (in, v);
if (state.passed ())
{
if (v.value <= 255)
{
t.value = std::uint8_t(v.value);
return State::pass;
}
return State::fail;
}
return state;
}
};
//------------------------------------------------------------------------------
// An dotted IPv4 address
struct IPv4Address
{
std::uint8_t value [4];
String toString () const
{
return String::fromNumber <int> (value [0]) + "." +
String::fromNumber <int> (value [1]) + "." +
String::fromNumber <int> (value [2]) + "." +
String::fromNumber <int> (value [3]);
}
};
template <>
struct Get <IPv4Address>
{
static State func (Input in, IPv4Address& t)
{
State state;
UInt8Str digit [4];
if (! read (in, digit [0], state))
return state;
if (! match (in, ".", state))
return state;
if (! read (in, digit [1], state))
return state;
if (! match (in, ".", state))
return state;
if (! read (in, digit [2], state))
return state;
if (! match (in, ".", state))
return state;
if (! read (in, digit [3], state))
return state;
t.value [0] = digit [0].value;
t.value [1] = digit [1].value;
t.value [2] = digit [2].value;
t.value [3] = digit [3].value;
return State::pass;
}
};
}
}
}
#endif

View File

@@ -0,0 +1,204 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_HANDSHAKE_PREFILLEDREADSTREAM_H_INCLUDED
#define BEAST_ASIO_HANDSHAKE_PREFILLEDREADSTREAM_H_INCLUDED
#include <beast/cxx14/type_traits.h> // <type_traits>
#include <utility>
namespace beast {
namespace asio {
/** Front-ends a stream with a provided block of data.
When read operations are performed on this object, bytes will first be
returned from the buffer provided on construction. When those bytes
are exhausted, read operations will then pass through to the underlying
stream.
Write operations are all simply passed through.
*/
template <class Stream>
class PrefilledReadStream : public Uncopyable
{
protected:
typedef boost::system::error_code error_code;
static void throw_if (error_code const& ec)
{
throw boost::system::system_error (ec);
}
public:
typedef std::remove_reference_t <Stream> next_layer_type;
typedef typename next_layer_type::lowest_layer_type lowest_layer_type;
/** Single argument constructor for when we are wrapped in something.
arg is passed through to the next layer's constructor.
*/
template <class Arg>
explicit PrefilledReadStream (Arg& arg)
: m_next_layer (arg)
{
}
/** Construct with the buffer, and argument passed through.
This creates a copy of the data. The argument is passed through
to the constructor of Stream.
*/
template <class Arg, class ConstBufferSequence>
PrefilledReadStream (Arg& arg, ConstBufferSequence const& buffers)
: m_next_layer (arg)
{
fill (buffers);
}
/** Place some input into the prefilled buffer.
Note that this is in no way thread safe. The only reason this function
is here is for the case when you can't pass the buffer through the
constructor because there is another object wrapping this stream.
*/
template <class ConstBufferSequence>
void fill (ConstBufferSequence const& buffers)
{
// We don't assume the caller's buffers will
// remain valid for the lifetime of this object.
//
m_buffer.commit (boost::asio::buffer_copy (
m_buffer.prepare (boost::asio::buffer_size (buffers)),
buffers));
}
next_layer_type& next_layer()
{
return m_next_layer;
}
next_layer_type const& next_layer() const
{
return m_next_layer;
}
lowest_layer_type& lowest_layer()
{
return m_next_layer.lowest_layer();
}
const lowest_layer_type& lowest_layer() const
{
return m_next_layer.lowest_layer();
}
boost::asio::io_service& get_io_service()
{
return m_next_layer.get_io_service();
}
void close()
{
error_code ec;
close (ec);
throw_if (ec);
}
error_code close (error_code& ec)
{
// VFALCO NOTE This is questionable. We can't
// call m_next_layer.close() because Stream might not
// support that function. For example, ssl::stream has no close()
//
return lowest_layer ().close(ec);
}
template <class MutableBufferSequence>
std::size_t read_some (MutableBufferSequence const& buffers)
{
error_code ec;
std::size_t const amount = read_some (buffers, ec);
throw_if (ec);
return amount;
}
template <class MutableBufferSequence>
std::size_t read_some (MutableBufferSequence const& buffers,
error_code& ec)
{
if (m_buffer.size () > 0)
{
ec = error_code ();
std::size_t const bytes_transferred = boost::asio::buffer_copy (
buffers, m_buffer.data ());
m_buffer.consume (bytes_transferred);
return bytes_transferred;
}
return m_next_layer.read_some (buffers, ec);
}
template <class ConstBufferSequence>
std::size_t write_some (ConstBufferSequence const& buffers)
{
error_code ec;
auto const amount (write_some (buffers, ec));
throw_if (ec);
return amount;
}
template <class ConstBufferSequence>
std::size_t write_some (ConstBufferSequence const& buffers,
error_code& ec)
{
return m_next_layer.write_some (buffers, ec);
}
template <class MutableBufferSequence, class ReadHandler>
void async_read_some (MutableBufferSequence const& buffers,
ReadHandler&& handler)
{
if (m_buffer.size () > 0)
{
auto const bytes_transferred (boost::asio::buffer_copy (
buffers, m_buffer.data ()));
m_buffer.consume (bytes_transferred);
get_io_service ().post (bind_handler (
std::forward <ReadHandler> (handler),
error_code (), bytes_transferred));
return;
}
m_next_layer.async_read_some (buffers,
std::forward <ReadHandler> (handler));
}
template <class ConstBufferSequence, class WriteHandler>
void async_write_some (ConstBufferSequence const& buffers,
WriteHandler&& handler)
{
m_next_layer.async_write_some (buffers,
std::forward <WriteHandler> (handler));
}
private:
Stream m_next_layer;
boost::asio::streambuf m_buffer;
};
}
}
#endif

View File

@@ -0,0 +1,60 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_SYSTEM_BOOSTINCLUDES_H_INCLUDED
#define BEAST_ASIO_SYSTEM_BOOSTINCLUDES_H_INCLUDED
// Make sure we take care of fixing boost::bind oddities first.
#if !defined(BEAST_CORE_H_INCLUDED)
#error core.h must be included before including this file
#endif
// These should have already been set in your project, but
// if you forgot then we will be optimistic and choose the latest.
//
#if BEAST_WIN32
# ifndef _WIN32_WINNT
# pragma message ("Warning: _WIN32_WINNT was not set in your project")
# define _WIN32_WINNT 0x0600
# endif
# ifndef _VARIADIC_MAX
# define _VARIADIC_MAX 10
# endif
#endif
// Unfortunately, we use some boost detail elements
//
// https://svn.boost.org/trac/boost/ticket/9024
#include <boost/version.hpp>
#include <boost/array.hpp>
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/bind.hpp>
#include <boost/foreach.hpp>
#include <boost/function.hpp>
#include <boost/type_traits.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
#include <boost/asio/detail/handler_cont_helpers.hpp>
// work-around for broken <boost/get_pointer.hpp>
#include <beast/boost/get_pointer.h>
#endif

View File

@@ -0,0 +1,40 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_SYSTEM_OPENSSLINCLUDES_H_INCLUDED
#define BEAST_ASIO_SYSTEM_OPENSSLINCLUDES_H_INCLUDED
#define OPENSSL_THREAD_DEFINES
#include <openssl/opensslconf.h>
//------------------------------------------------------------------------------
// Configure our settings based on what we find
//
#if defined(OPENSSL_THREADS)
# ifndef BEAST_OPENSSL_MULTITHREADED
# define BEAST_OPENSSL_MULTITHREADED 1
# endif
#else
# ifndef BEAST_OPENSSL_MULTITHREADED
# define BEAST_OPENSSL_MULTITHREADED 0
# endif
#endif
#endif

View File

@@ -0,0 +1,110 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast {
namespace asio {
PeerTest::Result::Result ()
: m_ec (TestPeerBasics::make_error (TestPeerBasics::errc::skipped))
, m_message (m_ec.message ())
{
}
PeerTest::Result::Result (boost::system::error_code const& ec, String const& prefix)
: m_ec (ec)
, m_message ((prefix == String::empty) ? ec.message ()
: prefix + ": " + ec.message ())
{
}
PeerTest::Result::Result (std::exception const& e, String const& prefix)
: m_ec (TestPeerBasics::make_error (TestPeerBasics::errc::exceptioned))
, m_message ((prefix == String::empty) ? e.what ()
: prefix + ": " + e.what ())
{
}
bool PeerTest::Result::operator== (Result const& other) const noexcept
{
return m_ec == other.m_ec;
}
bool PeerTest::Result::operator!= (Result const& other) const noexcept
{
return m_ec != other.m_ec;
}
bool PeerTest::Result::failed () const noexcept
{
return TestPeerBasics::failure (m_ec);
}
bool PeerTest::Result::timedout () const noexcept
{
return m_ec == TestPeerBasics::make_error (TestPeerBasics::errc::timeout);
}
String PeerTest::Result::message () const noexcept
{
return m_message;
}
bool PeerTest::Result::report (unit_test::suite& suite,
bool reportPassingTests) const
{
bool const success = suite.expect (! failed (),
message ().toStdString());
if (reportPassingTests && success)
suite.log <<
"pass " + message().toStdString();
return success;
}
//------------------------------------------------------------------------------
PeerTest::Results::Results ()
: name ("unknown")
{
}
bool PeerTest::Results::operator== (Results const& other) const noexcept
{
return (client == other.client) && (server == other.server);
}
bool PeerTest::Results::operator!= (Results const& other) const noexcept
{
return (client != other.client) || (server != other.server);
}
bool PeerTest::Results::report (unit_test::suite& suite,
bool beginTestCase) const
{
if (beginTestCase)
suite.testcase (name.toStdString());
bool success = true;
if (! client.report (suite))
success = false;
if (! server.report (suite))
success = false;
return success;
}
}
}

View File

@@ -0,0 +1,247 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_TESTS_PEERTEST_H_INCLUDED
#define BEAST_ASIO_TESTS_PEERTEST_H_INCLUDED
#include <beast/unit_test/suite.h>
namespace beast {
namespace asio {
/** Performs a test of two peers defined by template parameters. */
class PeerTest
{
public:
enum
{
/** How long to wait before aborting a peer and reporting a timeout.
@note Aborting synchronous logics may cause undefined behavior.
*/
defaultTimeoutSeconds = 30
};
//--------------------------------------------------------------------------
/** Holds the test results for one peer.
*/
class Result
{
public:
/** Default constructor indicates the test was skipped.
*/
Result ();
/** Construct from an error code.
The prefix is prepended to the error message.
*/
explicit Result (boost::system::error_code const& ec, String const& prefix = "");
explicit Result (std::exception const& e, String const& prefix = "");
/** Returns true if the error codes match (message is ignored).
*/
bool operator== (Result const& other) const noexcept;
bool operator!= (Result const& other) const noexcept;
/** Returns true if the peer failed.
*/
bool failed () const noexcept;
/** Convenience for determining if the peer timed out.
*/
bool timedout () const noexcept;
/** Provides a descriptive message.
This is suitable to pass to suite::fail.
*/
String message () const noexcept;
/** Report the result to a testsuite.
A return value of true indicates success.
*/
bool report (unit_test::suite& suite,
bool reportPassingTests = false) const;
private:
boost::system::error_code m_ec;
String m_message;
};
//--------------------------------------------------------------------------
/** Holds the results for both peers in a test.
*/
struct Results
{
String name; // A descriptive name for this test case.
Result client;
Result server;
Results ();
/** Determines if client and server results match. */
bool operator== (Results const& other) const noexcept;
bool operator!= (Results const& other) const noexcept;
/** Report the results to a suite object.
A return value of true indicates success.
@param beginTestCase `true` to call test.beginTestCase for you
*/
bool report (unit_test::suite& suite, bool beginTestCase = true) const;
};
//--------------------------------------------------------------------------
/** Test two peers and return the results.
*/
template <class Details, class ClientLogic, class ServerLogic,
class ClientArg, class ServerArg>
static Results run (ClientArg const& clientArg, ServerArg const& serverArg,
int timeoutSeconds = defaultTimeoutSeconds)
{
Results results;
if (Process::isRunningUnderDebugger ())
timeoutSeconds = -1;
try
{
TestPeerType <ServerLogic, Details> server (serverArg);
results.name = server.name () + Details::getArgName (serverArg);
try
{
TestPeerType <ClientLogic, Details> client (clientArg);
results.name << " / " + client.name () + Details::getArgName (clientArg);
try
{
server.start (timeoutSeconds);
try
{
client.start (timeoutSeconds);
boost::system::error_code const ec = client.join ();
results.client = Result (ec, client.name ());
try
{
boost::system::error_code const ec = server.join ();
results.server = Result (ec, server.name ());
}
catch (std::exception& e)
{
results.server = Result (e, server.name ());
}
catch (...)
{
results.server = Result (TestPeerBasics::make_error (
TestPeerBasics::errc::exceptioned), server.name ());
}
}
catch (std::exception& e)
{
results.server = Result (e, client.name ());
}
catch (...)
{
results.client = Result (TestPeerBasics::make_error (
TestPeerBasics::errc::exceptioned), client.name ());
}
}
catch (std::exception& e)
{
results.server = Result (e, server.name ());
}
catch (...)
{
results.server = Result (TestPeerBasics::make_error (
TestPeerBasics::errc::exceptioned), server.name ());
}
}
catch (std::exception& e)
{
results.server = Result (e, "client");
}
catch (...)
{
results.client = Result (TestPeerBasics::make_error (
TestPeerBasics::errc::exceptioned), "client");
}
}
catch (std::exception& e)
{
results.server = Result (e, "server");
}
catch (...)
{
results.server = Result (TestPeerBasics::make_error (
TestPeerBasics::errc::exceptioned), "server");
}
return results;
}
template <class Details, class ClientLogic, class ServerLogic, class Arg>
static Results run (Arg const& arg, int timeoutSeconds = defaultTimeoutSeconds)
{
return run <Details, ClientLogic, ServerLogic, Arg, Arg> (
arg, arg, timeoutSeconds);
}
//--------------------------------------------------------------------------
template <class Details, class Arg>
static void report_async (unit_test::suite& suite, Arg const& arg,
int timeoutSeconds = defaultTimeoutSeconds,
bool beginTestCase = true)
{
run <Details, TestPeerLogicAsyncClient, TestPeerLogicAsyncServer>
(arg, timeoutSeconds).report (suite, beginTestCase);
}
template <class Details, class Arg>
static
void
report (unit_test::suite& suite, Arg const& arg,
int timeoutSeconds = defaultTimeoutSeconds, bool beginTestCase = true)
{
run <Details, TestPeerLogicSyncClient, TestPeerLogicSyncServer>
(arg, timeoutSeconds).report (suite, beginTestCase);
run <Details, TestPeerLogicAsyncClient, TestPeerLogicSyncServer>
(arg, timeoutSeconds).report (suite, beginTestCase);
run <Details, TestPeerLogicSyncClient, TestPeerLogicAsyncServer>
(arg, timeoutSeconds).report (suite, beginTestCase);
report_async <Details> (suite, arg, timeoutSeconds, beginTestCase);
}
};
}
}
#endif

View File

@@ -0,0 +1,58 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_TESTS_TESTPEER_H_INCLUDED
#define BEAST_ASIO_TESTS_TESTPEER_H_INCLUDED
namespace beast {
namespace asio {
/** An abstract peer for unit tests. */
class TestPeer : public TestPeerBasics
{
public:
enum
{
// This should be long enough to go about your business.
defaultTimeout = 10
};
virtual ~TestPeer () { }
/** Get the name of this peer. */
virtual String name () const = 0;
/** Start the peer.
If timeoutSeconds is 0 or less, the wait is infinite.
@param timeoutSeconds How long until the peer should be
considered timed out.
*/
virtual void start (int timeoutSeconds = defaultTimeout) = 0;
/** Wait for the peer to finish.
@return Any error code generated during the server operation.
*/
virtual boost::system::error_code join () = 0;
};
}
}
#endif

View File

@@ -0,0 +1,161 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast {
namespace asio {
TestPeerBasics::Model::Model (model_t model)
: m_model (model)
{
}
String TestPeerBasics::Model::name () const noexcept
{
if (m_model == async)
return "async";
return "sync";
}
bool TestPeerBasics::Model::operator== (model_t model) const noexcept
{
return m_model == model;
}
boost::asio::ssl::stream_base::handshake_type
TestPeerBasics::to_handshake_type (PeerRole const& role)
{
if (role == PeerRole::client)
return boost::asio::ssl::stream_base::client;
return boost::asio::ssl::stream_base::server;
}
//------------------------------------------------------------------------------
boost::system::error_category const& TestPeerBasics::test_category () noexcept
{
struct test_category_type : boost::system::error_category
{
char const* name () const noexcept
{
return "TestPeer";
}
std::string message (int ev) const
{
switch (ev)
{
case errc::none: return "No error";
case errc::timeout: return "The timeout expired before the test could complete";
case errc::unexpected: return "An unexpected test result was encountered";
case errc::exceptioned: return "An unexpected exception was thrown";
case errc::skipped: return "The test was skipped because of previous errors";
default:
break;
};
return "An unknown error";
}
boost::system::error_condition default_error_condition (int ev) const noexcept
{
return boost::system::error_condition (ev, *this);
}
bool equivalent (int ev, boost::system::error_condition const& condition) const noexcept
{
return default_error_condition (ev) == condition;
}
bool equivalent (boost::system::error_code const& code, int ev) const noexcept
{
return *this == code.category() && code.value() == ev;
}
};
static test_category_type category;
return category;
}
boost::system::error_code TestPeerBasics::make_error (errc::errc_t ev) noexcept
{
return boost::system::error_code (ev, test_category ());
}
boost::system::error_code TestPeerBasics::make_error (errc::errc_t ev, boost::system::error_code& ec) noexcept
{
return ec = make_error (ev);
}
bool TestPeerBasics::success (boost::system::error_code const& ec, bool eofIsOkay) noexcept
{
if (eofIsOkay && ec == boost::asio::error::eof)
return true;
if (! ec)
return true;
breakpoint (ec);
return false;
}
bool TestPeerBasics::failure (boost::system::error_code const& ec, bool eofIsOkay) noexcept
{
return ! success (ec, eofIsOkay);
}
bool TestPeerBasics::expected (bool condition, boost::system::error_code& ec) noexcept
{
if (condition)
{
ec = boost::system::error_code ();
}
else
{
make_error (errc::unexpected, ec);
breakpoint (ec);
}
return condition;
}
bool TestPeerBasics::unexpected (bool condition, boost::system::error_code& ec) noexcept
{
return ! expected (condition, ec);
}
bool TestPeerBasics::aborted (boost::system::error_code const& ec) noexcept
{
return ec == boost::asio::error::operation_aborted;
}
//------------------------------------------------------------------------------
void TestPeerBasics::breakpoint (boost::system::error_code const& ec)
{
// Set a breakpoint here to catch a failure
std::string const& message = ec.message ();
char const* const c_str = message.c_str ();
breakpoint (c_str);
}
void TestPeerBasics::breakpoint (char const* const)
{
}
}
}

View File

@@ -0,0 +1,112 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_TESTS_TESTPEERBASICS_H_INCLUDED
#define BEAST_ASIO_TESTS_TESTPEERBASICS_H_INCLUDED
namespace beast {
namespace asio {
/** Common declarations for TestPeer.
@see TestPeer
*/
class TestPeerBasics
{
public:
/** Selects between synchronous or asynchronous networking i/o usage. */
struct Model
{
enum model_t
{
sync,
async
};
Model (model_t model);
String name () const noexcept;
bool operator== (model_t model) const noexcept;
private:
model_t m_model;
};
//--------------------------------------------------------------------------
/** Convert a PeerRole to boost::asio::ssl::stream_base_handshake_type */
static boost::asio::ssl::stream_base::handshake_type to_handshake_type (PeerRole const& role);
//--------------------------------------------------------------------------
// Custom error codes for distinguishing test conditions
struct errc
{
enum errc_t
{
none = 0,
timeout, // The peer join timeout expired
unexpected, // An expected condition was false
exceptioned, // An exception occurred
skipped // Test skipped due to previous errors
};
};
/** Returns the category that represents TestPeer errors.
*/
static boost::system::error_category const& test_category () noexcept;
/** Creates a test error_code from the give code value.
*/
static boost::system::error_code make_error (errc::errc_t ev) noexcept;
/** Sets the passed error_code to a test error and returns it.
*/
static boost::system::error_code make_error (errc::errc_t ev,
boost::system::error_code& ec) noexcept;
/** Returns true if the error code indicates success.
*/
static bool success (boost::system::error_code const& ec, bool eofIsOkay = false) noexcept;
/** Returns false if the error code indicates failure.
*/
static bool failure (boost::system::error_code const& ec, bool eofIsOkay = false) noexcept;
/** Set the error based on a failed condition and return the success.
*/
static bool expected (bool condition, boost::system::error_code& ec) noexcept;
/** Set the error based on a passed condition and return the success.
*/
static bool unexpected (bool condition, boost::system::error_code& ec) noexcept;
/** Returns true if the error condition indicates an aborted I/O. */
static bool aborted (boost::system::error_code const& ec) noexcept;
/** Provides a place to set a breakpoint to catch a failed condition. */
static void breakpoint (boost::system::error_code const& ec);
/** Forces the variable to exist in the debugger. */
static void breakpoint (char const* const message);
};
}
}
#endif

View File

@@ -0,0 +1,52 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_TESTS_TESTPEERDETAILS_H_INCLUDED
#define BEAST_ASIO_TESTS_TESTPEERDETAILS_H_INCLUDED
#include <beast/asio/abstract_socket.h>
namespace beast {
namespace asio {
/** Base class of all detail objects. */
class TestPeerDetails
{
public:
virtual ~TestPeerDetails () { }
virtual String name () const = 0;
virtual abstract_socket& get_socket () = 0;
virtual abstract_socket& get_acceptor () = 0;
boost::asio::io_service& get_io_service ()
{
return m_io_service;
}
private:
boost::asio::io_service m_io_service;
};
}
}
#endif

View File

@@ -0,0 +1,115 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_TESTS_TESTPEERDETAILSTCP_H_INCLUDED
#define BEAST_ASIO_TESTS_TESTPEERDETAILSTCP_H_INCLUDED
#include <beast/asio/socket_wrapper.h>
namespace beast {
namespace asio {
/** Some predefined Detail classes for TestPeer */
struct TcpDetails : public TestPeerDetails
{
protected:
typedef boost::asio::ip::tcp protocol_type;
typedef protocol_type::socket socket_type;
typedef protocol_type::acceptor acceptor_type;
typedef protocol_type::endpoint endpoint_type;
typedef protocol_type::resolver resolver_type;
public:
typedef protocol_type arg_type;
typedef socket_type native_socket_type;
typedef acceptor_type native_acceptor_type;
explicit TcpDetails (arg_type protocol)
: m_protocol (protocol)
, m_socket (get_io_service ())
, m_acceptor (get_io_service ())
, m_socket_wrapper (m_socket)
, m_acceptor_wrapper (m_acceptor)
{
}
static String getArgName (arg_type arg)
{
if (arg == protocol_type::v4 ())
return ".tcpv4";
else if (arg == protocol_type::v6 ())
return ".tcpv6";
return ".tcp?";
}
String name () const
{
return getArgName (m_protocol);
}
abstract_socket& get_socket ()
{
return m_socket_wrapper;
}
abstract_socket& get_acceptor ()
{
return m_acceptor_wrapper;
}
socket_type& get_native_socket ()
{
return m_socket;
}
acceptor_type& get_native_acceptor ()
{
return m_acceptor;
}
endpoint_type get_endpoint (PeerRole role)
{
if (m_protocol == protocol_type::v4 ())
{
if (role == PeerRole::server)
return endpoint_type (m_protocol, 1053);
else
return endpoint_type (boost::asio::ip::address_v4::loopback (), 1053);
}
else
{
if (role == PeerRole::server)
return endpoint_type (m_protocol, 1052);
else
return endpoint_type (boost::asio::ip::address_v6 ().from_string ("::1"), 1052);
}
}
protected:
protocol_type m_protocol;
socket_type m_socket;
acceptor_type m_acceptor;
socket_wrapper <socket_type&> m_socket_wrapper;
socket_wrapper <acceptor_type&> m_acceptor_wrapper;
};
}
}
#endif

View File

@@ -0,0 +1,69 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast {
namespace asio {
TestPeerLogic::TestPeerLogic (abstract_socket& socket)
: m_socket (&socket)
{
}
TestPeerLogic::error_code& TestPeerLogic::error () noexcept
{
return m_ec;
}
TestPeerLogic::error_code const& TestPeerLogic::error () const noexcept
{
return m_ec;
}
TestPeerLogic::error_code const& TestPeerLogic::error (error_code const& ec) noexcept
{
return m_ec = ec;
}
abstract_socket& TestPeerLogic::socket () noexcept
{
return *m_socket;
}
void TestPeerLogic::on_connect ()
{
pure_virtual ();
}
void TestPeerLogic::on_connect_async (error_code const&)
{
pure_virtual ();
}
void TestPeerLogic::finished ()
{
pure_virtual ();
}
void TestPeerLogic::pure_virtual ()
{
fatal_error ("A TestPeerLogic function was called incorrectly");
}
}
}

View File

@@ -0,0 +1,62 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_TESTS_TESTPEERLOGIC_H_INCLUDED
#define BEAST_ASIO_TESTS_TESTPEERLOGIC_H_INCLUDED
namespace beast {
namespace asio {
/** Interface for implementing the logic part of a peer test. */
class TestPeerLogic : public TestPeerBasics
{
public:
typedef boost::system::error_code error_code;
explicit TestPeerLogic (abstract_socket& socket);
error_code& error () noexcept;
error_code const& error () const noexcept;
error_code const& error (error_code const& ec) noexcept; // assigns to m_ec
abstract_socket& socket () noexcept;
virtual PeerRole get_role () const noexcept = 0;
virtual Model get_model () const noexcept = 0;
virtual void on_connect ();
virtual void on_connect_async (error_code const&);
// asynchronous logic classes
// must call this when they are done
virtual void finished ();
static void pure_virtual ();
private:
error_code m_ec;
abstract_socket* m_socket;
};
}
}
#endif

View File

@@ -0,0 +1,161 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast {
namespace asio {
TestPeerLogicAsyncClient::TestPeerLogicAsyncClient (abstract_socket& socket)
: TestPeerLogic (socket)
{
}
PeerRole TestPeerLogicAsyncClient::get_role () const noexcept
{
return PeerRole::client;
}
TestPeerBasics::Model TestPeerLogicAsyncClient::get_model () const noexcept
{
return Model::async;
}
void TestPeerLogicAsyncClient::on_connect_async (error_code const& ec)
{
if (aborted (ec) || failure (error (ec)))
return finished ();
if (socket ().needs_handshake ())
{
socket ().async_handshake (abstract_socket::client,
boost::bind (&TestPeerLogicAsyncClient::on_handshake, this,
boost::asio::placeholders::error));
}
else
{
on_handshake (ec);
}
}
void TestPeerLogicAsyncClient::on_handshake (error_code const& ec)
{
if (aborted (ec) || failure (error (ec)))
return finished ();
boost::asio::async_write (socket (), boost::asio::buffer ("hello", 5),
boost::bind (&TestPeerLogicAsyncClient::on_write, this,
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}
void TestPeerLogicAsyncClient::on_write (error_code const& ec, std::size_t bytes_transferred)
{
if (aborted (ec) || failure (error (ec)))
return finished ();
if (unexpected (bytes_transferred == 5, error ()))
return finished ();
boost::asio::async_read_until (socket (), m_buf, std::string ("goodbye"),
boost::bind (&TestPeerLogicAsyncClient::on_read, this,
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}
void TestPeerLogicAsyncClient::on_read (error_code const& ec, std::size_t bytes_transferred)
{
if (aborted (ec) || failure (error (ec)))
return finished ();
if (unexpected (bytes_transferred == 7, error ()))
return finished ();
// should check the data here?
m_buf.consume (bytes_transferred);
// Fire up a 1 byte read, to wait for the server to
// shut down its end of the connection.
boost::asio::async_read (socket (), m_buf.prepare (1),
boost::bind (&TestPeerLogicAsyncClient::on_read_final, this,
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}
void TestPeerLogicAsyncClient::on_read_final (error_code const& ec, std::size_t)
{
if (aborted (ec))
return finished ();
// An eof is the normal case. The server should have closed shop.
//
if (ec == boost::asio::error::eof)
{
if (socket ().needs_handshake ())
{
socket ().async_shutdown (boost::bind (&TestPeerLogicAsyncClient::on_shutdown, this,
boost::asio::placeholders::error));
}
else
{
// on_shutdown will call finished ()
error_code ec;
on_shutdown (socket ().shutdown (abstract_socket::shutdown_send, ec));
}
}
else
{
// If we don't get eof, then there should be some other
// error in there. We don't expect the server to send more bytes!
//
// This statement will do the following:
//
// error (ec) save ec into our error state
// success () return true if ec represents success
// unexpected () changes error() to 'unexpected' result if
// success() returned true
//
unexpected (success (error (ec)), error ());
return finished ();
}
}
void TestPeerLogicAsyncClient::on_shutdown (error_code const& ec)
{
if (! aborted (ec))
{
if (success (error (ec), true))
{
if (socket ().needs_handshake ())
{
socket ().shutdown (abstract_socket::shutdown_send, error ());
}
if (! error ())
{
if (success (socket ().close (error ())))
{
// doing nothing here is intended,
// as the calls to success() may set error()
}
}
}
}
finished ();
}
}
}

View File

@@ -0,0 +1,45 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_TESTS_TESTPEERLOGICASYNCCLIENT_H_INCLUDED
#define BEAST_ASIO_TESTS_TESTPEERLOGICASYNCCLIENT_H_INCLUDED
namespace beast {
namespace asio {
class TestPeerLogicAsyncClient : public TestPeerLogic
{
public:
explicit TestPeerLogicAsyncClient (abstract_socket& socket);
PeerRole get_role () const noexcept;
Model get_model () const noexcept;
void on_connect_async (error_code const& ec);
void on_handshake (error_code const& ec);
void on_write (error_code const& ec, std::size_t bytes_transferred);
void on_read (error_code const& ec, std::size_t bytes_transferred);
void on_read_final (error_code const& ec, std::size_t);
void on_shutdown (error_code const& ec);
private:
boost::asio::streambuf m_buf;
};
}
}
#endif

View File

@@ -0,0 +1,124 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast {
namespace asio {
TestPeerLogicAsyncServer::TestPeerLogicAsyncServer (abstract_socket& socket)
: TestPeerLogic (socket)
{
}
PeerRole TestPeerLogicAsyncServer::get_role () const noexcept
{
return PeerRole::server;
}
TestPeerBasics::Model TestPeerLogicAsyncServer::get_model () const noexcept
{
return Model::async;
}
void TestPeerLogicAsyncServer::on_connect_async (error_code const& ec)
{
if (aborted (ec) || failure (error (ec)))
return finished ();
if (socket ().needs_handshake ())
{
socket ().async_handshake (abstract_socket::server,
boost::bind (&TestPeerLogicAsyncServer::on_handshake, this,
boost::asio::placeholders::error));
}
else
{
on_handshake (ec);
}
}
void TestPeerLogicAsyncServer::on_handshake (error_code const& ec)
{
if (aborted (ec) || failure (error (ec)))
return finished ();
boost::asio::async_read_until (socket (), m_buf, std::string ("hello"),
boost::bind (&TestPeerLogicAsyncServer::on_read, this,
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}
void TestPeerLogicAsyncServer::on_read (error_code const& ec, std::size_t bytes_transferred)
{
if (aborted (ec) || failure (error (ec)))
return finished ();
if (unexpected (bytes_transferred == 5, error ()))
return finished ();
boost::asio::async_write (socket (), boost::asio::buffer ("goodbye", 7),
boost::bind (&TestPeerLogicAsyncServer::on_write, this,
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}
void TestPeerLogicAsyncServer::on_write (error_code const& ec, std::size_t bytes_transferred)
{
if (aborted (ec) || failure (error (ec)))
return finished ();
if (unexpected (bytes_transferred == 7, error ()))
return finished ();
if (socket ().needs_handshake ())
{
socket ().async_shutdown (boost::bind (&TestPeerLogicAsyncServer::on_shutdown, this,
boost::asio::placeholders::error));
}
else
{
// on_shutdown will call finished ()
// we need another instance of ec so we can call on_shutdown()
error_code ec;
on_shutdown (socket ().shutdown (abstract_socket::shutdown_receive, ec));
}
}
void TestPeerLogicAsyncServer::on_shutdown (error_code const& ec)
{
if (! aborted (ec))
{
if (success (error (ec), true))
{
if (socket ().needs_handshake ())
{
socket ().shutdown (abstract_socket::shutdown_receive, error ());
}
if (success (socket ().close (error ())))
{
// doing nothing here is intended,
// as the calls to success() may set error()
}
}
}
finished ();
}
}
}

View File

@@ -0,0 +1,44 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_TESTS_TESTPEERLOGICASYNCSERVER_H_INCLUDED
#define BEAST_ASIO_TESTS_TESTPEERLOGICASYNCSERVER_H_INCLUDED
namespace beast {
namespace asio {
class TestPeerLogicAsyncServer : public TestPeerLogic
{
public:
explicit TestPeerLogicAsyncServer (abstract_socket& socket);
PeerRole get_role () const noexcept;
Model get_model () const noexcept;
void on_connect_async (error_code const& ec);
void on_handshake (error_code const& ec);
void on_read (error_code const& ec, std::size_t bytes_transferred);
void on_write (error_code const& ec, std::size_t bytes_transferred);
void on_shutdown (error_code const& ec);
private:
boost::asio::streambuf m_buf;
};
}
}
#endif

View File

@@ -0,0 +1,42 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast {
namespace asio {
TestPeerLogicProxyClient::TestPeerLogicProxyClient (abstract_socket& socket)
: TestPeerLogicSyncClient (socket)
{
}
void TestPeerLogicProxyClient::on_pre_handshake ()
{
//ProxyHandshakeParser h;
static std::string line (
"PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r\n"
// 56 chars
);
boost::asio::write (socket (), boost::asio::buffer (line), error ());
}
}
}

View File

@@ -0,0 +1,37 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_TESTS_TESTPEERLOGICPROXYCLIENT_H_INCLUDED
#define BEAST_ASIO_TESTS_TESTPEERLOGICPROXYCLIENT_H_INCLUDED
namespace beast {
namespace asio {
/** A synchronous client logic that sends a PROXY protocol pre-handshake. */
class TestPeerLogicProxyClient : public TestPeerLogicSyncClient
{
public:
explicit TestPeerLogicProxyClient (abstract_socket& socket);
void on_pre_handshake ();
};
}
}
#endif

View File

@@ -0,0 +1,115 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast {
namespace asio {
TestPeerLogicSyncClient::TestPeerLogicSyncClient (abstract_socket& socket)
: TestPeerLogic (socket)
{
}
PeerRole TestPeerLogicSyncClient::get_role () const noexcept
{
return PeerRole::client;
}
TestPeerBasics::Model TestPeerLogicSyncClient::get_model () const noexcept
{
return Model::sync;
}
void TestPeerLogicSyncClient::on_connect ()
{
{
// pre-handshake hook is optional
on_pre_handshake ();
if (failure (error ()))
return ;
}
if (socket ().needs_handshake ())
{
if (failure (socket ().handshake (to_handshake_type (get_role ()), error ())))
return;
}
{
std::size_t const amount = boost::asio::write (
socket (), boost::asio::buffer ("hello", 5), error ());
if (failure (error ()))
return;
if (unexpected (amount == 5, error ()))
return;
}
{
char data [7];
size_t const amount = boost::asio::read (
socket (), boost::asio::buffer (data, 7), error ());
if (failure (error ()))
return;
if (unexpected (amount == 7, error ()))
return;
if (unexpected (memcmp (&data, "goodbye", 7) == 0, error ()))
return;
}
// Wait for 1 byte which should never come. Instead,
// the server should close its end and we will get eof
{
char data [1];
boost::asio::read (socket (), boost::asio::buffer (data, 1), error ());
if (error () == boost::asio::error::eof)
{
error () = error_code ();
}
else if (unexpected (failure (error ()), error ()))
{
return;
}
}
if (socket ().needs_handshake ())
{
if (failure (socket ().shutdown (error ()), true))
return;
error () = error_code ();
}
if (failure (socket ().shutdown (abstract_socket::shutdown_send, error ())))
return;
if (failure (socket ().close (error ())))
return;
}
void TestPeerLogicSyncClient::on_pre_handshake ()
{
}
}
}

View File

@@ -0,0 +1,39 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_TESTS_TESTPEERLOGICSYNCCLIENT_H_INCLUDED
#define BEAST_ASIO_TESTS_TESTPEERLOGICSYNCCLIENT_H_INCLUDED
namespace beast {
namespace asio {
class TestPeerLogicSyncClient : public TestPeerLogic
{
public:
explicit TestPeerLogicSyncClient (abstract_socket& socket);
PeerRole get_role () const noexcept;
Model get_model () const noexcept;
void on_connect ();
virtual void on_pre_handshake ();
};
}
}
#endif

View File

@@ -0,0 +1,86 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast {
namespace asio {
TestPeerLogicSyncServer::TestPeerLogicSyncServer (abstract_socket& socket)
: TestPeerLogic (socket)
{
}
PeerRole TestPeerLogicSyncServer::get_role () const noexcept
{
return PeerRole::server;
}
TestPeerBasics::Model TestPeerLogicSyncServer::get_model () const noexcept
{
return Model::sync;
}
void TestPeerLogicSyncServer::on_connect ()
{
if (socket ().needs_handshake ())
{
if (failure (socket ().handshake (to_handshake_type (get_role ()), error ())))
return;
}
{
boost::asio::streambuf buf (5);
std::size_t const amount = boost::asio::read_until (
socket (), buf, "hello", error ());
if (failure (error ()))
return;
if (unexpected (amount == 5, error ()))
return;
if (unexpected (buf.size () == 5, error ()))
return;
}
{
std::size_t const amount = boost::asio::write (
socket (), boost::asio::buffer ("goodbye", 7), error ());
if (failure (error ()))
return;
if (unexpected (amount == 7, error ()))
return;
}
if (socket ().needs_handshake ())
{
if (failure (socket ().shutdown (error ()), true))
return;
}
if (failure (socket ().shutdown (abstract_socket::shutdown_send, error ())))
return;
if (failure (socket ().close (error ())))
return;
}
}
}

View File

@@ -0,0 +1,38 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_TESTS_TESTPEERLOGICSYNCSERVER_H_INCLUDED
#define BEAST_ASIO_TESTS_TESTPEERLOGICSYNCSERVER_H_INCLUDED
namespace beast {
namespace asio {
class TestPeerLogicSyncServer : public TestPeerLogic
{
public:
explicit TestPeerLogicSyncServer (abstract_socket& socket);
PeerRole get_role () const noexcept;
Model get_model () const noexcept;
void on_connect ();
};
}
}
#endif

View File

@@ -0,0 +1,401 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ASIO_TESTS_TESTPEERTYPE_H_INCLUDED
#define BEAST_ASIO_TESTS_TESTPEERTYPE_H_INCLUDED
namespace beast {
namespace asio {
template <typename Logic, typename Details>
class TestPeerType
: public Details
, public Logic
, public TestPeer
, public Thread
{
protected:
// TestPeerDetails
using Details::get_socket;
using Details::get_acceptor;
using Details::get_io_service;
// Details
typedef typename Details::protocol_type protocol_type;
typedef typename Details::socket_type socket_type;
typedef typename Details::acceptor_type acceptor_type;
typedef typename Details::endpoint_type endpoint_type;
typedef typename Details::resolver_type resolver_type;
using Details::get_native_socket;
using Details::get_native_acceptor;
using Details::get_endpoint;
// TestPeerLogic
typedef typename Logic::error_code error_code;
using Logic::error;
using Logic::socket;
using Logic::get_role;
using Logic::get_model;
using Logic::on_connect;
using Logic::on_connect_async;
using Logic::pure_virtual;
typedef TestPeerType <Logic, Details> This;
public:
// Details
typedef typename Details::arg_type arg_type;
typedef typename Details::native_socket_type native_socket_type;
typedef typename Details::native_acceptor_type native_acceptor_type;
TestPeerType (arg_type const& arg)
: Details (arg)
, Logic (get_socket ())
, Thread (name ())
, m_timer (get_io_service ())
, m_timer_set (false)
, m_timed_out (false)
{
}
~TestPeerType ()
{
}
String name () const
{
return get_model ().name () + "_" + get_role ().name ();
}
bool is_async () const noexcept
{
return get_model () == Model::async;
}
void start (int timeoutSeconds)
{
if (is_async ())
{
if (timeoutSeconds > 0)
{
m_timer.expires_from_now (
boost::posix_time::seconds (timeoutSeconds));
m_timer.async_wait (boost::bind (&This::on_deadline,
this, boost::asio::placeholders::error));
m_timer_set = true;
}
else
{
// Don't set the timer, so infinite wait.
}
}
else
{
// Save the value for when join() is called later.
//
m_timeoutSeconds = timeoutSeconds;
}
startThread ();
// For server roles block until the thread is litening.
//
if (get_role () == PeerRole::server)
m_listening.wait ();
}
error_code join ()
{
if (is_async ())
{
// If the timer expired, then all our i/o should be
// aborted and the thread will exit. So we will wait
// for the thread for an infinite amount of time to
// prevent undefined behavior. If an asynchronous logic
// fails to end when the deadline timer expires, it
// means there's a bug in the logic code.
//
m_join.wait ();
// The wait was satisfied but now the thread is still on
// it's way out of the thread function, so block until
// we know its done.
//
stopThread ();
// If we timed out then always report the custom error
if (m_timed_out)
return error (make_error (errc::timeout));
}
else
{
if (m_timeoutSeconds > 0)
{
// Wait for the thread to finish
//
if (! m_join.wait (m_timeoutSeconds * 1000))
{
// Uh oh, we timed out! This is bad.
// The synchronous model requires that the thread
// be forcibly killed, which can result in undefined
// behavior. It's best not to perform tests with
// synchronous Logic objects that are supposed to time out.
// Force the thread to be killed, without waiting.
stopThread (0);
error () = make_error (errc::timeout);
}
else
{
stopThread ();
}
}
else
{
// They requested an infinite wait.
//
m_join.wait ();
stopThread ();
}
}
return error ();
}
//--------------------------------------------------------------------------
void run ()
{
if (is_async ())
{
if (get_role () == PeerRole::server)
{
run_async_server ();
}
else if (get_role () == PeerRole::client)
{
run_async_client ();
}
else
{
error () = make_error (errc::unexpected);
}
}
else if (get_model () == Model::sync)
{
if (get_role () == PeerRole::server)
{
run_sync_server ();
}
else if (get_role () == PeerRole::client)
{
run_sync_client ();
}
else
{
error () = make_error (errc::unexpected);
}
}
else
{
error () = make_error (errc::unexpected);
}
get_io_service ().run ();
}
//--------------------------------------------------------------------------
void run_sync_server ()
{
do_listen ();
if (failure (error ()))
return finished ();
if (failure (get_acceptor ().accept (get_socket (), error ())))
return finished ();
if (failure (get_acceptor ().close (error ())))
return finished ();
this->on_connect ();
finished ();
}
//--------------------------------------------------------------------------
void on_accept (error_code const& ec)
{
if (failure (ec))
return finished ();
// Close the acceptor down so we don't block the io_service forever
//
// VFALCO NOTE what difference between cancel and close?
#if 0
if (failure (get_acceptor ().close (error ())))
return finished ();
#endif
this->on_connect_async (ec);
}
void run_async_server ()
{
do_listen ();
if (failure (error ()))
return finished ();
get_acceptor ().async_accept (get_socket (), boost::bind (
&This::on_accept, this, boost::asio::placeholders::error));
}
//--------------------------------------------------------------------------
void run_sync_client ()
{
if (failure (get_native_socket ().connect (get_endpoint (get_role ()), error ())))
return finished ();
this->on_connect ();
finished ();
}
void run_async_client ()
{
get_native_socket ().async_connect (get_endpoint (get_role ()),
boost::bind (&Logic::on_connect_async, this, boost::asio::placeholders::error));
}
//--------------------------------------------------------------------------
void do_listen ()
{
if (failure (get_native_acceptor ().open (
get_endpoint (get_role ()).protocol (), error ())))
return;
// VFALCO TODO Figure out how to not hard code boost::asio::socket_base
if (failure (get_native_acceptor ().set_option (
boost::asio::socket_base::reuse_address (true), error ())))
return;
if (failure (get_native_acceptor ().bind (get_endpoint (get_role ()), error ())))
return;
// VFALCO TODO Figure out how to not hard code boost::asio::socket_base
if (failure (get_native_acceptor ().listen (
boost::asio::socket_base::max_connections, error ())))
return;
m_listening.signal ();
}
void on_deadline (error_code const& ec)
{
m_timer_set = false;
if (ec != boost::asio::error::operation_aborted)
{
// We expect that ec represents no error, since the
// timer expired and the operation wasn't aborted.
//
// If by some chance there is an error in ec we will
// report that as an unexpected test condition instead
// of a timeout.
//
if (expected (! ec, error ()))
m_timed_out = true;
}
else
{
// The timer was canceled because the Logic
// called finished(), so we do nothing here.
}
finished ();
}
void finished ()
{
// If the server errors out it will come through
// here so signal the listening event and unblock
// the main thread.
//
if (get_role () == PeerRole::server)
m_listening.signal ();
if (m_timer_set)
{
error_code ec;
std::size_t const amount = m_timer.cancel (ec);
// The Logic should not have any I/O pending when
// it calls finished, so amount should be zero.
//
unexpected (amount == 0, ec);
}
// The logic should close the socket at the end of
// its operations, unless it encounters an error.
// Therefore, we will clean everything up and squelch
// any errors, so that io_service::run() will return.
//
{
error_code ec;
this->get_socket ().close (ec);
}
// The acceptor will not have closed if the client
// never established the connection, so do it here.
{
error_code ec;
this->get_acceptor ().close (ec);
}
// Wake up the thread blocked on join()
m_join.signal ();
}
private:
WaitableEvent m_listening;
WaitableEvent m_join;
// for async peers
boost::asio::deadline_timer m_timer;
bool m_timer_set;
bool m_timed_out;
// for sync peers
int m_timeoutSeconds;
};
}
}
#endif

View File

@@ -0,0 +1,54 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <beast/unit_test/suite.h>
namespace beast {
namespace asio {
/** Test suite for the TestPeer family of objects. */
class TestPeer_test : public unit_test::suite
{
public:
template <typename Details, typename Arg >
void testDetails (Arg const& arg = Arg ())
{
PeerTest::report <Details> (*this, arg, timeoutSeconds);
}
void run ()
{
typedef boost::asio::ip::tcp protocol;
testDetails <TcpDetails, TcpDetails::arg_type> (protocol::v4 ());
testDetails <TcpDetails, TcpDetails::arg_type> (protocol::v6 ());
}
//--------------------------------------------------------------------------
enum
{
timeoutSeconds = 10
};
};
BEAST_DEFINE_TESTSUITE(TestPeer,beast_asio,beast);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,135 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ARRAYALLOCATIONBASE_H_INCLUDED
#define BEAST_ARRAYALLOCATIONBASE_H_INCLUDED
#include <beast/HeapBlock.h>
namespace beast {
//==============================================================================
/**
Implements some basic array storage allocation functions.
This class isn't really for public use - it's used by the other
array classes, but might come in handy for some purposes.
It inherits from a critical section class to allow the arrays to use
the "empty base class optimisation" pattern to reduce their footprint.
@see Array, SharedObjectArray
*/
template <class ElementType, class TypeOfCriticalSectionToUse>
class ArrayAllocationBase
: public TypeOfCriticalSectionToUse
{
public:
//==============================================================================
/** Creates an empty array. */
ArrayAllocationBase() noexcept
: numAllocated (0)
{
}
/** Destructor. */
~ArrayAllocationBase() noexcept
{
}
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
ArrayAllocationBase (ArrayAllocationBase<ElementType, TypeOfCriticalSectionToUse>&& other) noexcept
: elements (static_cast <HeapBlock <ElementType>&&> (other.elements)),
numAllocated (other.numAllocated)
{
}
ArrayAllocationBase& operator= (ArrayAllocationBase<ElementType, TypeOfCriticalSectionToUse>&& other) noexcept
{
elements = static_cast <HeapBlock <ElementType>&&> (other.elements);
numAllocated = other.numAllocated;
return *this;
}
#endif
//==============================================================================
/** Changes the amount of storage allocated.
This will retain any data currently held in the array, and either add or
remove extra space at the end.
@param numElements the number of elements that are needed
*/
void setAllocatedSize (const int numElements)
{
if (numAllocated != numElements)
{
if (numElements > 0)
elements.reallocate ((size_t) numElements);
else
elements.free_up();
numAllocated = numElements;
}
}
/** Increases the amount of storage allocated if it is less than a given amount.
This will retain any data currently held in the array, but will add
extra space at the end to make sure there it's at least as big as the size
passed in. If it's already bigger, no action is taken.
@param minNumElements the minimum number of elements that are needed
*/
void ensureAllocatedSize (const int minNumElements)
{
if (minNumElements > numAllocated)
setAllocatedSize ((minNumElements + minNumElements / 2 + 8) & ~7);
bassert (numAllocated <= 0 || elements != nullptr);
}
/** Minimises the amount of storage allocated so that it's no more than
the given number of elements.
*/
void shrinkToNoMoreThan (const int maxNumElements)
{
if (maxNumElements < numAllocated)
setAllocatedSize (maxNumElements);
}
/** Swap the contents of two objects. */
void swapWith (ArrayAllocationBase <ElementType, TypeOfCriticalSectionToUse>& other) noexcept
{
elements.swapWith (other.elements);
std::swap (numAllocated, other.numAllocated);
}
//==============================================================================
HeapBlock <ElementType> elements;
int numAllocated;
};
} // beast
#endif // BEAST_ARRAYALLOCATIONBASE_H_INCLUDED

View File

@@ -0,0 +1,194 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ELEMENTCOMPARATOR_H_INCLUDED
#define BEAST_ELEMENTCOMPARATOR_H_INCLUDED
namespace beast
{
#ifndef DOXYGEN
/** This is an internal helper class which converts a beast ElementComparator style
class (using a "compareElements" method) into a class that's compatible with
std::sort (i.e. using an operator() to compare the elements)
*/
template <typename ElementComparator>
struct SortFunctionConverter
{
SortFunctionConverter (ElementComparator& e) : comparator (e) {}
template <typename Type>
bool operator() (Type a, Type b) { return comparator.compareElements (a, b) < 0; }
private:
ElementComparator& comparator;
SortFunctionConverter& operator= (const SortFunctionConverter&);
};
#endif
//==============================================================================
/**
Sorts a range of elements in an array.
The comparator object that is passed-in must define a public method with the following
signature:
@code
int compareElements (ElementType first, ElementType second);
@endcode
..and this method must return:
- a value of < 0 if the first comes before the second
- a value of 0 if the two objects are equivalent
- a value of > 0 if the second comes before the first
To improve performance, the compareElements() method can be declared as static or const.
@param comparator an object which defines a compareElements() method
@param array the array to sort
@param firstElement the index of the first element of the range to be sorted
@param lastElement the index of the last element in the range that needs
sorting (this is inclusive)
@param retainOrderOfEquivalentItems if true, the order of items that the
comparator deems the same will be maintained - this will be
a slower algorithm than if they are allowed to be moved around.
@see sortArrayRetainingOrder
*/
template <class ElementType, class ElementComparator>
static void sortArray (ElementComparator& comparator,
ElementType* const array,
int firstElement,
int lastElement,
const bool retainOrderOfEquivalentItems)
{
SortFunctionConverter<ElementComparator> converter (comparator);
if (retainOrderOfEquivalentItems)
std::stable_sort (array + firstElement, array + lastElement + 1, converter);
else
std::sort (array + firstElement, array + lastElement + 1, converter);
}
//==============================================================================
/**
Searches a sorted array of elements, looking for the index at which a specified value
should be inserted for it to be in the correct order.
The comparator object that is passed-in must define a public method with the following
signature:
@code
int compareElements (ElementType first, ElementType second);
@endcode
..and this method must return:
- a value of < 0 if the first comes before the second
- a value of 0 if the two objects are equivalent
- a value of > 0 if the second comes before the first
To improve performance, the compareElements() method can be declared as static or const.
@param comparator an object which defines a compareElements() method
@param array the array to search
@param newElement the value that is going to be inserted
@param firstElement the index of the first element to search
@param lastElement the index of the last element in the range (this is non-inclusive)
*/
template <class ElementType, class ElementComparator>
static int findInsertIndexInSortedArray (ElementComparator& comparator,
ElementType* const array,
const ElementType newElement,
int firstElement,
int lastElement)
{
bassert (firstElement <= lastElement);
(void) comparator; // if you pass in an object with a static compareElements() method, this
// avoids getting warning messages about the parameter being unused
while (firstElement < lastElement)
{
if (comparator.compareElements (newElement, array [firstElement]) == 0)
{
++firstElement;
break;
}
else
{
const int halfway = (firstElement + lastElement) >> 1;
if (halfway == firstElement)
{
if (comparator.compareElements (newElement, array [halfway]) >= 0)
++firstElement;
break;
}
else if (comparator.compareElements (newElement, array [halfway]) >= 0)
{
firstElement = halfway;
}
else
{
lastElement = halfway;
}
}
}
return firstElement;
}
//==============================================================================
/**
A simple ElementComparator class that can be used to sort an array of
objects that support the '<' operator.
This will work for primitive types and objects that implement operator<().
Example: @code
Array <int> myArray;
DefaultElementComparator<int> sorter;
myArray.sort (sorter);
@endcode
@see ElementComparator
*/
template <class ElementType>
class DefaultElementComparator
{
private:
typedef ElementType ParameterType;
public:
static int compareElements (ParameterType first, ParameterType second)
{
return (first < second) ? -1 : ((second < first) ? 1 : 0);
}
};
} // beast
#endif

View File

@@ -0,0 +1,365 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_LINKEDLISTPOINTER_H_INCLUDED
#define BEAST_LINKEDLISTPOINTER_H_INCLUDED
namespace beast
{
//==============================================================================
/**
Helps to manipulate singly-linked lists of objects.
For objects that are designed to contain a pointer to the subsequent item in the
list, this class contains methods to deal with the list. To use it, the ObjectType
class that it points to must contain a LinkedListPointer called nextListItem, e.g.
@code
struct MyObject
{
int x, y, z;
// A linkable object must contain a member with this name and type, which must be
// accessible by the LinkedListPointer class. (This doesn't mean it has to be public -
// you could make your class a friend of a LinkedListPointer<MyObject> instead).
LinkedListPointer<MyObject> nextListItem;
};
LinkedListPointer<MyObject> myList;
myList.append (new MyObject());
myList.append (new MyObject());
int numItems = myList.size(); // returns 2
MyObject* lastInList = myList.getLast();
@endcode
*/
template <class ObjectType>
class LinkedListPointer : public Uncopyable
{
public:
//==============================================================================
/** Creates a null pointer to an empty list. */
LinkedListPointer() noexcept
: item (nullptr)
{
}
/** Creates a pointer to a list whose head is the item provided. */
explicit LinkedListPointer (ObjectType* const headItem) noexcept
: item (headItem)
{
}
/** Sets this pointer to point to a new list. */
LinkedListPointer& operator= (ObjectType* const newItem) noexcept
{
item = newItem;
return *this;
}
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
LinkedListPointer (LinkedListPointer&& other) noexcept
: item (other.item)
{
other.item = nullptr;
}
LinkedListPointer& operator= (LinkedListPointer&& other) noexcept
{
bassert (this != &other); // hopefully the compiler should make this situation impossible!
item = other.item;
other.item = nullptr;
return *this;
}
#endif
//==============================================================================
/** Returns the item which this pointer points to. */
inline operator ObjectType*() const noexcept
{
return item;
}
/** Returns the item which this pointer points to. */
inline ObjectType* get() const noexcept
{
return item;
}
/** Returns the last item in the list which this pointer points to.
This will iterate the list and return the last item found. Obviously the speed
of this operation will be proportional to the size of the list. If the list is
empty the return value will be this object.
If you're planning on appending a number of items to your list, it's much more
efficient to use the Appender class than to repeatedly call getLast() to find the end.
*/
LinkedListPointer& getLast() noexcept
{
LinkedListPointer* l = this;
while (l->item != nullptr)
l = &(l->item->nextListItem);
return *l;
}
/** Returns the number of items in the list.
Obviously with a simple linked list, getting the size involves iterating the list, so
this can be a lengthy operation - be careful when using this method in your code.
*/
int size() const noexcept
{
int total = 0;
for (ObjectType* i = item; i != nullptr; i = i->nextListItem)
++total;
return total;
}
/** Returns the item at a given index in the list.
Since the only way to find an item is to iterate the list, this operation can obviously
be slow, depending on its size, so you should be careful when using this in algorithms.
*/
LinkedListPointer& operator[] (int index) noexcept
{
LinkedListPointer* l = this;
while (--index >= 0 && l->item != nullptr)
l = &(l->item->nextListItem);
return *l;
}
/** Returns the item at a given index in the list.
Since the only way to find an item is to iterate the list, this operation can obviously
be slow, depending on its size, so you should be careful when using this in algorithms.
*/
const LinkedListPointer& operator[] (int index) const noexcept
{
const LinkedListPointer* l = this;
while (--index >= 0 && l->item != nullptr)
l = &(l->item->nextListItem);
return *l;
}
/** Returns true if the list contains the given item. */
bool contains (const ObjectType* const itemToLookFor) const noexcept
{
for (ObjectType* i = item; i != nullptr; i = i->nextListItem)
if (itemToLookFor == i)
return true;
return false;
}
//==============================================================================
/** Inserts an item into the list, placing it before the item that this pointer
currently points to.
*/
void insertNext (ObjectType* const newItem)
{
bassert (newItem != nullptr);
bassert (newItem->nextListItem == nullptr);
newItem->nextListItem = item;
item = newItem;
}
/** Inserts an item at a numeric index in the list.
Obviously this will involve iterating the list to find the item at the given index,
so be careful about the impact this may have on execution time.
*/
void insertAtIndex (int index, ObjectType* newItem)
{
bassert (newItem != nullptr);
LinkedListPointer* l = this;
while (index != 0 && l->item != nullptr)
{
l = &(l->item->nextListItem);
--index;
}
l->insertNext (newItem);
}
/** Replaces the object that this pointer points to, appending the rest of the list to
the new object, and returning the old one.
*/
ObjectType* replaceNext (ObjectType* const newItem) noexcept
{
bassert (newItem != nullptr);
bassert (newItem->nextListItem == nullptr);
ObjectType* const oldItem = item;
item = newItem;
item->nextListItem = oldItem->nextListItem.item;
oldItem->nextListItem.item = nullptr;
return oldItem;
}
/** Adds an item to the end of the list.
This operation involves iterating the whole list, so can be slow - if you need to
append a number of items to your list, it's much more efficient to use the Appender
class than to repeatedly call append().
*/
void append (ObjectType* const newItem)
{
getLast().item = newItem;
}
/** Creates copies of all the items in another list and adds them to this one.
This will use the ObjectType's copy constructor to try to create copies of each
item in the other list, and appends them to this list.
*/
void addCopyOfList (const LinkedListPointer& other)
{
LinkedListPointer* insertPoint = this;
for (ObjectType* i = other.item; i != nullptr; i = i->nextListItem)
{
insertPoint->insertNext (new ObjectType (*i));
insertPoint = &(insertPoint->item->nextListItem);
}
}
/** Removes the head item from the list.
This won't delete the object that is removed, but returns it, so the caller can
delete it if necessary.
*/
ObjectType* removeNext() noexcept
{
ObjectType* const oldItem = item;
if (oldItem != nullptr)
{
item = oldItem->nextListItem;
oldItem->nextListItem.item = nullptr;
}
return oldItem;
}
/** Removes a specific item from the list.
Note that this will not delete the item, it simply unlinks it from the list.
*/
void remove (ObjectType* const itemToRemove)
{
if (LinkedListPointer* const l = findPointerTo (itemToRemove))
l->removeNext();
}
/** Iterates the list, calling the delete operator on all of its elements and
leaving this pointer empty.
*/
void deleteAll()
{
while (item != nullptr)
{
ObjectType* const oldItem = item;
item = oldItem->nextListItem;
delete oldItem;
}
}
/** Finds a pointer to a given item.
If the item is found in the list, this returns the pointer that points to it. If
the item isn't found, this returns null.
*/
LinkedListPointer* findPointerTo (ObjectType* const itemToLookFor) noexcept
{
LinkedListPointer* l = this;
while (l->item != nullptr)
{
if (l->item == itemToLookFor)
return l;
l = &(l->item->nextListItem);
}
return nullptr;
}
/** Copies the items in the list to an array.
The destArray must contain enough elements to hold the entire list - no checks are
made for this!
*/
void copyToArray (ObjectType** destArray) const noexcept
{
bassert (destArray != nullptr);
for (ObjectType* i = item; i != nullptr; i = i->nextListItem)
*destArray++ = i;
}
/** Swaps this pointer with another one */
void swapWith (LinkedListPointer& other) noexcept
{
std::swap (item, other.item);
}
//==============================================================================
/**
Allows efficient repeated insertions into a list.
You can create an Appender object which points to the last element in your
list, and then repeatedly call Appender::append() to add items to the end
of the list in O(1) time.
*/
class Appender : public Uncopyable
{
public:
/** Creates an appender which will add items to the given list.
*/
Appender (LinkedListPointer& endOfListPointer) noexcept
: endOfList (&endOfListPointer)
{
// This can only be used to add to the end of a list.
bassert (endOfListPointer.item == nullptr);
}
/** Appends an item to the list. */
void append (ObjectType* const newItem) noexcept
{
*endOfList = newItem;
endOfList = &(newItem->nextListItem);
}
private:
LinkedListPointer* endOfList;
};
private:
//==============================================================================
ObjectType* item;
};
} // beast
#endif // BEAST_LINKEDLISTPOINTER_H_INCLUDED

View File

@@ -0,0 +1,96 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_SCOPEDVALUESETTER_H_INCLUDED
#define BEAST_SCOPEDVALUESETTER_H_INCLUDED
namespace beast
{
//==============================================================================
/**
Helper class providing an RAII-based mechanism for temporarily setting and
then re-setting a value.
E.g. @code
int x = 1;
{
ScopedValueSetter setter (x, 2);
// x is now 2
}
// x is now 1 again
{
ScopedValueSetter setter (x, 3, 4);
// x is now 3
}
// x is now 4
@endcode
*/
template <typename ValueType>
class ScopedValueSetter : public Uncopyable
{
public:
/** Creates a ScopedValueSetter that will immediately change the specified value to the
given new value, and will then reset it to its original value when this object is deleted.
*/
ScopedValueSetter (ValueType& valueToSet,
ValueType newValue)
: value (valueToSet),
originalValue (valueToSet)
{
valueToSet = newValue;
}
/** Creates a ScopedValueSetter that will immediately change the specified value to the
given new value, and will then reset it to be valueWhenDeleted when this object is deleted.
*/
ScopedValueSetter (ValueType& valueToSet,
ValueType newValue,
ValueType valueWhenDeleted)
: value (valueToSet),
originalValue (valueWhenDeleted)
{
valueToSet = newValue;
}
~ScopedValueSetter()
{
value = originalValue;
}
private:
//==============================================================================
ValueType& value;
const ValueType originalValue;
};
} // beast
#endif // BEAST_SCOPEDVALUESETTER_H_INCLUDED

184
beast/module/core/core.h Normal file
View File

@@ -0,0 +1,184 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_CORE_H_INCLUDED
#define BEAST_CORE_H_INCLUDED
// TargetPlatform.h should not use anything from BeastConfig.h
#include <beast/Config.h>
#include <beast/config/ContractChecks.h>
#include <beast/module/core/system/BeforeBoost.h>
#include <beast/module/core/system/BoostIncludes.h>
#include <beast/module/core/system/FunctionalIncludes.h>
#if BEAST_MSVC
# pragma warning (disable: 4251) // (DLL build warning, must be disabled before pushing the warning state)
# pragma warning (push)
# pragma warning (disable: 4786) // (long class name warning)
# ifdef __INTEL_COMPILER
# pragma warning (disable: 1125)
# endif
#endif
//------------------------------------------------------------------------------
// New header-only library modeled more closely according to boost
#include <beast/SmartPtr.h>
#include <beast/StaticAssert.h>
#include <beast/Uncopyable.h>
#include <beast/Atomic.h>
#include <beast/Arithmetic.h>
#include <beast/ByteOrder.h>
#include <beast/HeapBlock.h>
#include <beast/Memory.h>
#include <beast/Intrusive.h>
#include <beast/Strings.h>
#include <beast/Threads.h>
#include <beast/utility/Debug.h>
#include <beast/utility/Error.h>
#include <beast/utility/Journal.h>
#include <beast/utility/LeakChecked.h>
#include <beast/utility/PropertyStream.h>
#include <beast/utility/StaticObject.h>
#include <beast/module/core/system/StandardIncludes.h>
namespace beast
{
class InputStream;
class OutputStream;
class FileInputStream;
class FileOutputStream;
} // beast
// Order matters, since headers don't have their own #include lines.
// Add new includes to the bottom.
#include <beast/module/core/system/Functional.h>
#include <beast/module/core/time/AtExitHook.h>
#include <beast/module/core/time/Time.h>
#include <beast/module/core/threads/ScopedLock.h>
#include <beast/module/core/threads/CriticalSection.h>
#include <beast/module/core/containers/ElementComparator.h>
// If the MSVC debug heap headers were included, disable
// the macros during the juce include since they conflict.
#ifdef _CRTDBG_MAP_ALLOC
#pragma push_macro("calloc")
#pragma push_macro("free")
#pragma push_macro("malloc")
#pragma push_macro("realloc")
#pragma push_macro("_recalloc")
#pragma push_macro("_aligned_free")
#pragma push_macro("_aligned_malloc")
#pragma push_macro("_aligned_offset_malloc")
#pragma push_macro("_aligned_realloc")
#pragma push_macro("_aligned_recalloc")
#pragma push_macro("_aligned_offset_realloc")
#pragma push_macro("_aligned_offset_recalloc")
#pragma push_macro("_aligned_msize")
#undef calloc
#undef free
#undef malloc
#undef realloc
#undef _recalloc
#undef _aligned_free
#undef _aligned_malloc
#undef _aligned_offset_malloc
#undef _aligned_realloc
#undef _aligned_recalloc
#undef _aligned_offset_realloc
#undef _aligned_offset_recalloc
#undef _aligned_msize
#endif
#include <beast/module/core/containers/ArrayAllocationBase.h>
#ifdef _CRTDBG_MAP_ALLOC
#pragma pop_macro("_aligned_msize")
#pragma pop_macro("_aligned_offset_recalloc")
#pragma pop_macro("_aligned_offset_realloc")
#pragma pop_macro("_aligned_recalloc")
#pragma pop_macro("_aligned_realloc")
#pragma pop_macro("_aligned_offset_malloc")
#pragma pop_macro("_aligned_malloc")
#pragma pop_macro("_aligned_free")
#pragma pop_macro("_recalloc")
#pragma pop_macro("realloc")
#pragma pop_macro("malloc")
#pragma pop_macro("free")
#pragma pop_macro("calloc")
#endif
#include <beast/module/core/containers/Array.h>
#include <beast/module/core/misc/Result.h>
#include <beast/module/core/text/StringArray.h>
#include <beast/module/core/memory/MemoryBlock.h>
#include <beast/module/core/files/File.h>
#include <beast/module/core/thread/MutexTraits.h>
#include <beast/module/core/diagnostic/FatalError.h>
#include <beast/module/core/text/LexicalCast.h>
#include <beast/module/core/maths/Math.h>
#include <beast/module/core/logging/Logger.h>
#include <beast/module/core/containers/LinkedListPointer.h>
#include <beast/module/core/maths/Random.h>
#include <beast/module/core/text/StringPairArray.h>
#include <beast/module/core/containers/ScopedValueSetter.h>
#include <beast/module/core/maths/Range.h>
#include <beast/module/core/files/DirectoryIterator.h>
#include <beast/module/core/streams/InputStream.h>
#include <beast/module/core/files/FileInputStream.h>
#include <beast/module/core/streams/InputSource.h>
#include <beast/module/core/streams/FileInputSource.h>
#include <beast/module/core/streams/OutputStream.h>
#include <beast/module/core/files/FileOutputStream.h>
#include <beast/module/core/files/FileSearchPath.h>
#include <beast/module/core/files/RandomAccessFile.h>
#include <beast/module/core/files/TemporaryFile.h>
#include <beast/module/core/logging/Logger.h>
#include <beast/module/core/memory/SharedSingleton.h>
#include <beast/module/core/misc/WindowsRegistry.h>
#include <beast/module/core/streams/MemoryOutputStream.h>
#include <beast/module/core/system/SystemStats.h>
#include <beast/module/core/diagnostic/SemanticVersion.h>
#include <beast/module/core/threads/DynamicLibrary.h>
#include <beast/module/core/threads/Process.h>
#include <beast/module/core/diagnostic/UnitTestUtilities.h>
#include <beast/module/core/diagnostic/MeasureFunctionCallTime.h>
#include <beast/module/core/thread/DeadlineTimer.h>
#include <beast/module/core/thread/Workers.h>
#if BEAST_MSVC
#pragma warning (pop)
#endif
#endif

View File

@@ -0,0 +1,237 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#if BEAST_INCLUDE_BEASTCONFIG
#include <BeastConfig.h>
#endif
//==============================================================================
#include <beast/module/core/native/BasicNativeHeaders.h>
#include <beast/module/core/core.h>
#include <locale>
#include <cctype>
#if ! BEAST_BSD
#include <sys/timeb.h>
#endif
#if ! BEAST_ANDROID
#include <cwctype>
#endif
#if BEAST_WINDOWS
#include <ctime>
#include <winsock2.h>
#include <ws2tcpip.h>
#if ! BEAST_MINGW
#include <Dbghelp.h>
#if ! BEAST_DONT_AUTOLINK_TO_WIN32_LIBRARIES
#pragma comment (lib, "DbgHelp.lib")
#endif
#endif
#if BEAST_MINGW
#include <ws2spi.h>
#endif
#else
#if BEAST_LINUX || BEAST_ANDROID
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/errno.h>
#include <unistd.h>
#include <netinet/in.h>
#endif
#if BEAST_LINUX
#include <langinfo.h>
#endif
#include <pwd.h>
#include <fcntl.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <sys/time.h>
#include <net/if.h>
#include <sys/ioctl.h>
#if ! BEAST_ANDROID && ! BEAST_BSD
#include <execinfo.h>
#endif
#endif
#if BEAST_MAC || BEAST_IOS
#include <xlocale.h>
#include <mach/mach.h>
#endif
#if BEAST_ANDROID
#include <android/log.h>
#endif
//------------------------------------------------------------------------------
// If the MSVC debug heap headers were included, disable
// the macros during the juce include since they conflict.
#ifdef _CRTDBG_MAP_ALLOC
#pragma push_macro("calloc")
#pragma push_macro("free")
#pragma push_macro("malloc")
#pragma push_macro("realloc")
#pragma push_macro("_recalloc")
#pragma push_macro("_aligned_free")
#pragma push_macro("_aligned_malloc")
#pragma push_macro("_aligned_offset_malloc")
#pragma push_macro("_aligned_realloc")
#pragma push_macro("_aligned_recalloc")
#pragma push_macro("_aligned_offset_realloc")
#pragma push_macro("_aligned_offset_recalloc")
#pragma push_macro("_aligned_msize")
#undef calloc
#undef free
#undef malloc
#undef realloc
#undef _recalloc
#undef _aligned_free
#undef _aligned_malloc
#undef _aligned_offset_malloc
#undef _aligned_realloc
#undef _aligned_recalloc
#undef _aligned_offset_realloc
#undef _aligned_offset_recalloc
#undef _aligned_msize
#endif
#include <beast/module/core/diagnostic/FatalError.cpp>
#include <beast/module/core/diagnostic/SemanticVersion.cpp>
#include <beast/module/core/diagnostic/UnitTestUtilities.cpp>
#include <beast/module/core/files/DirectoryIterator.cpp>
#include <beast/module/core/files/File.cpp>
#include <beast/module/core/files/FileInputStream.cpp>
#include <beast/module/core/files/FileOutputStream.cpp>
#include <beast/module/core/files/FileSearchPath.cpp>
#include <beast/module/core/files/RandomAccessFile.cpp>
#include <beast/module/core/files/TemporaryFile.cpp>
#include <beast/module/core/logging/Logger.cpp>
#include <beast/module/core/maths/Random.cpp>
#include <beast/module/core/memory/MemoryBlock.cpp>
#include <beast/module/core/misc/Result.cpp>
#include <beast/module/core/streams/FileInputSource.cpp>
#include <beast/module/core/streams/InputStream.cpp>
#include <beast/module/core/streams/MemoryOutputStream.cpp>
#include <beast/module/core/streams/OutputStream.cpp>
#include <beast/module/core/system/SystemStats.cpp>
#include <beast/module/core/text/LexicalCast.cpp>
#include <beast/module/core/text/StringArray.cpp>
#include <beast/module/core/text/StringPairArray.cpp>
#include <beast/module/core/thread/DeadlineTimer.cpp>
#include <beast/module/core/thread/Workers.cpp>
#include <beast/module/core/time/AtExitHook.cpp>
#include <beast/module/core/time/Time.cpp>
#if BEAST_MAC || BEAST_IOS
#include <beast/module/core/native/osx_ObjCHelpers.h>
#endif
#if BEAST_ANDROID
#include "native/android_JNIHelpers.h"
#endif
#if ! BEAST_WINDOWS
#include <beast/module/core/native/posix_SharedCode.h>
#endif
#if BEAST_MAC || BEAST_IOS
#include <beast/module/core/native/mac_Files.mm>
#include <beast/module/core/native/mac_Strings.mm>
#include <beast/module/core/native/mac_SystemStats.mm>
#include <beast/module/core/native/mac_Threads.mm>
#elif BEAST_WINDOWS
#include <beast/module/core/native/win32_ComSmartPtr.h>
#include <beast/module/core/native/win32_Files.cpp>
#include <beast/module/core/native/win32_Registry.cpp>
#include <beast/module/core/native/win32_SystemStats.cpp>
#include <beast/module/core/native/win32_Threads.cpp>
#elif BEAST_LINUX
#include <beast/module/core/native/linux_Files.cpp>
#include <beast/module/core/native/linux_SystemStats.cpp>
#include <beast/module/core/native/linux_Threads.cpp>
#elif BEAST_BSD
#include <beast/module/core/native/bsd_Files.cpp>
#include <beast/module/core/native/bsd_SystemStats.cpp>
#include <beast/module/core/native/bsd_Threads.cpp>
#elif BEAST_ANDROID
#include "native/android_Files.cpp"
#include "native/android_Misc.cpp"
#include "native/android_SystemStats.cpp"
#include "native/android_Threads.cpp"
#endif
// Has to be outside the beast namespace
extern "C" {
void beast_reportFatalError (char const* message, char const* fileName, int lineNumber)
{
if (beast::beast_isRunningUnderDebugger())
beast_breakDebugger;
beast::FatalError (message, fileName, lineNumber);
BEAST_ANALYZER_NORETURN
}
}
#ifdef _CRTDBG_MAP_ALLOC
#pragma pop_macro("calloc")
#pragma pop_macro("free")
#pragma pop_macro("malloc")
#pragma pop_macro("realloc")
#pragma pop_macro("_recalloc")
#pragma pop_macro("_aligned_free")
#pragma pop_macro("_aligned_malloc")
#pragma pop_macro("_aligned_offset_malloc")
#pragma pop_macro("_aligned_realloc")
#pragma pop_macro("_aligned_recalloc")
#pragma pop_macro("_aligned_offset_realloc")
#pragma pop_macro("_aligned_offset_recalloc")
#pragma pop_macro("_aligned_msize")
#endif
// Must be outside the namespace
#include <beast/module/core/system/BoostPlaceholdersFix.cpp>

View File

@@ -0,0 +1,30 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#undef BEAST_COMPILE_OBJECTIVE_CPP
#define BEAST_COMPILE_OBJECTIVE_CPP 1
#include "beast_core.unity.cpp"
#undef BEAST_COMPILE_OBJECTIVE_CPP
#define BEAST_COMPILE_OBJECTIVE_CPP 0

View File

@@ -0,0 +1,128 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <beast/unit_test/suite.h>
namespace beast {
//
// FatalError::Reporter
//
void FatalError::Reporter::onFatalError (
char const* message, char const* stackBacktrace, char const* filePath, int lineNumber)
{
String formattedMessage = formatMessage (
message, stackBacktrace, filePath, lineNumber);
reportMessage (formattedMessage);
}
void FatalError::Reporter::reportMessage (String& formattedMessage)
{
std::cerr << formattedMessage.toRawUTF8 ();
}
String FatalError::Reporter::formatMessage (
char const* message, char const* stackBacktrace, char const* filePath, int lineNumber)
{
String formattedMessage;
formattedMessage.preallocateBytes (16 * 1024);
formattedMessage << message;
if (filePath != nullptr && filePath [0] != 0)
{
formattedMessage << ", in " << formatFilePath (filePath)
<< " line " << String (lineNumber);
}
formattedMessage << newLine;
if (stackBacktrace != nullptr && stackBacktrace [0] != 0)
{
formattedMessage << "Stack:" << newLine;
formattedMessage << stackBacktrace;
}
return formattedMessage;
}
String FatalError::Reporter::formatFilePath (char const* filePath)
{
return filePath;
}
//------------------------------------------------------------------------------
FatalError::Reporter *FatalError::s_reporter;
/** Returns the current fatal error reporter. */
FatalError::Reporter* FatalError::getReporter ()
{
return s_reporter;
}
FatalError::Reporter* FatalError::setReporter (Reporter* reporter)
{
Reporter* const previous (s_reporter);
s_reporter = reporter;
return previous;
}
FatalError::FatalError (char const* message, char const* fileName, int lineNumber)
{
typedef CriticalSection LockType;
static LockType s_mutex;
std::lock_guard <LockType> lock (s_mutex);
String const backtraceString = SystemStats::getStackBacktrace ();
char const* const szStackBacktrace = backtraceString.toRawUTF8 ();
String const fileNameString = fileName;
char const* const szFileName = fileNameString.toRawUTF8 ();
Reporter* const reporter (s_reporter);
if (reporter != nullptr)
{
reporter->onFatalError (message, szStackBacktrace, szFileName, lineNumber);
}
Process::terminate ();
}
//------------------------------------------------------------------------------
class FatalError_test : public unit_test::suite
{
public:
void run ()
{
int shouldBeZero (1);
check_invariant (shouldBeZero == 0);
}
};
BEAST_DEFINE_TESTSUITE_MANUAL(FatalError,beast_core,beast);
} // beast

View File

@@ -0,0 +1,154 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_CORE_FATALERROR_H_INCLUDED
#define BEAST_CORE_FATALERROR_H_INCLUDED
namespace beast
{
/** Signal a fatal error.
A fatal error indicates that the program has encountered an unexpected
situation and cannot continue safely. Reasons for raising a fatal error
would be to protect data integrity, prevent valuable resources from being
wasted, or to ensure that the user does not experience undefined behavior.
This function will end the process with exit code EXIT_FAILURE. Before
the process is terminated, a listener object gets notified so that the
client application can perform logging or emit further diagnostics.
*/
class FatalError : public Uncopyable
{
public:
struct Reporter
{
virtual ~Reporter () { }
/** Called when a fatal error is raised.
Because the program is likely in an inconsistent state, it is a
good idea to do as little as possible from within this function.
It will be called from the thread that raised the fatal error.
The default implementation of this function first calls
formatMessage to produce the string, then calls reportMessage
to report the results.
You can override this to perform custom formatting.
@note filePath may be a zero length string if identifying
information was stripped from the executable for security.
@note stackBacktrace will be a string with zero characters for
platforms for which which don't support stack crawls, or
when symbolic information is missing from the executable.
@param message The error message.
@param stackBackTrace The stack of the thread that raised the error.
@param filePath A full or partial path to the source file that raised the error.
@param lineNumber The line number in the source file.
*/
virtual void onFatalError (char const* message,
char const* stackBacktrace,
char const* filePath,
int lineNumber);
/** Called to report the message.
The default implementation simply writes this to standard error.
You can override this to perform additional things like logging
to a file or sending the message to another process.
@param formattedMessage The message to report.
*/
virtual void reportMessage (String& formattedMessage);
protected:
/** Called to format the message.
The default implementation calls formatFilePath to produce
a formatted file name, and then creates a suitable string
containing all of the information.
You can override this function to format your own messages.
@param message The message from the report.
@param stackBacktrace The stack backtrace from the report.
@param filePath The file path from the report.
@param lineNumber The line number from the report
*/
virtual String formatMessage (char const* message,
char const* stackBacktrace,
char const* filePath,
int lineNumber);
/** Call to reformat the file path.
Usually the file is a full path, which we really don't care
to see and can also be a security hole.
The default implementation removes most of the useless
directory components from the front.
You can override this to do a custom format on the file path.
*/
virtual String formatFilePath (char const* filePath);
};
/** Returns the current fatal error reporter. */
static Reporter* getReporter ();
/** Set the fatal error reporter.
Note that if a fatal error is raised during the construction of
objects with static storage duration, it might not be possible to
set the reporter before the error is raised. The solution is not
to use objects with static storage duration that have non-trivial
constructors, use SharedSingleton instead.
The default behavior when no reporter is set is to invoke
the base class version of Reporter::onFatalError.
If a reporter was previously set, this routine will do nothing.
@return The previous Reporter (Which may be null).
@see SharedSingleton, Reporter
*/
static Reporter* setReporter (Reporter* reporter);
/** Raise a fatal error.
If multiple threads raise an error, only one will succeed. The
other threads will be blocked before the process terminates.
@param message A null terminated string, which should come from a constant.
@param filePath Pass __FILE__ here.
@param lineNumber Pass __LINE__ here.
*/
FatalError (char const* message, char const* filePath, int lineNumber);
private:
static Reporter* s_reporter;
};
} // beast
#endif

View File

@@ -0,0 +1,85 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_CORE_DIAGNOSTIC_MEASUREFUNCTIONCALLTIME_H_INCLUDED
#define BEAST_CORE_DIAGNOSTIC_MEASUREFUNCTIONCALLTIME_H_INCLUDED
namespace beast
{
/** Measures the speed of invoking a function. */
/** @{ */
template <typename Function>
double measureFunctionCallTime (Function f)
{
std::int64_t const startTime (Time::getHighResolutionTicks ());
f ();
return Time::highResolutionTicksToSeconds (
Time::getHighResolutionTicks () - startTime);
}
#if 0
template <typename Function,
typename P1, typename P2, typename P3, typename P4,
typename P5, typename P6, typename P7, typename P8>
double measureFunctionCallTime (Function f, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8)
{
std::int64_t const startTime (Time::getHighResolutionTicks ());
f (p1, p2, p3, p4, p5 ,p6 ,p7 ,p8);
return Time::highResolutionTicksToSeconds (
Time::getHighResolutionTicks () - startTime);
}
template <typename Function,
typename P1, typename P2, typename P3, typename P4,
typename P5, typename P6, typename P7, typename P8>
double measureFunctionCallTime (Function f, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8)
{
std::int64_t const startTime (Time::getHighResolutionTicks ());
f (p1, p2, p3, p4, p5 ,p6 ,p7 ,p8);
return Time::highResolutionTicksToSeconds (
Time::getHighResolutionTicks () - startTime);
}
template <typename Function,
typename P1, typename P2, typename P3, typename P4,
typename P5, typename P6, typename P7, typename P8>
double measureFunctionCallTime (Function f, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8)
{
std::int64_t const startTime (Time::getHighResolutionTicks ());
f (p1, p2, p3, p4, p5 ,p6 ,p7 ,p8);
return Time::highResolutionTicksToSeconds (
Time::getHighResolutionTicks () - startTime);
}
template <typename Function,
typename P1, typename P2, typename P3, typename P4,
typename P5, typename P6, typename P7, typename P8>
double measureFunctionCallTime (Function f, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8)
{
std::int64_t const startTime (Time::getHighResolutionTicks ());
f (p1, p2, p3, p4, p5 ,p6 ,p7 ,p8);
return Time::highResolutionTicksToSeconds (
Time::getHighResolutionTicks () - startTime);
}
#endif
} // beast
#endif

View File

@@ -0,0 +1,521 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <beast/unit_test/suite.h>
namespace beast {
SemanticVersion::SemanticVersion ()
: majorVersion (0)
, minorVersion (0)
, patchVersion (0)
{
}
bool SemanticVersion::parse (String input)
{
// May not have leading or trailing whitespace
if (input.trim () != input)
return false;
// Must have major version number
if (! chopUInt (&majorVersion, std::numeric_limits <int>::max (), input))
return false;
if (! chop (".", input))
return false;
// Must have minor version number
if (! chopUInt (&minorVersion, std::numeric_limits <int>::max (), input))
return false;
if (! chop (".", input))
return false;
// Must have patch version number
if (! chopUInt (&patchVersion, std::numeric_limits <int>::max (), input))
return false;
// May have pre-release identifier list
if (chop ("-", input))
{
chopIdentifiers (&preReleaseIdentifiers, false, input);
// Must not be empty
if (preReleaseIdentifiers.size () <= 0)
return false;
}
// May have metadata identifier list
if (chop ("+", input))
{
chopIdentifiers (&metaData, true, input);
// Must not be empty
if (metaData.size () <= 0)
return false;
}
// May not have anything left
if (input.length () > 0)
return false;
return true;
}
String SemanticVersion::print () const
{
String s;
s << String (majorVersion) << "." << String (minorVersion) << "." << String (patchVersion);
if (preReleaseIdentifiers.size () > 0)
s << "-" << printIdentifiers (preReleaseIdentifiers);
if (metaData.size () > 0)
s << "+" << printIdentifiers (metaData);
return s;
}
int SemanticVersion::compare (SemanticVersion const& rhs) const noexcept
{
if (majorVersion > rhs.majorVersion)
return 1;
else if (majorVersion < rhs.majorVersion)
return -1;
if (minorVersion > rhs.minorVersion)
return 1;
else if (minorVersion < rhs.minorVersion)
return -1;
if (patchVersion > rhs.patchVersion)
return 1;
else if (patchVersion < rhs.patchVersion)
return -1;
if (isPreRelease () || rhs.isPreRelease ())
{
// Pre-releases have a lower precedence
if (isRelease () && rhs.isPreRelease ())
return 1;
else if (isPreRelease () && rhs.isRelease ())
return -1;
// Compare pre-release identifiers
for (int i = 0; i < bmax (preReleaseIdentifiers.size (), rhs.preReleaseIdentifiers.size ()); ++i)
{
// A larger list of identifiers has a higher precedence
if (i >= rhs.preReleaseIdentifiers.size ())
return 1;
else if (i >= preReleaseIdentifiers.size ())
return -1;
String const& left (preReleaseIdentifiers [i]);
String const& right (rhs.preReleaseIdentifiers [i]);
// Numeric identifiers have lower precedence
if (! isNumeric (left) && isNumeric (right))
return 1;
else if (isNumeric (left) && ! isNumeric (right))
return -1;
if (isNumeric (left))
{
bassert (isNumeric (right));
int const iLeft (left.getIntValue ());
int const iRight (right.getIntValue ());
if (iLeft > iRight)
return 1;
else if (iLeft < iRight)
return -1;
}
else
{
bassert (! isNumeric (right));
int result = left.compareLexicographically (right);
if (result != 0)
return result;
}
}
}
// metadata is ignored
return 0;
}
bool SemanticVersion::isNumeric (String const& s)
{
return String (s.getIntValue ()) == s;
}
bool SemanticVersion::chop (String const& what, String& input)
{
if (input.startsWith (what))
{
input = input.substring (what.length ());
return true;
}
return false;
}
String SemanticVersion::printIdentifiers (StringArray const& list)
{
String s;
if (list.size () > 0)
{
s << list [0];
for (int i = 1; i < list.size (); ++i)
s << "." << list [i];
}
return s;
}
bool SemanticVersion::chopUInt (int* value, int limit, String& input)
{
// Must not be empty
if (input.length () <= 0)
return false;
int firstNonDigit = 0;
for (; firstNonDigit < input.length (); ++firstNonDigit)
{
if (! CharacterFunctions::isDigit (input [firstNonDigit]))
break;
}
String const s = input.substring (0, firstNonDigit);
// Must not be empty
if (s.length () <= 0)
return false;
int const n = s.getIntValue ();
// Must not have leading zeroes
if (String (n) != s)
return false;
// Must not be out of range
if (n < 0 || n > limit)
return false;
input = input.substring (s.length ());
*value = n;
return true;
}
bool SemanticVersion::chopIdentifier (String* value, bool allowLeadingZeroes, String& input)
{
// Must not be empty
if (input.length () <= 0)
return false;
// Must not have a leading 0
if (! allowLeadingZeroes && input [0] == '0')
return false;
// Find the first character that cannot be part of an identifier
int i;
for (i = 0; i < input.length (); ++i)
{
static char const* validSet =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-";
if (! String (validSet).contains (String::charToString (input [i])))
break;
}
// Must not be empty
if (i <= 0)
return false;
*value = input.substring (0, i);
input = input.substring (i);
return true;
}
bool SemanticVersion::chopIdentifiers (StringArray* value, bool allowLeadingZeroes, String& input)
{
if (input.length () <= 0)
return false;
for (;;)
{
String s;
if (! chopIdentifier (&s, allowLeadingZeroes, input))
return false;
value->add (s);
if (! chop (".", input))
break;
}
return true;
}
//------------------------------------------------------------------------------
class SemanticVersion_test: public unit_test::suite
{
public:
void checkPass (String const& input, bool shouldPass = true)
{
SemanticVersion v;
if (shouldPass )
{
expect (v.parse (input));
expect (v.print () == input);
}
else
{
expect (! v.parse (input));
}
}
void checkFail (String const& input)
{
checkPass (input, false);
}
// check input and input with appended metadata
void checkMeta (String const& input, bool shouldPass)
{
checkPass (input, shouldPass);
checkPass (input + "+a", shouldPass);
checkPass (input + "+1", shouldPass);
checkPass (input + "+a.b", shouldPass);
checkPass (input + "+ab.cd", shouldPass);
checkFail (input + "!");
checkFail (input + "+");
checkFail (input + "++");
checkFail (input + "+!");
checkFail (input + "+.");
checkFail (input + "+a.!");
}
void checkMetaFail (String const& input)
{
checkMeta (input, false);
}
// check input, input with appended release data,
// input with appended metadata, and input with both
// appended release data and appended metadata
//
void checkRelease (String const& input, bool shouldPass = true)
{
checkMeta (input, shouldPass);
checkMeta (input + "-1", shouldPass);
checkMeta (input + "-a", shouldPass);
checkMeta (input + "-a1", shouldPass);
checkMeta (input + "-a1.b1", shouldPass);
checkMeta (input + "-ab.cd", shouldPass);
checkMeta (input + "--", shouldPass);
checkMetaFail (input + "+");
checkMetaFail (input + "!");
checkMetaFail (input + "-");
checkMetaFail (input + "-!");
checkMetaFail (input + "-.");
checkMetaFail (input + "-a.!");
checkMetaFail (input + "-0.a");
}
// Checks the major.minor.version string alone and with all
// possible combinations of release identifiers and metadata.
//
void check (String const& input, bool shouldPass = true)
{
checkRelease (input, shouldPass);
}
void negcheck (String const& input)
{
check (input, false);
}
void testParse ()
{
testcase ("parse");
check ("0.0.0");
check ("1.2.3");
check ("2147483647.2147483647.2147483647"); // max int
// negative values
negcheck ("-1.2.3");
negcheck ("1.-2.3");
negcheck ("1.2.-3");
// missing parts
negcheck ("");
negcheck ("1");
negcheck ("1.");
negcheck ("1.2");
negcheck ("1.2.");
negcheck (".2.3");
// whitespace
negcheck (" 1.2.3");
negcheck ("1 .2.3");
negcheck ("1.2 .3");
negcheck ("1.2.3 ");
// leading zeroes
negcheck ("01.2.3");
negcheck ("1.02.3");
negcheck ("1.2.03");
}
static StringArray ids ()
{
return StringArray ();
}
static StringArray ids (String const& s1)
{
StringArray v;
v.add (s1);
return v;
}
static StringArray ids (String const& s1, String const& s2)
{
StringArray v;
v.add (s1);
v.add (s2);
return v;
}
static StringArray ids (String const& s1, String const& s2, String const& s3)
{
StringArray v;
v.add (s1);
v.add (s2);
v.add (s3);
return v;
}
// Checks the decomposition of the input into appropriate values
void checkValues (String const& input,
int majorVersion,
int minorVersion,
int patchVersion,
StringArray const& preReleaseIdentifiers = StringArray (),
StringArray const& metaData = StringArray ())
{
SemanticVersion v;
expect (v.parse (input));
expect (v.majorVersion == majorVersion);
expect (v.minorVersion == minorVersion);
expect (v.patchVersion == patchVersion);
expect (v.preReleaseIdentifiers == preReleaseIdentifiers);
expect (v.metaData == metaData);
}
void testValues ()
{
checkValues ("0.1.2", 0, 1, 2);
checkValues ("1.2.3", 1, 2, 3);
checkValues ("1.2.3-rc1", 1, 2, 3, ids ("rc1"));
checkValues ("1.2.3-rc1.debug", 1, 2, 3, ids ("rc1", "debug"));
checkValues ("1.2.3-rc1.debug.asm", 1, 2, 3, ids ("rc1", "debug", "asm"));
checkValues ("1.2.3+full", 1, 2, 3, ids (), ids ("full"));
checkValues ("1.2.3+full.prod", 1, 2, 3, ids (), ids ("full", "prod"));
checkValues ("1.2.3+full.prod.x86", 1, 2, 3, ids (), ids ("full", "prod", "x86"));
checkValues ("1.2.3-rc1.debug.asm+full.prod.x86", 1, 2, 3,
ids ("rc1", "debug", "asm"), ids ("full", "prod", "x86"));
}
// makes sure the left version is less than the right
void checkLessInternal (String const& lhs, String const& rhs)
{
SemanticVersion left;
SemanticVersion right;
expect (left.parse (lhs));
expect (right.parse (rhs));
expect (left.compare (left) == 0);
expect (right.compare (right) == 0);
expect (left.compare (right) < 0);
expect (right.compare (left) > 0);
expect (left < right);
expect (right > left);
expect (left == left);
expect (right == right);
}
void checkLess (String const& lhs, String const& rhs)
{
checkLessInternal (lhs, rhs);
checkLessInternal (lhs + "+meta", rhs);
checkLessInternal (lhs, rhs + "+meta");
checkLessInternal (lhs + "+meta", rhs + "+meta");
}
void testCompare ()
{
checkLess ("1.0.0-alpha", "1.0.0-alpha.1");
checkLess ("1.0.0-alpha.1", "1.0.0-alpha.beta");
checkLess ("1.0.0-alpha.beta", "1.0.0-beta");
checkLess ("1.0.0-beta", "1.0.0-beta.2");
checkLess ("1.0.0-beta.2", "1.0.0-beta.11");
checkLess ("1.0.0-beta.11", "1.0.0-rc.1");
checkLess ("1.0.0-rc.1", "1.0.0");
checkLess ("0.9.9", "1.0.0");
}
void run ()
{
testParse ();
testValues ();
testCompare ();
}
};
BEAST_DEFINE_TESTSUITE(SemanticVersion,beast_core,beast);
} // beast

View File

@@ -0,0 +1,79 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_SEMANTICVERSION_H_INCLUDED
#define BEAST_SEMANTICVERSION_H_INCLUDED
namespace beast
{
/** A Semantic Version number.
Identifies the build of a particular version of software using
the Semantic Versioning Specification described here:
http://semver.org/
*/
class SemanticVersion
{
public:
int majorVersion;
int minorVersion;
int patchVersion;
StringArray preReleaseIdentifiers;
StringArray metaData;
SemanticVersion ();
/** Parse a semantic version string.
The parsing is as strict as possible.
@return `true` if the string was parsed.
*/
bool parse (String input);
/** Produce a string from semantic version components. */
String print () const;
inline bool isRelease () const noexcept { return preReleaseIdentifiers.size () <= 0; }
inline bool isPreRelease () const noexcept { return ! isRelease (); }
/** Compare this against another version.
The comparison follows the rules as per the specification.
*/
int compare (SemanticVersion const& rhs) const noexcept;
inline bool operator== (SemanticVersion const& other) const noexcept { return compare (other) == 0; }
inline bool operator!= (SemanticVersion const& other) const noexcept { return compare (other) != 0; }
inline bool operator>= (SemanticVersion const& other) const noexcept { return compare (other) >= 0; }
inline bool operator<= (SemanticVersion const& other) const noexcept { return compare (other) <= 0; }
inline bool operator> (SemanticVersion const& other) const noexcept { return compare (other) > 0; }
inline bool operator< (SemanticVersion const& other) const noexcept { return compare (other) < 0; }
private:
static bool isNumeric (String const& s);
static String printIdentifiers (StringArray const& list);
static bool chop (String const& what, String& input);
static bool chopUInt (int* value, int limit, String& input);
static bool chopIdentifier (String* value, bool allowLeadingZeroes, String& input);
static bool chopIdentifiers (StringArray* value, bool preRelease, String& input);
};
} // beast
#endif

View File

@@ -0,0 +1,24 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast {
namespace UnitTestUtilities {
} // UnitTestUtilities
} // beast

View File

@@ -0,0 +1,105 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_UNITTESTUTILITIES_H_INCLUDED
#define BEAST_UNITTESTUTILITIES_H_INCLUDED
namespace beast {
namespace UnitTestUtilities {
/** Fairly shuffle an array pseudo-randomly.
*/
template <class T>
void repeatableShuffle (int const numberOfItems, T& arrayOfItems, Random& r)
{
for (int i = numberOfItems - 1; i > 0; --i)
{
int const choice = r.nextInt (i + 1);
std::swap (arrayOfItems [i], arrayOfItems [choice]);
}
}
template <class T>
void repeatableShuffle (int const numberOfItems, T& arrayOfItems, std::int64_t seedValue)
{
Random r (seedValue);
repeatableShuffle (numberOfItems, arrayOfItems, r);
}
//------------------------------------------------------------------------------
/** A block of memory used for test data.
*/
struct Payload
{
/** Construct a payload with a buffer of the specified maximum size.
@param maximumBytes The size of the buffer, in bytes.
*/
explicit Payload (int maxBufferSize)
: bufferSize (maxBufferSize)
, data (maxBufferSize)
{
}
/** Generate a random block of data within a certain size range.
@param minimumBytes The smallest number of bytes in the resulting payload.
@param maximumBytes The largest number of bytes in the resulting payload.
@param seedValue The value to seed the random number generator with.
*/
void repeatableRandomFill (int minimumBytes, int maximumBytes, std::int64_t seedValue) noexcept
{
bassert (minimumBytes >=0 && maximumBytes <= bufferSize);
Random r (seedValue);
bytes = minimumBytes + r.nextInt (1 + maximumBytes - minimumBytes);
bassert (bytes >= minimumBytes && bytes <= bufferSize);
for (int i = 0; i < bytes; ++i)
data [i] = static_cast <unsigned char> (r.nextInt ());
}
/** Compare two payloads for equality.
*/
bool operator== (Payload const& other) const noexcept
{
if (bytes == other.bytes)
{
return memcmp (data.getData (), other.data.getData (), bytes) == 0;
}
else
{
return false;
}
}
public:
int const bufferSize;
int bytes;
HeapBlock <char> data;
};
} // UnitTestUtilities
} // beast
#endif

View File

@@ -0,0 +1,159 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
static StringArray parseWildcards (const String& pattern)
{
StringArray s;
s.addTokens (pattern, ";,", "\"'");
s.trim();
s.removeEmptyStrings();
return s;
}
static bool fileMatches (const StringArray& wildCards, const String& filename)
{
for (int i = 0; i < wildCards.size(); ++i)
if (filename.matchesWildcard (wildCards[i], ! File::areFileNamesCaseSensitive()))
return true;
return false;
}
DirectoryIterator::DirectoryIterator (const File& directory, bool recursive,
const String& pattern, const int type)
: wildCards (parseWildcards (pattern)),
fileFinder (directory, (recursive || wildCards.size() > 1) ? "*" : pattern),
wildCard (pattern),
path (File::addTrailingSeparator (directory.getFullPathName())),
index (-1),
totalNumFiles (-1),
whatToLookFor (type),
isRecursive (recursive),
hasBeenAdvanced (false)
{
// you have to specify the type of files you're looking for!
bassert ((type & (File::findFiles | File::findDirectories)) != 0);
bassert (type > 0 && type <= 7);
}
DirectoryIterator::~DirectoryIterator()
{
}
bool DirectoryIterator::next()
{
return next (nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
}
bool DirectoryIterator::next (bool* const isDirResult, bool* const isHiddenResult, std::int64_t* const fileSize,
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
{
hasBeenAdvanced = true;
if (subIterator != nullptr)
{
if (subIterator->next (isDirResult, isHiddenResult, fileSize, modTime, creationTime, isReadOnly))
return true;
subIterator = nullptr;
}
String filename;
bool isDirectory, isHidden = false;
while (fileFinder.next (filename, &isDirectory,
(isHiddenResult != nullptr || (whatToLookFor & File::ignoreHiddenFiles) != 0) ? &isHidden : nullptr,
fileSize, modTime, creationTime, isReadOnly))
{
++index;
if (! filename.containsOnly ("."))
{
bool matches = false;
if (isDirectory)
{
if (isRecursive && ((whatToLookFor & File::ignoreHiddenFiles) == 0 || ! isHidden))
subIterator = new DirectoryIterator (File::createFileWithoutCheckingPath (path + filename),
true, wildCard, whatToLookFor);
matches = (whatToLookFor & File::findDirectories) != 0;
}
else
{
matches = (whatToLookFor & File::findFiles) != 0;
}
// if we're not relying on the OS iterator to do the wildcard match, do it now..
if (matches && (isRecursive || wildCards.size() > 1))
matches = fileMatches (wildCards, filename);
if (matches && (whatToLookFor & File::ignoreHiddenFiles) != 0)
matches = ! isHidden;
if (matches)
{
currentFile = File::createFileWithoutCheckingPath (path + filename);
if (isHiddenResult != nullptr) *isHiddenResult = isHidden;
if (isDirResult != nullptr) *isDirResult = isDirectory;
return true;
}
if (subIterator != nullptr)
return next (isDirResult, isHiddenResult, fileSize, modTime, creationTime, isReadOnly);
}
}
return false;
}
const File& DirectoryIterator::getFile() const
{
if (subIterator != nullptr && subIterator->hasBeenAdvanced)
return subIterator->getFile();
// You need to call DirectoryIterator::next() before asking it for the file that it found!
bassert (hasBeenAdvanced);
return currentFile;
}
float DirectoryIterator::getEstimatedProgress() const
{
if (totalNumFiles < 0)
totalNumFiles = File (path).getNumberOfChildFiles (File::findFilesAndDirectories);
if (totalNumFiles <= 0)
return 0.0f;
const float detailedIndex = (subIterator != nullptr) ? index + subIterator->getEstimatedProgress()
: (float) index;
return detailedIndex / totalNumFiles;
}
} // beast

View File

@@ -0,0 +1,151 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_DIRECTORYITERATOR_H_INCLUDED
#define BEAST_DIRECTORYITERATOR_H_INCLUDED
namespace beast
{
//==============================================================================
/**
Searches through a the files in a directory, returning each file that is found.
A DirectoryIterator will search through a directory and its subdirectories using
a wildcard filepattern match.
If you may be finding a large number of files, this is better than
using File::findChildFiles() because it doesn't block while it finds them
all, and this is more memory-efficient.
It can also guess how far it's got using a wildly inaccurate algorithm.
*/
class DirectoryIterator : LeakChecked <DirectoryIterator>, public Uncopyable
{
public:
//==============================================================================
/** Creates a DirectoryIterator for a given directory.
After creating one of these, call its next() method to get the
first file - e.g. @code
DirectoryIterator iter (File ("/animals/mooses"), true, "*.moose");
while (iter.next())
{
File theFileItFound (iter.getFile());
... etc
}
@endcode
@param directory the directory to search in
@param isRecursive whether all the subdirectories should also be searched
@param wildCard the file pattern to match. This may contain multiple patterns
separated by a semi-colon or comma, e.g. "*.jpg;*.png"
@param whatToLookFor a value from the File::TypesOfFileToFind enum, specifying
whether to look for files, directories, or both.
*/
DirectoryIterator (const File& directory,
bool isRecursive,
const String& wildCard = "*",
int whatToLookFor = File::findFiles);
/** Destructor. */
~DirectoryIterator();
/** Moves the iterator along to the next file.
@returns true if a file was found (you can then use getFile() to see what it was) - or
false if there are no more matching files.
*/
bool next();
/** Moves the iterator along to the next file, and returns various properties of that file.
If you need to find out details about the file, it's more efficient to call this method than
to call the normal next() method and then find out the details afterwards.
All the parameters are optional, so pass null pointers for any items that you're not
interested in.
@returns true if a file was found (you can then use getFile() to see what it was) - or
false if there are no more matching files. If it returns false, then none of the
parameters will be filled-in.
*/
bool next (bool* isDirectory,
bool* isHidden,
std::int64_t* fileSize,
Time* modTime,
Time* creationTime,
bool* isReadOnly);
/** Returns the file that the iterator is currently pointing at.
The result of this call is only valid after a call to next() has returned true.
*/
const File& getFile() const;
/** Returns a guess of how far through the search the iterator has got.
@returns a value 0.0 to 1.0 to show the progress, although this won't be
very accurate.
*/
float getEstimatedProgress() const;
private:
//==============================================================================
class NativeIterator : LeakChecked <NativeIterator>, public Uncopyable
{
public:
NativeIterator (const File& directory, const String& wildCard);
~NativeIterator();
bool next (String& filenameFound,
bool* isDirectory, bool* isHidden, std::int64_t* fileSize,
Time* modTime, Time* creationTime, bool* isReadOnly);
class Pimpl;
private:
friend class DirectoryIterator;
friend class ScopedPointer<Pimpl>;
ScopedPointer<Pimpl> pimpl;
};
friend class ScopedPointer<NativeIterator::Pimpl>;
StringArray wildCards;
NativeIterator fileFinder;
String wildCard, path;
int index;
mutable int totalNumFiles;
const int whatToLookFor;
const bool isRecursive;
bool hasBeenAdvanced;
ScopedPointer <DirectoryIterator> subIterator;
File currentFile;
};
} // beast
#endif // BEAST_DIRECTORYITERATOR_H_INCLUDED

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,966 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_FILE_H_INCLUDED
#define BEAST_FILE_H_INCLUDED
#include <beast/module/core/containers/Array.h>
#include <beast/module/core/memory/MemoryBlock.h>
#include <beast/module/core/misc/Result.h>
#include <beast/module/core/time/Time.h>
#include <beast/module/core/text/StringArray.h>
#include <beast/module/core/threads/CriticalSection.h>
namespace beast {
class FileInputStream;
class FileOutputStream;
//==============================================================================
/**
Represents a local file or directory.
This class encapsulates the absolute pathname of a file or directory, and
has methods for finding out about the file and changing its properties.
To read or write to the file, there are methods for returning an input or
output stream.
@see FileInputStream, FileOutputStream
*/
class File
{
public:
//==============================================================================
/** Creates an (invalid) file object.
The file is initially set to an empty path, so getFullPath() will return
an empty string, and comparing the file to File::nonexistent will return
true.
You can use its operator= method to point it at a proper file.
*/
File() noexcept {}
/** Creates a file from an absolute path.
If the path supplied is a relative path, it is taken to be relative
to the current working directory (see File::getCurrentWorkingDirectory()),
but this isn't a recommended way of creating a file, because you
never know what the CWD is going to be.
On the Mac/Linux, the path can include "~" notation for referring to
user home directories.
*/
File (const String& absolutePath);
/** Creates a copy of another file object. */
File (const File&);
/** Destructor. */
~File() noexcept {}
/** Sets the file based on an absolute pathname.
If the path supplied is a relative path, it is taken to be relative
to the current working directory (see File::getCurrentWorkingDirectory()),
but this isn't a recommended way of creating a file, because you
never know what the CWD is going to be.
On the Mac/Linux, the path can include "~" notation for referring to
user home directories.
*/
File& operator= (const String& newAbsolutePath);
/** Copies from another file object. */
File& operator= (const File& otherFile);
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
File (File&&) noexcept;
File& operator= (File&&) noexcept;
#endif
//==============================================================================
/** This static constant is used for referring to an 'invalid' file. */
static File const& nonexistent ();
//==============================================================================
/** Checks whether the file actually exists.
@returns true if the file exists, either as a file or a directory.
@see existsAsFile, isDirectory
*/
bool exists() const;
/** Checks whether the file exists and is a file rather than a directory.
@returns true only if this is a real file, false if it's a directory
or doesn't exist
@see exists, isDirectory
*/
bool existsAsFile() const;
/** Checks whether the file is a directory that exists.
@returns true only if the file is a directory which actually exists, so
false if it's a file or doesn't exist at all
@see exists, existsAsFile
*/
bool isDirectory() const;
/** Returns the size of the file in bytes.
@returns the number of bytes in the file, or 0 if it doesn't exist.
*/
std::int64_t getSize() const;
/** Utility function to convert a file size in bytes to a neat string description.
So for example 100 would return "100 bytes", 2000 would return "2 KB",
2000000 would produce "2 MB", etc.
*/
static String descriptionOfSizeInBytes (std::int64_t bytes);
//==============================================================================
/** Returns the complete, absolute path of this file.
This includes the filename and all its parent folders. On Windows it'll
also include the drive letter prefix; on Mac or Linux it'll be a complete
path starting from the root folder.
If you just want the file's name, you should use getFileName() or
getFileNameWithoutExtension().
@see getFileName, getRelativePathFrom
*/
const String& getFullPathName() const noexcept { return fullPath; }
/** Returns the last section of the pathname.
Returns just the final part of the path - e.g. if the whole path
is "/moose/fish/foo.txt" this will return "foo.txt".
For a directory, it returns the final part of the path - e.g. for the
directory "/moose/fish" it'll return "fish".
If the filename begins with a dot, it'll return the whole filename, e.g. for
"/moose/.fish", it'll return ".fish"
@see getFullPathName, getFileNameWithoutExtension
*/
String getFileName() const;
/** Creates a relative path that refers to a file relatively to a given directory.
e.g. File ("/moose/foo.txt").getRelativePathFrom (File ("/moose/fish/haddock"))
would return "../../foo.txt".
If it's not possible to navigate from one file to the other, an absolute
path is returned. If the paths are invalid, an empty string may also be
returned.
@param directoryToBeRelativeTo the directory which the resultant string will
be relative to. If this is actually a file rather than
a directory, its parent directory will be used instead.
If it doesn't exist, it's assumed to be a directory.
@see getChildFile, isAbsolutePath
*/
String getRelativePathFrom (const File& directoryToBeRelativeTo) const;
//==============================================================================
/** Returns the file's extension.
Returns the file extension of this file, also including the dot.
e.g. "/moose/fish/foo.txt" would return ".txt"
@see hasFileExtension, withFileExtension, getFileNameWithoutExtension
*/
String getFileExtension() const;
/** Checks whether the file has a given extension.
@param extensionToTest the extension to look for - it doesn't matter whether or
not this string has a dot at the start, so ".wav" and "wav"
will have the same effect. To compare with multiple extensions, this
parameter can contain multiple strings, separated by semi-colons -
so, for example: hasFileExtension (".jpeg;png;gif") would return
true if the file has any of those three extensions.
@see getFileExtension, withFileExtension, getFileNameWithoutExtension
*/
bool hasFileExtension (const String& extensionToTest) const;
/** Returns a version of this file with a different file extension.
e.g. File ("/moose/fish/foo.txt").withFileExtension ("html") returns "/moose/fish/foo.html"
@param newExtension the new extension, either with or without a dot at the start (this
doesn't make any difference). To get remove a file's extension altogether,
pass an empty string into this function.
@see getFileName, getFileExtension, hasFileExtension, getFileNameWithoutExtension
*/
File withFileExtension (const String& newExtension) const;
/** Returns the last part of the filename, without its file extension.
e.g. for "/moose/fish/foo.txt" this will return "foo".
@see getFileName, getFileExtension, hasFileExtension, withFileExtension
*/
String getFileNameWithoutExtension() const;
//==============================================================================
/** Returns a 32-bit hash-code that identifies this file.
This is based on the filename. Obviously it's possible, although unlikely, that
two files will have the same hash-code.
*/
int hashCode() const;
/** Returns a 64-bit hash-code that identifies this file.
This is based on the filename. Obviously it's possible, although unlikely, that
two files will have the same hash-code.
*/
std::int64_t hashCode64() const;
//==============================================================================
/** Returns a file that represents a relative (or absolute) sub-path of the current one.
This will find a child file or directory of the current object.
e.g.
File ("/moose/fish").getChildFile ("foo.txt") will produce "/moose/fish/foo.txt".
File ("/moose/fish").getChildFile ("haddock/foo.txt") will produce "/moose/fish/haddock/foo.txt".
File ("/moose/fish").getChildFile ("../foo.txt") will produce "/moose/foo.txt".
If the string is actually an absolute path, it will be treated as such, e.g.
File ("/moose/fish").getChildFile ("/foo.txt") will produce "/foo.txt"
@see getSiblingFile, getParentDirectory, getRelativePathFrom, isAChildOf
*/
File getChildFile (String relativeOrAbsolutePath) const;
/** Returns a file which is in the same directory as this one.
This is equivalent to getParentDirectory().getChildFile (name).
@see getChildFile, getParentDirectory
*/
File getSiblingFile (const String& siblingFileName) const;
//==============================================================================
/** Returns the directory that contains this file or directory.
e.g. for "/moose/fish/foo.txt" this will return "/moose/fish".
*/
File getParentDirectory() const;
/** Checks whether a file is somewhere inside a directory.
Returns true if this file is somewhere inside a subdirectory of the directory
that is passed in. Neither file actually has to exist, because the function
just checks the paths for similarities.
e.g. File ("/moose/fish/foo.txt").isAChildOf ("/moose") is true.
File ("/moose/fish/foo.txt").isAChildOf ("/moose/fish") is also true.
*/
bool isAChildOf (const File& potentialParentDirectory) const;
//==============================================================================
/** Chooses a filename relative to this one that doesn't already exist.
If this file is a directory, this will return a child file of this
directory that doesn't exist, by adding numbers to a prefix and suffix until
it finds one that isn't already there.
If the prefix + the suffix doesn't exist, it won't bother adding a number.
e.g. File ("/moose/fish").getNonexistentChildFile ("foo", ".txt", true) might
return "/moose/fish/foo(2).txt" if there's already a file called "foo.txt".
@param prefix the string to use for the filename before the number
@param suffix the string to add to the filename after the number
@param putNumbersInBrackets if true, this will create filenames in the
format "prefix(number)suffix", if false, it will leave the
brackets out.
*/
File getNonexistentChildFile (const String& prefix,
const String& suffix,
bool putNumbersInBrackets = true) const;
/** Chooses a filename for a sibling file to this one that doesn't already exist.
If this file doesn't exist, this will just return itself, otherwise it
will return an appropriate sibling that doesn't exist, e.g. if a file
"/moose/fish/foo.txt" exists, this might return "/moose/fish/foo(2).txt".
@param putNumbersInBrackets whether to add brackets around the numbers that
get appended to the new filename.
*/
File getNonexistentSibling (bool putNumbersInBrackets = true) const;
//==============================================================================
/** Compares the pathnames for two files. */
bool operator== (const File&) const;
/** Compares the pathnames for two files. */
bool operator!= (const File&) const;
/** Compares the pathnames for two files. */
bool operator< (const File&) const;
/** Compares the pathnames for two files. */
bool operator> (const File&) const;
//==============================================================================
/** Checks whether a file can be created or written to.
@returns true if it's possible to create and write to this file. If the file
doesn't already exist, this will check its parent directory to
see if writing is allowed.
@see setReadOnly
*/
bool hasWriteAccess() const;
/** Changes the write-permission of a file or directory.
@param shouldBeReadOnly whether to add or remove write-permission
@param applyRecursively if the file is a directory and this is true, it will
recurse through all the subfolders changing the permissions
of all files
@returns true if it manages to change the file's permissions.
@see hasWriteAccess
*/
bool setReadOnly (bool shouldBeReadOnly,
bool applyRecursively = false) const;
/** Returns true if this file is a hidden or system file.
The criteria for deciding whether a file is hidden are platform-dependent.
*/
bool isHidden() const;
/** If this file is a link, this returns the file that it points to.
If this file isn't actually link, it'll just return itself.
*/
File getLinkedTarget() const;
//==============================================================================
/** Returns the last modification time of this file.
@returns the time, or an invalid time if the file doesn't exist.
@see setLastModificationTime, getLastAccessTime, getCreationTime
*/
Time getLastModificationTime() const;
/** Returns the last time this file was accessed.
@returns the time, or an invalid time if the file doesn't exist.
@see setLastAccessTime, getLastModificationTime, getCreationTime
*/
Time getLastAccessTime() const;
/** Returns the time that this file was created.
@returns the time, or an invalid time if the file doesn't exist.
@see getLastModificationTime, getLastAccessTime
*/
Time getCreationTime() const;
/** Changes the modification time for this file.
@param newTime the time to apply to the file
@returns true if it manages to change the file's time.
@see getLastModificationTime, setLastAccessTime, setCreationTime
*/
bool setLastModificationTime (Time newTime) const;
/** Changes the last-access time for this file.
@param newTime the time to apply to the file
@returns true if it manages to change the file's time.
@see getLastAccessTime, setLastModificationTime, setCreationTime
*/
bool setLastAccessTime (Time newTime) const;
/** Changes the creation date for this file.
@param newTime the time to apply to the file
@returns true if it manages to change the file's time.
@see getCreationTime, setLastModificationTime, setLastAccessTime
*/
bool setCreationTime (Time newTime) const;
/** If possible, this will try to create a version string for the given file.
The OS may be able to look at the file and give a version for it - e.g. with
executables, bundles, dlls, etc. If no version is available, this will
return an empty string.
*/
String getVersion() const;
//==============================================================================
/** Creates an empty file if it doesn't already exist.
If the file that this object refers to doesn't exist, this will create a file
of zero size.
If it already exists or is a directory, this method will do nothing.
@returns true if the file has been created (or if it already existed).
@see createDirectory
*/
Result create() const;
/** Creates a new directory for this filename.
This will try to create the file as a directory, and fill also create
any parent directories it needs in order to complete the operation.
@returns a result to indicate whether the directory was created successfully, or
an error message if it failed.
@see create
*/
Result createDirectory() const;
/** Deletes a file.
If this file is actually a directory, it may not be deleted correctly if it
contains files. See deleteRecursively() as a better way of deleting directories.
@returns true if the file has been successfully deleted (or if it didn't exist to
begin with).
@see deleteRecursively
*/
bool deleteFile() const;
/** Deletes a file or directory and all its subdirectories.
If this file is a directory, this will try to delete it and all its subfolders. If
it's just a file, it will just try to delete the file.
@returns true if the file and all its subfolders have been successfully deleted
(or if it didn't exist to begin with).
@see deleteFile
*/
bool deleteRecursively() const;
/** Moves this file or folder to the trash.
@returns true if the operation succeeded. It could fail if the trash is full, or
if the file is write-protected, so you should check the return value
and act appropriately.
*/
bool moveToTrash() const;
/** Moves or renames a file.
Tries to move a file to a different location.
If the target file already exists, this will attempt to delete it first, and
will fail if this can't be done.
Note that the destination file isn't the directory to put it in, it's the actual
filename that you want the new file to have.
@returns true if the operation succeeds
*/
bool moveFileTo (const File& targetLocation) const;
/** Copies a file.
Tries to copy a file to a different location.
If the target file already exists, this will attempt to delete it first, and
will fail if this can't be done.
@returns true if the operation succeeds
*/
bool copyFileTo (const File& targetLocation) const;
/** Copies a directory.
Tries to copy an entire directory, recursively.
If this file isn't a directory or if any target files can't be created, this
will return false.
@param newDirectory the directory that this one should be copied to. Note that this
is the name of the actual directory to create, not the directory
into which the new one should be placed, so there must be enough
write privileges to create it if it doesn't exist. Any files inside
it will be overwritten by similarly named ones that are copied.
*/
bool copyDirectoryTo (const File& newDirectory) const;
//==============================================================================
/** Used in file searching, to specify whether to return files, directories, or both.
*/
enum TypesOfFileToFind
{
findDirectories = 1, /**< Use this flag to indicate that you want to find directories. */
findFiles = 2, /**< Use this flag to indicate that you want to find files. */
findFilesAndDirectories = 3, /**< Use this flag to indicate that you want to find both files and directories. */
ignoreHiddenFiles = 4 /**< Add this flag to avoid returning any hidden files in the results. */
};
/** Searches inside a directory for files matching a wildcard pattern.
Assuming that this file is a directory, this method will search it
for either files or subdirectories whose names match a filename pattern.
@param results an array to which File objects will be added for the
files that the search comes up with
@param whatToLookFor a value from the TypesOfFileToFind enum, specifying whether to
return files, directories, or both. If the ignoreHiddenFiles flag
is also added to this value, hidden files won't be returned
@param searchRecursively if true, all subdirectories will be recursed into to do
an exhaustive search
@param wildCardPattern the filename pattern to search for, e.g. "*.txt"
@returns the number of results that have been found
@see getNumberOfChildFiles, DirectoryIterator
*/
int findChildFiles (Array<File>& results,
int whatToLookFor,
bool searchRecursively,
const String& wildCardPattern = "*") const;
/** Searches inside a directory and counts how many files match a wildcard pattern.
Assuming that this file is a directory, this method will search it
for either files or subdirectories whose names match a filename pattern,
and will return the number of matches found.
This isn't a recursive call, and will only search this directory, not
its children.
@param whatToLookFor a value from the TypesOfFileToFind enum, specifying whether to
count files, directories, or both. If the ignoreHiddenFiles flag
is also added to this value, hidden files won't be counted
@param wildCardPattern the filename pattern to search for, e.g. "*.txt"
@returns the number of matches found
@see findChildFiles, DirectoryIterator
*/
int getNumberOfChildFiles (int whatToLookFor,
const String& wildCardPattern = "*") const;
/** Returns true if this file is a directory that contains one or more subdirectories.
@see isDirectory, findChildFiles
*/
bool containsSubDirectories() const;
//==============================================================================
/** Creates a stream to read from this file.
@returns a stream that will read from this file (initially positioned at the
start of the file), or nullptr if the file can't be opened for some reason
@see createOutputStream, loadFileAsData
*/
FileInputStream* createInputStream() const;
/** Creates a stream to write to this file.
If the file exists, the stream that is returned will be positioned ready for
writing at the end of the file, so you might want to use deleteFile() first
to write to an empty file.
@returns a stream that will write to this file (initially positioned at the
end of the file), or nullptr if the file can't be opened for some reason
@see createInputStream, appendData, appendText
*/
FileOutputStream* createOutputStream (size_t bufferSize = 0x8000) const;
//==============================================================================
/** Loads a file's contents into memory as a block of binary data.
Of course, trying to load a very large file into memory will blow up, so
it's better to check first.
@param result the data block to which the file's contents should be appended - note
that if the memory block might already contain some data, you
might want to clear it first
@returns true if the file could all be read into memory
*/
bool loadFileAsData (MemoryBlock& result) const;
/** Reads a file into memory as a string.
Attempts to load the entire file as a zero-terminated string.
This makes use of InputStream::readEntireStreamAsString, which can
read either UTF-16 or UTF-8 file formats.
*/
String loadFileAsString() const;
/** Reads the contents of this file as text and splits it into lines, which are
appended to the given StringArray.
*/
void readLines (StringArray& destLines) const;
//==============================================================================
/** Appends a block of binary data to the end of the file.
This will try to write the given buffer to the end of the file.
@returns false if it can't write to the file for some reason
*/
bool appendData (const void* dataToAppend,
size_t numberOfBytes) const;
/** Replaces this file's contents with a given block of data.
This will delete the file and replace it with the given data.
A nice feature of this method is that it's safe - instead of deleting
the file first and then re-writing it, it creates a new temporary file,
writes the data to that, and then moves the new file to replace the existing
file. This means that if the power gets pulled out or something crashes,
you're a lot less likely to end up with a corrupted or unfinished file..
Returns true if the operation succeeds, or false if it fails.
@see appendText
*/
bool replaceWithData (const void* dataToWrite,
size_t numberOfBytes) const;
/** Appends a string to the end of the file.
This will try to append a text string to the file, as either 16-bit unicode
or 8-bit characters in the default system encoding.
It can also write the 'ff fe' unicode header bytes before the text to indicate
the endianness of the file.
Any single \\n characters in the string are replaced with \\r\\n before it is written.
@see replaceWithText
*/
bool appendText (const String& textToAppend,
bool asUnicode = false,
bool writeUnicodeHeaderBytes = false) const;
/** Replaces this file's contents with a given text string.
This will delete the file and replace it with the given text.
A nice feature of this method is that it's safe - instead of deleting
the file first and then re-writing it, it creates a new temporary file,
writes the text to that, and then moves the new file to replace the existing
file. This means that if the power gets pulled out or something crashes,
you're a lot less likely to end up with an empty file..
For an explanation of the parameters here, see the appendText() method.
Returns true if the operation succeeds, or false if it fails.
@see appendText
*/
bool replaceWithText (const String& textToWrite,
bool asUnicode = false,
bool writeUnicodeHeaderBytes = false) const;
/** Attempts to scan the contents of this file and compare it to another file, returning
true if this is possible and they match byte-for-byte.
*/
bool hasIdenticalContentTo (const File& other) const;
//==============================================================================
/** Creates a set of files to represent each file root.
e.g. on Windows this will create files for "c:\", "d:\" etc according
to which ones are available. On the Mac/Linux, this will probably
just add a single entry for "/".
*/
static void findFileSystemRoots (Array<File>& results);
/** Finds the name of the drive on which this file lives.
@returns the volume label of the drive, or an empty string if this isn't possible
*/
String getVolumeLabel() const;
/** Returns the serial number of the volume on which this file lives.
@returns the serial number, or zero if there's a problem doing this
*/
int getVolumeSerialNumber() const;
/** Returns the number of bytes free on the drive that this file lives on.
@returns the number of bytes free, or 0 if there's a problem finding this out
@see getVolumeTotalSize
*/
std::int64_t getBytesFreeOnVolume() const;
/** Returns the total size of the drive that contains this file.
@returns the total number of bytes that the volume can hold
@see getBytesFreeOnVolume
*/
std::int64_t getVolumeTotalSize() const;
/** Returns true if this file is on a CD or DVD drive. */
bool isOnCDRomDrive() const;
/** Returns true if this file is on a hard disk.
This will fail if it's a network drive, but will still be true for
removable hard-disks.
*/
bool isOnHardDisk() const;
/** Returns true if this file is on a removable disk drive.
This might be a usb-drive, a CD-rom, or maybe a network drive.
*/
bool isOnRemovableDrive() const;
//==============================================================================
/** Launches the file as a process.
- if the file is executable, this will run it.
- if it's a document of some kind, it will launch the document with its
default viewer application.
- if it's a folder, it will be opened in Explorer, Finder, or equivalent.
@see revealToUser
*/
bool startAsProcess (const String& parameters = String::empty) const;
/** Opens Finder, Explorer, or whatever the OS uses, to show the user this file's location.
@see startAsProcess
*/
void revealToUser() const;
//==============================================================================
/** A set of types of location that can be passed to the getSpecialLocation() method.
*/
enum SpecialLocationType
{
/** The user's home folder. This is the same as using File ("~"). */
userHomeDirectory,
/** The user's default documents folder. On Windows, this might be the user's
"My Documents" folder. On the Mac it'll be their "Documents" folder. Linux
doesn't tend to have one of these, so it might just return their home folder.
*/
userDocumentsDirectory,
/** The folder that contains the user's desktop objects. */
userDesktopDirectory,
/** The most likely place where a user might store their music files. */
userMusicDirectory,
/** The most likely place where a user might store their movie files. */
userMoviesDirectory,
/** The most likely place where a user might store their picture files. */
userPicturesDirectory,
/** The folder in which applications store their persistent user-specific settings.
On Windows, this might be "\Documents and Settings\username\Application Data".
On the Mac, it might be "~/Library". If you're going to store your settings in here,
always create your own sub-folder to put them in, to avoid making a mess.
*/
userApplicationDataDirectory,
/** An equivalent of the userApplicationDataDirectory folder that is shared by all users
of the computer, rather than just the current user.
On the Mac it'll be "/Library", on Windows, it could be something like
"\Documents and Settings\All Users\Application Data".
Depending on the setup, this folder may be read-only.
*/
commonApplicationDataDirectory,
/** A place to put documents which are shared by all users of the machine.
On Windows this may be somewhere like "C:\Users\Public\Documents", on OSX it
will be something like "/Users/Shared". Other OSes may have no such concept
though, so be careful.
*/
commonDocumentsDirectory,
/** The folder that should be used for temporary files.
Always delete them when you're finished, to keep the user's computer tidy!
*/
tempDirectory,
/** Returns this application's executable file.
If running as a plug-in or DLL, this will (where possible) be the DLL rather than the
host app.
On the mac this will return the unix binary, not the package folder - see
currentApplicationFile for that.
See also invokedExecutableFile, which is similar, but if the exe was launched from a
file link, invokedExecutableFile will return the name of the link.
*/
currentExecutableFile,
/** Returns this application's location.
If running as a plug-in or DLL, this will (where possible) be the DLL rather than the
host app.
On the mac this will return the package folder (if it's in one), not the unix binary
that's inside it - compare with currentExecutableFile.
*/
currentApplicationFile,
/** Returns the file that was invoked to launch this executable.
This may differ from currentExecutableFile if the app was started from e.g. a link - this
will return the name of the link that was used, whereas currentExecutableFile will return
the actual location of the target executable.
*/
invokedExecutableFile,
/** In a plugin, this will return the path of the host executable. */
hostApplicationPath,
/** The directory in which applications normally get installed.
So on windows, this would be something like "c:\program files", on the
Mac "/Applications", or "/usr" on linux.
*/
globalApplicationsDirectory
};
/** Finds the location of a special type of file or directory, such as a home folder or
documents folder.
@see SpecialLocationType
*/
static File getSpecialLocation (const SpecialLocationType type);
//==============================================================================
/** Returns a temporary file in the system's temp directory.
This will try to return the name of a non-existent temp file.
To get the temp folder, you can use getSpecialLocation (File::tempDirectory).
*/
static File createTempFile (const String& fileNameEnding);
//==============================================================================
/** Returns the current working directory.
@see setAsCurrentWorkingDirectory
*/
static File getCurrentWorkingDirectory();
/** Sets the current working directory to be this file.
For this to work the file must point to a valid directory.
@returns true if the current directory has been changed.
@see getCurrentWorkingDirectory
*/
bool setAsCurrentWorkingDirectory() const;
//==============================================================================
/** The system-specific file separator character.
On Windows, this will be '\', on Mac/Linux, it'll be '/'
*/
static const beast_wchar separator;
/** The system-specific file separator character, as a string.
On Windows, this will be '\', on Mac/Linux, it'll be '/'
*/
static const String separatorString;
//==============================================================================
/** Returns a version of a filename with any illegal characters removed.
This will return a copy of the given string after removing characters
that are not allowed in a legal filename, and possibly shortening the
string if it's too long.
Because this will remove slashes, don't use it on an absolute pathname - use
createLegalPathName() for that.
@see createLegalPathName
*/
static String createLegalFileName (const String& fileNameToFix);
/** Returns a version of a path with any illegal characters removed.
Similar to createLegalFileName(), but this won't remove slashes, so can
be used on a complete pathname.
@see createLegalFileName
*/
static String createLegalPathName (const String& pathNameToFix);
/** Indicates whether filenames are case-sensitive on the current operating system. */
static bool areFileNamesCaseSensitive();
/** Returns true if the string seems to be a fully-specified absolute path. */
static bool isAbsolutePath (const String& path);
/** Creates a file that simply contains this string, without doing the sanity-checking
that the normal constructors do.
Best to avoid this unless you really know what you're doing.
*/
static File createFileWithoutCheckingPath (const String& absolutePath) noexcept;
/** Adds a separator character to the end of a path if it doesn't already have one. */
static String addTrailingSeparator (const String& path);
#if BEAST_MAC || BEAST_IOS || DOXYGEN
//==============================================================================
/** OSX ONLY - Finds the OSType of a file from the its resources. */
OSType getMacOSType() const;
/** OSX ONLY - Returns true if this file is actually a bundle. */
bool isBundle() const;
#endif
#if BEAST_MAC || DOXYGEN
/** OSX ONLY - Adds this file to the OSX dock */
void addToDock() const;
#endif
#if BEAST_WINDOWS
/** Windows ONLY - Creates a win32 .LNK shortcut file that links to this file. */
bool createLink (const String& description, const File& linkFileToCreate) const;
#endif
private:
//==============================================================================
String fullPath;
static String parseAbsolutePath (const String&);
String getPathUpToLastSlash() const;
Result createDirectoryInternal (const String&) const;
bool copyInternal (const File&) const;
bool moveInternal (const File&) const;
bool setFileTimesInternal (std::int64_t m, std::int64_t a, std::int64_t c) const;
void getFileTimesInternal (std::int64_t& m, std::int64_t& a, std::int64_t& c) const;
bool setFileReadOnlyInternal (bool) const;
};
} // beast
#endif

View File

@@ -0,0 +1,95 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
std::int64_t beast_fileSetPosition (void* handle, std::int64_t pos);
//==============================================================================
FileInputStream::FileInputStream (const File& f)
: file (f),
fileHandle (nullptr),
currentPosition (0),
status (Result::ok()),
needToSeek (true)
{
openHandle();
}
FileInputStream::~FileInputStream()
{
closeHandle();
}
//==============================================================================
std::int64_t FileInputStream::getTotalLength()
{
return file.getSize();
}
int FileInputStream::read (void* buffer, int bytesToRead)
{
bassert (openedOk());
bassert (buffer != nullptr && bytesToRead >= 0);
if (needToSeek)
{
if (beast_fileSetPosition (fileHandle, currentPosition) < 0)
return 0;
needToSeek = false;
}
const size_t num = readInternal (buffer, (size_t) bytesToRead);
currentPosition += num;
return (int) num;
}
bool FileInputStream::isExhausted()
{
return currentPosition >= getTotalLength();
}
std::int64_t FileInputStream::getPosition()
{
return currentPosition;
}
bool FileInputStream::setPosition (std::int64_t pos)
{
bassert (openedOk());
if (pos != currentPosition)
{
pos = blimit ((std::int64_t) 0, getTotalLength(), pos);
needToSeek |= (currentPosition != pos);
currentPosition = pos;
}
return true;
}
} // beast

View File

@@ -0,0 +1,95 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_FILEINPUTSTREAM_H_INCLUDED
#define BEAST_FILEINPUTSTREAM_H_INCLUDED
namespace beast
{
//==============================================================================
/**
An input stream that reads from a local file.
@see InputStream, FileOutputStream, File::createInputStream
*/
class FileInputStream
: public InputStream
, LeakChecked <FileInputStream>
{
public:
//==============================================================================
/** Creates a FileInputStream.
@param fileToRead the file to read from - if the file can't be accessed for some
reason, then the stream will just contain no data
*/
explicit FileInputStream (const File& fileToRead);
/** Destructor. */
~FileInputStream();
//==============================================================================
/** Returns the file that this stream is reading from. */
const File& getFile() const noexcept { return file; }
/** Returns the status of the file stream.
The result will be ok if the file opened successfully. If an error occurs while
opening or reading from the file, this will contain an error message.
*/
const Result& getStatus() const noexcept { return status; }
/** Returns true if the stream couldn't be opened for some reason.
@see getResult()
*/
bool failedToOpen() const noexcept { return status.failed(); }
/** Returns true if the stream opened without problems.
@see getResult()
*/
bool openedOk() const noexcept { return status.wasOk(); }
//==============================================================================
std::int64_t getTotalLength();
int read (void* destBuffer, int maxBytesToRead);
bool isExhausted();
std::int64_t getPosition();
bool setPosition (std::int64_t pos);
private:
//==============================================================================
File file;
void* fileHandle;
std::int64_t currentPosition;
Result status;
bool needToSeek;
void openHandle();
void closeHandle();
size_t readInternal (void* buffer, size_t numBytes);
};
} // beast
#endif // BEAST_FILEINPUTSTREAM_H_INCLUDED

View File

@@ -0,0 +1,135 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
std::int64_t beast_fileSetPosition (void* handle, std::int64_t pos);
//==============================================================================
FileOutputStream::FileOutputStream (const File& f, const size_t bufferSizeToUse)
: file (f),
fileHandle (nullptr),
status (Result::ok()),
currentPosition (0),
bufferSize (bufferSizeToUse),
bytesInBuffer (0),
buffer (bmax (bufferSizeToUse, (size_t) 16))
{
openHandle();
}
FileOutputStream::~FileOutputStream()
{
flushBuffer();
flushInternal();
closeHandle();
}
std::int64_t FileOutputStream::getPosition()
{
return currentPosition;
}
bool FileOutputStream::setPosition (std::int64_t newPosition)
{
if (newPosition != currentPosition)
{
flushBuffer();
currentPosition = beast_fileSetPosition (fileHandle, newPosition);
}
return newPosition == currentPosition;
}
bool FileOutputStream::flushBuffer()
{
bool ok = true;
if (bytesInBuffer > 0)
{
ok = (writeInternal (buffer, bytesInBuffer) == (std::ptrdiff_t) bytesInBuffer);
bytesInBuffer = 0;
}
return ok;
}
void FileOutputStream::flush()
{
flushBuffer();
flushInternal();
}
bool FileOutputStream::write (const void* const src, const size_t numBytes)
{
bassert (src != nullptr && ((std::ptrdiff_t) numBytes) >= 0);
if (bytesInBuffer + numBytes < bufferSize)
{
memcpy (buffer + bytesInBuffer, src, numBytes);
bytesInBuffer += numBytes;
currentPosition += numBytes;
}
else
{
if (! flushBuffer())
return false;
if (numBytes < bufferSize)
{
memcpy (buffer + bytesInBuffer, src, numBytes);
bytesInBuffer += numBytes;
currentPosition += numBytes;
}
else
{
const std::ptrdiff_t bytesWritten = writeInternal (src, numBytes);
if (bytesWritten < 0)
return false;
currentPosition += bytesWritten;
return bytesWritten == (std::ptrdiff_t) numBytes;
}
}
return true;
}
bool FileOutputStream::writeRepeatedByte (std::uint8_t byte, size_t numBytes)
{
bassert (((std::ptrdiff_t) numBytes) >= 0);
if (bytesInBuffer + numBytes < bufferSize)
{
memset (buffer + bytesInBuffer, byte, numBytes);
bytesInBuffer += numBytes;
currentPosition += numBytes;
return true;
}
return OutputStream::writeRepeatedByte (byte, numBytes);
}
} // beast

View File

@@ -0,0 +1,115 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
#ifndef BEAST_FILEOUTPUTSTREAM_H_INCLUDED
#define BEAST_FILEOUTPUTSTREAM_H_INCLUDED
//==============================================================================
/**
An output stream that writes into a local file.
@see OutputStream, FileInputStream, File::createOutputStream
*/
class FileOutputStream
: public OutputStream
, LeakChecked <FileOutputStream>
{
public:
//==============================================================================
/** Creates a FileOutputStream.
If the file doesn't exist, it will first be created. If the file can't be
created or opened, the failedToOpen() method will return
true.
If the file already exists when opened, the stream's write-postion will
be set to the end of the file. To overwrite an existing file,
use File::deleteFile() before opening the stream, or use setPosition(0)
after it's opened (although this won't truncate the file).
@see TemporaryFile
*/
FileOutputStream (const File& fileToWriteTo,
size_t bufferSizeToUse = 16384);
/** Destructor. */
~FileOutputStream();
//==============================================================================
/** Returns the file that this stream is writing to.
*/
const File& getFile() const { return file; }
/** Returns the status of the file stream.
The result will be ok if the file opened successfully. If an error occurs while
opening or writing to the file, this will contain an error message.
*/
const Result& getStatus() const noexcept { return status; }
/** Returns true if the stream couldn't be opened for some reason.
@see getResult()
*/
bool failedToOpen() const noexcept { return status.failed(); }
/** Returns true if the stream opened without problems.
@see getResult()
*/
bool openedOk() const noexcept { return status.wasOk(); }
/** Attempts to truncate the file to the current write position.
To truncate a file to a specific size, first use setPosition() to seek to the
appropriate location, and then call this method.
*/
Result truncate();
//==============================================================================
void flush() override;
std::int64_t getPosition() override;
bool setPosition (std::int64_t) override;
bool write (const void*, size_t) override;
bool writeRepeatedByte (std::uint8_t byte, size_t numTimesToRepeat) override;
private:
//==============================================================================
File file;
void* fileHandle;
Result status;
std::int64_t currentPosition;
size_t bufferSize, bytesInBuffer;
HeapBlock <char> buffer;
void openHandle();
void closeHandle();
void flushInternal();
bool flushBuffer();
std::int64_t setPositionInternal (std::int64_t);
std::ptrdiff_t writeInternal (const void*, size_t);
};
} // beast
#endif

View File

@@ -0,0 +1,171 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
FileSearchPath::FileSearchPath()
{
}
FileSearchPath::FileSearchPath (const String& path)
{
init (path);
}
FileSearchPath::FileSearchPath (const FileSearchPath& other)
: directories (other.directories)
{
}
FileSearchPath::~FileSearchPath()
{
}
FileSearchPath& FileSearchPath::operator= (const String& path)
{
init (path);
return *this;
}
void FileSearchPath::init (const String& path)
{
directories.clear();
directories.addTokens (path, ";", "\"");
directories.trim();
directories.removeEmptyStrings();
for (int i = directories.size(); --i >= 0;)
directories.set (i, directories[i].unquoted());
}
int FileSearchPath::getNumPaths() const
{
return directories.size();
}
File FileSearchPath::operator[] (const int index) const
{
return File (directories [index]);
}
String FileSearchPath::toString() const
{
StringArray directories2 (directories);
for (int i = directories2.size(); --i >= 0;)
if (directories2[i].containsChar (';'))
directories2.set (i, directories2[i].quoted());
return directories2.joinIntoString (";");
}
void FileSearchPath::add (const File& dir, const int insertIndex)
{
directories.insert (insertIndex, dir.getFullPathName());
}
void FileSearchPath::addIfNotAlreadyThere (const File& dir)
{
for (int i = 0; i < directories.size(); ++i)
if (File (directories[i]) == dir)
return;
add (dir);
}
void FileSearchPath::remove (const int index)
{
directories.remove (index);
}
void FileSearchPath::addPath (const FileSearchPath& other)
{
for (int i = 0; i < other.getNumPaths(); ++i)
addIfNotAlreadyThere (other[i]);
}
void FileSearchPath::removeRedundantPaths()
{
for (int i = directories.size(); --i >= 0;)
{
const File d1 (directories[i]);
for (int j = directories.size(); --j >= 0;)
{
const File d2 (directories[j]);
if ((i != j) && (d1.isAChildOf (d2) || d1 == d2))
{
directories.remove (i);
break;
}
}
}
}
void FileSearchPath::removeNonExistentPaths()
{
for (int i = directories.size(); --i >= 0;)
if (! File (directories[i]).isDirectory())
directories.remove (i);
}
int FileSearchPath::findChildFiles (Array<File>& results,
const int whatToLookFor,
const bool searchRecursively,
const String& wildCardPattern) const
{
int total = 0;
for (int i = 0; i < directories.size(); ++i)
total += operator[] (i).findChildFiles (results,
whatToLookFor,
searchRecursively,
wildCardPattern);
return total;
}
bool FileSearchPath::isFileInPath (const File& fileToCheck,
const bool checkRecursively) const
{
for (int i = directories.size(); --i >= 0;)
{
const File d (directories[i]);
if (checkRecursively)
{
if (fileToCheck.isAChildOf (d))
return true;
}
else
{
if (fileToCheck.getParentDirectory() == d)
return true;
}
}
return false;
}
} // beast

View File

@@ -0,0 +1,163 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_FILESEARCHPATH_H_INCLUDED
#define BEAST_FILESEARCHPATH_H_INCLUDED
namespace beast
{
//==============================================================================
/**
Encapsulates a set of folders that make up a search path.
@see File
*/
class FileSearchPath : LeakChecked <FileSearchPath>
{
public:
//==============================================================================
/** Creates an empty search path. */
FileSearchPath();
/** Creates a search path from a string of pathnames.
The path can be semicolon- or comma-separated, e.g.
"/foo/bar;/foo/moose;/fish/moose"
The separate folders are tokenised and added to the search path.
*/
FileSearchPath (const String& path);
/** Creates a copy of another search path. */
FileSearchPath (const FileSearchPath& other);
/** Destructor. */
~FileSearchPath();
/** Uses a string containing a list of pathnames to re-initialise this list.
This search path is cleared and the semicolon- or comma-separated folders
in this string are added instead. e.g. "/foo/bar;/foo/moose;/fish/moose"
*/
FileSearchPath& operator= (const String& path);
//==============================================================================
/** Returns the number of folders in this search path.
@see operator[]
*/
int getNumPaths() const;
/** Returns one of the folders in this search path.
The file returned isn't guaranteed to actually be a valid directory.
@see getNumPaths
*/
File operator[] (int index) const;
/** Returns the search path as a semicolon-separated list of directories. */
String toString() const;
//==============================================================================
/** Adds a new directory to the search path.
The new directory is added to the end of the list if the insertIndex parameter is
less than zero, otherwise it is inserted at the given index.
*/
void add (const File& directoryToAdd,
int insertIndex = -1);
/** Adds a new directory to the search path if it's not already in there. */
void addIfNotAlreadyThere (const File& directoryToAdd);
/** Removes a directory from the search path. */
void remove (int indexToRemove);
/** Merges another search path into this one.
This will remove any duplicate directories.
*/
void addPath (const FileSearchPath& other);
/** Removes any directories that are actually subdirectories of one of the other directories in the search path.
If the search is intended to be recursive, there's no point having nested folders in the search
path, because they'll just get searched twice and you'll get duplicate results.
e.g. if the path is "c:\abc\de;c:\abc", this method will simplify it to "c:\abc"
*/
void removeRedundantPaths();
/** Removes any directories that don't actually exist. */
void removeNonExistentPaths();
//==============================================================================
/** Searches the path for a wildcard.
This will search all the directories in the search path in order, adding any
matching files to the results array.
@param results an array to append the results to
@param whatToLookFor a value from the File::TypesOfFileToFind enum, specifying whether to
return files, directories, or both.
@param searchRecursively whether to recursively search the subdirectories too
@param wildCardPattern a pattern to match against the filenames
@returns the number of files added to the array
@see File::findChildFiles
*/
int findChildFiles (Array<File>& results,
int whatToLookFor,
bool searchRecursively,
const String& wildCardPattern = "*") const;
//==============================================================================
/** Finds out whether a file is inside one of the path's directories.
This will return true if the specified file is a child of one of the
directories specified by this path. Note that this doesn't actually do any
searching or check that the files exist - it just looks at the pathnames
to work out whether the file would be inside a directory.
@param fileToCheck the file to look for
@param checkRecursively if true, then this will return true if the file is inside a
subfolder of one of the path's directories (at any depth). If false
it will only return true if the file is actually a direct child
of one of the directories.
@see File::isAChildOf
*/
bool isFileInPath (const File& fileToCheck,
bool checkRecursively) const;
private:
//==============================================================================
StringArray directories;
void init (const String& path);
};
} // beast
#endif // BEAST_FILESEARCHPATH_H_INCLUDED

View File

@@ -0,0 +1,274 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <beast/unit_test/suite.h>
namespace beast {
RandomAccessFile::RandomAccessFile () noexcept
: fileHandle (nullptr)
, currentPosition (0)
{
}
RandomAccessFile::~RandomAccessFile ()
{
close ();
}
Result RandomAccessFile::open (File const& path, Mode mode)
{
close ();
return nativeOpen (path, mode);
}
void RandomAccessFile::close ()
{
if (isOpen ())
{
nativeFlush ();
nativeClose ();
}
}
Result RandomAccessFile::setPosition (FileOffset newPosition)
{
if (newPosition != currentPosition)
{
// VFALCO NOTE I dislike return from the middle but
// Result::ok() is showing up in the profile
//
return nativeSetPosition (newPosition);
}
return Result::ok ();
}
Result RandomAccessFile::read (void* buffer, ByteCount numBytes, ByteCount* pActualAmount)
{
return nativeRead (buffer, numBytes, pActualAmount);
}
Result RandomAccessFile::write (const void* data, ByteCount numBytes, ByteCount* pActualAmount)
{
bassert (data != nullptr && ((std::ptrdiff_t) numBytes) >= 0);
Result result (Result::ok ());
ByteCount amountWritten = 0;
result = nativeWrite (data, numBytes, &amountWritten);
if (result.wasOk ())
currentPosition += amountWritten;
if (pActualAmount != nullptr)
*pActualAmount = amountWritten;
return result;
}
Result RandomAccessFile::truncate ()
{
Result result = flush ();
if (result.wasOk ())
result = nativeTruncate ();
return result;
}
Result RandomAccessFile::flush ()
{
return nativeFlush ();
}
//------------------------------------------------------------------------------
class RandomAccessFile_test : public unit_test::suite
{
public:
enum
{
maxPayload = 8192
};
/* For this test we will create a file which consists of a fixed
number of variable length records. Each record is numbered sequentially
starting at 0. To calculate the position of each record we first build
a table of size/offset pairs using a pseudorandom number generator.
*/
struct Record
{
int index;
int bytes;
int offset;
};
typedef HeapBlock <Record> Records;
// Produce the pseudo-random set of records.
static void createRecords (HeapBlock <Record>& records,
int numRecords,
int maxBytes,
std::int64_t seedValue)
{
using namespace UnitTestUtilities;
Random r (seedValue);
records.malloc (numRecords);
int offset = 0;
for (int i = 0; i < numRecords; ++i)
{
int const bytes = r.nextInt (maxBytes) + 1;
records [i].index = i;
records [i].bytes = bytes;
records [i].offset = offset;
offset += bytes;
}
repeatableShuffle (numRecords, records, seedValue);
}
// Write all the records to the file.
// The payload is pseudo-randomly generated.
void writeRecords (RandomAccessFile& file,
int numRecords,
HeapBlock <Record> const& records,
std::int64_t seedValue)
{
using namespace UnitTestUtilities;
for (int i = 0; i < numRecords; ++i)
{
Payload p (records [i].bytes);
p.repeatableRandomFill (records [i].bytes,
records [i].bytes,
records [i].index + seedValue);
file.setPosition (records [i].offset);
Result result = file.write (p.data.getData (), p.bytes);
expect (result.wasOk (), "Should be ok");
}
}
// Read the records and verify the consistency.
void readRecords (RandomAccessFile& file,
int numRecords,
HeapBlock <Record> const& records,
std::int64_t seedValue)
{
using namespace UnitTestUtilities;
for (int i = 0; i < numRecords; ++i)
{
Record const& record (records [i]);
int const bytes = record.bytes;
Payload p1 (bytes);
Payload p2 (bytes);
p1.repeatableRandomFill (bytes, bytes, record.index + seedValue);
file.setPosition (record.offset);
Result result = file.read (p2.data.getData (), bytes);
expect (result.wasOk (), "Should be ok");
if (result.wasOk ())
{
p2.bytes = bytes;
expect (p1 == p2, "Should be equal");
}
}
}
// Perform the test at the given buffer size.
void testFile (int const numRecords)
{
using namespace UnitTestUtilities;
int const seedValue = 50;
std::stringstream ss;
ss << numRecords << " records";
testcase (ss.str());
// Calculate the path
File const path (File::createTempFile ("RandomAccessFile"));
// Create a predictable set of records
HeapBlock <Record> records (numRecords);
createRecords (records, numRecords, maxPayload, seedValue);
Result result (Result::ok ());
{
// Create the file
RandomAccessFile file;
result = file.open (path, RandomAccessFile::readWrite);
expect (result.wasOk (), "Should be ok");
if (result.wasOk ())
{
writeRecords (file, numRecords, records, seedValue);
readRecords (file, numRecords, records, seedValue);
repeatableShuffle (numRecords, records, seedValue);
readRecords (file, numRecords, records, seedValue);
}
}
if (result.wasOk ())
{
// Re-open the file in read only mode
RandomAccessFile file;
result = file.open (path, RandomAccessFile::readOnly);
expect (result.wasOk (), "Should be ok");
if (result.wasOk ())
{
readRecords (file, numRecords, records, seedValue);
}
}
}
void run ()
{
testFile (10000);
}
};
BEAST_DEFINE_TESTSUITE(RandomAccessFile,beast_core,beast);
} // beast

View File

@@ -0,0 +1,200 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_RANDOMACCESSFILE_H_INCLUDED
#define BEAST_RANDOMACCESSFILE_H_INCLUDED
namespace beast
{
/** Provides random access reading and writing to an operating system file.
This class wraps the underlying native operating system routines for
opening and closing a file for reading and/or writing, seeking within
the file, and performing read and write operations. There are also methods
provided for obtaining an input or output stream which will work with
the file.
@note All files are opened in binary mode. No text newline conversions
are performed.
@note None of these members are thread safe. The caller is responsible
for synchronization.
@see FileInputStream, FileOutputStream
*/
class RandomAccessFile : public Uncopyable, LeakChecked <RandomAccessFile>
{
public:
/** The type of an FileOffset.
This can be useful when writing templates.
*/
typedef std::int64_t FileOffset;
/** The type of a byte count.
This can be useful when writing templates.
*/
typedef size_t ByteCount;
/** The access mode.
@see open
*/
enum Mode
{
readOnly,
readWrite
};
//==============================================================================
/** Creates an unopened file object.
@see open, isOpen
*/
RandomAccessFile () noexcept;
/** Destroy the file object.
If the operating system file is open it will be closed.
*/
~RandomAccessFile ();
/** Determine if a file is open.
@return `true` if the operating system file is open.
*/
bool isOpen () const noexcept { return fileHandle != nullptr; }
/** Opens a file object.
The file is opened with the specified permissions. The initial
position is set to the beginning of the file.
@note If a file is already open, it will be closed first.
@param path The path to the file
@param mode The access permissions
@return An indication of the success of the operation.
@see Mode
*/
Result open (File const& path, Mode mode);
/** Closes the file object.
Any data that needs to be flushed will be written before the file is closed.
@note If no file is opened, this call does nothing.
*/
void close ();
/** Retrieve the @ref File associated with this object.
@return The associated @ref File.
*/
File const& getFile () const noexcept { return file; }
/** Get the current position.
The next read or write will take place from here.
@return The current position, as an absolute byte FileOffset from the begining.
*/
FileOffset getPosition () const noexcept { return currentPosition; }
/** Set the current position.
The next read or write will take place at this location.
@param newPosition The byte FileOffset from the beginning of the file to move to.
@return `true` if the operation was successful.
*/
Result setPosition (FileOffset newPosition);
/** Read data at the current position.
The caller is responsible for making sure that the memory pointed to
by `buffer` is at least as large as `bytesToRead`.
@note The file must have been opened with read permission.
@param buffer The memory to store the incoming data
@param numBytes The number of bytes to read.
@param pActualAmount Pointer to store the actual amount read, or `nullptr`.
@return `true` if all the bytes were read.
*/
Result read (void* buffer, ByteCount numBytes, ByteCount* pActualAmount = 0);
/** Write data at the current position.
The current position is advanced past the data written. If data is
written past the end of the file, the file size is increased on disk.
The caller is responsible for making sure that the memory pointed to
by `buffer` is at least as large as `bytesToWrite`.
@note The file must have been opened with write permission.
@param data A pointer to the data buffer to write to the file.
@param numBytes The number of bytes to write.
@param pActualAmount Pointer to store the actual amount written, or `nullptr`.
@return `true` if all the data was written.
*/
Result write (const void* data, ByteCount numBytes, ByteCount* pActualAmount = 0);
/** Truncate the file at the current position.
*/
Result truncate ();
/** Flush the output buffers.
This calls the operating system to make sure all data has been written.
*/
Result flush();
//==============================================================================
private:
// Some of these these methods are implemented natively on
// the corresponding platform.
//
// See beast_posix_SharedCode.h and beast_win32_Files.cpp
//
Result nativeOpen (File const& path, Mode mode);
void nativeClose ();
Result nativeSetPosition (FileOffset newPosition);
Result nativeRead (void* buffer, ByteCount numBytes, ByteCount* pActualAmount = 0);
Result nativeWrite (const void* data, ByteCount numBytes, ByteCount* pActualAmount = 0);
Result nativeTruncate ();
Result nativeFlush ();
private:
File file;
void* fileHandle;
FileOffset currentPosition;
};
} // beast
#endif

View File

@@ -0,0 +1,117 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
static File createTempFile (const File& parentDirectory, String name,
const String& suffix, const int optionFlags)
{
if ((optionFlags & TemporaryFile::useHiddenFile) != 0)
name = "." + name;
return parentDirectory.getNonexistentChildFile (name, suffix, (optionFlags & TemporaryFile::putNumbersInBrackets) != 0);
}
TemporaryFile::TemporaryFile (const String& suffix, const int optionFlags)
: temporaryFile (createTempFile (File::getSpecialLocation (File::tempDirectory),
"temp_" + String::toHexString (Random::getSystemRandom().nextInt()),
suffix, optionFlags))
{
}
TemporaryFile::TemporaryFile (const File& target, const int optionFlags)
: temporaryFile (createTempFile (target.getParentDirectory(),
target.getFileNameWithoutExtension()
+ "_temp" + String::toHexString (Random::getSystemRandom().nextInt()),
target.getFileExtension(), optionFlags)),
targetFile (target)
{
// If you use this constructor, you need to give it a valid target file!
bassert (targetFile != File::nonexistent ());
}
TemporaryFile::TemporaryFile (const File& target, const File& temporary)
: temporaryFile (temporary), targetFile (target)
{
}
TemporaryFile::~TemporaryFile()
{
if (! deleteTemporaryFile())
{
/* Failed to delete our temporary file! The most likely reason for this would be
that you've not closed an output stream that was being used to write to file.
If you find that something beyond your control is changing permissions on
your temporary files and preventing them from being deleted, you may want to
call TemporaryFile::deleteTemporaryFile() to detect those error cases and
handle them appropriately.
*/
bassertfalse;
}
}
//==============================================================================
bool TemporaryFile::overwriteTargetFileWithTemporary() const
{
// This method only works if you created this object with the constructor
// that takes a target file!
bassert (targetFile != File::nonexistent ());
if (temporaryFile.exists())
{
// Have a few attempts at overwriting the file before giving up..
for (int i = 5; --i >= 0;)
{
if (temporaryFile.moveFileTo (targetFile))
return true;
Thread::sleep (100);
}
}
else
{
// There's no temporary file to use. If your write failed, you should
// probably check, and not bother calling this method.
bassertfalse;
}
return false;
}
bool TemporaryFile::deleteTemporaryFile() const
{
// Have a few attempts at deleting the file before giving up..
for (int i = 5; --i >= 0;)
{
if (temporaryFile.deleteFile())
return true;
Thread::sleep (50);
}
return false;
}
} // beast

View File

@@ -0,0 +1,166 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_TEMPORARYFILE_H_INCLUDED
#define BEAST_TEMPORARYFILE_H_INCLUDED
namespace beast
{
//==============================================================================
/**
Manages a temporary file, which will be deleted when this object is deleted.
This object is intended to be used as a stack based object, using its scope
to make sure the temporary file isn't left lying around.
For example:
@code
{
File myTargetFile ("~/myfile.txt");
// this will choose a file called something like "~/myfile_temp239348.txt"
// which definitely doesn't exist at the time the constructor is called.
TemporaryFile temp (myTargetFile);
// create a stream to the temporary file, and write some data to it...
ScopedPointer <FileOutputStream> out (temp.getFile().createOutputStream());
if (out != nullptr)
{
out->write ( ...etc )
out = nullptr; // (deletes the stream)
// ..now we've finished writing, this will rename the temp file to
// make it replace the target file we specified above.
bool succeeded = temp.overwriteTargetFileWithTemporary();
}
// ..and even if something went wrong and our overwrite failed,
// as the TemporaryFile object goes out of scope here, it'll make sure
// that the temp file gets deleted.
}
@endcode
@see File, FileOutputStream
*/
class TemporaryFile : LeakChecked <TemporaryFile>, public Uncopyable
{
public:
//==============================================================================
enum OptionFlags
{
useHiddenFile = 1, /**< Indicates that the temporary file should be hidden -
i.e. its name should start with a dot. */
putNumbersInBrackets = 2 /**< Indicates that when numbers are appended to make sure
the file is unique, they should go in brackets rather
than just being appended (see File::getNonexistentSibling() )*/
};
//==============================================================================
/** Creates a randomly-named temporary file in the default temp directory.
@param suffix a file suffix to use for the file
@param optionFlags a combination of the values listed in the OptionFlags enum
The file will not be created until you write to it. And remember that when
this object is deleted, the file will also be deleted!
*/
TemporaryFile (const String& suffix = String::empty,
int optionFlags = 0);
/** Creates a temporary file in the same directory as a specified file.
This is useful if you have a file that you want to overwrite, but don't
want to harm the original file if the write operation fails. You can
use this to create a temporary file next to the target file, then
write to the temporary file, and finally use overwriteTargetFileWithTemporary()
to replace the target file with the one you've just written.
This class won't create any files until you actually write to them. And remember
that when this object is deleted, the temporary file will also be deleted!
@param targetFile the file that you intend to overwrite - the temporary
file will be created in the same directory as this
@param optionFlags a combination of the values listed in the OptionFlags enum
*/
TemporaryFile (const File& targetFile,
int optionFlags = 0);
/** Creates a temporary file using an explicit filename.
The other constructors are a better choice than this one, unless for some reason
you need to explicitly specify the temporary file you want to use.
@param targetFile the file that you intend to overwrite
@param temporaryFile the temporary file to be used
*/
TemporaryFile (const File& targetFile,
const File& temporaryFile);
/** Destructor.
When this object is deleted it will make sure that its temporary file is
also deleted! If the operation fails, it'll throw an assertion in debug
mode.
*/
~TemporaryFile();
//==============================================================================
/** Returns the temporary file. */
const File& getFile() const noexcept { return temporaryFile; }
/** Returns the target file that was specified in the constructor. */
const File& getTargetFile() const noexcept { return targetFile; }
/** Tries to move the temporary file to overwrite the target file that was
specified in the constructor.
If you used the constructor that specified a target file, this will attempt
to replace that file with the temporary one.
Before calling this, make sure:
- that you've actually written to the temporary file
- that you've closed any open streams that you were using to write to it
- and that you don't have any streams open to the target file, which would
prevent it being overwritten
If the file move succeeds, this returns false, and the temporary file will
have disappeared. If it fails, the temporary file will probably still exist,
but will be deleted when this object is destroyed.
*/
bool overwriteTargetFileWithTemporary() const;
/** Attempts to delete the temporary file, if it exists.
@returns true if the file is successfully deleted (or if it didn't exist).
*/
bool deleteTemporaryFile() const;
private:
//==============================================================================
const File temporaryFile, targetFile;
};
} // beast
#endif // BEAST_TEMPORARYFILE_H_INCLUDED

View File

@@ -0,0 +1,63 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
Logger::Logger() {}
Logger::~Logger()
{
// You're deleting this logger while it's still being used!
// Always call Logger::setCurrentLogger (nullptr) before deleting the active logger.
bassert (currentLogger != this);
}
Logger* Logger::currentLogger = nullptr;
void Logger::setCurrentLogger (Logger* const newLogger) noexcept { currentLogger = newLogger; }
Logger* Logger::getCurrentLogger() noexcept { return currentLogger; }
void Logger::writeToLog (const String& message)
{
if (currentLogger != nullptr)
currentLogger->logMessage (message);
else
outputDebugString (message);
}
#if BEAST_LOG_ASSERTIONS || BEAST_DEBUG
void logAssertion (const char* const filename, const int lineNum)
{
String m ("BEAST Assertion failure in ");
m << File::createFileWithoutCheckingPath (filename).getFileName() << ':' << lineNum;
#if BEAST_LOG_ASSERTIONS
Logger::writeToLog (m);
#else
BDBG (m);
#endif
}
#endif
} // beast

View File

@@ -0,0 +1,93 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_LOGGER_H_INCLUDED
#define BEAST_LOGGER_H_INCLUDED
namespace beast
{
//==============================================================================
/**
Acts as an application-wide logging class.
A subclass of Logger can be created and passed into the Logger::setCurrentLogger
method and this will then be used by all calls to writeToLog.
The logger class also contains methods for writing messages to the debugger's
output stream.
*/
class Logger
{
public:
//==============================================================================
/** Destructor. */
virtual ~Logger();
//==============================================================================
/** Sets the current logging class to use.
Note that the object passed in will not be owned or deleted by the logger, so
the caller must make sure that it is not deleted while still being used.
A null pointer can be passed-in to disable any logging.
*/
static void setCurrentLogger (Logger* newLogger) noexcept;
/** Returns the current logger, or nullptr if none has been set. */
static Logger* getCurrentLogger() noexcept;
/** Writes a string to the current logger.
This will pass the string to the logger's logMessage() method if a logger
has been set.
@see logMessage
*/
static void writeToLog (const String& message);
//==============================================================================
/** Writes a message to the standard error stream.
This can be called directly, or by using the DBG() macro in
CompilerConfig.h (which will avoid calling the method in non-debug builds).
*/
static void outputDebugString (const String& text);
protected:
//==============================================================================
Logger();
/** This is overloaded by subclasses to implement custom logging behaviour.
@see setCurrentLogger
*/
virtual void logMessage (const String& message) = 0;
private:
static Logger* currentLogger;
};
} // beast
#endif // BEAST_LOGGER_H_INCLUDED

View File

@@ -0,0 +1,89 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_MATH_H_INCLUDED
#define BEAST_MATH_H_INCLUDED
namespace beast
{
//
// Miscellaneous mathematical calculations
//
// Calculate the bin for a value given the bin size.
// This correctly handles negative numbers. For example
// if value == -1 then calc_bin returns -1.
template <typename Ty>
inline Ty calc_bin (Ty value, int size)
{
if (value >= 0)
return value / size;
else
return (value - size + 1) / size;
}
// Given a number and a bin size, this returns the first
// corresponding value of the bin associated with the given number.
// It correctly handles negative numbers. For example,
// if value == -1 then calc_bin always returns -size
template <typename Ty>
inline Ty calc_bin_start (Ty value, int size)
{
return calc_bin (value, size) * size;
}
template <class T>
inline T pi () noexcept
{
return 3.14159265358979;
}
template <class T>
inline T twoPi () noexcept
{
return 6.28318530717958;
}
template <class T>
inline T oneOverTwoPi () noexcept
{
return 0.1591549430918955;
}
template <class T, class U>
inline T degreesToRadians (U degrees)
{
return T (degrees * 0.0174532925199433);
}
template <class T, class U>
inline T radiansToDegrees (U radians)
{
T deg = T (radians * U (57.29577951308238));
if (deg < 0)
deg += 360;
return deg;
}
} // beast
#endif

View File

@@ -0,0 +1,155 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <beast/unit_test/suite.h>
namespace beast {
Random::Random (const std::int64_t seedValue) noexcept
: seed (seedValue)
{
nextInt (); // fixes a bug where the first int is always 0
}
Random::Random()
: seed (1)
{
setSeedRandomly();
}
Random::~Random() noexcept
{
}
void Random::setSeed (const std::int64_t newSeed) noexcept
{
seed = newSeed;
nextInt (); // fixes a bug where the first int is always 0
}
void Random::combineSeed (const std::int64_t seedValue) noexcept
{
seed ^= nextInt64() ^ seedValue;
}
void Random::setSeedRandomly()
{
static std::int64_t globalSeed = 0;
combineSeed (globalSeed ^ (std::int64_t) (std::intptr_t) this);
combineSeed (Time::getMillisecondCounter());
combineSeed (Time::getHighResolutionTicks());
combineSeed (Time::getHighResolutionTicksPerSecond());
combineSeed (Time::currentTimeMillis());
globalSeed ^= seed;
nextInt (); // fixes a bug where the first int is always 0
}
Random& Random::getSystemRandom() noexcept
{
static Random sysRand;
return sysRand;
}
//==============================================================================
int Random::nextInt() noexcept
{
seed = (seed * 0x5deece66dLL + 11) & 0xffffffffffffULL;
return (int) (seed >> 16);
}
int Random::nextInt (const int maxValue) noexcept
{
bassert (maxValue > 0);
return (int) ((((unsigned int) nextInt()) * (std::uint64_t) maxValue) >> 32);
}
std::int64_t Random::nextInt64() noexcept
{
return (((std::int64_t) nextInt()) << 32) | (std::int64_t) (std::uint64_t) (std::uint32_t) nextInt();
}
bool Random::nextBool() noexcept
{
return (nextInt() & 0x40000000) != 0;
}
float Random::nextFloat() noexcept
{
return static_cast <std::uint32_t> (nextInt()) / (float) 0xffffffff;
}
double Random::nextDouble() noexcept
{
return static_cast <std::uint32_t> (nextInt()) / (double) 0xffffffff;
}
void Random::fillBitsRandomly (void* const buffer, size_t bytes)
{
int* d = static_cast<int*> (buffer);
for (; bytes >= sizeof (int); bytes -= sizeof (int))
*d++ = nextInt();
if (bytes > 0)
{
const int lastBytes = nextInt();
memcpy (d, &lastBytes, bytes);
}
}
//==============================================================================
class Random_test : public unit_test::suite
{
public:
void run()
{
for (int j = 10; --j >= 0;)
{
Random r;
r.setSeedRandomly();
for (int i = 20; --i >= 0;)
{
expect (r.nextDouble() >= 0.0 && r.nextDouble() < 1.0);
expect (r.nextFloat() >= 0.0f && r.nextFloat() < 1.0f);
expect (r.nextInt (5) >= 0 && r.nextInt (5) < 5);
expect (r.nextInt (1) == 0);
int n = r.nextInt (50) + 1;
expect (r.nextInt (n) >= 0 && r.nextInt (n) < n);
n = r.nextInt (0x7ffffffe) + 1;
expect (r.nextInt (n) >= 0 && r.nextInt (n) < n);
}
}
}
};
BEAST_DEFINE_TESTSUITE(Random,beast_core,beast);
} // beast

View File

@@ -0,0 +1,128 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_RANDOM_H_INCLUDED
#define BEAST_RANDOM_H_INCLUDED
namespace beast
{
//==============================================================================
/**
A random number generator.
You can create a Random object and use it to generate a sequence of random numbers.
*/
class Random
{
public:
//==============================================================================
/** Creates a Random object based on a seed value.
For a given seed value, the subsequent numbers generated by this object
will be predictable, so a good idea is to set this value based
on the time, e.g.
new Random (Time::currentTimeMillis())
*/
explicit Random (std::int64_t seedValue) noexcept;
/** Creates a Random object using a random seed value.
Internally, this calls setSeedRandomly() to randomise the seed.
*/
Random();
/** Destructor. */
~Random() noexcept;
/** Returns the next random 32 bit integer.
@returns a random integer from the full range 0x80000000 to 0x7fffffff
*/
int nextInt() noexcept;
/** Returns the next random number, limited to a given range.
The maxValue parameter may not be negative, or zero.
@returns a random integer between 0 (inclusive) and maxValue (exclusive).
*/
int nextInt (int maxValue) noexcept;
/** Returns the next 64-bit random number.
@returns a random integer from the full range 0x8000000000000000 to 0x7fffffffffffffff
*/
std::int64_t nextInt64() noexcept;
/** Returns the next random floating-point number.
@returns a random value in the range 0 to 1.0
*/
float nextFloat() noexcept;
/** Returns the next random floating-point number.
@returns a random value in the range 0 to 1.0
*/
double nextDouble() noexcept;
/** Returns the next random boolean value.
*/
bool nextBool() noexcept;
/** Fills a block of memory with random values. */
void fillBitsRandomly (void* bufferToFill, size_t sizeInBytes);
//==============================================================================
/** Resets this Random object to a given seed value. */
void setSeed (std::int64_t newSeed) noexcept;
/** Merges this object's seed with another value.
This sets the seed to be a value created by combining the current seed and this
new value.
*/
void combineSeed (std::int64_t seedValue) noexcept;
/** Reseeds this generator using a value generated from various semi-random system
properties like the current time, etc.
Because this function convolves the time with the last seed value, calling
it repeatedly will increase the randomness of the final result.
*/
void setSeedRandomly();
/** The overhead of creating a new Random object is fairly small, but if you want to avoid
it, you can call this method to get a global shared Random object.
It's not thread-safe though, so threads should use their own Random object, otherwise
you run the risk of your random numbers becoming.. erm.. randomly corrupted..
*/
static Random& getSystemRandom() noexcept;
private:
//==============================================================================
std::int64_t seed;
};
} // beast
#endif // BEAST_RANDOM_H_INCLUDED

View File

@@ -0,0 +1,263 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_RANGE_H_INCLUDED
#define BEAST_RANGE_H_INCLUDED
namespace beast
{
//==============================================================================
/** A general-purpose range object, that simply represents any linear range with
a start and end point.
The templated parameter is expected to be a primitive integer or floating point
type, though class types could also be used if they behave in a number-like way.
*/
template <typename ValueType>
class Range
{
public:
//==============================================================================
/** Constructs an empty range. */
Range() noexcept : start(), end()
{
}
/** Constructs a range with given start and end values. */
Range (const ValueType startValue, const ValueType endValue) noexcept
: start (startValue), end (bmax (startValue, endValue))
{
}
/** Constructs a copy of another range. */
Range (const Range& other) noexcept
: start (other.start), end (other.end)
{
}
/** Copies another range object. */
Range& operator= (Range other) noexcept
{
start = other.start;
end = other.end;
return *this;
}
/** Returns the range that lies between two positions (in either order). */
static Range between (const ValueType position1, const ValueType position2) noexcept
{
return position1 < position2 ? Range (position1, position2)
: Range (position2, position1);
}
/** Returns a range with the specified start position and a length of zero. */
static Range emptyRange (const ValueType start) noexcept
{
return Range (start, start);
}
//==============================================================================
/** Returns the start of the range. */
inline ValueType getStart() const noexcept { return start; }
/** Returns the length of the range. */
inline ValueType getLength() const noexcept { return end - start; }
/** Returns the end of the range. */
inline ValueType getEnd() const noexcept { return end; }
/** Returns true if the range has a length of zero. */
inline bool isEmpty() const noexcept { return start == end; }
//==============================================================================
/** Changes the start position of the range, leaving the end position unchanged.
If the new start position is higher than the current end of the range, the end point
will be pushed along to equal it, leaving an empty range at the new position.
*/
void setStart (const ValueType newStart) noexcept
{
start = newStart;
if (end < newStart)
end = newStart;
}
/** Returns a range with the same end as this one, but a different start.
If the new start position is higher than the current end of the range, the end point
will be pushed along to equal it, returning an empty range at the new position.
*/
Range withStart (const ValueType newStart) const noexcept
{
return Range (newStart, bmax (newStart, end));
}
/** Returns a range with the same length as this one, but moved to have the given start position. */
Range movedToStartAt (const ValueType newStart) const noexcept
{
return Range (newStart, end + (newStart - start));
}
/** Changes the end position of the range, leaving the start unchanged.
If the new end position is below the current start of the range, the start point
will be pushed back to equal the new end point.
*/
void setEnd (const ValueType newEnd) noexcept
{
end = newEnd;
if (newEnd < start)
start = newEnd;
}
/** Returns a range with the same start position as this one, but a different end.
If the new end position is below the current start of the range, the start point
will be pushed back to equal the new end point.
*/
Range withEnd (const ValueType newEnd) const noexcept
{
return Range (bmin (start, newEnd), newEnd);
}
/** Returns a range with the same length as this one, but moved to have the given end position. */
Range movedToEndAt (const ValueType newEnd) const noexcept
{
return Range (start + (newEnd - end), newEnd);
}
/** Changes the length of the range.
Lengths less than zero are treated as zero.
*/
void setLength (const ValueType newLength) noexcept
{
end = start + bmax (ValueType(), newLength);
}
/** Returns a range with the same start as this one, but a different length.
Lengths less than zero are treated as zero.
*/
Range withLength (const ValueType newLength) const noexcept
{
return Range (start, start + newLength);
}
//==============================================================================
/** Adds an amount to the start and end of the range. */
inline Range operator+= (const ValueType amountToAdd) noexcept
{
start += amountToAdd;
end += amountToAdd;
return *this;
}
/** Subtracts an amount from the start and end of the range. */
inline Range operator-= (const ValueType amountToSubtract) noexcept
{
start -= amountToSubtract;
end -= amountToSubtract;
return *this;
}
/** Returns a range that is equal to this one with an amount added to its
start and end.
*/
Range operator+ (const ValueType amountToAdd) const noexcept
{
return Range (start + amountToAdd, end + amountToAdd);
}
/** Returns a range that is equal to this one with the specified amount
subtracted from its start and end. */
Range operator- (const ValueType amountToSubtract) const noexcept
{
return Range (start - amountToSubtract, end - amountToSubtract);
}
bool operator== (Range other) const noexcept { return start == other.start && end == other.end; }
bool operator!= (Range other) const noexcept { return start != other.start || end != other.end; }
//==============================================================================
/** Returns true if the given position lies inside this range. */
bool contains (const ValueType position) const noexcept
{
return start <= position && position < end;
}
/** Returns the nearest value to the one supplied, which lies within the range. */
ValueType clipValue (const ValueType value) const noexcept
{
return blimit (start, end, value);
}
/** Returns true if the given range lies entirely inside this range. */
bool contains (Range other) const noexcept
{
return start <= other.start && end >= other.end;
}
/** Returns true if the given range intersects this one. */
bool intersects (Range other) const noexcept
{
return other.start < end && start < other.end;
}
/** Returns the range that is the intersection of the two ranges, or an empty range
with an undefined start position if they don't overlap. */
Range getIntersectionWith (Range other) const noexcept
{
return Range (bmax (start, other.start),
bmin (end, other.end));
}
/** Returns the smallest range that contains both this one and the other one. */
Range getUnionWith (Range other) const noexcept
{
return Range (bmin (start, other.start),
bmax (end, other.end));
}
/** Returns a given range, after moving it forwards or backwards to fit it
within this range.
If the supplied range has a greater length than this one, the return value
will be this range.
Otherwise, if the supplied range is smaller than this one, the return value
will be the new range, shifted forwards or backwards so that it doesn't extend
beyond this one, but keeping its original length.
*/
Range constrainRange (Range rangeToConstrain) const noexcept
{
const ValueType otherLen = rangeToConstrain.getLength();
return getLength() <= otherLen
? *this
: rangeToConstrain.movedToStartAt (blimit (start, end - otherLen, rangeToConstrain.getStart()));
}
private:
//==============================================================================
ValueType start, end;
};
} // beast
#endif // BEAST_RANGE_H_INCLUDED

View File

@@ -0,0 +1,410 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
MemoryBlock::MemoryBlock() noexcept
: size (0)
{
}
MemoryBlock::MemoryBlock (const size_t initialSize, const bool initialiseToZero)
{
if (initialSize > 0)
{
size = initialSize;
data.allocate (initialSize, initialiseToZero);
}
else
{
size = 0;
}
}
MemoryBlock::MemoryBlock (const MemoryBlock& other)
: size (other.size)
{
if (size > 0)
{
bassert (other.data != nullptr);
data.malloc (size);
memcpy (data, other.data, size);
}
}
MemoryBlock::MemoryBlock (const void* const dataToInitialiseFrom, const size_t sizeInBytes)
: size (sizeInBytes)
{
bassert (((std::ptrdiff_t) sizeInBytes) >= 0);
if (size > 0)
{
bassert (dataToInitialiseFrom != nullptr); // non-zero size, but a zero pointer passed-in?
data.malloc (size);
if (dataToInitialiseFrom != nullptr)
memcpy (data, dataToInitialiseFrom, size);
}
}
MemoryBlock::~MemoryBlock() noexcept
{
}
MemoryBlock& MemoryBlock::operator= (const MemoryBlock& other)
{
if (this != &other)
{
setSize (other.size, false);
memcpy (data, other.data, size);
}
return *this;
}
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
MemoryBlock::MemoryBlock (MemoryBlock&& other) noexcept
: data (static_cast <HeapBlock <char>&&> (other.data)),
size (other.size)
{
}
MemoryBlock& MemoryBlock::operator= (MemoryBlock&& other) noexcept
{
data = static_cast <HeapBlock <char>&&> (other.data);
size = other.size;
return *this;
}
#endif
//==============================================================================
bool MemoryBlock::operator== (const MemoryBlock& other) const noexcept
{
return matches (other.data, other.size);
}
bool MemoryBlock::operator!= (const MemoryBlock& other) const noexcept
{
return ! operator== (other);
}
bool MemoryBlock::matches (const void* dataToCompare, size_t dataSize) const noexcept
{
return size == dataSize
&& memcmp (data, dataToCompare, size) == 0;
}
//==============================================================================
// this will resize the block to this size
void MemoryBlock::setSize (const size_t newSize, const bool initialiseToZero)
{
if (size != newSize)
{
if (newSize <= 0)
{
data.free_up();
size = 0;
}
else
{
if (data != nullptr)
{
data.reallocate (newSize);
if (initialiseToZero && (newSize > size))
zeromem (data + size, newSize - size);
}
else
{
data.allocate (newSize, initialiseToZero);
}
size = newSize;
}
}
}
void MemoryBlock::ensureSize (const size_t minimumSize, const bool initialiseToZero)
{
if (size < minimumSize)
setSize (minimumSize, initialiseToZero);
}
void MemoryBlock::swapWith (MemoryBlock& other) noexcept
{
std::swap (size, other.size);
data.swapWith (other.data);
}
//==============================================================================
void MemoryBlock::fillWith (const std::uint8_t value) noexcept
{
memset (data, (int) value, size);
}
void MemoryBlock::append (const void* const srcData, const size_t numBytes)
{
if (numBytes > 0)
{
bassert (srcData != nullptr); // this must not be null!
const size_t oldSize = size;
setSize (size + numBytes);
memcpy (data + oldSize, srcData, numBytes);
}
}
void MemoryBlock::replaceWith (const void* const srcData, const size_t numBytes)
{
if (numBytes > 0)
{
bassert (srcData != nullptr); // this must not be null!
setSize (numBytes);
memcpy (data, srcData, numBytes);
}
}
void MemoryBlock::insert (const void* const srcData, const size_t numBytes, size_t insertPosition)
{
if (numBytes > 0)
{
bassert (srcData != nullptr); // this must not be null!
insertPosition = bmin (size, insertPosition);
const size_t trailingDataSize = size - insertPosition;
setSize (size + numBytes, false);
if (trailingDataSize > 0)
memmove (data + insertPosition + numBytes,
data + insertPosition,
trailingDataSize);
memcpy (data + insertPosition, srcData, numBytes);
}
}
void MemoryBlock::removeSection (const size_t startByte, const size_t numBytesToRemove)
{
if (startByte + numBytesToRemove >= size)
{
setSize (startByte);
}
else if (numBytesToRemove > 0)
{
memmove (data + startByte,
data + startByte + numBytesToRemove,
size - (startByte + numBytesToRemove));
setSize (size - numBytesToRemove);
}
}
void MemoryBlock::copyFrom (const void* const src, int offset, size_t num) noexcept
{
const char* d = static_cast<const char*> (src);
if (offset < 0)
{
d -= offset;
num += (size_t) -offset;
offset = 0;
}
if ((size_t) offset + num > size)
num = size - (size_t) offset;
if (num > 0)
memcpy (data + offset, d, num);
}
void MemoryBlock::copyTo (void* const dst, int offset, size_t num) const noexcept
{
char* d = static_cast<char*> (dst);
if (offset < 0)
{
zeromem (d, (size_t) -offset);
d -= offset;
num -= (size_t) -offset;
offset = 0;
}
if ((size_t) offset + num > size)
{
const size_t newNum = size - (size_t) offset;
zeromem (d + newNum, num - newNum);
num = newNum;
}
if (num > 0)
memcpy (d, data + offset, num);
}
String MemoryBlock::toString() const
{
return String (CharPointer_UTF8 (data), size);
}
//==============================================================================
int MemoryBlock::getBitRange (const size_t bitRangeStart, size_t numBits) const noexcept
{
int res = 0;
size_t byte = bitRangeStart >> 3;
size_t offsetInByte = bitRangeStart & 7;
size_t bitsSoFar = 0;
while (numBits > 0 && (size_t) byte < size)
{
const size_t bitsThisTime = bmin (numBits, 8 - offsetInByte);
const int mask = (0xff >> (8 - bitsThisTime)) << offsetInByte;
res |= (((data[byte] & mask) >> offsetInByte) << bitsSoFar);
bitsSoFar += bitsThisTime;
numBits -= bitsThisTime;
++byte;
offsetInByte = 0;
}
return res;
}
void MemoryBlock::setBitRange (const size_t bitRangeStart, size_t numBits, int bitsToSet) noexcept
{
size_t byte = bitRangeStart >> 3;
size_t offsetInByte = bitRangeStart & 7;
std::uint32_t mask = ~((((std::uint32_t) 0xffffffff) << (32 - numBits)) >> (32 - numBits));
while (numBits > 0 && (size_t) byte < size)
{
const size_t bitsThisTime = bmin (numBits, 8 - offsetInByte);
const std::uint32_t tempMask = (mask << offsetInByte) | ~((((std::uint32_t) 0xffffffff) >> offsetInByte) << offsetInByte);
const std::uint32_t tempBits = (std::uint32_t) bitsToSet << offsetInByte;
data[byte] = (char) (((std::uint32_t) data[byte] & tempMask) | tempBits);
++byte;
numBits -= bitsThisTime;
bitsToSet >>= bitsThisTime;
mask >>= bitsThisTime;
offsetInByte = 0;
}
}
//==============================================================================
void MemoryBlock::loadFromHexString (const String& hex)
{
ensureSize ((size_t) hex.length() >> 1);
char* dest = data;
String::CharPointerType t (hex.getCharPointer());
for (;;)
{
int byte = 0;
for (int loop = 2; --loop >= 0;)
{
byte <<= 4;
for (;;)
{
const beast_wchar c = t.getAndAdvance();
if (c >= '0' && c <= '9') { byte |= c - '0'; break; }
if (c >= 'a' && c <= 'z') { byte |= c - ('a' - 10); break; }
if (c >= 'A' && c <= 'Z') { byte |= c - ('A' - 10); break; }
if (c == 0)
{
setSize (static_cast <size_t> (dest - data));
return;
}
}
}
*dest++ = (char) byte;
}
}
//==============================================================================
static char const* const base64EncodingTable = ".ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+";
String MemoryBlock::toBase64Encoding() const
{
const size_t numChars = ((size << 3) + 5) / 6;
String destString ((unsigned int) size); // store the length, followed by a '.', and then the data.
const int initialLen = destString.length();
destString.preallocateBytes (sizeof (String::CharPointerType::CharType) * (size_t) initialLen + 2 + numChars);
String::CharPointerType d (destString.getCharPointer());
d += initialLen;
d.write ('.');
for (size_t i = 0; i < numChars; ++i)
d.write ((beast_wchar) (std::uint8_t) base64EncodingTable [getBitRange (i * 6, 6)]);
d.writeNull();
return destString;
}
bool MemoryBlock::fromBase64Encoding (const String& s)
{
const int startPos = s.indexOfChar ('.') + 1;
if (startPos <= 0)
return false;
const int numBytesNeeded = s.substring (0, startPos - 1).getIntValue();
setSize ((size_t) numBytesNeeded, true);
const int numChars = s.length() - startPos;
String::CharPointerType srcChars (s.getCharPointer());
srcChars += startPos;
int pos = 0;
for (int i = 0; i < numChars; ++i)
{
const char c = (char) srcChars.getAndAdvance();
for (int j = 0; j < 64; ++j)
{
if (base64EncodingTable[j] == c)
{
setBitRange ((size_t) pos, 6, j);
pos += 6;
break;
}
}
}
return true;
}
} // beast

Some files were not shown because too many files have changed in this diff Show More