diff options
Diffstat (limited to 'lib/libUPnP/Neptune/Source/Core')
84 files changed, 29704 insertions, 0 deletions
diff --git a/lib/libUPnP/Neptune/Source/Core/Neptune.cpp b/lib/libUPnP/Neptune/Source/Core/Neptune.cpp new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/Neptune.cpp diff --git a/lib/libUPnP/Neptune/Source/Core/Neptune.h b/lib/libUPnP/Neptune/Source/Core/Neptune.h new file mode 100644 index 0000000..8ea4fa1 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/Neptune.h @@ -0,0 +1,86 @@ +/***************************************************************** +| +| Neptune - Toplevel Include +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +#ifndef _NEPTUNE_H_ +#define _NEPTUNE_H_ + +/*---------------------------------------------------------------------- +| flags ++---------------------------------------------------------------------*/ +#define NPT_EXTERNAL_USE /* do not expose internal definitions */ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptConfig.h" +#include "NptCommon.h" +#include "NptResults.h" +#include "NptTypes.h" +#include "NptConstants.h" +#include "NptReferences.h" +#include "NptStreams.h" +#include "NptBufferedStreams.h" +#include "NptFile.h" +#include "NptNetwork.h" +#include "NptSockets.h" +#include "NptTime.h" +#include "NptThreads.h" +#include "NptSystem.h" +#include "NptMessaging.h" +#include "NptQueue.h" +#include "NptSimpleMessageQueue.h" +#include "NptSelectableMessageQueue.h" +#include "NptXml.h" +#include "NptStrings.h" +#include "NptArray.h" +#include "NptList.h" +#include "NptMap.h" +#include "NptStack.h" +#include "NptUri.h" +#include "NptHttp.h" +#include "NptDataBuffer.h" +#include "NptUtils.h" +#include "NptRingBuffer.h" +#include "NptBase64.h" +#include "NptConsole.h" +#include "NptLogging.h" +#include "NptSerialPort.h" +#include "NptVersion.h" +#include "NptDynamicLibraries.h" +#include "NptDynamicCast.h" +#include "NptDigest.h" +#include "NptCrypto.h" + +// optional modules +#include "NptZip.h" +#include "NptTls.h" + +#endif // _NEPTUNE_H_ diff --git a/lib/libUPnP/Neptune/Source/Core/NptArray.h b/lib/libUPnP/Neptune/Source/Core/NptArray.h new file mode 100644 index 0000000..721bac8 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptArray.h @@ -0,0 +1,522 @@ +/***************************************************************** +| +| Neptune - Arrays +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| +****************************************************************/ + +#ifndef _NPT_ARRAY_H_ +#define _NPT_ARRAY_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptConfig.h" +#if defined(NPT_CONFIG_HAVE_NEW_H) +#include <new> +#endif +#include "NptTypes.h" +#include "NptResults.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const int NPT_ARRAY_INITIAL_MAX_SIZE = 128; // bytes + +/*---------------------------------------------------------------------- +| NPT_Array ++---------------------------------------------------------------------*/ +template <typename T> +class NPT_Array +{ +public: + // types + typedef T Element; + typedef T* Iterator; + + // methods + NPT_Array<T>(): m_Capacity(0), m_ItemCount(0), m_Items(0) {} + explicit NPT_Array<T>(NPT_Cardinal count); + NPT_Array<T>(NPT_Cardinal count, const T& item); + NPT_Array<T>(const T* items, NPT_Cardinal item_count); + ~NPT_Array<T>(); + NPT_Array<T>(const NPT_Array<T>& copy); + NPT_Array<T>& operator=(const NPT_Array<T>& copy); + bool operator==(const NPT_Array<T>& other) const; + bool operator!=(const NPT_Array<T>& other) const; + NPT_Cardinal GetItemCount() const { return m_ItemCount; } + NPT_Result Add(const T& item); + T& operator[](NPT_Ordinal pos) { return m_Items[pos]; } + const T& operator[](NPT_Ordinal pos) const { return m_Items[pos]; } + NPT_Result Erase(Iterator which); + NPT_Result Erase(NPT_Ordinal which) { return Erase(&m_Items[which]); } + NPT_Result Erase(Iterator first, Iterator last); + NPT_Result Erase(NPT_Ordinal first, NPT_Ordinal last) { return Erase(&m_Items[first], &m_Items[last]); } + NPT_Result Insert(Iterator where, const T& item, NPT_Cardinal count = 1); + NPT_Result Reserve(NPT_Cardinal count); + NPT_Cardinal GetCapacity() const { return m_Capacity; } + NPT_Result Resize(NPT_Cardinal count); + NPT_Result Resize(NPT_Cardinal count, const T& fill); + NPT_Result Clear(); + bool Contains(const T& data) const; + Iterator GetFirstItem() const { return m_ItemCount?&m_Items[0]:NULL; } + Iterator GetLastItem() const { return m_ItemCount?&m_Items[m_ItemCount-1]:NULL; } + Iterator GetItem(NPT_Ordinal n) { return n<m_ItemCount?&m_Items[n]:NULL; } + + // template list operations + // keep these template members defined here because MSV6 does not let + // us define them later + template <typename X> + NPT_Result Apply(const X& function) const + { + for (unsigned int i=0; i<m_ItemCount; i++) function(m_Items[i]); + return NPT_SUCCESS; + } + + template <typename X, typename P> + NPT_Result ApplyUntil(const X& function, const P& predicate, bool* match = NULL) const + { + for (unsigned int i=0; i<m_ItemCount; i++) { + NPT_Result return_value; + if (predicate(function(m_Items[i]), return_value)) { + if (match) *match = true; + return return_value; + } + } + if (match) *match = false; + return NPT_SUCCESS; + } + + template <typename X> + T* Find(const X& predicate, NPT_Ordinal n=0, NPT_Ordinal* pos = NULL) const + { + if (pos) *pos = -1; + + for (unsigned int i=0; i<m_ItemCount; i++) { + if (predicate(m_Items[i])) { + if (pos) *pos = i; + if (n == 0) return &m_Items[i]; + --n; + } + } + return NULL; + } + +protected: + // methods + T* Allocate(NPT_Cardinal count, NPT_Cardinal& allocated); + + // members + NPT_Cardinal m_Capacity; + NPT_Cardinal m_ItemCount; + T* m_Items; +}; + +/*---------------------------------------------------------------------- +| NPT_Array<T>::NPT_Array<T> ++---------------------------------------------------------------------*/ +template <typename T> +inline +NPT_Array<T>::NPT_Array(NPT_Cardinal count) : + m_Capacity(0), + m_ItemCount(0), + m_Items(0) +{ + Reserve(count); +} + +/*---------------------------------------------------------------------- +| NPT_Array<T>::NPT_Array<T> ++---------------------------------------------------------------------*/ +template <typename T> +inline +NPT_Array<T>::NPT_Array(const NPT_Array<T>& copy) : + m_Capacity(0), + m_ItemCount(0), + m_Items(0) +{ + Reserve(copy.GetItemCount()); + for (NPT_Ordinal i=0; i<copy.m_ItemCount; i++) { + new ((void*)&m_Items[i]) T(copy.m_Items[i]); + } + m_ItemCount = copy.m_ItemCount; +} + +/*---------------------------------------------------------------------- +| NPT_Array<T>::NPT_Array<T> ++---------------------------------------------------------------------*/ +template <typename T> +inline +NPT_Array<T>::NPT_Array(NPT_Cardinal count, const T& item) : + m_Capacity(0), + m_ItemCount(count), + m_Items(0) +{ + Reserve(count); + for (NPT_Ordinal i=0; i<count; i++) { + new ((void*)&m_Items[i]) T(item); + } +} + +/*---------------------------------------------------------------------- +| NPT_Array<T>::NPT_Array<T> ++---------------------------------------------------------------------*/ +template <typename T> +inline +NPT_Array<T>::NPT_Array(const T* items, NPT_Cardinal item_count) : + m_Capacity(0), + m_ItemCount(item_count), + m_Items(0) +{ + Reserve(item_count); + for (NPT_Ordinal i=0; i<item_count; i++) { + new ((void*)&m_Items[i]) T(items[i]); + } +} + +/*---------------------------------------------------------------------- +| NPT_Array<T>::~NPT_Array<T> ++---------------------------------------------------------------------*/ +template <typename T> +inline +NPT_Array<T>::~NPT_Array() +{ + // remove all items + Clear(); + + // free the memory + ::operator delete((void*)m_Items); +} + +/*---------------------------------------------------------------------- +| NPT_Array<T>::operator= ++---------------------------------------------------------------------*/ +template <typename T> +NPT_Array<T>& +NPT_Array<T>::operator=(const NPT_Array<T>& copy) +{ + // do nothing if we're assigning to ourselves + if (this == ©) return *this; + + // destroy all elements + Clear(); + + // copy all elements from the other object + Reserve(copy.GetItemCount()); + m_ItemCount = copy.m_ItemCount; + for (NPT_Ordinal i=0; i<copy.m_ItemCount; i++) { + new ((void*)&m_Items[i]) T(copy.m_Items[i]); + } + + return *this; +} + +/*---------------------------------------------------------------------- +| NPT_Array<T>::Clear ++---------------------------------------------------------------------*/ +template <typename T> +NPT_Result +NPT_Array<T>::Clear() +{ + // destroy all items + for (NPT_Ordinal i=0; i<m_ItemCount; i++) { + m_Items[i].~T(); + } + + m_ItemCount = 0; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_Array<T>::Allocate ++---------------------------------------------------------------------*/ +template <typename T> +T* +NPT_Array<T>::Allocate(NPT_Cardinal count, NPT_Cardinal& allocated) +{ + if (m_Capacity) { + allocated = 2*m_Capacity; + } else { + // start with just enough elements to fill + // NPT_ARRAY_INITIAL_MAX_SIZE worth of memory + allocated = NPT_ARRAY_INITIAL_MAX_SIZE/sizeof(T); + if (allocated == 0) allocated = 1; + } + if (allocated < count) allocated = count; + + // allocate the items + return (T*)::operator new(allocated*sizeof(T)); +} + +/*---------------------------------------------------------------------- +| NPT_Array<T>::Reserve ++---------------------------------------------------------------------*/ +template <typename T> +NPT_Result +NPT_Array<T>::Reserve(NPT_Cardinal count) +{ + if (count <= m_Capacity) return NPT_SUCCESS; + + // (re)allocate the items + NPT_Cardinal new_capacity; + T* new_items = Allocate(count, new_capacity); + if (new_items == NULL) { + return NPT_ERROR_OUT_OF_MEMORY; + } + if (m_ItemCount && m_Items) { + for (unsigned int i=0; i<m_ItemCount; i++) { + // construct the copy + new ((void*)&new_items[i])T(m_Items[i]); + + // destroy the item + m_Items[i].~T(); + } + } + ::operator delete((void*)m_Items); + m_Items = new_items; + m_Capacity = new_capacity; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_Array<T>::Add ++---------------------------------------------------------------------*/ +template <typename T> +inline +NPT_Result +NPT_Array<T>::Add(const T& item) +{ + // ensure capacity + NPT_Result result = Reserve(m_ItemCount+1); + if (result != NPT_SUCCESS) return result; + + // store the item + new ((void*)&m_Items[m_ItemCount++]) T(item); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_Array<T>::Erase ++---------------------------------------------------------------------*/ +template <typename T> +inline +NPT_Result +NPT_Array<T>::Erase(Iterator which) +{ + return Erase(which, which); +} + +/*---------------------------------------------------------------------- +| NPT_Array<T>::Erase ++---------------------------------------------------------------------*/ +template <typename T> +NPT_Result +NPT_Array<T>::Erase(Iterator first, Iterator last) +{ + // check parameters + if (first == NULL || last == NULL) return NPT_ERROR_INVALID_PARAMETERS; + + // check the bounds + NPT_Ordinal first_index = (NPT_Ordinal)(NPT_POINTER_TO_LONG(first-m_Items)); + NPT_Ordinal last_index = (NPT_Ordinal)(NPT_POINTER_TO_LONG(last-m_Items)); + if (first_index >= m_ItemCount || + last_index >= m_ItemCount || + first_index > last_index) { + return NPT_ERROR_INVALID_PARAMETERS; + } + + // shift items to the left + NPT_Cardinal interval = last_index-first_index+1; + NPT_Cardinal shifted = m_ItemCount-last_index-1; + for (NPT_Ordinal i=first_index; i<first_index+shifted; i++) { + m_Items[i] = m_Items[i+interval]; + } + + // destruct the remaining items + for (NPT_Ordinal i=first_index+shifted; i<m_ItemCount; i++) { + m_Items[i].~T(); + } + + // update the item count + m_ItemCount -= interval; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_Array<T>::Insert ++---------------------------------------------------------------------*/ +template <typename T> +NPT_Result +NPT_Array<T>::Insert(Iterator where, const T& item, NPT_Cardinal repeat) +{ + // check bounds + NPT_Ordinal where_index = where?((NPT_Ordinal)NPT_POINTER_TO_LONG(where-m_Items)):m_ItemCount; + if (where > &m_Items[m_ItemCount] || repeat == 0) return NPT_ERROR_INVALID_PARAMETERS; + + NPT_Cardinal needed = m_ItemCount+repeat; + if (needed > m_Capacity) { + // allocate more memory + NPT_Cardinal new_capacity; + T* new_items = Allocate(needed, new_capacity); + if (new_items == NULL) return NPT_ERROR_OUT_OF_MEMORY; + m_Capacity = new_capacity; + + // move the items before the insertion point + for (NPT_Ordinal i=0; i<where_index; i++) { + new((void*)&new_items[i])T(m_Items[i]); + m_Items[i].~T(); + } + + // move the items after the insertion point + for (NPT_Ordinal i=where_index; i<m_ItemCount; i++) { + new((void*)&new_items[i+repeat])T(m_Items[i]); + m_Items[i].~T(); + } + + // use the new items instead of the current ones + ::operator delete((void*)m_Items); + m_Items = new_items; + } else { + // shift items after the insertion point to the right + for (NPT_Ordinal i=m_ItemCount; i>where_index; i--) { + new((void*)&m_Items[i+repeat-1])T(m_Items[i-1]); + m_Items[i-1].~T(); + } + } + + // insert the new items + for (NPT_Cardinal i=where_index; i<where_index+repeat; i++) { + new((void*)&m_Items[i])T(item); + } + + // update the item count + m_ItemCount += repeat; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_Array<T>::Resize ++---------------------------------------------------------------------*/ +template <typename T> +NPT_Result +NPT_Array<T>::Resize(NPT_Cardinal size) +{ + if (size < m_ItemCount) { + // shrink + for (NPT_Ordinal i=size; i<m_ItemCount; i++) { + m_Items[i].~T(); + } + m_ItemCount = size; + } else if (size > m_ItemCount) { + return Resize(size, T()); + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_Array<T>::Resize ++---------------------------------------------------------------------*/ +template <typename T> +NPT_Result +NPT_Array<T>::Resize(NPT_Cardinal size, const T& fill) +{ + if (size < m_ItemCount) { + return Resize(size); + } else if (size > m_ItemCount) { + Reserve(size); + for (NPT_Ordinal i=m_ItemCount; i<size; i++) { + new ((void*)&m_Items[i]) T(fill); + } + m_ItemCount = size; + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_Array<T>::Contains ++---------------------------------------------------------------------*/ +template <typename T> +bool +NPT_Array<T>::Contains(const T& data) const +{ + for (NPT_Ordinal i=0; i<m_ItemCount; i++) { + if (m_Items[i] == data) return true; + } + + return false; +} + +/*---------------------------------------------------------------------- +| NPT_Array<T>::operator== ++---------------------------------------------------------------------*/ +template <typename T> +bool +NPT_Array<T>::operator==(const NPT_Array<T>& other) const +{ + // we need the same number of items + if (other.m_ItemCount != m_ItemCount) return false; + + // compare all items + for (NPT_Ordinal i=0; i<m_ItemCount; i++) { + if (!(m_Items[i] == other.m_Items[i])) return false; + } + + return true; +} + +/*---------------------------------------------------------------------- +| NPT_Array<T>::operator!= ++---------------------------------------------------------------------*/ +template <typename T> +inline +bool +NPT_Array<T>::operator!=(const NPT_Array<T>& other) const +{ + return !(*this == other); +} + +#endif // _NPT_ARRAY_H_ + + + + + + + + + + + + + diff --git a/lib/libUPnP/Neptune/Source/Core/NptAutomaticCleaner.cpp b/lib/libUPnP/Neptune/Source/Core/NptAutomaticCleaner.cpp new file mode 100644 index 0000000..9f677e4 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptAutomaticCleaner.cpp @@ -0,0 +1,101 @@ +/***************************************************************** +| +| Neptune - Automatic Cleaner +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| +****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptAutomaticCleaner.h" +#include "NptThreads.h" + +/*---------------------------------------------------------------------- +| NPT_AutomaticCleaner::NPT_AutomaticCleaner ++---------------------------------------------------------------------*/ +NPT_AutomaticCleaner::NPT_AutomaticCleaner() : + m_TlsContext(NULL), + m_HttpConnectionManager(NULL) +{ +} + +/*---------------------------------------------------------------------- +| NPT_AutomaticCleaner::~NPT_AutomaticCleaner ++---------------------------------------------------------------------*/ +NPT_AutomaticCleaner::~NPT_AutomaticCleaner() +{ + // When using TLS, the order to destroy singletons is important as + // connections may still need the TLS context up until they're + // cleaned up + delete m_HttpConnectionManager; + delete m_TlsContext; + + // Finally we can destroy the rest such as the NPT_HttpClient::ConnectionCanceller + m_Singletons.Apply(NPT_ObjectDeleter<Singleton>()); +} + +/*---------------------------------------------------------------------- +| NPT_AutomaticCleaner::GetInstance ++---------------------------------------------------------------------*/ +NPT_AutomaticCleaner* +NPT_AutomaticCleaner::GetInstance() +{ + return &Instance; +} +NPT_AutomaticCleaner NPT_AutomaticCleaner::Instance; + +/*---------------------------------------------------------------------- +| NPT_AutomaticCleaner::RegisterTlsContext ++---------------------------------------------------------------------*/ +NPT_Result +NPT_AutomaticCleaner::RegisterTlsContext(Singleton* singleton) +{ + m_TlsContext = singleton; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_AutomaticCleaner::RegisterHttpConnectionManager ++---------------------------------------------------------------------*/ +NPT_Result +NPT_AutomaticCleaner::RegisterHttpConnectionManager(Singleton* singleton) +{ + m_HttpConnectionManager = singleton; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_AutomaticCleaner::Register ++---------------------------------------------------------------------*/ +NPT_Result +NPT_AutomaticCleaner::Register(Singleton *singleton) +{ + // Prevent double insertion + m_Singletons.Remove(singleton); + return m_Singletons.Insert(m_Singletons.GetFirstItem(), singleton); +} diff --git a/lib/libUPnP/Neptune/Source/Core/NptAutomaticCleaner.h b/lib/libUPnP/Neptune/Source/Core/NptAutomaticCleaner.h new file mode 100644 index 0000000..21ff7c0 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptAutomaticCleaner.h @@ -0,0 +1,74 @@ +/***************************************************************** +| +| Neptune - Automatic Cleaner +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| +****************************************************************/ + +#ifndef _NPT_AUTOMATIC_CLEANER_H_ +#define _NPT_AUTOMATIC_CLEANER_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptList.h" + +/*---------------------------------------------------------------------- +| NPT_AutomaticCleaner ++---------------------------------------------------------------------*/ +class NPT_AutomaticCleaner +{ +public: + class Singleton { + public: + virtual ~Singleton() {} + }; + + static NPT_AutomaticCleaner* GetInstance(); + + // destructor + ~NPT_AutomaticCleaner(); + + // methods + NPT_Result Register(Singleton* singleton); + NPT_Result RegisterTlsContext(Singleton* singleton); + NPT_Result RegisterHttpConnectionManager(Singleton* singleton); + +private: + // class members + static NPT_AutomaticCleaner Instance; + + // constructor + NPT_AutomaticCleaner(); + + // members + NPT_List<Singleton*> m_Singletons; + Singleton* m_TlsContext; + Singleton* m_HttpConnectionManager; +}; + +#endif // _NPT_AUTOMATIC_CLEANER_H_ diff --git a/lib/libUPnP/Neptune/Source/Core/NptAutoreleasePool.h b/lib/libUPnP/Neptune/Source/Core/NptAutoreleasePool.h new file mode 100644 index 0000000..6f704f7 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptAutoreleasePool.h @@ -0,0 +1,57 @@ +/***************************************************************** +| +| Neptune - AutoreleasePool +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +#ifndef _NPT_AUTORELEASE_POOL_H_ +#define _NPT_AUTORELEASE_POOL_H_ + +/*---------------------------------------------------------------------- +| NPT_AutoreleasePoolInterface ++---------------------------------------------------------------------*/ +class NPT_AutoreleasePoolInterface +{ +public: + virtual ~NPT_AutoreleasePoolInterface() {} +}; + +/*---------------------------------------------------------------------- +| NPT_AutoreleasePool ++---------------------------------------------------------------------*/ +class NPT_AutoreleasePool : public NPT_AutoreleasePoolInterface +{ +public: + NPT_AutoreleasePool(); + ~NPT_AutoreleasePool() override; + +private: + NPT_AutoreleasePoolInterface* m_Delegate; +}; + +#endif // _NPT_AUTORELEASE_POOL_H_ diff --git a/lib/libUPnP/Neptune/Source/Core/NptBase64.cpp b/lib/libUPnP/Neptune/Source/Core/NptBase64.cpp new file mode 100644 index 0000000..b5ecc25 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptBase64.cpp @@ -0,0 +1,194 @@ +/***************************************************************** +| +| Neptune - Base64 +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| +****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptBase64.h" +#include "NptUtils.h" +#include "NptResults.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +static const signed char NPT_Base64_Bytes[128] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0x3E, -1, -1, -1, 0x3F, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, -1, -1, -1, 0x7F, -1, -1, + -1, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, + 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, -1, -1, -1, -1, -1, + -1, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, -1, -1, -1, -1, -1 +}; + +static const char NPT_Base64_Chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +const char NPT_BASE64_PAD_CHAR = '='; +const char NPT_BASE64_PAD_BYTE = 0x7F; + +/*---------------------------------------------------------------------- +| NPT_Base64::Decode ++---------------------------------------------------------------------*/ +NPT_Result +NPT_Base64::Decode(const char* base64, + NPT_Size size, + NPT_DataBuffer& data, + bool url_safe /* = false */) +{ + // estimate the data size + data.SetBufferSize(size); + + // reset the buffer + data.SetDataSize(0); + + // keep a pointer to the buffer + unsigned char* buffer = data.UseData(); + NPT_Size data_size = 0; + + // iterate over all characters + unsigned char codes[4]; + unsigned int code_count = 0; + while (size--) { + unsigned char c = *base64++; + if (c >= NPT_ARRAY_SIZE(NPT_Base64_Bytes)) continue; + if (url_safe) { + // remap some characters and forbid the mapped variants + if (c == '-') { + c = '+'; + } else if (c == '_') { + c = '/'; + } else if (c == '+' || c == '/') { + c = 0; // will be ignored later + } + } + signed char code = NPT_Base64_Bytes[c]; + if (code >= 0) { + // valid code + codes[code_count++] = code; + if (code_count == 4) { + // group complete + if (codes[0] == NPT_BASE64_PAD_BYTE || codes[1] == NPT_BASE64_PAD_BYTE) { + return NPT_ERROR_INVALID_FORMAT; + } + if (codes[2] == NPT_BASE64_PAD_BYTE) { + // pad at char 3 + if (codes[3] == NPT_BASE64_PAD_BYTE) { + // double padding + unsigned int packed = (codes[0]<<2)|(codes[1]>>4); + buffer[data_size++] = (unsigned char)packed; + } else { + // invalid padding + return NPT_ERROR_INVALID_FORMAT; + } + } else if (codes[3] == NPT_BASE64_PAD_BYTE) { + // single padding + unsigned int packed = (codes[0]<<10)|(codes[1]<<4)|(codes[2]>>2); + buffer[data_size++] = (unsigned char)(packed >> 8); + buffer[data_size++] = (unsigned char)(packed ); + } else { + // no padding + unsigned int packed = (codes[0]<<18)|(codes[1]<<12)|(codes[2]<<6)|codes[3]; + buffer[data_size++] = (unsigned char)(packed >> 16); + buffer[data_size++] = (unsigned char)(packed >> 8); + buffer[data_size++] = (unsigned char)(packed ); + } + code_count = 0; + } + } + } + + if (code_count) return NPT_ERROR_INVALID_FORMAT; + + // update the data size + data.SetDataSize(data_size); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_Base64::Encode ++---------------------------------------------------------------------*/ +NPT_Result +NPT_Base64::Encode(const NPT_Byte* data, + NPT_Size size, + NPT_String& base64, + NPT_Cardinal max_blocks_per_line /* = 0 */, + bool url_safe /* = false */) +{ + unsigned int block_count = 0; + unsigned int i = 0; + + // reserve space for the string + base64.Reserve(4*((size+3)/3) + 2*(max_blocks_per_line?(size/(3*max_blocks_per_line)):0)); + char* buffer = base64.UseChars(); + + // encode each byte + while (size >= 3) { + // output a block + *buffer++ = NPT_Base64_Chars[ (data[i ] >> 2) & 0x3F]; + *buffer++ = NPT_Base64_Chars[((data[i ] & 0x03) << 4) | ((data[i+1] >> 4) & 0x0F)]; + *buffer++ = NPT_Base64_Chars[((data[i+1] & 0x0F) << 2) | ((data[i+2] >> 6) & 0x03)]; + *buffer++ = NPT_Base64_Chars[ data[i+2] & 0x3F]; + + size -= 3; + i += 3; + if (++block_count == max_blocks_per_line) { + *buffer++ = '\r'; + *buffer++ = '\n'; + block_count = 0; + } + } + + // deal with the tail + if (size == 2) { + *buffer++ = NPT_Base64_Chars[ (data[i ] >> 2) & 0x3F]; + *buffer++ = NPT_Base64_Chars[((data[i ] & 0x03) << 4) | ((data[i+1] >> 4) & 0x0F)]; + *buffer++ = NPT_Base64_Chars[ (data[i+1] & 0x0F) << 2]; + *buffer++ = NPT_BASE64_PAD_CHAR; + } else if (size == 1) { + *buffer++ = NPT_Base64_Chars[(data[i] >> 2) & 0x3F]; + *buffer++ = NPT_Base64_Chars[(data[i] & 0x03) << 4]; + *buffer++ = NPT_BASE64_PAD_CHAR; + *buffer++ = NPT_BASE64_PAD_CHAR; + } + + // update the string size + NPT_ASSERT((NPT_Size)(buffer-base64.GetChars()) <= base64.GetCapacity()); + base64.SetLength((NPT_Size)(buffer-base64.GetChars())); + + // deal with url safe remapping + if (url_safe) { + base64.Replace('+','-'); + base64.Replace('/','_'); + } + + return NPT_SUCCESS; +} diff --git a/lib/libUPnP/Neptune/Source/Core/NptBase64.h b/lib/libUPnP/Neptune/Source/Core/NptBase64.h new file mode 100644 index 0000000..89950de --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptBase64.h @@ -0,0 +1,68 @@ +/***************************************************************** +| +| Neptune - Base64 +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| +****************************************************************/ + +#ifndef _NPT_BASE64_H_ +#define _NPT_BASE64_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptDataBuffer.h" +#include "NptStrings.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const NPT_Cardinal NPT_BASE64_MIME_BLOCKS_PER_LINE = 19; +const NPT_Cardinal NPT_BASE64_PEM_BLOCKS_PER_LINE = 16; + +/*---------------------------------------------------------------------- +| NPT_Base64 ++---------------------------------------------------------------------*/ +class NPT_Base64 { +public: + // class methods + static NPT_Result Decode(const char* base64, + NPT_Size size, + NPT_DataBuffer& data, + bool url_safe = false); + static NPT_Result Encode(const NPT_Byte* data, + NPT_Size size, + NPT_String& base64, + NPT_Cardinal max_blocks_per_line = 0, + bool url_safe = false); + +private: + // this class is purely static + NPT_Base64(); +}; + +#endif // _NPT_BASE64_H_ diff --git a/lib/libUPnP/Neptune/Source/Core/NptBufferedStreams.cpp b/lib/libUPnP/Neptune/Source/Core/NptBufferedStreams.cpp new file mode 100644 index 0000000..157a5bc --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptBufferedStreams.cpp @@ -0,0 +1,471 @@ +/***************************************************************** +| +| Neptune - Buffered Streams +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptTypes.h" +#include "NptInterfaces.h" +#include "NptConstants.h" +#include "NptBufferedStreams.h" +#include "NptUtils.h" +#include "NptLogging.h" + +/*---------------------------------------------------------------------- +| logging ++---------------------------------------------------------------------*/ +NPT_SET_LOCAL_LOGGER("neptune.bufferedstreams") + +#define NPT_CHECK_NOLOGTIMEOUT(_x) \ +do { \ + NPT_Result __result = (_x); \ + if (__result != NPT_SUCCESS) { \ + if (__result != NPT_ERROR_TIMEOUT && __result != NPT_ERROR_EOS) { \ + NPT_CHECK_WARNING(__result); \ + } \ + return __result; \ + } \ +} while(0) + +/*---------------------------------------------------------------------- +| NPT_BufferedInputStream::NPT_BufferedInputStream ++---------------------------------------------------------------------*/ +NPT_BufferedInputStream::NPT_BufferedInputStream(NPT_InputStreamReference& source, NPT_Size buffer_size) : + m_Source(source), + m_Position(0), + m_SkipNewline(false), + m_Eos(false) +{ + // setup the read buffer + m_Buffer.data = NULL; + m_Buffer.offset = 0; + m_Buffer.valid = 0; + m_Buffer.size = buffer_size; +} + +/*---------------------------------------------------------------------- +| NPT_BufferedInputStream::~NPT_BufferedInputStream ++---------------------------------------------------------------------*/ +NPT_BufferedInputStream::~NPT_BufferedInputStream() +{ + // release the buffer + delete[] m_Buffer.data; +} + +/*---------------------------------------------------------------------- +| NPT_BufferedInputStream::SetBufferSize ++---------------------------------------------------------------------*/ +NPT_Result +NPT_BufferedInputStream::SetBufferSize(NPT_Size size, bool force /* = false */) +{ + if (m_Buffer.data != NULL) { + // we already have a buffer + if (m_Buffer.size < size || force) { + // the current buffer is too small or we want to move + // existing data to the beginning of the buffer, reallocate + NPT_Byte* buffer = new NPT_Byte[size]; + if (buffer == NULL) return NPT_ERROR_OUT_OF_MEMORY; + + // copy existing data + NPT_Size need_to_copy = m_Buffer.valid - m_Buffer.offset; + if (need_to_copy) { + NPT_CopyMemory((void*)buffer, + m_Buffer.data+m_Buffer.offset, + need_to_copy); + } + + // use the new buffer + delete[] m_Buffer.data; + m_Buffer.data = buffer; + m_Buffer.valid -= m_Buffer.offset; + m_Buffer.offset = 0; + } + } + m_Buffer.size = size; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_BufferedInputStream::FillBuffer ++---------------------------------------------------------------------*/ +NPT_Result +NPT_BufferedInputStream::FillBuffer() +{ + // shortcut + if (m_Eos) return NPT_ERROR_EOS; + + // check that there is nothing left in the buffer and the buffer + // size is not 0 + NPT_ASSERT(m_Buffer.valid == m_Buffer.offset); + NPT_ASSERT(m_Buffer.size != 0); + + // allocate the read buffer if it has not been done yet + if (m_Buffer.data == NULL) { + m_Buffer.data = new NPT_Byte[m_Buffer.size]; + if (m_Buffer.data == NULL) return NPT_ERROR_OUT_OF_MEMORY; + } + + // refill the buffer + m_Buffer.offset = 0; + NPT_Result result = m_Source->Read(m_Buffer.data, m_Buffer.size, &m_Buffer.valid); + if (NPT_FAILED(result)) m_Buffer.valid = 0; + return result; +} + +/*---------------------------------------------------------------------- +| NPT_BufferedInputStream::ReleaseBuffer ++---------------------------------------------------------------------*/ +NPT_Result +NPT_BufferedInputStream::ReleaseBuffer() +{ + NPT_ASSERT(m_Buffer.size == 0); + NPT_ASSERT(m_Buffer.offset == m_Buffer.valid); + + delete[] m_Buffer.data; + m_Buffer.data = NULL; + m_Buffer.offset = 0; + m_Buffer.valid = 0; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_BufferedInputStream::ReadLine ++---------------------------------------------------------------------*/ +NPT_Result +NPT_BufferedInputStream::ReadLine(char* buffer, + NPT_Size size, + NPT_Size* chars_read, + bool break_on_cr) +{ + NPT_Result result = NPT_SUCCESS; + char* buffer_start = buffer; + char* buffer_end = buffer_start+size-1; + bool skip_newline = false; + + // check parameters + if (buffer == NULL || size < 1) { + if (chars_read) *chars_read = 0; + return NPT_ERROR_INVALID_PARAMETERS; + } + + // read until EOF or newline + for (;;) { + while (m_Buffer.offset != m_Buffer.valid) { + // there is some data left in the buffer + NPT_Byte c = m_Buffer.data[m_Buffer.offset++]; + if (c == '\r') { + if (break_on_cr) { + skip_newline = true; + goto done; + } + } else if (c == '\n') { + if (m_SkipNewline && (buffer == buffer_start)) { + continue; + } + goto done; + } else { + if (buffer == buffer_end) { + result = NPT_ERROR_NOT_ENOUGH_SPACE; + goto done; + } + *buffer++ = c; + } + } + + if (m_Buffer.size == 0 && !m_Eos) { + // unbuffered mode + if (m_Buffer.data != NULL) ReleaseBuffer(); + while (NPT_SUCCEEDED(result = m_Source->Read(buffer, 1, NULL))) { + if (*buffer == '\r') { + if (break_on_cr) { + skip_newline = true; + goto done; + } + } else if (*buffer == '\n') { + goto done; + } else { + if (buffer == buffer_end) { + result = NPT_ERROR_NOT_ENOUGH_SPACE; + goto done; + } + ++buffer; + } + } + } else { + // refill the buffer + result = FillBuffer(); + } + if (NPT_FAILED(result)) goto done; + } + +done: + // update the newline skipping state + m_SkipNewline = skip_newline; + + // NULL-terminate the line + *buffer = '\0'; + + // return what we have + m_Position += (NPT_Size)(buffer-buffer_start); + if (chars_read) *chars_read = (NPT_Size)(buffer-buffer_start); + if (result == NPT_ERROR_EOS) { + m_Eos = true; + if (buffer != buffer_start) { + // we have reached the end of the stream, but we have read + // some chars, so do not return EOS now + return NPT_SUCCESS; + } + } + return result; +} + +/*---------------------------------------------------------------------- +| NPT_BufferedInputStream::ReadLine ++---------------------------------------------------------------------*/ +NPT_Result +NPT_BufferedInputStream::ReadLine(NPT_String& line, + NPT_Size max_chars, + bool break_on_cr) +{ + // clear the line + line.SetLength(0); + + // reserve space for the chars + line.Reserve(max_chars); + + // read the line + NPT_Size chars_read = 0; + NPT_Result result = ReadLine(line.UseChars(), max_chars, &chars_read, break_on_cr); + NPT_CHECK_NOLOGTIMEOUT(result); + + // adjust the length of the string object + line.SetLength(chars_read); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_BufferedInputStream::Read ++---------------------------------------------------------------------*/ +NPT_Result +NPT_BufferedInputStream::Read(void* buffer, + NPT_Size bytes_to_read, + NPT_Size* bytes_read) +{ + NPT_Result result = NPT_SUCCESS; + NPT_Size total_read = 0; + NPT_Size buffered; + + // check for a possible shortcut + if (bytes_to_read == 0) return NPT_SUCCESS; + + // skip a newline char if needed + if (m_SkipNewline) { + m_SkipNewline = false; + result = Read(buffer, 1, NULL); + if (NPT_FAILED(result)) goto done; + NPT_Byte c = *(NPT_Byte*)buffer; + if (c != '\n') { + buffer = (void*)((NPT_Byte*)buffer+1); + --bytes_to_read; + total_read = 1; + } + } + + // compute how much is buffered + buffered = m_Buffer.valid-m_Buffer.offset; + if (bytes_to_read > buffered) { + // there is not enough in the buffer, take what's there + if (buffered) { + NPT_CopyMemory(buffer, + m_Buffer.data + m_Buffer.offset, + buffered); + buffer = (void*)((NPT_Byte*)buffer+buffered); + m_Buffer.offset += buffered; + bytes_to_read -= buffered; + total_read += buffered; + goto done; + } + + // read the rest from the source + if (m_Buffer.size == 0) { + // unbuffered mode, read directly into the supplied buffer + if (m_Buffer.data != NULL) ReleaseBuffer(); // cleanup if necessary + NPT_Size local_read = 0; + result = m_Source->Read(buffer, bytes_to_read, &local_read); + if (NPT_SUCCEEDED(result)) { + total_read += local_read; + } + goto done; + } else { + // refill the buffer + result = FillBuffer(); + if (NPT_FAILED(result)) goto done; + buffered = m_Buffer.valid; + if (bytes_to_read > buffered) bytes_to_read = buffered; + } + } + + // get what we can from the buffer + if (bytes_to_read) { + NPT_CopyMemory(buffer, + m_Buffer.data + m_Buffer.offset, + bytes_to_read); + m_Buffer.offset += bytes_to_read; + total_read += bytes_to_read; + } + +done: + m_Position += total_read; + if (bytes_read) *bytes_read = total_read; + if (result == NPT_ERROR_EOS) { + m_Eos = true; + if (total_read != 0) { + // we have reached the end of the stream, but we have read + // some chars, so do not return EOS now + return NPT_SUCCESS; + } + } + return result; +} + +/*---------------------------------------------------------------------- +| NPT_BufferedInputStream::Peek ++---------------------------------------------------------------------*/ +NPT_Result +NPT_BufferedInputStream::Peek(void* buffer, + NPT_Size bytes_to_read, + NPT_Size* bytes_read) +{ + NPT_Result result = NPT_SUCCESS; + NPT_Size buffered; + NPT_Size new_size = m_Buffer.size?m_Buffer.size:NPT_BUFFERED_BYTE_STREAM_DEFAULT_SIZE; + + // check for a possible shortcut + if (bytes_to_read == 0) return NPT_SUCCESS; + + // compute how much is buffered + buffered = m_Buffer.valid-m_Buffer.offset; + if (bytes_to_read > buffered && buffered < new_size && !m_Eos) { + // we need more data than what we have + // switch to unbuffered mode and resize to force relocation + // of data to the beginning of the buffer + SetBufferSize(new_size, true); + // fill up the end of the buffer + result = FillBuffer(); + // continue even if it failed + buffered = m_Buffer.valid; + } + + // make sure we're returning what we can + if (bytes_to_read > buffered) bytes_to_read = buffered; + + // get what we can from the buffer + NPT_CopyMemory(buffer, + m_Buffer.data + m_Buffer.offset, + bytes_to_read); + + if (bytes_read) *bytes_read = bytes_to_read; + if (result == NPT_ERROR_EOS) { + m_Eos = true; + if (bytes_to_read != 0) { + // we have reached the end of the stream, but we have read + // some chars, so do not return EOS now + return NPT_SUCCESS; + } + } + return result; +} + +/*---------------------------------------------------------------------- +| NPT_BufferedInputStream::Seek ++---------------------------------------------------------------------*/ +NPT_Result +NPT_BufferedInputStream::Seek(NPT_Position offset) +{ + NPT_Result result; + + if (offset >= m_Position && + offset - m_Position < m_Buffer.valid - m_Buffer.offset) { + NPT_Position diff = offset - m_Position; + m_Buffer.offset += ((NPT_Size)diff); + m_Position = offset; + return NPT_SUCCESS; + } + + result = m_Source->Seek(offset); + if (NPT_FAILED(result)) return result; + + m_Buffer.offset = 0; + m_Buffer.valid = 0; + m_Eos = false; + m_Position = offset; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_BufferedInputStream::Tell ++---------------------------------------------------------------------*/ +NPT_Result +NPT_BufferedInputStream::Tell(NPT_Position& offset) +{ + offset = m_Position; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_BufferedInputStream::GetSize ++---------------------------------------------------------------------*/ +NPT_Result +NPT_BufferedInputStream::GetSize(NPT_LargeSize& size) +{ + return m_Source->GetSize(size); +} + +/*---------------------------------------------------------------------- +| NPT_BufferedInputStream::GetAvailable ++---------------------------------------------------------------------*/ +NPT_Result +NPT_BufferedInputStream::GetAvailable(NPT_LargeSize& available) +{ + NPT_LargeSize source_available = 0; + NPT_Result result = m_Source->GetAvailable(source_available); + if (NPT_SUCCEEDED(result)) { + available = m_Buffer.valid-m_Buffer.offset + source_available; + return NPT_SUCCESS; + } else { + available = m_Buffer.valid-m_Buffer.offset; + return available?NPT_SUCCESS:result; + } +} diff --git a/lib/libUPnP/Neptune/Source/Core/NptBufferedStreams.h b/lib/libUPnP/Neptune/Source/Core/NptBufferedStreams.h new file mode 100644 index 0000000..6e37051 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptBufferedStreams.h @@ -0,0 +1,102 @@ +/***************************************************************** +| +| Neptune - Buffered Byte Stream +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +#ifndef _NPT_BUFFERED_STREAMS_H_ +#define _NPT_BUFFERED_STREAMS_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptStreams.h" +#include "NptTypes.h" +#include "NptConstants.h" +#include "NptStrings.h" +#include "NptDebug.h" + +/*---------------------------------------------------------------------- +| NPT_BufferedStream ++---------------------------------------------------------------------*/ +const NPT_Size NPT_BUFFERED_BYTE_STREAM_DEFAULT_SIZE = 4096; + +/*---------------------------------------------------------------------- +| NPT_BufferedInputStream ++---------------------------------------------------------------------*/ +class NPT_BufferedInputStream : public NPT_InputStream +{ +public: + // constructors and destructor + NPT_BufferedInputStream(NPT_InputStreamReference& stream, + NPT_Size buffer_size = NPT_BUFFERED_BYTE_STREAM_DEFAULT_SIZE); + ~NPT_BufferedInputStream() override; + + // methods + virtual NPT_Result ReadLine(NPT_String& line, + NPT_Size max_chars = 4096, + bool break_on_cr = false); + virtual NPT_Result ReadLine(char* buffer, + NPT_Size buffer_size, + NPT_Size* chars_read = NULL, + bool break_on_cr = false); + virtual NPT_Result SetBufferSize(NPT_Size size, bool force = false); + virtual NPT_Result Peek(void* buffer, + NPT_Size bytes_to_read, + NPT_Size* bytes_read); + + // NPT_InputStream methods + NPT_Result Read(void* buffer, + NPT_Size bytes_to_read, + NPT_Size* bytes_read = NULL) override; + NPT_Result Seek(NPT_Position offset) override; + NPT_Result Tell(NPT_Position& offset) override; + NPT_Result GetSize(NPT_LargeSize& size) override; + NPT_Result GetAvailable(NPT_LargeSize& available) override; + +protected: + // members + NPT_InputStreamReference m_Source; + NPT_Position m_Position; + bool m_SkipNewline; + bool m_Eos; + struct { + NPT_Byte* data; + NPT_Size offset; + NPT_Size valid; + NPT_Size size; + } m_Buffer; + + // methods + virtual NPT_Result FillBuffer(); + virtual NPT_Result ReleaseBuffer(); +}; + +typedef NPT_Reference<NPT_BufferedInputStream> NPT_BufferedInputStreamReference; + +#endif // _NPT_BUFFERED_STREAMS_H_ diff --git a/lib/libUPnP/Neptune/Source/Core/NptCommon.cpp b/lib/libUPnP/Neptune/Source/Core/NptCommon.cpp new file mode 100644 index 0000000..3a94380 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptCommon.cpp @@ -0,0 +1,38 @@ +/***************************************************************** +| +| Neptune - Common Classes +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptCommon.h" + + + diff --git a/lib/libUPnP/Neptune/Source/Core/NptCommon.h b/lib/libUPnP/Neptune/Source/Core/NptCommon.h new file mode 100644 index 0000000..9137d31 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptCommon.h @@ -0,0 +1,169 @@ +/***************************************************************** +| +| Neptune - Common Definitions +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +#ifndef _NPT_COMMON_H_ +#define _NPT_COMMON_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptTypes.h" +#include "NptResults.h" + +/*---------------------------------------------------------------------- +| NPT_ObjectDeleter ++---------------------------------------------------------------------*/ +template <class T> +class NPT_ObjectDeleter { +public: + void operator()(T* object) const { + delete object; + } +}; + +/*---------------------------------------------------------------------- +| NPT_ObjectComparator ++---------------------------------------------------------------------*/ +template <class T> +class NPT_ObjectComparator { +public: + NPT_ObjectComparator(T& object) : m_Object(object) {} + bool operator()(const T& object) const { + return object == m_Object; + } +private: + T& m_Object; +}; + +/*---------------------------------------------------------------------- +| NPT_ContainerFind ++---------------------------------------------------------------------*/ +template <typename T, typename P> +NPT_Result NPT_ContainerFind(T& container, + const P& predicate, + typename T::Element& item, + NPT_Ordinal n=0) +{ + typename T::Iterator found = container.Find(predicate, n); + if (found) { + item = *found; + return NPT_SUCCESS; + } else { + return NPT_ERROR_NO_SUCH_ITEM; + } +} + +/*---------------------------------------------------------------------- +| NPT_ContainerFind ++---------------------------------------------------------------------*/ +template <typename T, typename P> +NPT_Result NPT_ContainerFind(T& container, + const P& predicate, + typename T::Iterator& iter, + NPT_Ordinal n=0) +{ + iter = container.Find(predicate, n); + return iter?NPT_SUCCESS:NPT_ERROR_NO_SUCH_ITEM; +} + +/*---------------------------------------------------------------------- +| NPT_UntilResultEquals ++---------------------------------------------------------------------*/ +class NPT_UntilResultEquals +{ +public: + // methods + NPT_UntilResultEquals(NPT_Result condition_result, + NPT_Result return_value = NPT_SUCCESS) : + m_ConditionResult(condition_result), + m_ReturnValue(return_value) {} + bool operator()(NPT_Result result, NPT_Result& return_value) const { + if (result == m_ConditionResult) { + return_value = m_ReturnValue; + return true; + } else { + return false; + } + } + +private: + // members + NPT_Result m_ConditionResult; + NPT_Result m_ReturnValue; +}; + +/*---------------------------------------------------------------------- +| NPT_UntilResultNotEquals ++---------------------------------------------------------------------*/ +class NPT_UntilResultNotEquals +{ +public: + // methods + NPT_UntilResultNotEquals(NPT_Result condition_result) : + m_ConditionResult(condition_result) {} + bool operator()(NPT_Result result, NPT_Result& return_value) const { + if (result != m_ConditionResult) { + return_value = result; + return true; + } else { + return false; + } + } + +private: + // members + NPT_Result m_ConditionResult; +}; + +/*---------------------------------------------------------------------- +| NPT_PropertyValue ++---------------------------------------------------------------------*/ +class NPT_PropertyValue +{ + public: + // typedefs + typedef enum {UNKNOWN, INTEGER, STRING} Type; + + // methods + NPT_PropertyValue() : m_Type(UNKNOWN), m_Integer(0) {} + NPT_PropertyValue(int value) : m_Type(INTEGER), m_Integer(value) {} + NPT_PropertyValue(const char* value) : m_Type(STRING), m_String(value) {} + + // members + Type m_Type; + union { + int m_Integer; + const char* m_String; + }; +}; + +#endif // _NPT_COMMON_H_ + diff --git a/lib/libUPnP/Neptune/Source/Core/NptConfig.h b/lib/libUPnP/Neptune/Source/Core/NptConfig.h new file mode 100644 index 0000000..e4be01e --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptConfig.h @@ -0,0 +1,381 @@ +/***************************************************************** +| +| Neptune - Configuration +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +#ifndef _NPT_CONFIG_H_ +#define _NPT_CONFIG_H_ + +/*---------------------------------------------------------------------- +| defaults ++---------------------------------------------------------------------*/ +#define NPT_CONFIG_HAVE_ASSERT_H +#define NPT_CONFIG_HAVE_STD_C +#define NPT_CONFIG_HAVE_POSIX_TIME +#define NPT_CONFIG_HAVE_ASSERT_H +#define NPT_CONFIG_HAVE_STDLIB_H +#define NPT_CONFIG_HAVE_STDIO_H +#define NPT_CONFIG_HAVE_STDARG_H +#define NPT_CONFIG_HAVE_STDINT_H +#define NPT_CONFIG_HAVE_STRING_H +#define NPT_CONFIG_HAVE_LIMITS_H + +/*---------------------------------------------------------------------- +| standard C runtime ++---------------------------------------------------------------------*/ +#if defined(NPT_CONFIG_HAVE_STD_C) +#define NPT_CONFIG_HAVE_MALLOC +#define NPT_CONFIG_HAVE_CALLOC +#define NPT_CONFIG_HAVE_REALLOC +#define NPT_CONFIG_HAVE_FREE +#define NPT_CONFIG_HAVE_MEMCPY +#define NPT_CONFIG_HAVE_MEMSET +#define NPT_CONFIG_HAVE_MEMCMP +#define NPT_CONFIG_HAVE_GETENV +#define NPT_CONFIG_HAVE_SETENV +#define NPT_CONFIG_HAVE_UNSETENV +#if defined(TARGET_WINDOWS_STORE) +#undef NPT_CONFIG_HAVE_GETENV +#undef NPT_CONFIG_HAVE_SETENV +#undef NPT_CONFIG_HAVE_UNSETENV +#endif +#define NPT_CONFIG_HAVE_READDIR_R +#endif /* NPT_CONFIG_HAS_STD_C */ + +#if defined(NPT_CONFIG_HAVE_POSIX_TIME) +#define NPT_CONFIG_HAVE_GMTIME +#define NPT_CONFIG_HAVE_GMTIME_R +#define NPT_CONFIG_HAVE_LOCALTIME +#define NPT_CONFIG_HAVE_LOCALTIME_R +#define NPT_CONFIG_HAVE_TM_GMTOFF +#endif + +#if defined(NPT_CONFIG_HAVE_STRING_H) +#define NPT_CONFIG_HAVE_STRCMP +#define NPT_CONFIG_HAVE_STRNCMP +#define NPT_CONFIG_HAVE_STRDUP +#define NPT_CONFIG_HAVE_STRLEN +#define NPT_CONFIG_HAVE_STRCPY +#define NPT_CONFIG_HAVE_STRNCPY +#endif /* NPT_CONFIG_HAVE_STRING_H */ + +#if defined(NPT_CONFIG_HAVE_STDIO_H) +#define NPT_CONFIG_HAVE_SPRINTF +#define NPT_CONFIG_HAVE_SNPRINTF +#define NPT_CONFIG_HAVE_VSPRINTF +#define NPT_CONFIG_HAVE_VSNPRINTF +#endif /* NPT_CONFIG_HAVE_STDIO_H */ + +#if defined(NPT_CONFIG_HAVE_LIMITS_H) +#define NPT_CONFIG_HAVE_INT_MIN +#define NPT_CONFIG_HAVE_INT_MAX +#define NPT_CONFIG_HAVE_UINT_MAX +#define NPT_CONFIG_HAVE_LONG_MIN +#define NPT_CONFIG_HAVE_LONG_MAX +#define NPT_CONFIG_HAVE_ULONG_MAX +#endif + +/*---------------------------------------------------------------------- +| standard C++ runtime ++---------------------------------------------------------------------*/ +#define NPT_CONFIG_HAVE_NEW_H + +/*---------------------------------------------------------------------- +| defaults ++---------------------------------------------------------------------*/ +#define NPT_CONFIG_HAVE_SOCKADDR_SA_LEN + +/*---------------------------------------------------------------------- +| platform specifics ++---------------------------------------------------------------------*/ +/* Windows 32 */ +#if defined(_WIN32) || defined(_XBOX) +#if !defined(STRICT) +#define STRICT +#endif +#endif + +/* XBox */ +#if defined(_XBOX) +#define NPT_CONFIG_THREAD_STACK_SIZE 0x10000 +#endif + +/* QNX */ +#if defined(__QNX__) +#define NPT_CONFIG_HAVE_GETADDRINFO +#endif + +/* cygwin */ +#if defined(__CYGWIN__) +#undef NPT_CONFIG_HAVE_SOCKADDR_SA_LEN +#endif + +/* linux */ +#if defined(__linux__) +#define NPT_CONFIG_HAVE_GETADDRINFO +//#define NPT_CONFIG_HAVE_GETIFADDRS // Linux has getifaddrs, but it doesn't return the MAC addrs + // in a convenient way, so we don't use it +#undef NPT_CONFIG_HAVE_SOCKADDR_SA_LEN +#define NPT_CONFIG_HAVE_ARPA_INET_H +#define NPT_CONFIG_HAVE_INET_NTOP +#define NPT_CONFIG_HAVE_INET_PTON +#endif + +/* symbian */ +#if defined(__SYMBIAN32__) +/* If defined, specify the stack size of each NPT_Thread. */ +#define NPT_CONFIG_THREAD_STACK_SIZE 0x14000 +#endif + +/* android */ +#if defined(ANDROID) +#define NPT_CONFIG_HAVE_GETADDRINFO +#undef NPT_CONFIG_HAVE_SOCKADDR_SA_LEN +#define NPT_CONFIG_HAVE_ARPA_INET_H +#define NPT_CONFIG_HAVE_INET_NTOP +#define NPT_CONFIG_HAVE_INET_PTON +#endif + +/* OSX and iOS */ +#if defined(__APPLE__) +#define NPT_CONFIG_HAVE_GETADDRINFO +#define NPT_CONFIG_HAVE_GETIFADDRS +#define NPT_CONFIG_HAVE_AUTORELEASE_POOL +#define NPT_CONFIG_HAVE_SOCKADDR_IN_SIN_LEN +#define NPT_CONFIG_HAVE_ARPA_INET_H +#define NPT_CONFIG_HAVE_INET_NTOP +#define NPT_CONFIG_HAVE_INET_PTON +#define NPT_CONFIG_HAVE_NET_IF_DL_H +#define NPT_CONFIG_HAVE_SOCKADDR_DL +#endif + +/*---------------------------------------------------------------------- +| compiler specifics ++---------------------------------------------------------------------*/ +/* GCC */ +#if defined(__GNUC__) +#define NPT_LocalFunctionName __FUNCTION__ +#define NPT_COMPILER_UNUSED(p) (void)p +#else +#define NPT_COMPILER_UNUSED(p) +#endif + +/* TriMedia C/C++ Compiler */ +#if defined(__TCS__) +#undef NPT_CONFIG_HAVE_ASSERT_H +#undef NPT_CONFIG_HAVE_SNPRINTF +#undef NPT_CONFIG_HAVE_VSNPRINTF +#endif + +/* palmos compiler */ +#if defined(__PALMOS__) +#if __PALMOS__ <= 0x05000000 +#undef NPT_CONFIG_HAVE_ASSERT_H +#undef NPT_CONFIG_HAVE_SNPRINTF +#undef NPT_CONFIG_HAVE_VSNPRINTF +#endif +#endif + +/* Microsoft C/C++ Compiler */ +#if defined(_MSC_VER) +#undef NPT_CONFIG_HAVE_STDINT_H +#define NPT_CONFIG_HAVE_GETADDRINFO +#define NPT_CONFIG_STAT_ST_CTIME_IS_ST_BIRTHTIME +#define NPT_FORMAT_64 "I64" +#define NPT_CONFIG_INT64_TYPE __int64 +#define NPT_INT64_MIN _I64_MIN +#define NPT_INT64_MAX _I64_MAX +#define NPT_UINT64_MAX _UI64_MAX +#define NPT_INT64_C(_x) _x##i64 +#define NPT_UINT64_C(_x) _x##ui64 +#define NPT_LocalFunctionName __FUNCTION__ +#if !defined(_WIN32_WCE) +#define NPT_fseek _fseeki64 +#define NPT_ftell _ftelli64 +#else +#define NPT_fseek(a,b,c) fseek((a),(long)(b), (c)) +#define NPT_ftell ftell +#endif +#define NPT_stat NPT_stat_utf8 +#define NPT_stat_struct struct __stat64 +#if defined(_WIN64) +typedef __int64 NPT_PointerLong; +#else +#if _MSC_VER >= 1400 +typedef __w64 long NPT_PointerLong; +#else +typedef long NPT_PointerLong; +#endif +#endif +#define NPT_POINTER_TO_LONG(_p) ((NPT_PointerLong) (_p) ) +#if _MSC_VER >= 1400 && !defined(_WIN32_WCE) +#define gmtime_r(a,b) gmtime_s(a,b) +#define localtime_r(a,b) localtime_s(b,a) +#define NPT_CONFIG_HAVE_FOPEN_S +#define NPT_CONFIG_HAVE_FSOPEN +#define NPT_CONFIG_HAVE_SHARE_H +#define NPT_vsnprintf(s,c,f,a) _vsnprintf_s(s,c,_TRUNCATE,f,a) +#define NPT_snprintf(s,c,f,...) _snprintf_s(s,c,_TRUNCATE,f,__VA_ARGS__) +#define NPT_strncpy(d,s,c) strncpy_s(d,c+1,s,c) +#define NPT_strcpy(d,s) strcpy_s(d,strlen(s)+1,s) +#undef NPT_CONFIG_HAVE_GETENV +#ifdef TARGET_WINDOWS_STORE +#undef NPT_CONFIG_HAVE_GETENV +#undef NPT_CONFIG_HAVE_DUPENV_S +#undef NPT_CONFIG_HAVE_SETENV +#undef NPT_CONFIG_HAVE_UNSETENV +#undef NPT_CONFIG_HAVE_PUTENV_S +#else +#define NPT_CONFIG_HAVE_DUPENV_S +#define dupenv_s _dupenv_s +#undef NPT_CONFIG_HAVE_SETENV +#undef NPT_CONFIG_HAVE_UNSETENV +#define NPT_CONFIG_HAVE_PUTENV_S +#define putenv_s _putenv_s +#endif +#else +#undef NPT_CONFIG_HAVE_GMTIME_R +#undef NPT_CONFIG_HAVE_LOCALTIME_R +#define NPT_vsnprintf _vsnprintf +#define NPT_snprintf _snprintf +#endif +#if defined(_DEBUG) +#define _CRTDBG_MAP_ALLOC +#endif +#endif + +/* Windows CE */ +#if defined(_WIN32_WCE) +#if defined(NPT_CONFIG_HAVE_FOPEN_S) +#undef NPT_CONFIG_HAVE_FOPEN_S +#endif +#endif + +/* Symbian */ +#if defined(__SYMBIAN32__) +#undef NPT_CONFIG_HAVE_NEW_H +#include "e32std.h" +#define explicit +#define NPT_fseek fseek // no fseeko ? +#define NPT_ftell ftell // no ftello ? +#endif + +/* Android */ +#if defined(ANDROID) +#if !defined(NPT_CONFIG_NO_RTTI) +#define NPT_CONFIG_NO_RTTI +#endif +//#define NPT_ftell ftello64 +//#define NPT_fseek fseeko64 +#endif + +/* OSX and iOS */ +#if defined(__APPLE__) +#include <TargetConditionals.h> +#include <AvailabilityMacros.h> +#if !defined(TARGET_OS_IPHONE) || !TARGET_OS_IPHONE +#define NPT_CONFIG_HAVE_NET_IF_TYPES_H +#if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6) +#define NPT_CONFIG_HAVE_STAT_ST_BIRTHTIME +#endif +#define NPT_CONFIG_HAVE_DEV_URANDOM +#endif +#endif + +/*---------------------------------------------------------------------- +| defaults ++---------------------------------------------------------------------*/ +#if !defined(NPT_FORMAT_64) +#define NPT_FORMAT_64 "ll" +#endif + +#if !defined(NPT_POINTER_TO_LONG) +#define NPT_POINTER_TO_LONG(_p) ((long)(_p)) +#endif + +#if !defined(NPT_CONFIG_INT64_TYPE) +#define NPT_CONFIG_INT64_TYPE long long +#endif + +#if !defined(NPT_INT64_C) +#define NPT_INT64_C(_x) _x##LL +#endif + +#if !defined(NPT_UINT64_C) +#define NPT_UINT64_C(_x) _x##ULL +#endif + +#if !defined(NPT_snprintf) +#define NPT_snprintf snprintf +#endif + +#if !defined(NPT_strcpy) +#define NPT_strcpy strcpy +#endif + +#if !defined(NPT_strncpy) +#define NPT_strncpy strncpy +#endif + +#if !defined(NPT_vsnprintf) +#define NPT_vsnprintf vsnprintf +#endif + +#if !defined(NPT_LocalFunctionName) +#define NPT_LocalFunctionName (NULL) +#endif + +#if !defined(NPT_CONFIG_THREAD_STACK_SIZE) +#define NPT_CONFIG_THREAD_STACK_SIZE 0 +#endif + +#if !defined(NPT_fseek) +#define NPT_fseek fseeko +#endif + +#if !defined(NPT_ftell) +#define NPT_ftell ftello +#endif + +#if !defined(NPT_stat) +#define NPT_stat stat +#endif + +#if !defined(NPT_stat_struct) +#define NPT_stat_struct struct stat +#endif + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#if defined(DMALLOC) +#include <dmalloc.h> +#endif + +#endif // _NPT_CONFIG_H_ diff --git a/lib/libUPnP/Neptune/Source/Core/NptConsole.cpp b/lib/libUPnP/Neptune/Source/Core/NptConsole.cpp new file mode 100644 index 0000000..bbd92dd --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptConsole.cpp @@ -0,0 +1,67 @@ +/***************************************************************** +| +| Neptune - Console +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| +****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptConfig.h" + +#if defined(NPT_CONFIG_HAVE_STDARG_H) +#include <stdarg.h> +#endif + +#include "NptConfig.h" +#include "NptConsole.h" +#include "NptUtils.h" + +/*---------------------------------------------------------------------- +| NPT_ConsoleOutputFunction ++---------------------------------------------------------------------*/ +static void +NPT_ConsoleOutputFunction(void*, const char* message) +{ + NPT_Console::Output(message); +} + +/*---------------------------------------------------------------------- +| NPT_ConsoleOutputF ++---------------------------------------------------------------------*/ +void +NPT_Console::OutputF(const char* format, ...) +{ + va_list args; + va_start(args, format); + + NPT_FormatOutput(NPT_ConsoleOutputFunction, NULL, format, args); + + va_end(args); +} + diff --git a/lib/libUPnP/Neptune/Source/Core/NptConsole.h b/lib/libUPnP/Neptune/Source/Core/NptConsole.h new file mode 100644 index 0000000..6502a79 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptConsole.h @@ -0,0 +1,55 @@ +/***************************************************************** +| +| Neptune - Console +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| +****************************************************************/ +/** @file +* Header file for console support +*/ + +#ifndef _NPT_CONSOLE_H_ +#define _NPT_CONSOLE_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptTypes.h" +#include "NptResults.h" + +/*---------------------------------------------------------------------- +| prototypes ++---------------------------------------------------------------------*/ +class NPT_Console { +public: + // class methods + static void Output(const char* message); + static void OutputF(const char* format, ...); +}; + + +#endif /* _NPT_CONSOLE_H_ */ diff --git a/lib/libUPnP/Neptune/Source/Core/NptConstants.h b/lib/libUPnP/Neptune/Source/Core/NptConstants.h new file mode 100644 index 0000000..6618bf8 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptConstants.h @@ -0,0 +1,44 @@ +/***************************************************************** +| +| Neptune - Constants +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +#ifndef _NPT_CONSTANTS_H_ +#define _NPT_CONSTANTS_H_ + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +#ifndef NULL +#define NULL 0 +#endif + +const int NPT_TIMEOUT_INFINITE = -1; + +#endif // _NPT_CONSTANTS_H_ diff --git a/lib/libUPnP/Neptune/Source/Core/NptCrypto.cpp b/lib/libUPnP/Neptune/Source/Core/NptCrypto.cpp new file mode 100644 index 0000000..20b128b --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptCrypto.cpp @@ -0,0 +1,833 @@ +/***************************************************************** +| +| Neptune - Message Digests +| +| Copyright (c) 2002-2010, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +/* + Portions of this code are based on the code of LibTomCrypt + that was released into public domain by Tom St Denis. +*/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptCrypto.h" +#include "NptUtils.h" +#include "NptTypes.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +#define NPT_AES_BLOCK_SIZE 16 + +static const NPT_UInt32 TE0[256] = { + 0xc66363a5UL, 0xf87c7c84UL, 0xee777799UL, 0xf67b7b8dUL, + 0xfff2f20dUL, 0xd66b6bbdUL, 0xde6f6fb1UL, 0x91c5c554UL, + 0x60303050UL, 0x02010103UL, 0xce6767a9UL, 0x562b2b7dUL, + 0xe7fefe19UL, 0xb5d7d762UL, 0x4dababe6UL, 0xec76769aUL, + 0x8fcaca45UL, 0x1f82829dUL, 0x89c9c940UL, 0xfa7d7d87UL, + 0xeffafa15UL, 0xb25959ebUL, 0x8e4747c9UL, 0xfbf0f00bUL, + 0x41adadecUL, 0xb3d4d467UL, 0x5fa2a2fdUL, 0x45afafeaUL, + 0x239c9cbfUL, 0x53a4a4f7UL, 0xe4727296UL, 0x9bc0c05bUL, + 0x75b7b7c2UL, 0xe1fdfd1cUL, 0x3d9393aeUL, 0x4c26266aUL, + 0x6c36365aUL, 0x7e3f3f41UL, 0xf5f7f702UL, 0x83cccc4fUL, + 0x6834345cUL, 0x51a5a5f4UL, 0xd1e5e534UL, 0xf9f1f108UL, + 0xe2717193UL, 0xabd8d873UL, 0x62313153UL, 0x2a15153fUL, + 0x0804040cUL, 0x95c7c752UL, 0x46232365UL, 0x9dc3c35eUL, + 0x30181828UL, 0x379696a1UL, 0x0a05050fUL, 0x2f9a9ab5UL, + 0x0e070709UL, 0x24121236UL, 0x1b80809bUL, 0xdfe2e23dUL, + 0xcdebeb26UL, 0x4e272769UL, 0x7fb2b2cdUL, 0xea75759fUL, + 0x1209091bUL, 0x1d83839eUL, 0x582c2c74UL, 0x341a1a2eUL, + 0x361b1b2dUL, 0xdc6e6eb2UL, 0xb45a5aeeUL, 0x5ba0a0fbUL, + 0xa45252f6UL, 0x763b3b4dUL, 0xb7d6d661UL, 0x7db3b3ceUL, + 0x5229297bUL, 0xdde3e33eUL, 0x5e2f2f71UL, 0x13848497UL, + 0xa65353f5UL, 0xb9d1d168UL, 0x00000000UL, 0xc1eded2cUL, + 0x40202060UL, 0xe3fcfc1fUL, 0x79b1b1c8UL, 0xb65b5bedUL, + 0xd46a6abeUL, 0x8dcbcb46UL, 0x67bebed9UL, 0x7239394bUL, + 0x944a4adeUL, 0x984c4cd4UL, 0xb05858e8UL, 0x85cfcf4aUL, + 0xbbd0d06bUL, 0xc5efef2aUL, 0x4faaaae5UL, 0xedfbfb16UL, + 0x864343c5UL, 0x9a4d4dd7UL, 0x66333355UL, 0x11858594UL, + 0x8a4545cfUL, 0xe9f9f910UL, 0x04020206UL, 0xfe7f7f81UL, + 0xa05050f0UL, 0x783c3c44UL, 0x259f9fbaUL, 0x4ba8a8e3UL, + 0xa25151f3UL, 0x5da3a3feUL, 0x804040c0UL, 0x058f8f8aUL, + 0x3f9292adUL, 0x219d9dbcUL, 0x70383848UL, 0xf1f5f504UL, + 0x63bcbcdfUL, 0x77b6b6c1UL, 0xafdada75UL, 0x42212163UL, + 0x20101030UL, 0xe5ffff1aUL, 0xfdf3f30eUL, 0xbfd2d26dUL, + 0x81cdcd4cUL, 0x180c0c14UL, 0x26131335UL, 0xc3ecec2fUL, + 0xbe5f5fe1UL, 0x359797a2UL, 0x884444ccUL, 0x2e171739UL, + 0x93c4c457UL, 0x55a7a7f2UL, 0xfc7e7e82UL, 0x7a3d3d47UL, + 0xc86464acUL, 0xba5d5de7UL, 0x3219192bUL, 0xe6737395UL, + 0xc06060a0UL, 0x19818198UL, 0x9e4f4fd1UL, 0xa3dcdc7fUL, + 0x44222266UL, 0x542a2a7eUL, 0x3b9090abUL, 0x0b888883UL, + 0x8c4646caUL, 0xc7eeee29UL, 0x6bb8b8d3UL, 0x2814143cUL, + 0xa7dede79UL, 0xbc5e5ee2UL, 0x160b0b1dUL, 0xaddbdb76UL, + 0xdbe0e03bUL, 0x64323256UL, 0x743a3a4eUL, 0x140a0a1eUL, + 0x924949dbUL, 0x0c06060aUL, 0x4824246cUL, 0xb85c5ce4UL, + 0x9fc2c25dUL, 0xbdd3d36eUL, 0x43acacefUL, 0xc46262a6UL, + 0x399191a8UL, 0x319595a4UL, 0xd3e4e437UL, 0xf279798bUL, + 0xd5e7e732UL, 0x8bc8c843UL, 0x6e373759UL, 0xda6d6db7UL, + 0x018d8d8cUL, 0xb1d5d564UL, 0x9c4e4ed2UL, 0x49a9a9e0UL, + 0xd86c6cb4UL, 0xac5656faUL, 0xf3f4f407UL, 0xcfeaea25UL, + 0xca6565afUL, 0xf47a7a8eUL, 0x47aeaee9UL, 0x10080818UL, + 0x6fbabad5UL, 0xf0787888UL, 0x4a25256fUL, 0x5c2e2e72UL, + 0x381c1c24UL, 0x57a6a6f1UL, 0x73b4b4c7UL, 0x97c6c651UL, + 0xcbe8e823UL, 0xa1dddd7cUL, 0xe874749cUL, 0x3e1f1f21UL, + 0x964b4bddUL, 0x61bdbddcUL, 0x0d8b8b86UL, 0x0f8a8a85UL, + 0xe0707090UL, 0x7c3e3e42UL, 0x71b5b5c4UL, 0xcc6666aaUL, + 0x904848d8UL, 0x06030305UL, 0xf7f6f601UL, 0x1c0e0e12UL, + 0xc26161a3UL, 0x6a35355fUL, 0xae5757f9UL, 0x69b9b9d0UL, + 0x17868691UL, 0x99c1c158UL, 0x3a1d1d27UL, 0x279e9eb9UL, + 0xd9e1e138UL, 0xebf8f813UL, 0x2b9898b3UL, 0x22111133UL, + 0xd26969bbUL, 0xa9d9d970UL, 0x078e8e89UL, 0x339494a7UL, + 0x2d9b9bb6UL, 0x3c1e1e22UL, 0x15878792UL, 0xc9e9e920UL, + 0x87cece49UL, 0xaa5555ffUL, 0x50282878UL, 0xa5dfdf7aUL, + 0x038c8c8fUL, 0x59a1a1f8UL, 0x09898980UL, 0x1a0d0d17UL, + 0x65bfbfdaUL, 0xd7e6e631UL, 0x844242c6UL, 0xd06868b8UL, + 0x824141c3UL, 0x299999b0UL, 0x5a2d2d77UL, 0x1e0f0f11UL, + 0x7bb0b0cbUL, 0xa85454fcUL, 0x6dbbbbd6UL, 0x2c16163aUL, +}; + +static const NPT_UInt32 Te4[256] = { + 0x63636363UL, 0x7c7c7c7cUL, 0x77777777UL, 0x7b7b7b7bUL, + 0xf2f2f2f2UL, 0x6b6b6b6bUL, 0x6f6f6f6fUL, 0xc5c5c5c5UL, + 0x30303030UL, 0x01010101UL, 0x67676767UL, 0x2b2b2b2bUL, + 0xfefefefeUL, 0xd7d7d7d7UL, 0xababababUL, 0x76767676UL, + 0xcacacacaUL, 0x82828282UL, 0xc9c9c9c9UL, 0x7d7d7d7dUL, + 0xfafafafaUL, 0x59595959UL, 0x47474747UL, 0xf0f0f0f0UL, + 0xadadadadUL, 0xd4d4d4d4UL, 0xa2a2a2a2UL, 0xafafafafUL, + 0x9c9c9c9cUL, 0xa4a4a4a4UL, 0x72727272UL, 0xc0c0c0c0UL, + 0xb7b7b7b7UL, 0xfdfdfdfdUL, 0x93939393UL, 0x26262626UL, + 0x36363636UL, 0x3f3f3f3fUL, 0xf7f7f7f7UL, 0xccccccccUL, + 0x34343434UL, 0xa5a5a5a5UL, 0xe5e5e5e5UL, 0xf1f1f1f1UL, + 0x71717171UL, 0xd8d8d8d8UL, 0x31313131UL, 0x15151515UL, + 0x04040404UL, 0xc7c7c7c7UL, 0x23232323UL, 0xc3c3c3c3UL, + 0x18181818UL, 0x96969696UL, 0x05050505UL, 0x9a9a9a9aUL, + 0x07070707UL, 0x12121212UL, 0x80808080UL, 0xe2e2e2e2UL, + 0xebebebebUL, 0x27272727UL, 0xb2b2b2b2UL, 0x75757575UL, + 0x09090909UL, 0x83838383UL, 0x2c2c2c2cUL, 0x1a1a1a1aUL, + 0x1b1b1b1bUL, 0x6e6e6e6eUL, 0x5a5a5a5aUL, 0xa0a0a0a0UL, + 0x52525252UL, 0x3b3b3b3bUL, 0xd6d6d6d6UL, 0xb3b3b3b3UL, + 0x29292929UL, 0xe3e3e3e3UL, 0x2f2f2f2fUL, 0x84848484UL, + 0x53535353UL, 0xd1d1d1d1UL, 0x00000000UL, 0xededededUL, + 0x20202020UL, 0xfcfcfcfcUL, 0xb1b1b1b1UL, 0x5b5b5b5bUL, + 0x6a6a6a6aUL, 0xcbcbcbcbUL, 0xbebebebeUL, 0x39393939UL, + 0x4a4a4a4aUL, 0x4c4c4c4cUL, 0x58585858UL, 0xcfcfcfcfUL, + 0xd0d0d0d0UL, 0xefefefefUL, 0xaaaaaaaaUL, 0xfbfbfbfbUL, + 0x43434343UL, 0x4d4d4d4dUL, 0x33333333UL, 0x85858585UL, + 0x45454545UL, 0xf9f9f9f9UL, 0x02020202UL, 0x7f7f7f7fUL, + 0x50505050UL, 0x3c3c3c3cUL, 0x9f9f9f9fUL, 0xa8a8a8a8UL, + 0x51515151UL, 0xa3a3a3a3UL, 0x40404040UL, 0x8f8f8f8fUL, + 0x92929292UL, 0x9d9d9d9dUL, 0x38383838UL, 0xf5f5f5f5UL, + 0xbcbcbcbcUL, 0xb6b6b6b6UL, 0xdadadadaUL, 0x21212121UL, + 0x10101010UL, 0xffffffffUL, 0xf3f3f3f3UL, 0xd2d2d2d2UL, + 0xcdcdcdcdUL, 0x0c0c0c0cUL, 0x13131313UL, 0xececececUL, + 0x5f5f5f5fUL, 0x97979797UL, 0x44444444UL, 0x17171717UL, + 0xc4c4c4c4UL, 0xa7a7a7a7UL, 0x7e7e7e7eUL, 0x3d3d3d3dUL, + 0x64646464UL, 0x5d5d5d5dUL, 0x19191919UL, 0x73737373UL, + 0x60606060UL, 0x81818181UL, 0x4f4f4f4fUL, 0xdcdcdcdcUL, + 0x22222222UL, 0x2a2a2a2aUL, 0x90909090UL, 0x88888888UL, + 0x46464646UL, 0xeeeeeeeeUL, 0xb8b8b8b8UL, 0x14141414UL, + 0xdedededeUL, 0x5e5e5e5eUL, 0x0b0b0b0bUL, 0xdbdbdbdbUL, + 0xe0e0e0e0UL, 0x32323232UL, 0x3a3a3a3aUL, 0x0a0a0a0aUL, + 0x49494949UL, 0x06060606UL, 0x24242424UL, 0x5c5c5c5cUL, + 0xc2c2c2c2UL, 0xd3d3d3d3UL, 0xacacacacUL, 0x62626262UL, + 0x91919191UL, 0x95959595UL, 0xe4e4e4e4UL, 0x79797979UL, + 0xe7e7e7e7UL, 0xc8c8c8c8UL, 0x37373737UL, 0x6d6d6d6dUL, + 0x8d8d8d8dUL, 0xd5d5d5d5UL, 0x4e4e4e4eUL, 0xa9a9a9a9UL, + 0x6c6c6c6cUL, 0x56565656UL, 0xf4f4f4f4UL, 0xeaeaeaeaUL, + 0x65656565UL, 0x7a7a7a7aUL, 0xaeaeaeaeUL, 0x08080808UL, + 0xbabababaUL, 0x78787878UL, 0x25252525UL, 0x2e2e2e2eUL, + 0x1c1c1c1cUL, 0xa6a6a6a6UL, 0xb4b4b4b4UL, 0xc6c6c6c6UL, + 0xe8e8e8e8UL, 0xddddddddUL, 0x74747474UL, 0x1f1f1f1fUL, + 0x4b4b4b4bUL, 0xbdbdbdbdUL, 0x8b8b8b8bUL, 0x8a8a8a8aUL, + 0x70707070UL, 0x3e3e3e3eUL, 0xb5b5b5b5UL, 0x66666666UL, + 0x48484848UL, 0x03030303UL, 0xf6f6f6f6UL, 0x0e0e0e0eUL, + 0x61616161UL, 0x35353535UL, 0x57575757UL, 0xb9b9b9b9UL, + 0x86868686UL, 0xc1c1c1c1UL, 0x1d1d1d1dUL, 0x9e9e9e9eUL, + 0xe1e1e1e1UL, 0xf8f8f8f8UL, 0x98989898UL, 0x11111111UL, + 0x69696969UL, 0xd9d9d9d9UL, 0x8e8e8e8eUL, 0x94949494UL, + 0x9b9b9b9bUL, 0x1e1e1e1eUL, 0x87878787UL, 0xe9e9e9e9UL, + 0xcecececeUL, 0x55555555UL, 0x28282828UL, 0xdfdfdfdfUL, + 0x8c8c8c8cUL, 0xa1a1a1a1UL, 0x89898989UL, 0x0d0d0d0dUL, + 0xbfbfbfbfUL, 0xe6e6e6e6UL, 0x42424242UL, 0x68686868UL, + 0x41414141UL, 0x99999999UL, 0x2d2d2d2dUL, 0x0f0f0f0fUL, + 0xb0b0b0b0UL, 0x54545454UL, 0xbbbbbbbbUL, 0x16161616UL, +}; + +static const NPT_UInt32 TD0[256] = { + 0x51f4a750UL, 0x7e416553UL, 0x1a17a4c3UL, 0x3a275e96UL, + 0x3bab6bcbUL, 0x1f9d45f1UL, 0xacfa58abUL, 0x4be30393UL, + 0x2030fa55UL, 0xad766df6UL, 0x88cc7691UL, 0xf5024c25UL, + 0x4fe5d7fcUL, 0xc52acbd7UL, 0x26354480UL, 0xb562a38fUL, + 0xdeb15a49UL, 0x25ba1b67UL, 0x45ea0e98UL, 0x5dfec0e1UL, + 0xc32f7502UL, 0x814cf012UL, 0x8d4697a3UL, 0x6bd3f9c6UL, + 0x038f5fe7UL, 0x15929c95UL, 0xbf6d7aebUL, 0x955259daUL, + 0xd4be832dUL, 0x587421d3UL, 0x49e06929UL, 0x8ec9c844UL, + 0x75c2896aUL, 0xf48e7978UL, 0x99583e6bUL, 0x27b971ddUL, + 0xbee14fb6UL, 0xf088ad17UL, 0xc920ac66UL, 0x7dce3ab4UL, + 0x63df4a18UL, 0xe51a3182UL, 0x97513360UL, 0x62537f45UL, + 0xb16477e0UL, 0xbb6bae84UL, 0xfe81a01cUL, 0xf9082b94UL, + 0x70486858UL, 0x8f45fd19UL, 0x94de6c87UL, 0x527bf8b7UL, + 0xab73d323UL, 0x724b02e2UL, 0xe31f8f57UL, 0x6655ab2aUL, + 0xb2eb2807UL, 0x2fb5c203UL, 0x86c57b9aUL, 0xd33708a5UL, + 0x302887f2UL, 0x23bfa5b2UL, 0x02036abaUL, 0xed16825cUL, + 0x8acf1c2bUL, 0xa779b492UL, 0xf307f2f0UL, 0x4e69e2a1UL, + 0x65daf4cdUL, 0x0605bed5UL, 0xd134621fUL, 0xc4a6fe8aUL, + 0x342e539dUL, 0xa2f355a0UL, 0x058ae132UL, 0xa4f6eb75UL, + 0x0b83ec39UL, 0x4060efaaUL, 0x5e719f06UL, 0xbd6e1051UL, + 0x3e218af9UL, 0x96dd063dUL, 0xdd3e05aeUL, 0x4de6bd46UL, + 0x91548db5UL, 0x71c45d05UL, 0x0406d46fUL, 0x605015ffUL, + 0x1998fb24UL, 0xd6bde997UL, 0x894043ccUL, 0x67d99e77UL, + 0xb0e842bdUL, 0x07898b88UL, 0xe7195b38UL, 0x79c8eedbUL, + 0xa17c0a47UL, 0x7c420fe9UL, 0xf8841ec9UL, 0x00000000UL, + 0x09808683UL, 0x322bed48UL, 0x1e1170acUL, 0x6c5a724eUL, + 0xfd0efffbUL, 0x0f853856UL, 0x3daed51eUL, 0x362d3927UL, + 0x0a0fd964UL, 0x685ca621UL, 0x9b5b54d1UL, 0x24362e3aUL, + 0x0c0a67b1UL, 0x9357e70fUL, 0xb4ee96d2UL, 0x1b9b919eUL, + 0x80c0c54fUL, 0x61dc20a2UL, 0x5a774b69UL, 0x1c121a16UL, + 0xe293ba0aUL, 0xc0a02ae5UL, 0x3c22e043UL, 0x121b171dUL, + 0x0e090d0bUL, 0xf28bc7adUL, 0x2db6a8b9UL, 0x141ea9c8UL, + 0x57f11985UL, 0xaf75074cUL, 0xee99ddbbUL, 0xa37f60fdUL, + 0xf701269fUL, 0x5c72f5bcUL, 0x44663bc5UL, 0x5bfb7e34UL, + 0x8b432976UL, 0xcb23c6dcUL, 0xb6edfc68UL, 0xb8e4f163UL, + 0xd731dccaUL, 0x42638510UL, 0x13972240UL, 0x84c61120UL, + 0x854a247dUL, 0xd2bb3df8UL, 0xaef93211UL, 0xc729a16dUL, + 0x1d9e2f4bUL, 0xdcb230f3UL, 0x0d8652ecUL, 0x77c1e3d0UL, + 0x2bb3166cUL, 0xa970b999UL, 0x119448faUL, 0x47e96422UL, + 0xa8fc8cc4UL, 0xa0f03f1aUL, 0x567d2cd8UL, 0x223390efUL, + 0x87494ec7UL, 0xd938d1c1UL, 0x8ccaa2feUL, 0x98d40b36UL, + 0xa6f581cfUL, 0xa57ade28UL, 0xdab78e26UL, 0x3fadbfa4UL, + 0x2c3a9de4UL, 0x5078920dUL, 0x6a5fcc9bUL, 0x547e4662UL, + 0xf68d13c2UL, 0x90d8b8e8UL, 0x2e39f75eUL, 0x82c3aff5UL, + 0x9f5d80beUL, 0x69d0937cUL, 0x6fd52da9UL, 0xcf2512b3UL, + 0xc8ac993bUL, 0x10187da7UL, 0xe89c636eUL, 0xdb3bbb7bUL, + 0xcd267809UL, 0x6e5918f4UL, 0xec9ab701UL, 0x834f9aa8UL, + 0xe6956e65UL, 0xaaffe67eUL, 0x21bccf08UL, 0xef15e8e6UL, + 0xbae79bd9UL, 0x4a6f36ceUL, 0xea9f09d4UL, 0x29b07cd6UL, + 0x31a4b2afUL, 0x2a3f2331UL, 0xc6a59430UL, 0x35a266c0UL, + 0x744ebc37UL, 0xfc82caa6UL, 0xe090d0b0UL, 0x33a7d815UL, + 0xf104984aUL, 0x41ecdaf7UL, 0x7fcd500eUL, 0x1791f62fUL, + 0x764dd68dUL, 0x43efb04dUL, 0xccaa4d54UL, 0xe49604dfUL, + 0x9ed1b5e3UL, 0x4c6a881bUL, 0xc12c1fb8UL, 0x4665517fUL, + 0x9d5eea04UL, 0x018c355dUL, 0xfa877473UL, 0xfb0b412eUL, + 0xb3671d5aUL, 0x92dbd252UL, 0xe9105633UL, 0x6dd64713UL, + 0x9ad7618cUL, 0x37a10c7aUL, 0x59f8148eUL, 0xeb133c89UL, + 0xcea927eeUL, 0xb761c935UL, 0xe11ce5edUL, 0x7a47b13cUL, + 0x9cd2df59UL, 0x55f2733fUL, 0x1814ce79UL, 0x73c737bfUL, + 0x53f7cdeaUL, 0x5ffdaa5bUL, 0xdf3d6f14UL, 0x7844db86UL, + 0xcaaff381UL, 0xb968c43eUL, 0x3824342cUL, 0xc2a3405fUL, + 0x161dc372UL, 0xbce2250cUL, 0x283c498bUL, 0xff0d9541UL, + 0x39a80171UL, 0x080cb3deUL, 0xd8b4e49cUL, 0x6456c190UL, + 0x7bcb8461UL, 0xd532b670UL, 0x486c5c74UL, 0xd0b85742UL, +}; + +static const NPT_UInt32 Td4[256] = { + 0x52525252UL, 0x09090909UL, 0x6a6a6a6aUL, 0xd5d5d5d5UL, + 0x30303030UL, 0x36363636UL, 0xa5a5a5a5UL, 0x38383838UL, + 0xbfbfbfbfUL, 0x40404040UL, 0xa3a3a3a3UL, 0x9e9e9e9eUL, + 0x81818181UL, 0xf3f3f3f3UL, 0xd7d7d7d7UL, 0xfbfbfbfbUL, + 0x7c7c7c7cUL, 0xe3e3e3e3UL, 0x39393939UL, 0x82828282UL, + 0x9b9b9b9bUL, 0x2f2f2f2fUL, 0xffffffffUL, 0x87878787UL, + 0x34343434UL, 0x8e8e8e8eUL, 0x43434343UL, 0x44444444UL, + 0xc4c4c4c4UL, 0xdedededeUL, 0xe9e9e9e9UL, 0xcbcbcbcbUL, + 0x54545454UL, 0x7b7b7b7bUL, 0x94949494UL, 0x32323232UL, + 0xa6a6a6a6UL, 0xc2c2c2c2UL, 0x23232323UL, 0x3d3d3d3dUL, + 0xeeeeeeeeUL, 0x4c4c4c4cUL, 0x95959595UL, 0x0b0b0b0bUL, + 0x42424242UL, 0xfafafafaUL, 0xc3c3c3c3UL, 0x4e4e4e4eUL, + 0x08080808UL, 0x2e2e2e2eUL, 0xa1a1a1a1UL, 0x66666666UL, + 0x28282828UL, 0xd9d9d9d9UL, 0x24242424UL, 0xb2b2b2b2UL, + 0x76767676UL, 0x5b5b5b5bUL, 0xa2a2a2a2UL, 0x49494949UL, + 0x6d6d6d6dUL, 0x8b8b8b8bUL, 0xd1d1d1d1UL, 0x25252525UL, + 0x72727272UL, 0xf8f8f8f8UL, 0xf6f6f6f6UL, 0x64646464UL, + 0x86868686UL, 0x68686868UL, 0x98989898UL, 0x16161616UL, + 0xd4d4d4d4UL, 0xa4a4a4a4UL, 0x5c5c5c5cUL, 0xccccccccUL, + 0x5d5d5d5dUL, 0x65656565UL, 0xb6b6b6b6UL, 0x92929292UL, + 0x6c6c6c6cUL, 0x70707070UL, 0x48484848UL, 0x50505050UL, + 0xfdfdfdfdUL, 0xededededUL, 0xb9b9b9b9UL, 0xdadadadaUL, + 0x5e5e5e5eUL, 0x15151515UL, 0x46464646UL, 0x57575757UL, + 0xa7a7a7a7UL, 0x8d8d8d8dUL, 0x9d9d9d9dUL, 0x84848484UL, + 0x90909090UL, 0xd8d8d8d8UL, 0xababababUL, 0x00000000UL, + 0x8c8c8c8cUL, 0xbcbcbcbcUL, 0xd3d3d3d3UL, 0x0a0a0a0aUL, + 0xf7f7f7f7UL, 0xe4e4e4e4UL, 0x58585858UL, 0x05050505UL, + 0xb8b8b8b8UL, 0xb3b3b3b3UL, 0x45454545UL, 0x06060606UL, + 0xd0d0d0d0UL, 0x2c2c2c2cUL, 0x1e1e1e1eUL, 0x8f8f8f8fUL, + 0xcacacacaUL, 0x3f3f3f3fUL, 0x0f0f0f0fUL, 0x02020202UL, + 0xc1c1c1c1UL, 0xafafafafUL, 0xbdbdbdbdUL, 0x03030303UL, + 0x01010101UL, 0x13131313UL, 0x8a8a8a8aUL, 0x6b6b6b6bUL, + 0x3a3a3a3aUL, 0x91919191UL, 0x11111111UL, 0x41414141UL, + 0x4f4f4f4fUL, 0x67676767UL, 0xdcdcdcdcUL, 0xeaeaeaeaUL, + 0x97979797UL, 0xf2f2f2f2UL, 0xcfcfcfcfUL, 0xcecececeUL, + 0xf0f0f0f0UL, 0xb4b4b4b4UL, 0xe6e6e6e6UL, 0x73737373UL, + 0x96969696UL, 0xacacacacUL, 0x74747474UL, 0x22222222UL, + 0xe7e7e7e7UL, 0xadadadadUL, 0x35353535UL, 0x85858585UL, + 0xe2e2e2e2UL, 0xf9f9f9f9UL, 0x37373737UL, 0xe8e8e8e8UL, + 0x1c1c1c1cUL, 0x75757575UL, 0xdfdfdfdfUL, 0x6e6e6e6eUL, + 0x47474747UL, 0xf1f1f1f1UL, 0x1a1a1a1aUL, 0x71717171UL, + 0x1d1d1d1dUL, 0x29292929UL, 0xc5c5c5c5UL, 0x89898989UL, + 0x6f6f6f6fUL, 0xb7b7b7b7UL, 0x62626262UL, 0x0e0e0e0eUL, + 0xaaaaaaaaUL, 0x18181818UL, 0xbebebebeUL, 0x1b1b1b1bUL, + 0xfcfcfcfcUL, 0x56565656UL, 0x3e3e3e3eUL, 0x4b4b4b4bUL, + 0xc6c6c6c6UL, 0xd2d2d2d2UL, 0x79797979UL, 0x20202020UL, + 0x9a9a9a9aUL, 0xdbdbdbdbUL, 0xc0c0c0c0UL, 0xfefefefeUL, + 0x78787878UL, 0xcdcdcdcdUL, 0x5a5a5a5aUL, 0xf4f4f4f4UL, + 0x1f1f1f1fUL, 0xddddddddUL, 0xa8a8a8a8UL, 0x33333333UL, + 0x88888888UL, 0x07070707UL, 0xc7c7c7c7UL, 0x31313131UL, + 0xb1b1b1b1UL, 0x12121212UL, 0x10101010UL, 0x59595959UL, + 0x27272727UL, 0x80808080UL, 0xececececUL, 0x5f5f5f5fUL, + 0x60606060UL, 0x51515151UL, 0x7f7f7f7fUL, 0xa9a9a9a9UL, + 0x19191919UL, 0xb5b5b5b5UL, 0x4a4a4a4aUL, 0x0d0d0d0dUL, + 0x2d2d2d2dUL, 0xe5e5e5e5UL, 0x7a7a7a7aUL, 0x9f9f9f9fUL, + 0x93939393UL, 0xc9c9c9c9UL, 0x9c9c9c9cUL, 0xefefefefUL, + 0xa0a0a0a0UL, 0xe0e0e0e0UL, 0x3b3b3b3bUL, 0x4d4d4d4dUL, + 0xaeaeaeaeUL, 0x2a2a2a2aUL, 0xf5f5f5f5UL, 0xb0b0b0b0UL, + 0xc8c8c8c8UL, 0xebebebebUL, 0xbbbbbbbbUL, 0x3c3c3c3cUL, + 0x83838383UL, 0x53535353UL, 0x99999999UL, 0x61616161UL, + 0x17171717UL, 0x2b2b2b2bUL, 0x04040404UL, 0x7e7e7e7eUL, + 0xbabababaUL, 0x77777777UL, 0xd6d6d6d6UL, 0x26262626UL, + 0xe1e1e1e1UL, 0x69696969UL, 0x14141414UL, 0x63636363UL, + 0x55555555UL, 0x21212121UL, 0x0c0c0c0cUL, 0x7d7d7d7dUL, +}; + +static const NPT_UInt32 rcon[] = { + 0x01000000UL, 0x02000000UL, 0x04000000UL, 0x08000000UL, + 0x10000000UL, 0x20000000UL, 0x40000000UL, 0x80000000UL, + 0x1B000000UL, 0x36000000UL, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ +}; + +/*---------------------------------------------------------------------- +| macros ++---------------------------------------------------------------------*/ +#define RORc(x, y) \ + ( ((((NPT_UInt32)(x)&0xFFFFFFFFUL)>>(NPT_UInt32)(y)) | \ + ((NPT_UInt32)(x)<<(NPT_UInt32)(32-(y)))) & 0xFFFFFFFFUL) + +#define Te0(x) TE0[x] +#define Te1(x) RORc(TE0[x], 8) +#define Te2(x) RORc(TE0[x], 16) +#define Te3(x) RORc(TE0[x], 24) + +#define Td0(x) TD0[x] +#define Td1(x) RORc(TD0[x], 8) +#define Td2(x) RORc(TD0[x], 16) +#define Td3(x) RORc(TD0[x], 24) + +#define Te4_0 0x000000FF & Te4 +#define Te4_1 0x0000FF00 & Te4 +#define Te4_2 0x00FF0000 & Te4 +#define Te4_3 0xFF000000 & Te4 + +#define NPT_BYTE(x,n) (((unsigned char)((x) >> (8 * (n))))) + +/*---------------------------------------------------------------------- +| local utility functions ++---------------------------------------------------------------------*/ +static NPT_UInt32 setup_mix(NPT_UInt32 temp) +{ + return (Te4_3[NPT_BYTE(temp, 2)]) ^ + (Te4_2[NPT_BYTE(temp, 1)]) ^ + (Te4_1[NPT_BYTE(temp, 0)]) ^ + (Te4_0[NPT_BYTE(temp, 3)]); +} + +static NPT_UInt32 setup_mix2(NPT_UInt32 temp) +{ + return Td0(0xFF & Te4[NPT_BYTE(temp, 3)]) ^ + Td1(0xFF & Te4[NPT_BYTE(temp, 2)]) ^ + Td2(0xFF & Te4[NPT_BYTE(temp, 1)]) ^ + Td3(0xFF & Te4[NPT_BYTE(temp, 0)]); +} + +static inline NPT_UInt32 LOAD32H(const NPT_UInt8* p) +{ + return ((((NPT_UInt32)p[0])<<24) | + (((NPT_UInt32)p[1])<<16) | + (((NPT_UInt32)p[2])<< 8) | + (((NPT_UInt32)p[3]) )); +} + +static inline void STORE32H(NPT_UInt32 x, NPT_UInt8* p) +{ + p[0] = (NPT_UInt8)(x>>24); + p[1] = (NPT_UInt8)(x>>16); + p[2] = (NPT_UInt8)(x>> 8); + p[3] = (NPT_UInt8)(x ); +} + +/*---------------------------------------------------------------------- +| NPT_AesBlockCipher ++---------------------------------------------------------------------*/ +class NPT_AesBlockCipher : public NPT_BlockCipher +{ +public: + NPT_AesBlockCipher(const NPT_UInt8* key, + NPT_Size key_size); + NPT_Result ProcessBlock(const NPT_UInt8* , NPT_UInt8*) { + return NPT_ERROR_INTERNAL; + } + NPT_Size GetBlockSize() { return NPT_AES_BLOCK_SIZE; } + Algorithm GetAlgorithm() { return AES_128; } + +protected: + NPT_UInt32 m_eK[60]; + NPT_UInt32 m_dK[60]; + NPT_Cardinal m_RoundCount; +}; + +/*---------------------------------------------------------------------- +| NPT_AesBlockEncrypter ++---------------------------------------------------------------------*/ +class NPT_AesBlockEncrypter : public NPT_AesBlockCipher { +public: + NPT_AesBlockEncrypter(const NPT_UInt8* key, NPT_Size key_size) : + NPT_AesBlockCipher(key, key_size) {} + Direction GetDirection() { return ENCRYPT; } + NPT_Result ProcessBlock(const NPT_UInt8* block_in, NPT_UInt8* block_out); +}; + +/*---------------------------------------------------------------------- +| NPT_AesBlockDecrypter ++---------------------------------------------------------------------*/ +class NPT_AesBlockDecrypter : public NPT_AesBlockCipher { +public: + NPT_AesBlockDecrypter(const NPT_UInt8* key, NPT_Size key_size) : + NPT_AesBlockCipher(key, key_size) {} + Direction GetDirection() { return DECRYPT; } + NPT_Result ProcessBlock(const NPT_UInt8* block_in, NPT_UInt8* block_out); +}; + +/*---------------------------------------------------------------------- +| NPT_AesBlockCipher::NPT_AesBlockCipher ++---------------------------------------------------------------------*/ +NPT_AesBlockCipher::NPT_AesBlockCipher(const NPT_UInt8* key, + NPT_Size key_size) +{ + unsigned int i, j; + NPT_UInt32 temp; + NPT_UInt32 *rrk; + + m_RoundCount = 10 + ((key_size/8)-2)*2; + + /* setup the forward key */ + i = 0; + NPT_UInt32* rk = m_eK; + rk[0] = LOAD32H(key ); + rk[1] = LOAD32H(key + 4); + rk[2] = LOAD32H(key + 8); + rk[3] = LOAD32H(key + 12); + if (key_size == 16) { + j = 44; + for (;;) { + temp = rk[3]; + rk[4] = rk[0] ^ setup_mix(temp) ^ rcon[i]; + rk[5] = rk[1] ^ rk[4]; + rk[6] = rk[2] ^ rk[5]; + rk[7] = rk[3] ^ rk[6]; + if (++i == 10) { + break; + } + rk += 4; + } + } else if (key_size == 24) { + j = 52; + rk[4] = LOAD32H(key + 16); + rk[5] = LOAD32H(key + 20); + for (;;) { + #ifdef _MSC_VER + temp = m_eK[rk - m_eK + 5]; + #else + temp = rk[5]; + #endif + rk[ 6] = rk[ 0] ^ setup_mix(temp) ^ rcon[i]; + rk[ 7] = rk[ 1] ^ rk[ 6]; + rk[ 8] = rk[ 2] ^ rk[ 7]; + rk[ 9] = rk[ 3] ^ rk[ 8]; + if (++i == 8) { + break; + } + rk[10] = rk[ 4] ^ rk[ 9]; + rk[11] = rk[ 5] ^ rk[10]; + rk += 6; + } + } else if (key_size == 32) { + j = 60; + rk[4] = LOAD32H(key + 16); + rk[5] = LOAD32H(key + 20); + rk[6] = LOAD32H(key + 24); + rk[7] = LOAD32H(key + 28); + for (;;) { + temp = rk[7]; + rk[ 8] = rk[ 0] ^ setup_mix(temp) ^ rcon[i]; + rk[ 9] = rk[ 1] ^ rk[ 8]; + rk[10] = rk[ 2] ^ rk[ 9]; + rk[11] = rk[ 3] ^ rk[10]; + if (++i == 7) { + break; + } + temp = rk[11]; + rk[12] = rk[ 4] ^ setup_mix(RORc(temp, 8)); + rk[13] = rk[ 5] ^ rk[12]; + rk[14] = rk[ 6] ^ rk[13]; + rk[15] = rk[ 7] ^ rk[14]; + rk += 8; + } + } else { + /* this can't happen */ + return; + } + + /* setup the inverse key now */ + rk = m_dK; + rrk = m_eK + j - 4; + + /* apply the inverse MixColumn transform to all round keys but the first and the last: */ + /* copy first */ + *rk++ = *rrk++; + *rk++ = *rrk++; + *rk++ = *rrk++; + *rk = *rrk; + rk -= 3; rrk -= 3; + + for (i = 1; i < m_RoundCount; i++) { + rrk -= 4; + rk += 4; + temp = rrk[0]; + rk[0] = setup_mix2(temp); + temp = rrk[1]; + rk[1] = setup_mix2(temp); + temp = rrk[2]; + rk[2] = setup_mix2(temp); + temp = rrk[3]; + rk[3] = setup_mix2(temp); + } + + /* copy last */ + rrk -= 4; + rk += 4; + *rk++ = *rrk++; + *rk++ = *rrk++; + *rk++ = *rrk++; + *rk = *rrk; +} + +/*---------------------------------------------------------------------- +| NPT_AesBlockEncrypter::ProcessBlock ++---------------------------------------------------------------------*/ +NPT_Result +NPT_AesBlockEncrypter::ProcessBlock(const NPT_UInt8* pt, NPT_UInt8* ct) +{ + NPT_UInt32 s0, s1, s2, s3, t0, t1, t2, t3; + int Nr = m_RoundCount; + NPT_UInt32* rk = m_eK; + + /* + * map byte array block to cipher state + * and add initial round key: + */ + s0 = LOAD32H(pt ); s0 ^= rk[0]; + s1 = LOAD32H(pt + 4); s1 ^= rk[1]; + s2 = LOAD32H(pt + 8); s2 ^= rk[2]; + s3 = LOAD32H(pt + 12); s3 ^= rk[3]; + + for (int r = 0; ; r++) { + rk += 4; + t0 = + Te0(NPT_BYTE(s0, 3)) ^ + Te1(NPT_BYTE(s1, 2)) ^ + Te2(NPT_BYTE(s2, 1)) ^ + Te3(NPT_BYTE(s3, 0)) ^ + rk[0]; + t1 = + Te0(NPT_BYTE(s1, 3)) ^ + Te1(NPT_BYTE(s2, 2)) ^ + Te2(NPT_BYTE(s3, 1)) ^ + Te3(NPT_BYTE(s0, 0)) ^ + rk[1]; + t2 = + Te0(NPT_BYTE(s2, 3)) ^ + Te1(NPT_BYTE(s3, 2)) ^ + Te2(NPT_BYTE(s0, 1)) ^ + Te3(NPT_BYTE(s1, 0)) ^ + rk[2]; + t3 = + Te0(NPT_BYTE(s3, 3)) ^ + Te1(NPT_BYTE(s0, 2)) ^ + Te2(NPT_BYTE(s1, 1)) ^ + Te3(NPT_BYTE(s2, 0)) ^ + rk[3]; + if (r == Nr-2) { + break; + } + s0 = t0; s1 = t1; s2 = t2; s3 = t3; + } + rk += 4; + + /* + * apply last round and + * map cipher state to byte array block: + */ + s0 = + (Te4_3[NPT_BYTE(t0, 3)]) ^ + (Te4_2[NPT_BYTE(t1, 2)]) ^ + (Te4_1[NPT_BYTE(t2, 1)]) ^ + (Te4_0[NPT_BYTE(t3, 0)]) ^ + rk[0]; + STORE32H(s0, ct); + s1 = + (Te4_3[NPT_BYTE(t1, 3)]) ^ + (Te4_2[NPT_BYTE(t2, 2)]) ^ + (Te4_1[NPT_BYTE(t3, 1)]) ^ + (Te4_0[NPT_BYTE(t0, 0)]) ^ + rk[1]; + STORE32H(s1, ct+4); + s2 = + (Te4_3[NPT_BYTE(t2, 3)]) ^ + (Te4_2[NPT_BYTE(t3, 2)]) ^ + (Te4_1[NPT_BYTE(t0, 1)]) ^ + (Te4_0[NPT_BYTE(t1, 0)]) ^ + rk[2]; + STORE32H(s2, ct+8); + s3 = + (Te4_3[NPT_BYTE(t3, 3)]) ^ + (Te4_2[NPT_BYTE(t0, 2)]) ^ + (Te4_1[NPT_BYTE(t1, 1)]) ^ + (Te4_0[NPT_BYTE(t2, 0)]) ^ + rk[3]; + STORE32H(s3, ct+12); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_AesBlockDecrypter::ProcessBlock ++---------------------------------------------------------------------*/ +NPT_Result +NPT_AesBlockDecrypter::ProcessBlock(const NPT_UInt8* ct, NPT_UInt8* pt) +{ + NPT_UInt32 s0, s1, s2, s3, t0, t1, t2, t3; + + int Nr = m_RoundCount; + NPT_UInt32* rk = m_dK; + + /* + * map byte array block to cipher state + * and add initial round key: + */ + s0 = LOAD32H(ct ); s0 ^= rk[0]; + s1 = LOAD32H(ct + 4); s1 ^= rk[1]; + s2 = LOAD32H(ct + 8); s2 ^= rk[2]; + s3 = LOAD32H(ct + 12); s3 ^= rk[3]; + + for (int r = 0; ; r++) { + rk += 4; + t0 = + Td0(NPT_BYTE(s0, 3)) ^ + Td1(NPT_BYTE(s3, 2)) ^ + Td2(NPT_BYTE(s2, 1)) ^ + Td3(NPT_BYTE(s1, 0)) ^ + rk[0]; + t1 = + Td0(NPT_BYTE(s1, 3)) ^ + Td1(NPT_BYTE(s0, 2)) ^ + Td2(NPT_BYTE(s3, 1)) ^ + Td3(NPT_BYTE(s2, 0)) ^ + rk[1]; + t2 = + Td0(NPT_BYTE(s2, 3)) ^ + Td1(NPT_BYTE(s1, 2)) ^ + Td2(NPT_BYTE(s0, 1)) ^ + Td3(NPT_BYTE(s3, 0)) ^ + rk[2]; + t3 = + Td0(NPT_BYTE(s3, 3)) ^ + Td1(NPT_BYTE(s2, 2)) ^ + Td2(NPT_BYTE(s1, 1)) ^ + Td3(NPT_BYTE(s0, 0)) ^ + rk[3]; + if (r == Nr-2) { + break; + } + s0 = t0; s1 = t1; s2 = t2; s3 = t3; + } + rk += 4; + + /* + * apply last round and + * map cipher state to byte array block: + */ + s0 = + (Td4[NPT_BYTE(t0, 3)] & 0xff000000) ^ + (Td4[NPT_BYTE(t3, 2)] & 0x00ff0000) ^ + (Td4[NPT_BYTE(t2, 1)] & 0x0000ff00) ^ + (Td4[NPT_BYTE(t1, 0)] & 0x000000ff) ^ + rk[0]; + STORE32H(s0, pt); + s1 = + (Td4[NPT_BYTE(t1, 3)] & 0xff000000) ^ + (Td4[NPT_BYTE(t0, 2)] & 0x00ff0000) ^ + (Td4[NPT_BYTE(t3, 1)] & 0x0000ff00) ^ + (Td4[NPT_BYTE(t2, 0)] & 0x000000ff) ^ + rk[1]; + STORE32H(s1, pt+4); + s2 = + (Td4[NPT_BYTE(t2, 3)] & 0xff000000) ^ + (Td4[NPT_BYTE(t1, 2)] & 0x00ff0000) ^ + (Td4[NPT_BYTE(t0, 1)] & 0x0000ff00) ^ + (Td4[NPT_BYTE(t3, 0)] & 0x000000ff) ^ + rk[2]; + STORE32H(s2, pt+8); + s3 = + (Td4[NPT_BYTE(t3, 3)] & 0xff000000) ^ + (Td4[NPT_BYTE(t2, 2)] & 0x00ff0000) ^ + (Td4[NPT_BYTE(t1, 1)] & 0x0000ff00) ^ + (Td4[NPT_BYTE(t0, 0)] & 0x000000ff) ^ + rk[3]; + STORE32H(s3, pt+12); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_BlockCipher::Create ++---------------------------------------------------------------------*/ +NPT_Result +NPT_BlockCipher::Create(Algorithm algorithm, + Direction direction, + const NPT_UInt8* key, + NPT_Size key_size, + NPT_BlockCipher*& cipher) +{ + cipher = NULL; + switch (algorithm) { + case AES_128: + if (key == NULL || key_size != 16) return NPT_ERROR_INVALID_PARAMETERS; + switch (direction) { + case ENCRYPT: + cipher = new NPT_AesBlockEncrypter(key, 16); + return NPT_SUCCESS; + + case DECRYPT: + cipher = new NPT_AesBlockDecrypter(key, 16); + return NPT_SUCCESS; + + default: + return NPT_ERROR_INVALID_PARAMETERS; + } + default: + return NPT_ERROR_NOT_SUPPORTED; + } +} + +/*---------------------------------------------------------------------- +| NPT_BlockCipher::ProcessCbc ++---------------------------------------------------------------------*/ +NPT_Result +NPT_BlockCipher::ProcessCbc(const NPT_UInt8* input, NPT_Size input_size, const NPT_UInt8* iv, NPT_DataBuffer& output) +{ + // this version only supports block sizes of 16 + if (GetBlockSize() != 16) return NPT_ERROR_NOT_SUPPORTED; + + // decrypt or encrypt depending on the direction of the cipher + NPT_UInt8 chain[16]; + if (iv) { + NPT_CopyMemory(chain, iv, 16); + } else { + NPT_SetMemory(chain, 0, 16); + } + if (GetDirection() == ENCRYPT) { + // pad + unsigned int padding_size = 16-(input_size%16); + NPT_DataBuffer padded_input; + padded_input.SetDataSize(input_size+padding_size); + NPT_UInt8* plaintext = padded_input.UseData(); + NPT_CopyMemory(plaintext, input, input_size); + for (unsigned int x=0; x<padding_size; x++) { + plaintext[input_size+x] = padding_size; + } + + // process all blocks + unsigned int block_count = (input_size+padding_size)/16; + output.SetDataSize(block_count*16); + NPT_UInt8* ciphertext = output.UseData(); + for (unsigned int x=0; x<block_count; x++) { + // xor with the chaining block + for (unsigned int y=0; y<16; y++) { + plaintext[y] ^= chain[y]; + } + + // encrypt the block + NPT_Result result = ProcessBlock(plaintext, ciphertext); + if (NPT_FAILED(result)) return result; + + // chain and move forward to the next block + NPT_CopyMemory(chain, ciphertext, 16); + plaintext += 16; + ciphertext += 16; + } + } else { + // check that we have an integral number of blocks + if (input_size%16) return NPT_ERROR_INVALID_PARAMETERS; + + // process all blocks + unsigned int block_count = input_size/16; + output.SetBufferSize(block_count*16); + NPT_UInt8* plaintext = output.UseData(); + const NPT_UInt8* ciphertext = input; + for (unsigned int x=0; x<block_count; x++) { + // decrypt block + NPT_Result result = ProcessBlock(ciphertext, plaintext); + if (NPT_FAILED(result)) return result; + + // xor with the chaining block + for (unsigned int y=0; y<16; y++) { + plaintext[y] ^= chain[y]; + } + + // chain and move forward to the next block + NPT_CopyMemory(chain, ciphertext, 16); + plaintext += 16; + ciphertext += 16; + } + + // padding + plaintext -= 16; + unsigned int padding_size = plaintext[15]; + if (padding_size == 0 || padding_size > 16) { + return NPT_ERROR_INVALID_FORMAT; + } + for (unsigned int y=0; y<padding_size; y++) { + if (plaintext[15-y] != padding_size) { + return NPT_ERROR_INVALID_FORMAT; + } + } + output.SetDataSize(block_count*16 - padding_size); + } + + return NPT_SUCCESS; +} + diff --git a/lib/libUPnP/Neptune/Source/Core/NptCrypto.h b/lib/libUPnP/Neptune/Source/Core/NptCrypto.h new file mode 100644 index 0000000..04eb58f --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptCrypto.h @@ -0,0 +1,78 @@ +/***************************************************************** +| +| Neptune - Crypto +| +| Copyright (c) 2002-2010, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +#ifndef _NPT_CRYPTO_H_ +#define _NPT_CRYPTO_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptTypes.h" +#include "NptDataBuffer.h" + +/*---------------------------------------------------------------------- +| NPT_BlockCipher ++---------------------------------------------------------------------*/ +class NPT_BlockCipher { +public: + // types + typedef enum { + AES_128 + } Algorithm; + + typedef enum { + ENCRYPT, + DECRYPT + } Direction; + + // factory + static NPT_Result Create(Algorithm algorithm, + Direction direction, + const NPT_UInt8* key, + NPT_Size key_size, + NPT_BlockCipher*& cipher); + + // methods + virtual ~NPT_BlockCipher() {} + virtual NPT_Size GetBlockSize() = 0; + virtual Direction GetDirection() = 0; + virtual Algorithm GetAlgorithm() = 0; + virtual NPT_Result ProcessBlock(const NPT_UInt8* input, NPT_UInt8* output) = 0; + /** + * @param iv Initial vector (same size as cipher block size), or NULL for an IV made up of all zeros. + */ + virtual NPT_Result ProcessCbc(const NPT_UInt8* input, NPT_Size input_size, const NPT_UInt8* iv, NPT_DataBuffer& output); + +protected: + NPT_BlockCipher() {} // don't instantiate directly +}; + +#endif // _NPT_CRYPTO_H_ diff --git a/lib/libUPnP/Neptune/Source/Core/NptDataBuffer.cpp b/lib/libUPnP/Neptune/Source/Core/NptDataBuffer.cpp new file mode 100644 index 0000000..f5ab03c --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptDataBuffer.cpp @@ -0,0 +1,256 @@ +/***************************************************************** +| +| Neptune - Data Buffer +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptDataBuffer.h" +#include "NptUtils.h" +#include "NptResults.h" + +/*---------------------------------------------------------------------- +| NPT_DataBuffer::NPT_DataBuffer ++---------------------------------------------------------------------*/ +NPT_DataBuffer::NPT_DataBuffer() : + m_BufferIsLocal(true), + m_Buffer(NULL), + m_BufferSize(0), + m_DataSize(0) +{ +} + +/*---------------------------------------------------------------------- +| NPT_DataBuffer::NPT_DataBuffer ++---------------------------------------------------------------------*/ +NPT_DataBuffer::NPT_DataBuffer(NPT_Size bufferSize) : + m_BufferIsLocal(true), + m_Buffer(bufferSize?new NPT_Byte[bufferSize]:NULL), + m_BufferSize(bufferSize), + m_DataSize(0) +{ +} + +/*---------------------------------------------------------------------- +| NPT_DataBuffer::NPT_DataBuffer ++---------------------------------------------------------------------*/ +NPT_DataBuffer::NPT_DataBuffer(const void* data, NPT_Size data_size, bool copy) : + m_BufferIsLocal(copy), + m_Buffer(copy?(data_size?new NPT_Byte[data_size]:NULL):reinterpret_cast<NPT_Byte*>(const_cast<void*>(data))), + m_BufferSize(data_size), + m_DataSize(data_size) +{ + if (copy && data_size) NPT_CopyMemory(m_Buffer, data, data_size); +} + +/*---------------------------------------------------------------------- +| NPT_DataBuffer::NPT_DataBuffer ++---------------------------------------------------------------------*/ +NPT_DataBuffer::NPT_DataBuffer(const NPT_DataBuffer& other) : + m_BufferIsLocal(true), + m_Buffer(NULL), + m_BufferSize(other.m_DataSize), + m_DataSize(other.m_DataSize) +{ + if (m_BufferSize) { + m_Buffer = new NPT_Byte[m_BufferSize]; + NPT_CopyMemory(m_Buffer, other.m_Buffer, m_BufferSize); + } +} + +/*---------------------------------------------------------------------- +| NPT_DataBuffer::~NPT_DataBuffer ++---------------------------------------------------------------------*/ +NPT_DataBuffer::~NPT_DataBuffer() +{ + Clear(); +} + +/*---------------------------------------------------------------------- +| NPT_DataBuffer::Clear ++---------------------------------------------------------------------*/ +NPT_Result +NPT_DataBuffer::Clear() +{ + if (m_BufferIsLocal) { + delete[] m_Buffer; + } + m_Buffer = NULL; + m_DataSize = 0; + m_BufferSize = 0; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_DataBuffer::operator= ++---------------------------------------------------------------------*/ +NPT_DataBuffer& +NPT_DataBuffer::operator=(const NPT_DataBuffer& copy) +{ + // do nothing if we're assigning to ourselves + if (this != ©) { + Clear(); + + m_BufferIsLocal = true; + m_BufferSize = copy.m_BufferSize; + m_DataSize = copy.m_DataSize; + + if (m_BufferSize) { + m_Buffer = new NPT_Byte[m_BufferSize]; + NPT_CopyMemory(m_Buffer, copy.m_Buffer, m_BufferSize); + } + } + return *this; +} + +/*---------------------------------------------------------------------- +| NPT_DataBuffer::operator== ++---------------------------------------------------------------------*/ +bool +NPT_DataBuffer::operator==(const NPT_DataBuffer& other) const +{ + // check that the sizes match + if (m_DataSize != other.m_DataSize) return false; + + return NPT_MemoryEqual(m_Buffer, + other.m_Buffer, + m_DataSize); +} + +/*---------------------------------------------------------------------- +| NPT_DataBuffer::SetBuffer ++---------------------------------------------------------------------*/ +NPT_Result +NPT_DataBuffer::SetBuffer(NPT_Byte* buffer, NPT_Size buffer_size) +{ + Clear(); + + // we're now using an external buffer + m_BufferIsLocal = false; + m_Buffer = buffer; + m_BufferSize = buffer_size; + m_DataSize = 0; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_DataBuffer::SetBufferSize ++---------------------------------------------------------------------*/ +NPT_Result +NPT_DataBuffer::SetBufferSize(NPT_Size buffer_size) +{ + if (m_BufferIsLocal) { + return ReallocateBuffer(buffer_size); + } else { + return NPT_ERROR_NOT_SUPPORTED; // you cannot change the + // buffer management mode + } +} + +/*---------------------------------------------------------------------- +| NPT_DataBuffer::Reserve ++---------------------------------------------------------------------*/ +NPT_Result +NPT_DataBuffer::Reserve(NPT_Size size) +{ + if (size <= m_BufferSize) return NPT_SUCCESS; + + // try doubling the buffer to accomodate for the new size + NPT_Size new_size = m_BufferSize*2; + if (new_size < size) new_size = size; + return SetBufferSize(new_size); +} + +/*---------------------------------------------------------------------- +| NPT_DataBuffer::SetDataSize ++---------------------------------------------------------------------*/ +NPT_Result +NPT_DataBuffer::SetDataSize(NPT_Size size) +{ + if (size > m_BufferSize) { + // the buffer is too small, we need to reallocate it + if (m_BufferIsLocal) { + NPT_CHECK(ReallocateBuffer(size)); + } else { + // we cannot reallocate an external buffer + return NPT_ERROR_NOT_SUPPORTED; + } + } + m_DataSize = size; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_DataBuffer::SetData ++---------------------------------------------------------------------*/ +NPT_Result +NPT_DataBuffer::SetData(const NPT_Byte* data, NPT_Size size) +{ + if (size > m_BufferSize) { + if (m_BufferIsLocal) { + NPT_CHECK(ReallocateBuffer(size)); + } else { + return NPT_ERROR_INVALID_STATE; + } + } + if (data) NPT_CopyMemory(m_Buffer, data, size); + m_DataSize = size; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_DataBuffer::ReallocateBuffer ++---------------------------------------------------------------------*/ +NPT_Result +NPT_DataBuffer::ReallocateBuffer(NPT_Size size) +{ + // check that the existing data fits + if (m_DataSize > size) return NPT_ERROR_INVALID_PARAMETERS; + + // allocate a new buffer + NPT_Byte* newBuffer = new NPT_Byte[size]; + + // copy the contents of the previous buffer, if any + if (m_Buffer && m_DataSize) { + NPT_CopyMemory(newBuffer, m_Buffer, m_DataSize); + } + + // destroy the previous buffer + delete[] m_Buffer; + + // use the new buffer + m_Buffer = newBuffer; + m_BufferSize = size; + + return NPT_SUCCESS; +} diff --git a/lib/libUPnP/Neptune/Source/Core/NptDataBuffer.h b/lib/libUPnP/Neptune/Source/Core/NptDataBuffer.h new file mode 100644 index 0000000..7e57c01 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptDataBuffer.h @@ -0,0 +1,83 @@ +/***************************************************************** +| +| Neptune - Datagram Packets +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +#ifndef _NPT_DATA_BUFFER_H_ +#define _NPT_DATA_BUFFER_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptTypes.h" +#include "NptConstants.h" + +/*---------------------------------------------------------------------- +| NPT_DataBuffer ++---------------------------------------------------------------------*/ +class NPT_DataBuffer +{ + public: + // constructors & destructor + NPT_DataBuffer(); // size unknown until first set + NPT_DataBuffer(NPT_Size size); // initial size specified + NPT_DataBuffer(const void* data, NPT_Size size, bool copy = true); // initial data and size specified + NPT_DataBuffer(const NPT_DataBuffer& other); + virtual ~NPT_DataBuffer(); + + // operators + NPT_DataBuffer& operator=(const NPT_DataBuffer& copy); + bool operator==(const NPT_DataBuffer& other) const; + + // data buffer handling methods + virtual NPT_Result SetBuffer(NPT_Byte* buffer, NPT_Size bufferSize); + virtual NPT_Result SetBufferSize(NPT_Size bufferSize); + virtual NPT_Size GetBufferSize() const { return m_BufferSize; } + virtual NPT_Result Reserve(NPT_Size size); + virtual NPT_Result Clear(); + + // data handling methods + virtual const NPT_Byte* GetData() const { return m_Buffer; } + virtual NPT_Byte* UseData() { return m_Buffer; }; + virtual NPT_Size GetDataSize() const { return m_DataSize; } + virtual NPT_Result SetDataSize(NPT_Size size); + virtual NPT_Result SetData(const NPT_Byte* data, NPT_Size dataSize); + + protected: + // members + bool m_BufferIsLocal; + NPT_Byte* m_Buffer; + NPT_Size m_BufferSize; + NPT_Size m_DataSize; + + // methods + NPT_Result ReallocateBuffer(NPT_Size size); +}; + +#endif // _NPT_DATA_BUFFER_H_ diff --git a/lib/libUPnP/Neptune/Source/Core/NptDebug.cpp b/lib/libUPnP/Neptune/Source/Core/NptDebug.cpp new file mode 100644 index 0000000..d9b7041 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptDebug.cpp @@ -0,0 +1,83 @@ +/***************************************************************** +| +| Neptune - Debug Utilities +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include <stdarg.h> +#include "NptUtils.h" +#include "NptDebug.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +#define NPT_DEBUG_LOCAL_BUFFER_SIZE 1024 +#define NPT_DEBUG_BUFFER_INCREMENT 4096 +#define NPT_DEBUG_BUFFER_MAX_SIZE 65536 + +/*---------------------------------------------------------------------- +| NPT_Debug ++---------------------------------------------------------------------*/ +void +NPT_Debug(const char* format, ...) +{ +#if defined(NPT_DEBUG) + char local_buffer[NPT_DEBUG_LOCAL_BUFFER_SIZE]; + unsigned int buffer_size = NPT_DEBUG_LOCAL_BUFFER_SIZE; + char* buffer = local_buffer; + va_list args; + + va_start(args, format); + + for(;;) { + int result; + + /* try to format the message (it might not fit) */ + result = NPT_FormatStringVN(buffer, buffer_size-1, format, args); + buffer[buffer_size-1] = 0; /* force a NULL termination */ + if (result >= 0) break; + + /* the buffer was too small, try something bigger */ + buffer_size = (buffer_size+NPT_DEBUG_BUFFER_INCREMENT)*2; + if (buffer_size > NPT_DEBUG_BUFFER_MAX_SIZE) break; + if (buffer != local_buffer) delete[] buffer; + buffer = new char[buffer_size]; + if (buffer == NULL) return; + } + + NPT_DebugOutput(buffer); + if (buffer != local_buffer) delete[] buffer; + + va_end(args); +#else + NPT_COMPILER_UNUSED(format); +#endif +} diff --git a/lib/libUPnP/Neptune/Source/Core/NptDebug.h b/lib/libUPnP/Neptune/Source/Core/NptDebug.h new file mode 100644 index 0000000..d4973a2 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptDebug.h @@ -0,0 +1,56 @@ +/***************************************************************** +| +| Neptune - Debug Utilities +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +#ifndef _NPT_DEBUG_H_ +#define _NPT_DEBUG_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptConfig.h" + +/*---------------------------------------------------------------------- +| standard macros ++---------------------------------------------------------------------*/ +#if defined(NPT_CONFIG_HAVE_ASSERT_H) && defined(NPT_DEBUG) +#include <assert.h> +#define NPT_ASSERT(x) assert(x) +#else +#define NPT_ASSERT(x) ((void)0) +#endif + +/*---------------------------------------------------------------------- +| NPT_Debug ++---------------------------------------------------------------------*/ +extern void NPT_Debug(const char* format, ...); +extern void NPT_DebugOutput(const char* message); + +#endif // _NPT_DEBUG_H_ diff --git a/lib/libUPnP/Neptune/Source/Core/NptDefs.h b/lib/libUPnP/Neptune/Source/Core/NptDefs.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptDefs.h diff --git a/lib/libUPnP/Neptune/Source/Core/NptDigest.cpp b/lib/libUPnP/Neptune/Source/Core/NptDigest.cpp new file mode 100644 index 0000000..4e7fb74 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptDigest.cpp @@ -0,0 +1,685 @@ +/***************************************************************** +| +| Neptune - Message Digests +| +| Copyright (c) 2002-2010, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +/* + Portions of this code are based on the code of LibTomCrypt + that was released into public domain by Tom St Denis. +*/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptDigest.h" +#include "NptUtils.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +#define NPT_BASIC_DIGEST_BLOCK_SIZE 64 + +/*---------------------------------------------------------------------- +| macros ++---------------------------------------------------------------------*/ +#define NPT_Digest_ROL(x, y) \ +( (((NPT_UInt32)(x) << (y)) | (((NPT_UInt32)(x) & 0xFFFFFFFFUL) >> (32 - (y)))) & 0xFFFFFFFFUL) +#define NPT_Digest_ROR(x, y) \ +( ((((NPT_UInt32)(x)&0xFFFFFFFFUL)>>(NPT_UInt32)((y)&31)) | ((NPT_UInt32)(x)<<(NPT_UInt32)(32-((y)&31)))) & 0xFFFFFFFFUL) + +#define NPT_Sha1_F0(x,y,z) (z ^ (x & (y ^ z))) +#define NPT_Sha1_F1(x,y,z) (x ^ y ^ z) +#define NPT_Sha1_F2(x,y,z) ((x & y) | (z & (x | y))) +#define NPT_Sha1_F3(x,y,z) (x ^ y ^ z) + +#define NPT_Sha1_FF0(a,b,c,d,e,i) e = (NPT_Digest_ROL(a, 5) + NPT_Sha1_F0(b,c,d) + e + W[i] + 0x5a827999UL); b = NPT_Digest_ROL(b, 30); +#define NPT_Sha1_FF1(a,b,c,d,e,i) e = (NPT_Digest_ROL(a, 5) + NPT_Sha1_F1(b,c,d) + e + W[i] + 0x6ed9eba1UL); b = NPT_Digest_ROL(b, 30); +#define NPT_Sha1_FF2(a,b,c,d,e,i) e = (NPT_Digest_ROL(a, 5) + NPT_Sha1_F2(b,c,d) + e + W[i] + 0x8f1bbcdcUL); b = NPT_Digest_ROL(b, 30); +#define NPT_Sha1_FF3(a,b,c,d,e,i) e = (NPT_Digest_ROL(a, 5) + NPT_Sha1_F3(b,c,d) + e + W[i] + 0xca62c1d6UL); b = NPT_Digest_ROL(b, 30); + +#define NPT_Sha256_Ch(x,y,z) (z ^ (x & (y ^ z))) +#define NPT_Sha256_Maj(x,y,z) (((x | y) & z) | (x & y)) +#define NPT_Sha256_S(x, n) NPT_Digest_ROR((x),(n)) +#define NPT_Sha256_R(x, n) (((x)&0xFFFFFFFFUL)>>(n)) +#define NPT_Sha256_Sigma0(x) (NPT_Sha256_S(x, 2) ^ NPT_Sha256_S(x, 13) ^ NPT_Sha256_S(x, 22)) +#define NPT_Sha256_Sigma1(x) (NPT_Sha256_S(x, 6) ^ NPT_Sha256_S(x, 11) ^ NPT_Sha256_S(x, 25)) +#define NPT_Sha256_Gamma0(x) (NPT_Sha256_S(x, 7) ^ NPT_Sha256_S(x, 18) ^ NPT_Sha256_R(x, 3)) +#define NPT_Sha256_Gamma1(x) (NPT_Sha256_S(x, 17) ^ NPT_Sha256_S(x, 19) ^ NPT_Sha256_R(x, 10)) + + +#define NPT_Md5_F(x,y,z) (z ^ (x & (y ^ z))) +#define NPT_Md5_G(x,y,z) (y ^ (z & (y ^ x))) +#define NPT_Md5_H(x,y,z) (x ^ y ^ z) +#define NPT_Md5_I(x,y,z) (y ^ (x | (~z))) + +#define NPT_Md5_FF(a,b,c,d,M,s,t) \ + a = (a + NPT_Md5_F(b,c,d) + M + t); a = NPT_Digest_ROL(a, s) + b; + +#define NPT_Md5_GG(a,b,c,d,M,s,t) \ + a = (a + NPT_Md5_G(b,c,d) + M + t); a = NPT_Digest_ROL(a, s) + b; + +#define NPT_Md5_HH(a,b,c,d,M,s,t) \ + a = (a + NPT_Md5_H(b,c,d) + M + t); a = NPT_Digest_ROL(a, s) + b; + +#define NPT_Md5_II(a,b,c,d,M,s,t) \ + a = (a + NPT_Md5_I(b,c,d) + M + t); a = NPT_Digest_ROL(a, s) + b; + +/*---------------------------------------------------------------------- +| NPT_BasicDigest ++---------------------------------------------------------------------*/ +class NPT_BasicDigest : public NPT_Digest +{ +public: + NPT_BasicDigest(); + + // NPT_Digest methods + virtual NPT_Result Update(const NPT_UInt8* data, NPT_Size data_size); + +protected: + // methods + NPT_Result ComputeDigest(NPT_UInt32* state, + NPT_Cardinal state_count, + bool big_endian, + NPT_DataBuffer& digest); + virtual void CompressBlock(const NPT_UInt8* block) = 0; + + // members + NPT_UInt64 m_Length; + NPT_UInt32 m_Pending; + NPT_UInt8 m_Buffer[NPT_BASIC_DIGEST_BLOCK_SIZE]; +}; + +/*---------------------------------------------------------------------- +| NPT_BasicDigest::NPT_BasicDigest ++---------------------------------------------------------------------*/ +NPT_BasicDigest::NPT_BasicDigest() : + m_Length(0), + m_Pending(0) +{ +} + +/*---------------------------------------------------------------------- +| NPT_BasicDigest::Update ++---------------------------------------------------------------------*/ +NPT_Result +NPT_BasicDigest::Update(const NPT_UInt8* data, NPT_Size data_size) +{ + while (data_size > 0) { + if (m_Pending == 0 && data_size >= NPT_BASIC_DIGEST_BLOCK_SIZE) { + CompressBlock(data); + m_Length += NPT_BASIC_DIGEST_BLOCK_SIZE * 8; + data += NPT_BASIC_DIGEST_BLOCK_SIZE; + data_size -= NPT_BASIC_DIGEST_BLOCK_SIZE; + } else { + unsigned int chunk = data_size; + if (chunk > (NPT_BASIC_DIGEST_BLOCK_SIZE - m_Pending)) { + chunk = NPT_BASIC_DIGEST_BLOCK_SIZE - m_Pending; + } + NPT_CopyMemory(&m_Buffer[m_Pending], data, chunk); + m_Pending += chunk; + data += chunk; + data_size -= chunk; + if (m_Pending == NPT_BASIC_DIGEST_BLOCK_SIZE) { + CompressBlock(m_Buffer); + m_Length += 8 * NPT_BASIC_DIGEST_BLOCK_SIZE; + m_Pending = 0; + } + } + } + + return NPT_SUCCESS; +} + + +/*---------------------------------------------------------------------- +| NPT_BasicDigest::ComputeDigest ++---------------------------------------------------------------------*/ +NPT_Result +NPT_BasicDigest::ComputeDigest(NPT_UInt32* state, + NPT_Cardinal state_count, + bool big_endian, + NPT_DataBuffer& digest) +{ + // increase the length of the message + m_Length += m_Pending * 8; + + // append the '1' bit + m_Buffer[m_Pending++] = 0x80; + + // if there isn't enough space left for the size (8 bytes), then compress. + // then we can fall back to padding zeros and length encoding as normal. + if (m_Pending > NPT_BASIC_DIGEST_BLOCK_SIZE-8) { + while (m_Pending < NPT_BASIC_DIGEST_BLOCK_SIZE) { + m_Buffer[m_Pending++] = 0; + } + CompressBlock(m_Buffer); + m_Pending = 0; + } + + // pad with zeroes up until the length + while (m_Pending < NPT_BASIC_DIGEST_BLOCK_SIZE-8) { + m_Buffer[m_Pending++] = 0; + } + + // store length + if (big_endian) { + NPT_BytesFromInt64Be(&m_Buffer[NPT_BASIC_DIGEST_BLOCK_SIZE-8], m_Length); + } else { + NPT_BytesFromInt64Le(&m_Buffer[NPT_BASIC_DIGEST_BLOCK_SIZE-8], m_Length); + } + CompressBlock(m_Buffer); + + // copy output + digest.SetDataSize(4*state_count); + NPT_UInt8* out = digest.UseData(); + if (big_endian) { + for (unsigned int i = 0; i < state_count; i++) { + NPT_BytesFromInt32Be(out, state[i]); + out += 4; + } + } else { + for (unsigned int i = 0; i < state_count; i++) { + NPT_BytesFromInt32Le(out, state[i]); + out += 4; + } + } + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_Sha1Digest ++---------------------------------------------------------------------*/ +class NPT_Sha1Digest : public NPT_BasicDigest +{ +public: + NPT_Sha1Digest(); + + // NPT_Digest methods + virtual NPT_Result GetDigest(NPT_DataBuffer& digest); + virtual unsigned int GetSize() { return 20; } + +private: + // methods + virtual void CompressBlock(const NPT_UInt8* block); + + // members + NPT_UInt32 m_State[5]; +}; + +/*---------------------------------------------------------------------- +| NPT_Sha1Digest::NPT_Sha1Digest ++---------------------------------------------------------------------*/ +NPT_Sha1Digest::NPT_Sha1Digest() +{ + m_State[0] = 0x67452301UL; + m_State[1] = 0xefcdab89UL; + m_State[2] = 0x98badcfeUL; + m_State[3] = 0x10325476UL; + m_State[4] = 0xc3d2e1f0UL; +} + +/*---------------------------------------------------------------------- +| NPT_Sha1Digest::CompressBlock ++---------------------------------------------------------------------*/ +void +NPT_Sha1Digest::CompressBlock(const NPT_UInt8* block) +{ + NPT_UInt32 a,b,c,d,e,t,W[80]; + + // copy the 512-bit block into W[0..15] + for (unsigned int i = 0; i < 16; i++) { + W[i] = NPT_BytesToInt32Be(&block[4*i]); + } + + // copy the state to local variables + a = m_State[0]; + b = m_State[1]; + c = m_State[2]; + d = m_State[3]; + e = m_State[4]; + + // expand it + unsigned int i; + for (i = 16; i < 80; i++) { + W[i] = NPT_Digest_ROL(W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16], 1); + } + + // compress + for (i = 0; i < 20; ) { + NPT_Sha1_FF0(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t; + } + + for (; i < 40; ) { + NPT_Sha1_FF1(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t; + } + + for (; i < 60; ) { + NPT_Sha1_FF2(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t; + } + + for (; i < 80; ) { + NPT_Sha1_FF3(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t; + } + + // store the variables back into the state + m_State[0] += a; + m_State[1] += b; + m_State[2] += c; + m_State[3] += d; + m_State[4] += e; +} + +/*---------------------------------------------------------------------- +| NPT_Sha1Digest::GetDigest ++---------------------------------------------------------------------*/ +NPT_Result +NPT_Sha1Digest::GetDigest(NPT_DataBuffer& digest) +{ + return ComputeDigest(m_State, 5, true, digest); +} + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +static const NPT_UInt32 NPT_Sha256_K[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, + 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL, + 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, + 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL, + 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, + 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, + 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, + 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL, + 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, + 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL +}; + +/*---------------------------------------------------------------------- +| NPT_Sha256Digest ++---------------------------------------------------------------------*/ +class NPT_Sha256Digest : public NPT_BasicDigest +{ +public: + NPT_Sha256Digest(); + + // NPT_Digest methods + virtual NPT_Result GetDigest(NPT_DataBuffer& digest); + virtual unsigned int GetSize() { return 32; } + +private: + // methods + virtual void CompressBlock(const NPT_UInt8* block); + + // members + NPT_UInt32 m_State[8]; +}; + +/*---------------------------------------------------------------------- +| NPT_Sha256Digest::NPT_Sha256Digest ++---------------------------------------------------------------------*/ +NPT_Sha256Digest::NPT_Sha256Digest() +{ + m_State[0] = 0x6A09E667UL; + m_State[1] = 0xBB67AE85UL; + m_State[2] = 0x3C6EF372UL; + m_State[3] = 0xA54FF53AUL; + m_State[4] = 0x510E527FUL; + m_State[5] = 0x9B05688CUL; + m_State[6] = 0x1F83D9ABUL; + m_State[7] = 0x5BE0CD19UL; +} + +/*---------------------------------------------------------------------- +| NPT_Sha256Digest::CompressBlock ++---------------------------------------------------------------------*/ +void +NPT_Sha256Digest::CompressBlock(const NPT_UInt8* block) +{ + NPT_UInt32 S[8], W[64]; + + // copy the state into the local workspace + for (unsigned int i = 0; i < 8; i++) { + S[i] = m_State[i]; + } + + // copy the 512-bit block into W[0..15] + for (unsigned int i = 0; i < 16; i++) { + W[i] = NPT_BytesToInt32Be(&block[4*i]); + } + + // fill W[16..63] + for (unsigned int i = 16; i < 64; i++) { + W[i] = NPT_Sha256_Gamma1(W[i - 2]) + W[i - 7] + NPT_Sha256_Gamma0(W[i - 15]) + W[i - 16]; + } + + // compress + for (unsigned int i = 0; i < 64; ++i) { + NPT_UInt32 t0 = + S[7] + + NPT_Sha256_Sigma1(S[4]) + + NPT_Sha256_Ch(S[4], S[5], S[6]) + + NPT_Sha256_K[i] + + W[i]; + NPT_UInt32 t1 = NPT_Sha256_Sigma0(S[0]) + NPT_Sha256_Maj(S[0], S[1], S[2]); + S[3] += t0; + S[7] = t0 + t1; + + NPT_UInt32 t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4]; + S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t; + } + + // store the local variables back into the state + for (unsigned i = 0; i < 8; i++) { + m_State[i] += S[i]; + } +} + +/*---------------------------------------------------------------------- +| NPT_Sha256Digest::GetDigest ++---------------------------------------------------------------------*/ +NPT_Result +NPT_Sha256Digest::GetDigest(NPT_DataBuffer& digest) +{ + return ComputeDigest(m_State, 8, true, digest); +} + +/*---------------------------------------------------------------------- +| NPT_Md5Digest ++---------------------------------------------------------------------*/ +class NPT_Md5Digest : public NPT_BasicDigest +{ +public: + NPT_Md5Digest(); + + // NPT_Digest methods + virtual NPT_Result GetDigest(NPT_DataBuffer& digest); + virtual unsigned int GetSize() { return 16; } + +protected: + // methods + virtual void CompressBlock(const NPT_UInt8* block); + + // members + NPT_UInt32 m_State[4]; +}; + +/*---------------------------------------------------------------------- +| NPT_Md5Digest::NPT_Md5Digest ++---------------------------------------------------------------------*/ +NPT_Md5Digest::NPT_Md5Digest() +{ + m_State[0] = 0x67452301UL; + m_State[1] = 0xefcdab89UL; + m_State[2] = 0x98badcfeUL; + m_State[3] = 0x10325476UL; +} + +/*---------------------------------------------------------------------- +| NPT_Md5Digest::CompressBlock ++---------------------------------------------------------------------*/ +void +NPT_Md5Digest::CompressBlock(const NPT_UInt8* block) +{ + NPT_UInt32 a,b,c,d,W[16]; + + // copy the 512-bit block into W[0..15] + unsigned int i; + for (i = 0; i < 16; i++) { + W[i] = NPT_BytesToInt32Le(&block[4*i]); + } + + // copy the state to local variables + a = m_State[0]; + b = m_State[1]; + c = m_State[2]; + d = m_State[3]; + + // round 1 + NPT_Md5_FF(a,b,c,d,W[ 0], 7,0xd76aa478UL) + NPT_Md5_FF(d,a,b,c,W[ 1],12,0xe8c7b756UL) + NPT_Md5_FF(c,d,a,b,W[ 2],17,0x242070dbUL) + NPT_Md5_FF(b,c,d,a,W[ 3],22,0xc1bdceeeUL) + NPT_Md5_FF(a,b,c,d,W[ 4], 7,0xf57c0fafUL) + NPT_Md5_FF(d,a,b,c,W[ 5],12,0x4787c62aUL) + NPT_Md5_FF(c,d,a,b,W[ 6],17,0xa8304613UL) + NPT_Md5_FF(b,c,d,a,W[ 7],22,0xfd469501UL) + NPT_Md5_FF(a,b,c,d,W[ 8], 7,0x698098d8UL) + NPT_Md5_FF(d,a,b,c,W[ 9],12,0x8b44f7afUL) + NPT_Md5_FF(c,d,a,b,W[10],17,0xffff5bb1UL) + NPT_Md5_FF(b,c,d,a,W[11],22,0x895cd7beUL) + NPT_Md5_FF(a,b,c,d,W[12], 7,0x6b901122UL) + NPT_Md5_FF(d,a,b,c,W[13],12,0xfd987193UL) + NPT_Md5_FF(c,d,a,b,W[14],17,0xa679438eUL) + NPT_Md5_FF(b,c,d,a,W[15],22,0x49b40821UL) + + // round 2 + NPT_Md5_GG(a,b,c,d,W[ 1], 5,0xf61e2562UL) + NPT_Md5_GG(d,a,b,c,W[ 6], 9,0xc040b340UL) + NPT_Md5_GG(c,d,a,b,W[11],14,0x265e5a51UL) + NPT_Md5_GG(b,c,d,a,W[ 0],20,0xe9b6c7aaUL) + NPT_Md5_GG(a,b,c,d,W[ 5], 5,0xd62f105dUL) + NPT_Md5_GG(d,a,b,c,W[10], 9,0x02441453UL) + NPT_Md5_GG(c,d,a,b,W[15],14,0xd8a1e681UL) + NPT_Md5_GG(b,c,d,a,W[ 4],20,0xe7d3fbc8UL) + NPT_Md5_GG(a,b,c,d,W[ 9], 5,0x21e1cde6UL) + NPT_Md5_GG(d,a,b,c,W[14], 9,0xc33707d6UL) + NPT_Md5_GG(c,d,a,b,W[ 3],14,0xf4d50d87UL) + NPT_Md5_GG(b,c,d,a,W[ 8],20,0x455a14edUL) + NPT_Md5_GG(a,b,c,d,W[13], 5,0xa9e3e905UL) + NPT_Md5_GG(d,a,b,c,W[ 2], 9,0xfcefa3f8UL) + NPT_Md5_GG(c,d,a,b,W[ 7],14,0x676f02d9UL) + NPT_Md5_GG(b,c,d,a,W[12],20,0x8d2a4c8aUL) + + // round 3 + NPT_Md5_HH(a,b,c,d,W[ 5], 4,0xfffa3942UL) + NPT_Md5_HH(d,a,b,c,W[ 8],11,0x8771f681UL) + NPT_Md5_HH(c,d,a,b,W[11],16,0x6d9d6122UL) + NPT_Md5_HH(b,c,d,a,W[14],23,0xfde5380cUL) + NPT_Md5_HH(a,b,c,d,W[ 1], 4,0xa4beea44UL) + NPT_Md5_HH(d,a,b,c,W[ 4],11,0x4bdecfa9UL) + NPT_Md5_HH(c,d,a,b,W[ 7],16,0xf6bb4b60UL) + NPT_Md5_HH(b,c,d,a,W[10],23,0xbebfbc70UL) + NPT_Md5_HH(a,b,c,d,W[13], 4,0x289b7ec6UL) + NPT_Md5_HH(d,a,b,c,W[ 0],11,0xeaa127faUL) + NPT_Md5_HH(c,d,a,b,W[ 3],16,0xd4ef3085UL) + NPT_Md5_HH(b,c,d,a,W[ 6],23,0x04881d05UL) + NPT_Md5_HH(a,b,c,d,W[ 9], 4,0xd9d4d039UL) + NPT_Md5_HH(d,a,b,c,W[12],11,0xe6db99e5UL) + NPT_Md5_HH(c,d,a,b,W[15],16,0x1fa27cf8UL) + NPT_Md5_HH(b,c,d,a,W[ 2],23,0xc4ac5665UL) + + // round 4 + NPT_Md5_II(a,b,c,d,W[ 0], 6,0xf4292244UL) + NPT_Md5_II(d,a,b,c,W[ 7],10,0x432aff97UL) + NPT_Md5_II(c,d,a,b,W[14],15,0xab9423a7UL) + NPT_Md5_II(b,c,d,a,W[ 5],21,0xfc93a039UL) + NPT_Md5_II(a,b,c,d,W[12], 6,0x655b59c3UL) + NPT_Md5_II(d,a,b,c,W[ 3],10,0x8f0ccc92UL) + NPT_Md5_II(c,d,a,b,W[10],15,0xffeff47dUL) + NPT_Md5_II(b,c,d,a,W[ 1],21,0x85845dd1UL) + NPT_Md5_II(a,b,c,d,W[ 8], 6,0x6fa87e4fUL) + NPT_Md5_II(d,a,b,c,W[15],10,0xfe2ce6e0UL) + NPT_Md5_II(c,d,a,b,W[ 6],15,0xa3014314UL) + NPT_Md5_II(b,c,d,a,W[13],21,0x4e0811a1UL) + NPT_Md5_II(a,b,c,d,W[ 4], 6,0xf7537e82UL) + NPT_Md5_II(d,a,b,c,W[11],10,0xbd3af235UL) + NPT_Md5_II(c,d,a,b,W[ 2],15,0x2ad7d2bbUL) + NPT_Md5_II(b,c,d,a,W[ 9],21,0xeb86d391UL) + + // store the variables back into the state + m_State[0] += a; + m_State[1] += b; + m_State[2] += c; + m_State[3] += d; +} + +/*---------------------------------------------------------------------- +| NPT_Md5Digest::GetDigest ++---------------------------------------------------------------------*/ +NPT_Result +NPT_Md5Digest::GetDigest(NPT_DataBuffer& digest) +{ + return ComputeDigest(m_State, 4, false, digest); +} + +/*---------------------------------------------------------------------- +| NPT_HmacDigest +| +| compute Digest(key XOR opad, Digest(key XOR ipad, data)) +| key is the MAC key +| ipad is the byte 0x36 repeated 64 times +| opad is the byte 0x5c repeated 64 times +| and data is the data to authenticate +| ++---------------------------------------------------------------------*/ +class NPT_HmacDigest : public NPT_Digest +{ +public: + NPT_HmacDigest(NPT_Digest::Algorithm algorithm, + const NPT_UInt8* key, + NPT_Size key_size); + ~NPT_HmacDigest(); + + // NPT_Digest methods + virtual NPT_Result Update(const NPT_UInt8* data, NPT_Size data_size) { + return m_InnerDigest->Update(data, data_size); + } + virtual NPT_Result GetDigest(NPT_DataBuffer& buffer); + virtual unsigned int GetSize() { return m_InnerDigest->GetSize(); } + +private: + NPT_Digest* m_InnerDigest; + NPT_Digest* m_OuterDigest; +}; + +/*---------------------------------------------------------------------- +| NPT_HmacDigest::NPT_HmacDigest ++---------------------------------------------------------------------*/ +NPT_HmacDigest::NPT_HmacDigest(NPT_Digest::Algorithm algorithm, + const NPT_UInt8* key, + NPT_Size key_size) +{ + NPT_Digest::Create(algorithm, m_InnerDigest); + NPT_Digest::Create(algorithm, m_OuterDigest); + + NPT_UInt8 workspace[NPT_BASIC_DIGEST_BLOCK_SIZE]; + + // if the key is larger than the block size, use a digest of the key + NPT_DataBuffer hk; + if (key_size > NPT_BASIC_DIGEST_BLOCK_SIZE) { + NPT_Digest* key_digest = NULL; + NPT_Digest::Create(algorithm, key_digest); + key_digest->Update(key, key_size); + key_digest->GetDigest(hk); + key = hk.GetData(); + key_size = hk.GetDataSize(); + delete key_digest; + } + + // compute key XOR ipad + for (unsigned int i = 0; i < key_size; i++) { + workspace[i] = key[i] ^ 0x36; + } + for (unsigned int i = key_size; i < NPT_BASIC_DIGEST_BLOCK_SIZE; i++) { + workspace[i] = 0x36; + } + + // start the inner digest with (key XOR ipad) + m_InnerDigest->Update(workspace, NPT_BASIC_DIGEST_BLOCK_SIZE); + + // compute key XOR opad + for (unsigned int i = 0; i < key_size; i++) { + workspace[i] = key[i] ^ 0x5c; + } + for (unsigned int i = key_size; i < NPT_BASIC_DIGEST_BLOCK_SIZE; i++) { + workspace[i] = 0x5c; + } + + // start the outer digest with (key XOR opad) + m_OuterDigest->Update(workspace, NPT_BASIC_DIGEST_BLOCK_SIZE); +} + +/*---------------------------------------------------------------------- +| NPT_HmacDigest::~NPT_HmacDigest ++---------------------------------------------------------------------*/ +NPT_HmacDigest::~NPT_HmacDigest() +{ + delete m_InnerDigest; + delete m_OuterDigest; +} + +/*---------------------------------------------------------------------- +| NPT_HmacDigest::GetDigest ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HmacDigest::GetDigest(NPT_DataBuffer& mac) +{ + // finish the outer digest with the value of the inner digest + NPT_DataBuffer inner; + m_InnerDigest->GetDigest(inner); + m_OuterDigest->Update(inner.GetData(), inner.GetDataSize()); + + // return the value of the outer digest + return m_OuterDigest->GetDigest(mac); +} + +/*---------------------------------------------------------------------- +| NPT_Digest::Create ++---------------------------------------------------------------------*/ +NPT_Result +NPT_Digest::Create(Algorithm algorithm, NPT_Digest*& digest) +{ + switch (algorithm) { + case ALGORITHM_SHA1: digest = new NPT_Sha1Digest(); return NPT_SUCCESS; + case ALGORITHM_SHA256: digest = new NPT_Sha256Digest(); return NPT_SUCCESS; + case ALGORITHM_MD5: digest = new NPT_Md5Digest(); return NPT_SUCCESS; + default: return NPT_ERROR_NOT_SUPPORTED; + } +} + +/*---------------------------------------------------------------------- +| NPT_Hmac::Create ++---------------------------------------------------------------------*/ +NPT_Result +NPT_Hmac::Create(NPT_Digest::Algorithm algorithm, + const NPT_UInt8* key, + NPT_Size key_size, + NPT_Digest*& digest) +{ + switch (algorithm) { + case NPT_Digest::ALGORITHM_SHA1: + case NPT_Digest::ALGORITHM_MD5: + digest = new NPT_HmacDigest(algorithm, key, key_size); + return NPT_SUCCESS; + default: return NPT_ERROR_NOT_SUPPORTED; + } +} diff --git a/lib/libUPnP/Neptune/Source/Core/NptDigest.h b/lib/libUPnP/Neptune/Source/Core/NptDigest.h new file mode 100644 index 0000000..85b744c --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptDigest.h @@ -0,0 +1,78 @@ +/***************************************************************** +| +| Neptune - Message Digests +| +| Copyright (c) 2002-2010, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +#ifndef _NPT_DIGEST_H_ +#define _NPT_DIGEST_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptTypes.h" +#include "NptDataBuffer.h" + +/*---------------------------------------------------------------------- +| NPT_Digest ++---------------------------------------------------------------------*/ +class NPT_Digest { +public: + // types + typedef enum { + ALGORITHM_SHA1, + ALGORITHM_SHA256, + ALGORITHM_MD5 + } Algorithm; + + // factory + static NPT_Result Create(Algorithm algorithm, NPT_Digest*& digest); + + // methods + virtual ~NPT_Digest() {} + virtual unsigned int GetSize() = 0; + virtual NPT_Result Update(const NPT_UInt8* data, NPT_Size data_size) = 0; + virtual NPT_Result GetDigest(NPT_DataBuffer& digest) = 0; + +protected: + NPT_Digest() {} // don't instantiate directly +}; + +class NPT_Hmac { +public: + static NPT_Result Create(NPT_Digest::Algorithm algorithm, + const NPT_UInt8* key, + NPT_Size key_size, + NPT_Digest*& digest); + +private: + // methods + NPT_Hmac() {} // don't instantiate +}; + +#endif // _NPT_DIGEST_H_ diff --git a/lib/libUPnP/Neptune/Source/Core/NptDynamicCast.h b/lib/libUPnP/Neptune/Source/Core/NptDynamicCast.h new file mode 100644 index 0000000..0acab88 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptDynamicCast.h @@ -0,0 +1,89 @@ +/***************************************************************** +| +| Neptune - Dynamic Cast Support +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +#ifndef _NPT_DYNAMIC_CAST_H_ +#define _NPT_DYNAMIC_CAST_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptTypes.h" +#include "NptCommon.h" +#include "NptResults.h" +#include "NptConfig.h" + +/*---------------------------------------------------------------------- +| macros ++---------------------------------------------------------------------*/ +#if defined(NPT_CONFIG_NO_RTTI) +#define NPT_DYNAMIC_CAST(_class,_object) \ +( ((_object)==0) ? 0 : reinterpret_cast<_class*>((_object)->DynamicCast(&_class::_class_##_class)) ) +#define NPT_IMPLEMENT_DYNAMIC_CAST(_class) \ +static int _class_##_class; \ +virtual void* DynamicCast(const void* class_anchor) { \ + if (class_anchor == &_class::_class_##_class) { \ + return static_cast<_class*>(this); \ + } \ + return NULL; \ +} +#define NPT_IMPLEMENT_DYNAMIC_CAST_D(_class,_superclass)\ +static int _class_##_class; \ +virtual void* DynamicCast(const void* class_anchor) { \ + if (class_anchor == &_class::_class_##_class) { \ + return static_cast<_class*>(this); \ + } else { \ + return _superclass::DynamicCast(class_anchor); \ + } \ +} +#define NPT_IMPLEMENT_DYNAMIC_CAST_D2(_class,_superclass,_mixin)\ +static int _class_##_class; \ +virtual void* DynamicCast(const void* class_anchor) { \ + if (class_anchor == &_class::_class_##_class) { \ + return static_cast<_class*>(this); \ + } else { \ + void* sup = _superclass::DynamicCast(class_anchor); \ + if (sup) return sup; \ + return _mixin::DynamicCast(class_anchor); \ + } \ +} +#define NPT_DEFINE_DYNAMIC_CAST_ANCHOR(_class) int _class::_class_##_class = 0; + +#else + +#define NPT_DYNAMIC_CAST(_class,_object) dynamic_cast<_class*>(_object) +#define NPT_IMPLEMENT_DYNAMIC_CAST(_class) +#define NPT_IMPLEMENT_DYNAMIC_CAST_D(_class,_superclass) +#define NPT_IMPLEMENT_DYNAMIC_CAST_D2(_class,_superclass,_mixin) +#define NPT_DEFINE_DYNAMIC_CAST_ANCHOR(_class) + +#endif + +#endif // _NPT_DYNAMIC_CAST_H_ diff --git a/lib/libUPnP/Neptune/Source/Core/NptDynamicLibraries.cpp b/lib/libUPnP/Neptune/Source/Core/NptDynamicLibraries.cpp new file mode 100644 index 0000000..556a4d8 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptDynamicLibraries.cpp @@ -0,0 +1,36 @@ +/***************************************************************** +| +| Neptune - Dynamic Libraries +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptDynamicLibraries.h" + diff --git a/lib/libUPnP/Neptune/Source/Core/NptDynamicLibraries.h b/lib/libUPnP/Neptune/Source/Core/NptDynamicLibraries.h new file mode 100644 index 0000000..50186cc --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptDynamicLibraries.h @@ -0,0 +1,84 @@ +/***************************************************************** +| +| Neptune - Dynamic Libraries +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +#ifndef _NPT_DYNAMIC_LIBRARIES_H_ +#define _NPT_DYNAMIC_LIBRARIES_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptTypes.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +#define NPT_DYANMIC_LIBRARY_LOAD_FLAG_NOW 1 + +/*---------------------------------------------------------------------- +| NPT_DynamicLibraryInterface ++---------------------------------------------------------------------*/ +class NPT_DynamicLibraryInterface +{ +public: + virtual ~NPT_DynamicLibraryInterface() {} + virtual NPT_Result FindSymbol(const char* name, void*& symbol) = 0; + virtual NPT_Result Unload() = 0; +}; + +/*---------------------------------------------------------------------- +| NPT_DynamicLibrary ++---------------------------------------------------------------------*/ +class NPT_DynamicLibrary : public NPT_DynamicLibraryInterface +{ +public: + // class methods + static NPT_Result Load(const char* name, NPT_Flags flags, NPT_DynamicLibrary*& library); + + // destructor + ~NPT_DynamicLibrary() override { delete m_Delegate; } + + // NPT_DynamicLibraryInterface methods + NPT_Result FindSymbol(const char* name, void*& symbol) override { + return m_Delegate->FindSymbol(name, symbol); + } + NPT_Result Unload() override { + return m_Delegate->Unload(); + } + +private: + // methods + NPT_DynamicLibrary(NPT_DynamicLibraryInterface* delegate) : m_Delegate(delegate) {} + + // members + NPT_DynamicLibraryInterface* m_Delegate; +}; + +#endif // _NPT_DYNAMIC_LIBRARIES_H_ diff --git a/lib/libUPnP/Neptune/Source/Core/NptFile.cpp b/lib/libUPnP/Neptune/Source/Core/NptFile.cpp new file mode 100644 index 0000000..e88e180 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptFile.cpp @@ -0,0 +1,409 @@ +/***************************************************************** +| +| Neptune - Files +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| +****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptFile.h" +#include "NptUtils.h" +#include "NptConstants.h" +#include "NptStreams.h" +#include "NptDataBuffer.h" +#include "NptLogging.h" + +/*---------------------------------------------------------------------- +| logging ++---------------------------------------------------------------------*/ +NPT_SET_LOCAL_LOGGER("neptune.file") + +/*---------------------------------------------------------------------- +| NPT_FilePath::BaseName ++---------------------------------------------------------------------*/ +NPT_String +NPT_FilePath::BaseName(const char* path, bool with_extension /* = true */) +{ + NPT_String result = path; + int separator = result.ReverseFind(Separator); + if (separator >= 0) { + result = path+separator+NPT_StringLength(Separator); + } + + if (!with_extension) { + int dot = result.ReverseFind('.'); + if (dot >= 0) { + result.SetLength(dot); + } + } + + return result; +} + +/*---------------------------------------------------------------------- +| NPT_FilePath::DirName ++---------------------------------------------------------------------*/ +NPT_String +NPT_FilePath::DirName(const char* path) +{ + NPT_String result = path; + int separator = result.ReverseFind(Separator); + if (separator >= 0) { + if (separator == 0) { + result.SetLength(NPT_StringLength(Separator)); + } else { + result.SetLength(separator); + } + } else { + result.SetLength(0); + } + + return result; +} + +/*---------------------------------------------------------------------- +| NPT_FilePath::FileExtension ++---------------------------------------------------------------------*/ +NPT_String +NPT_FilePath::FileExtension(const char* path) +{ + NPT_String result = path; + int separator = result.ReverseFind('.'); + if (separator >= 0) { + result = path+separator; + } else { + result.SetLength(0); + } + + return result; +} + +/*---------------------------------------------------------------------- +| NPT_FilePath::Create ++---------------------------------------------------------------------*/ +NPT_String +NPT_FilePath::Create(const char* directory, const char* basename) +{ + if (!directory || NPT_StringLength(directory) == 0) return basename; + if (!basename || NPT_StringLength(basename) == 0) return directory; + + NPT_String result = directory; + if (!result.EndsWith(Separator) && basename[0] != Separator[0]) { + result += Separator; + } + result += basename; + + return result; +} + +/*---------------------------------------------------------------------- +| NPT_File::CreateDir ++---------------------------------------------------------------------*/ +NPT_Result +NPT_File::CreateDir(const char* path, bool create_intermediate_dirs) +{ + NPT_String full_path = path; + + // normalize path separators + full_path.Replace((NPT_FilePath::Separator[0] == '/')?'\\':'/', NPT_FilePath::Separator); + + // remove superfluous delimiters at the end + full_path.TrimRight(NPT_FilePath::Separator); + + // create intermediate directories if needed + if (create_intermediate_dirs) { + NPT_String dir_path; + + // look for the next path separator + int separator = full_path.Find(NPT_FilePath::Separator, 1); + while (separator > 0) { + // copy the path up to the separator + dir_path = full_path.SubString(0, separator); + + // create the directory non recursively + NPT_CHECK_WARNING(NPT_File::CreateDir(dir_path, false)); + + // look for the next delimiter + separator = full_path.Find(NPT_FilePath::Separator, separator + 1); + } + } + + // create the final directory + NPT_Result result = NPT_File::CreateDir(full_path); + + // return error only if file didn't exist + if (NPT_FAILED(result) && result != NPT_ERROR_FILE_ALREADY_EXISTS) { + return result; + } + + return NPT_SUCCESS; +} + + +/*---------------------------------------------------------------------- +| NPT_File::RemoveDir ++---------------------------------------------------------------------*/ +NPT_Result +NPT_File::RemoveDir(const char* path, bool force_if_not_empty) +{ + NPT_String root_path = path; + + // normalize path separators + root_path.Replace((NPT_FilePath::Separator[0] == '/')?'\\':'/', NPT_FilePath::Separator); + + // remove superfluous delimiters at the end + root_path.TrimRight(NPT_FilePath::Separator); + + // remove all entries in the directory if required + if (force_if_not_empty) { + // enumerate all entries + NPT_File dir(root_path); + NPT_List<NPT_String> entries; + NPT_CHECK_WARNING(dir.ListDir(entries)); + for (NPT_List<NPT_String>::Iterator it = entries.GetFirstItem(); it; ++it) { + NPT_File::Remove(NPT_FilePath::Create(root_path, *it), true); + } + } + + // remove the (now empty) directory + return NPT_File::RemoveDir(root_path); +} + +/*---------------------------------------------------------------------- +| NPT_File::Load ++---------------------------------------------------------------------*/ +NPT_Result +NPT_File::Load(const char* path, NPT_DataBuffer& buffer, NPT_FileInterface::OpenMode mode) +{ + // create and open the file + NPT_File file(path); + NPT_Result result = file.Open(mode); + if (NPT_FAILED(result)) return result; + + // load the file + result = file.Load(buffer); + + // close the file + file.Close(); + + return result; +} + +/*---------------------------------------------------------------------- +| NPT_File::Load ++---------------------------------------------------------------------*/ +NPT_Result +NPT_File::Load(const char* path, NPT_String& data, NPT_FileInterface::OpenMode mode) +{ + NPT_DataBuffer buffer; + + // reset ouput params + data = ""; + + // create and open the file + NPT_File file(path); + NPT_Result result = file.Open(mode); + if (NPT_FAILED(result)) return result; + + // load the file + result = file.Load(buffer); + + if (NPT_SUCCEEDED(result) && buffer.GetDataSize() > 0) { + data.Assign((const char*)buffer.GetData(), buffer.GetDataSize()); + data.SetLength(buffer.GetDataSize()); + } + + // close the file + file.Close(); + + return result; +} + +/*---------------------------------------------------------------------- +| NPT_File::Save ++---------------------------------------------------------------------*/ +NPT_Result +NPT_File::Save(const char* filename, NPT_String& data) +{ + NPT_DataBuffer buffer(data.GetChars(), data.GetLength()); + return NPT_File::Save(filename, buffer); +} + +/*---------------------------------------------------------------------- +| NPT_File::Save ++---------------------------------------------------------------------*/ +NPT_Result +NPT_File::Save(const char* filename, const NPT_DataBuffer& buffer) +{ + // create and open the file + NPT_File file(filename); + NPT_Result result = file.Open(NPT_FILE_OPEN_MODE_WRITE | NPT_FILE_OPEN_MODE_CREATE | NPT_FILE_OPEN_MODE_TRUNCATE); + if (NPT_FAILED(result)) return result; + + // load the file + result = file.Save(buffer); + + // close the file + file.Close(); + + return result; +} + +/*---------------------------------------------------------------------- +| NPT_File::Load ++---------------------------------------------------------------------*/ +NPT_Result +NPT_File::Load(NPT_DataBuffer& buffer) +{ + NPT_InputStreamReference input; + + // get the input stream for the file + NPT_CHECK_WARNING(GetInputStream(input)); + + // read the stream + return input->Load(buffer); +} + +/*---------------------------------------------------------------------- +| NPT_File::Save ++---------------------------------------------------------------------*/ +NPT_Result +NPT_File::Save(const NPT_DataBuffer& buffer) +{ + NPT_OutputStreamReference output; + + // get the output stream for the file + NPT_CHECK_WARNING(GetOutputStream(output)); + + // write to the stream + return output->WriteFully(buffer.GetData(), buffer.GetDataSize()); +} + +/*---------------------------------------------------------------------- +| NPT_File::GetInfo ++---------------------------------------------------------------------*/ +NPT_Result +NPT_File::GetInfo(NPT_FileInfo& info) +{ + if (m_IsSpecial) { + info.m_Type = NPT_FileInfo::FILE_TYPE_SPECIAL; + info.m_Size = 0; + info.m_Attributes = 0; + info.m_AttributesMask = 0; + return NPT_SUCCESS; + } + return GetInfo(m_Path.GetChars(), &info); +} + +/*---------------------------------------------------------------------- +| NPT_File::GetSize ++---------------------------------------------------------------------*/ +NPT_Result +NPT_File::GetSize(NPT_LargeSize& size) +{ + // default value + size = 0; + + // get the file info + NPT_FileInfo info; + NPT_Result result = GetInfo(info); + if (NPT_FAILED(result)) { + return result; + } + + switch (info.m_Type) { + case NPT_FileInfo::FILE_TYPE_DIRECTORY: { + NPT_List<NPT_String> entries; + NPT_CHECK_WARNING(ListDir(entries)); + size = entries.GetItemCount(); + break; + } + + case NPT_FileInfo::FILE_TYPE_REGULAR: + case NPT_FileInfo::FILE_TYPE_OTHER: + size = info.m_Size; + return NPT_SUCCESS; + + default: + break; + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_File::GetSize ++---------------------------------------------------------------------*/ +NPT_Result +NPT_File::GetSize(const char* path, NPT_LargeSize& size) +{ + NPT_File file(path); + return file.GetSize(size); +} + +/*---------------------------------------------------------------------- +| NPT_File::Remove ++---------------------------------------------------------------------*/ +NPT_Result +NPT_File::Remove(const char* path, bool recurse /* = false */) +{ + NPT_FileInfo info; + + // make sure the path exists + NPT_CHECK_WARNING(GetInfo(path, &info)); + + if (info.m_Type == NPT_FileInfo::FILE_TYPE_DIRECTORY) { + return RemoveDir(path, recurse); + } else { + return RemoveFile(path); + } +} + +/*---------------------------------------------------------------------- +| NPT_File::Rename ++---------------------------------------------------------------------*/ +NPT_Result +NPT_File::Rename(const char* path) +{ + NPT_Result result = Rename(m_Path.GetChars(), path); + if (NPT_SUCCEEDED(result)) { + m_Path = path; + } + return result; +} + +/*---------------------------------------------------------------------- +| NPT_File::ListDir ++---------------------------------------------------------------------*/ +NPT_Result +NPT_File::ListDir(NPT_List<NPT_String>& entries) +{ + entries.Clear(); + return ListDir(m_Path.GetChars(), entries); +} diff --git a/lib/libUPnP/Neptune/Source/Core/NptFile.h b/lib/libUPnP/Neptune/Source/Core/NptFile.h new file mode 100644 index 0000000..c6b2db2 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptFile.h @@ -0,0 +1,229 @@ +/***************************************************************** +| +| Neptune - Files +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +#ifndef _NPT_FILE_H_ +#define _NPT_FILE_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptTypes.h" +#include "NptStreams.h" +#include "NptTime.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const int NPT_ERROR_NO_SUCH_FILE = NPT_ERROR_BASE_FILE - 0; +const int NPT_ERROR_FILE_NOT_OPEN = NPT_ERROR_BASE_FILE - 1; +const int NPT_ERROR_FILE_BUSY = NPT_ERROR_BASE_FILE - 2; +const int NPT_ERROR_FILE_ALREADY_OPEN = NPT_ERROR_BASE_FILE - 3; +const int NPT_ERROR_FILE_NOT_READABLE = NPT_ERROR_BASE_FILE - 4; +const int NPT_ERROR_FILE_NOT_WRITABLE = NPT_ERROR_BASE_FILE - 5; +const int NPT_ERROR_FILE_NOT_DIRECTORY = NPT_ERROR_BASE_FILE - 6; +const int NPT_ERROR_FILE_ALREADY_EXISTS = NPT_ERROR_BASE_FILE - 7; +const int NPT_ERROR_FILE_NOT_ENOUGH_SPACE = NPT_ERROR_BASE_FILE - 8; +const int NPT_ERROR_DIRECTORY_NOT_EMPTY = NPT_ERROR_BASE_FILE - 9; + +/** + * File open modes. + * Use a combination of these flags to indicate how a file should be opened + * Note all combinations of flags are valid or meaningful: + * If NPT_FILE_OPEN_MODE_WRITE is not set, then NPT_FILE_OPEN_MODE_CREATE, + * NPT_FILE_OPEN_MODE_TRUNCATE and NPT_FILE_OPEN_MODE_APPEND are ignored. + * If NPT_FILE_OPEN_MODE_APPEND is set, then NPT_FILE_OPEN_MODE_CREATE is + * automatically implied whether it is set or not. + * NPT_FILE_OPEN_MODE_CREATE and NPT_FILE_OPEN_MODE_TRUNCATE imply each + * other (if one is set, the other one is automatically implied) + */ +const unsigned int NPT_FILE_OPEN_MODE_READ = 0x01; +const unsigned int NPT_FILE_OPEN_MODE_WRITE = 0x02; +const unsigned int NPT_FILE_OPEN_MODE_CREATE = 0x04; +const unsigned int NPT_FILE_OPEN_MODE_TRUNCATE = 0x08; +const unsigned int NPT_FILE_OPEN_MODE_UNBUFFERED = 0x10; +const unsigned int NPT_FILE_OPEN_MODE_APPEND = 0x20; + +const unsigned int NPT_FILE_ATTRIBUTE_READ_ONLY = 0x01; +const unsigned int NPT_FILE_ATTRIBUTE_LINK = 0x02; + +#define NPT_FILE_STANDARD_INPUT "@STDIN" +#define NPT_FILE_STANDARD_OUTPUT "@STDOUT" +#define NPT_FILE_STANDARD_ERROR "@STDERR" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class NPT_DataBuffer; + +/*---------------------------------------------------------------------- +| NPT_FileInfo ++---------------------------------------------------------------------*/ +struct NPT_FileInfo +{ + // types + typedef enum { + FILE_TYPE_NONE, + FILE_TYPE_REGULAR, + FILE_TYPE_DIRECTORY, + FILE_TYPE_SPECIAL, + FILE_TYPE_OTHER + } FileType; + + // constructor + NPT_FileInfo() : m_Type(FILE_TYPE_NONE), m_Size(0), m_AttributesMask(0), m_Attributes(0) {} + + // members + FileType m_Type; + NPT_UInt64 m_Size; + NPT_Flags m_AttributesMask; + NPT_Flags m_Attributes; + NPT_TimeStamp m_CreationTime; + NPT_TimeStamp m_ModificationTime; +}; + +/*---------------------------------------------------------------------- +| NPT_FilePath ++---------------------------------------------------------------------*/ +class NPT_FilePath +{ +public: + // class members + static const char* const Separator; + + // class methods + static NPT_String BaseName(const char* path, bool with_extension = true); + static NPT_String DirName(const char* path); + static NPT_String FileExtension(const char* path); + static NPT_String Create(const char* directory, const char* base); + +private: + NPT_FilePath() {} // this class can't have instances +}; + +/*---------------------------------------------------------------------- +| NPT_FileInterface ++---------------------------------------------------------------------*/ +class NPT_FileInterface +{ +public: + // types + typedef unsigned int OpenMode; + + // constructors and destructor + virtual ~NPT_FileInterface() {} + + // methods + virtual NPT_Result Open(OpenMode mode) = 0; + virtual NPT_Result Close() = 0; + virtual NPT_Result GetInputStream(NPT_InputStreamReference& stream) = 0; + virtual NPT_Result GetOutputStream(NPT_OutputStreamReference& stream) = 0; +}; + +/*---------------------------------------------------------------------- +| NPT_File ++---------------------------------------------------------------------*/ +class NPT_File : public NPT_FileInterface +{ +public: + // class methods + static NPT_Result GetRoots(NPT_List<NPT_String>& roots); + static NPT_Result GetSize(const char* path, NPT_LargeSize &size); + static NPT_Result GetInfo(const char* path, NPT_FileInfo* info = NULL); + static bool Exists(const char* path) { return NPT_SUCCEEDED(GetInfo(path)); } + static NPT_Result Remove(const char* path, bool recurse = false); + static NPT_Result RemoveFile(const char* path); + static NPT_Result RemoveDir(const char* path); + static NPT_Result RemoveDir(const char* path, bool force_if_not_empty); + static NPT_Result Rename(const char* from_path, const char* to_path); + static NPT_Result ListDir(const char* path, NPT_List<NPT_String>& entries, NPT_Ordinal start = 0, NPT_Cardinal count = 0); + static NPT_Result CreateDir(const char* path); + static NPT_Result CreateDir(const char* path, bool create_intermediate_dirs); + static NPT_Result GetWorkingDir(NPT_String& path); + static NPT_Result Load(const char* path, NPT_DataBuffer& buffer, NPT_FileInterface::OpenMode mode = NPT_FILE_OPEN_MODE_READ); + static NPT_Result Load(const char* path, NPT_String& data, NPT_FileInterface::OpenMode mode = NPT_FILE_OPEN_MODE_READ); + static NPT_Result Save(const char* path, NPT_String& data); + static NPT_Result Save(const char* path, const NPT_DataBuffer& buffer); + + // constructors and destructor + NPT_File(const char* path); + ~NPT_File() override { delete m_Delegate; } + + // methods + NPT_Result Load(NPT_DataBuffer& buffer); + NPT_Result Save(const NPT_DataBuffer& buffer); + const NPT_String& GetPath() { return m_Path; } + NPT_Result GetSize(NPT_LargeSize &size); + NPT_Result GetInfo(NPT_FileInfo& info); + NPT_Result ListDir(NPT_List<NPT_String>& entries); + NPT_Result Rename(const char* path); + + // NPT_FileInterface methods + NPT_Result Open(OpenMode mode) override { + return m_Delegate->Open(mode); + } + NPT_Result Close() override { + return m_Delegate->Close(); + } + NPT_Result GetInputStream(NPT_InputStreamReference& stream) override { + return m_Delegate->GetInputStream(stream); + } + NPT_Result GetOutputStream(NPT_OutputStreamReference& stream) override { + return m_Delegate->GetOutputStream(stream); + } + + // operators + NPT_File& operator=(const NPT_File& file); + +protected: + // members + NPT_FileInterface* m_Delegate; + NPT_String m_Path; + bool m_IsSpecial; +}; + +/*---------------------------------------------------------------------- +| NPT_FileDateComparator ++---------------------------------------------------------------------*/ +class NPT_FileDateComparator { +public: + NPT_FileDateComparator(const char* directory) : m_Directory(directory) {} + NPT_Int32 operator()(const NPT_String& file1, const NPT_String& file2) const { + NPT_FileInfo info1, info2; + if (NPT_FAILED(NPT_File::GetInfo(NPT_FilePath::Create(m_Directory, file1), &info1))) return -1; + if (NPT_FAILED(NPT_File::GetInfo(NPT_FilePath::Create(m_Directory, file2), &info2))) return -1; + return (info1.m_ModificationTime == info2.m_ModificationTime) ? 0 : (info1.m_ModificationTime < info2.m_ModificationTime ? -1 : 1); + } + +private: + NPT_String m_Directory; +}; + +#endif // _NPT_FILE_H_ diff --git a/lib/libUPnP/Neptune/Source/Core/NptHash.cpp b/lib/libUPnP/Neptune/Source/Core/NptHash.cpp new file mode 100644 index 0000000..05d6aa4 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptHash.cpp @@ -0,0 +1,137 @@ +/***************************************************************** +| +| Neptune - Hashing +| +| Copyright (c) 2002-2010, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| +****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptTypes.h" +#include "NptResults.h" +#include "NptHash.h" + +/*---------------------------------------------------------------------- +| local constants ++---------------------------------------------------------------------*/ +// 32 bit magic FNV-1a prime +const NPT_UInt32 NPT_FNV_32_PRIME = 0x01000193; + +/*---------------------------------------------------------------------- +| NPT_Fnv1aHash32 ++---------------------------------------------------------------------*/ +NPT_UInt32 +NPT_Fnv1aHash32(const NPT_UInt8* data, NPT_Size data_size, NPT_UInt32 hash_init) +{ + const NPT_UInt8* data_end = data + data_size; + NPT_UInt32 hash_value = hash_init; + + while (data < data_end) { + hash_value ^= (NPT_UInt32)*data++; + +#if defined(NPT_CONFIG_FNV_HASH_USE_SHIFT_MUL) + hash_value += (hash_value<<1) + (hash_value<<4) + (hash_value<<7) + (hash_value<<8) + (hash_value<<24); +#else + hash_value *= NPT_FNV_32_PRIME; +#endif + } + + return hash_value; +} + + +/*---------------------------------------------------------------------- +| NPT_Fnv1aHashStr32 ++---------------------------------------------------------------------*/ +NPT_UInt32 +NPT_Fnv1aHashStr32(const char* data, NPT_UInt32 hash_init) +{ + NPT_UInt32 hash_value = hash_init; + + while (*data) { + hash_value ^= (NPT_UInt32)*data++; + +#if defined(NPT_CONFIG_FNV_HASH_USE_SHIFT_MUL) + hash_value += (hash_value<<1) + (hash_value<<4) + (hash_value<<7) + (hash_value<<8) + (hash_value<<24); +#else + hash_value *= NPT_FNV_32_PRIME; +#endif + } + + return hash_value; +} + +/*---------------------------------------------------------------------- +| NPT_FnvHash32 ++---------------------------------------------------------------------*/ +// 64 bit magic FNV-1a prime +const NPT_UInt64 NPT_FNV_64_PRIME = 0x100000001b3ULL; + +/*---------------------------------------------------------------------- +| NPT_Fnv1aHash64 ++---------------------------------------------------------------------*/ +NPT_UInt64 +NPT_Fnv1aHash64(const NPT_UInt8* data, NPT_Size data_size, NPT_UInt64 hash_init) +{ + const NPT_UInt8* data_end = data + data_size; + NPT_UInt64 hash_value = hash_init; + + while (data < data_end) { + hash_value ^= (NPT_UInt64)*data++; + +#if defined(NPT_CONFIG_FNV_HASH_USE_SHIFT_MUL) + hash_value += (hash_value << 1) + (hash_value << 4) + (hash_value << 5) + (hash_value << 7) + (hash_value << 8) + (hash_value << 40); +#else + hash_value *= NPT_FNV_64_PRIME; +#endif + } + + return hash_value; +} + + +/*---------------------------------------------------------------------- +| NPT_Fnv1aHashStr64 ++---------------------------------------------------------------------*/ +NPT_UInt64 +NPT_Fnv1aHashStr64(const char* data, NPT_UInt64 hash_init) +{ + NPT_UInt64 hash_value = hash_init; + + while (*data) { + hash_value ^= (NPT_UInt64)*data++; + +#if defined(NPT_CONFIG_FNV_HASH_USE_SHIFT_MUL) + hash_value += (hash_value << 1) + (hash_value << 4) + (hash_value << 5) + (hash_value << 7) + (hash_value << 8) + (hash_value << 40); +#else + hash_value *= NPT_FNV_64_PRIME; +#endif + } + + return hash_value; +} diff --git a/lib/libUPnP/Neptune/Source/Core/NptHash.h b/lib/libUPnP/Neptune/Source/Core/NptHash.h new file mode 100644 index 0000000..d7b8776 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptHash.h @@ -0,0 +1,83 @@ +/***************************************************************** +| +| Neptune - Hashing +| +| Copyright (c) 2002-2010, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| +****************************************************************/ + +#ifndef _NPT_HASH_H_ +#define _NPT_HASH_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptTypes.h" +#include "NptResults.h" + +/*---------------------------------------------------------------------- +| Fowler/Noll/Vo FNV-1a hash functions ++---------------------------------------------------------------------*/ +const NPT_UInt32 NPT_FNV1A_32_INIT = ((NPT_UInt32)0x811c9dc5); +NPT_UInt32 NPT_Fnv1aHash32(const NPT_UInt8* data, NPT_Size data_size, NPT_UInt32 hash_init=NPT_FNV1A_32_INIT); +NPT_UInt32 NPT_Fnv1aHashStr32(const char* data, NPT_UInt32 hash_init=NPT_FNV1A_32_INIT); +const NPT_UInt64 NPT_FNV1A_64_INIT = ((NPT_UInt64)0xcbf29ce484222325ULL); +NPT_UInt64 NPT_Fnv1aHash64(const NPT_UInt8* data, NPT_Size data_size, NPT_UInt64 hash_init=NPT_FNV1A_64_INIT); +NPT_UInt64 NPT_Fnv1aHashStr64(const char* data, NPT_UInt64 hash_init=NPT_FNV1A_64_INIT); + +/*---------------------------------------------------------------------- +| NPT_Hash ++---------------------------------------------------------------------*/ +template <typename K> +struct NPT_Hash +{ +}; + +template <> +struct NPT_Hash<const char*> +{ + NPT_UInt32 operator()(const char* s) const { return NPT_Fnv1aHashStr32(s); } +}; + +template <> +struct NPT_Hash<char*> +{ + NPT_UInt32 operator()(char* s) const { return NPT_Fnv1aHashStr32(s); } +}; + +template <> +struct NPT_Hash<int> +{ + NPT_UInt32 operator()(int i) const { return NPT_Fnv1aHash32(reinterpret_cast<const NPT_UInt8*>(&i), sizeof(int)); } +}; + +template <> +struct NPT_Hash<unsigned int> +{ + NPT_UInt32 operator()(unsigned int i) const { return NPT_Fnv1aHash32(reinterpret_cast<const NPT_UInt8*>(&i), sizeof(int)); } +}; + +#endif // _NPT_HASH_H_ diff --git a/lib/libUPnP/Neptune/Source/Core/NptHttp.cpp b/lib/libUPnP/Neptune/Source/Core/NptHttp.cpp new file mode 100644 index 0000000..db2c507 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptHttp.cpp @@ -0,0 +1,3483 @@ +/***************************************************************** +| +| Neptune - HTTP Protocol +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptHttp.h" +#include "NptSockets.h" +#include "NptBufferedStreams.h" +#include "NptDebug.h" +#include "NptVersion.h" +#include "NptUtils.h" +#include "NptFile.h" +#include "NptSystem.h" +#include "NptLogging.h" +#include "NptTls.h" +#include "NptStreams.h" + +/*---------------------------------------------------------------------- +| logging ++---------------------------------------------------------------------*/ +NPT_SET_LOCAL_LOGGER("neptune.http") + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const char* const NPT_HTTP_DEFAULT_403_HTML = "<html><head><title>403 Forbidden</title></head><body><h1>Forbidden</h1><p>Access to this URL is forbidden.</p></html>"; +const char* const NPT_HTTP_DEFAULT_404_HTML = "<html><head><title>404 Not Found</title></head><body><h1>Not Found</h1><p>The requested URL was not found on this server.</p></html>"; +const char* const NPT_HTTP_DEFAULT_500_HTML = "<html><head><title>500 Internal Error</title></head><body><h1>Internal Error</h1><p>The server encountered an unexpected condition which prevented it from fulfilling the request.</p></html>"; + +/*---------------------------------------------------------------------- +| NPT_HttpUrl::NPT_HttpUrl ++---------------------------------------------------------------------*/ +NPT_HttpUrl::NPT_HttpUrl(const char* url, bool ignore_scheme) : + NPT_Url(url) +{ + if (!ignore_scheme) { + if (GetSchemeId() != NPT_Uri::SCHEME_ID_HTTP && + GetSchemeId() != NPT_Uri::SCHEME_ID_HTTPS) { + Reset(); + } + } +} + +/*---------------------------------------------------------------------- +| NPT_HttpUrl::NPT_HttpUrl ++---------------------------------------------------------------------*/ +NPT_HttpUrl::NPT_HttpUrl(const char* host, + NPT_UInt16 port, + const char* path, + const char* query, + const char* fragment) : + NPT_Url("http", host, port, path, query, fragment) +{ +} + +/*---------------------------------------------------------------------- +| NPT_HttpUrl::ToString ++---------------------------------------------------------------------*/ +NPT_String +NPT_HttpUrl::ToString(bool with_fragment) const +{ + NPT_UInt16 default_port; + switch (m_SchemeId) { + case SCHEME_ID_HTTP: default_port = NPT_HTTP_DEFAULT_PORT; break; + case SCHEME_ID_HTTPS: default_port = NPT_HTTPS_DEFAULT_PORT; break; + default: default_port = 0; + } + return NPT_Url::ToStringWithDefaultPort(default_port, with_fragment); +} + +/*---------------------------------------------------------------------- +| NPT_HttpHeader::NPT_HttpHeader ++---------------------------------------------------------------------*/ +NPT_HttpHeader::NPT_HttpHeader(const char* name, const char* value): + m_Name(name), + m_Value(value) +{ +} + +/*---------------------------------------------------------------------- +| NPT_HttpHeader::~NPT_HttpHeader ++---------------------------------------------------------------------*/ +NPT_HttpHeader::~NPT_HttpHeader() +{ +} + +/*---------------------------------------------------------------------- +| NPT_HttpHeader::Emit ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpHeader::Emit(NPT_OutputStream& stream) const +{ + stream.WriteString(m_Name); + stream.WriteFully(": ", 2); + stream.WriteString(m_Value); + stream.WriteFully(NPT_HTTP_LINE_TERMINATOR, 2); + NPT_LOG_FINEST_2("header %s: %s", m_Name.GetChars(), m_Value.GetChars()); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpHeader::SetName ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpHeader::SetName(const char* name) +{ + m_Name = name; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpHeader::~NPT_HttpHeader ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpHeader::SetValue(const char* value) +{ + m_Value = value; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpHeaders::NPT_HttpHeaders ++---------------------------------------------------------------------*/ +NPT_HttpHeaders::NPT_HttpHeaders() +{ +} + +/*---------------------------------------------------------------------- +| NPT_HttpHeaders::~NPT_HttpHeaders ++---------------------------------------------------------------------*/ +NPT_HttpHeaders::~NPT_HttpHeaders() +{ + m_Headers.Apply(NPT_ObjectDeleter<NPT_HttpHeader>()); +} + +/*---------------------------------------------------------------------- +| NPT_HttpHeaders::Parse ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpHeaders::Parse(NPT_BufferedInputStream& stream) +{ + NPT_String header_name; + NPT_String header_value; + bool header_pending = false; + NPT_String line; + + while (NPT_SUCCEEDED(stream.ReadLine(line, NPT_HTTP_PROTOCOL_MAX_LINE_LENGTH))) { + if (line.GetLength() == 0) { + // empty line, end of headers + break; + } + if (header_pending && (line[0] == ' ' || line[0] == '\t')) { + // continuation (folded header) + header_value.Append(line.GetChars()+1, line.GetLength()-1); + } else { + // add the pending header to the list + if (header_pending) { + header_value.Trim(); + AddHeader(header_name, header_value); + header_pending = false; + NPT_LOG_FINEST_2("header - %s: %s", + header_name.GetChars(), + header_value.GetChars()); + } + + // find the colon separating the name and the value + int colon_index = line.Find(':'); + if (colon_index < 1) { + // invalid syntax, ignore + continue; + } + header_name = line.Left(colon_index); + + // the field value starts at the first non-whitespace + const char* value = line.GetChars()+colon_index+1; + while (*value == ' ' || *value == '\t') { + value++; + } + header_value = value; + + // the header is pending + header_pending = true; + } + } + + // if we have a header pending, add it now + if (header_pending) { + header_value.Trim(); + AddHeader(header_name, header_value); + NPT_LOG_FINEST_2("header %s: %s", + header_name.GetChars(), + header_value.GetChars()); + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpHeaders::Emit ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpHeaders::Emit(NPT_OutputStream& stream) const +{ + // for each header in the list + NPT_List<NPT_HttpHeader*>::Iterator header = m_Headers.GetFirstItem(); + while (header) { + // emit the header + NPT_CHECK_WARNING((*header)->Emit(stream)); + ++header; + } + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpHeaders::GetHeader ++---------------------------------------------------------------------*/ +NPT_HttpHeader* +NPT_HttpHeaders::GetHeader(const char* name) const +{ + // check args + if (name == NULL) return NULL; + + // find a matching header + NPT_List<NPT_HttpHeader*>::Iterator header = m_Headers.GetFirstItem(); + while (header) { + if ((*header)->GetName().Compare(name, true) == 0) { + return *header; + } + ++header; + } + + // not found + return NULL; +} + +/*---------------------------------------------------------------------- +| NPT_HttpHeaders::AddHeader ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpHeaders::AddHeader(const char* name, const char* value) +{ + return m_Headers.Add(new NPT_HttpHeader(name, value)); +} + +/*---------------------------------------------------------------------- +| NPT_HttpHeaders::RemoveHeader ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpHeaders::RemoveHeader(const char* name) +{ + bool found = false; + + NPT_HttpHeader* header = NULL; + while ((header = GetHeader(name))) { + m_Headers.Remove(header); + delete header; + found = true; + } + return found?NPT_SUCCESS:NPT_ERROR_NO_SUCH_ITEM; +} + +/*---------------------------------------------------------------------- +| NPT_HttpHeaders::SetHeader ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpHeaders::SetHeader(const char* name, const char* value, bool replace) +{ + NPT_HttpHeader* header = GetHeader(name); + if (header == NULL) { + return AddHeader(name, value); + } else if (replace) { + return header->SetValue(value); + } else { + return NPT_SUCCESS; + } +} + +/*---------------------------------------------------------------------- +| NPT_HttpHeaders::GetHeaderValue ++---------------------------------------------------------------------*/ +const NPT_String* +NPT_HttpHeaders::GetHeaderValue(const char* name) const +{ + NPT_HttpHeader* header = GetHeader(name); + if (header == NULL) { + return NULL; + } else { + return &header->GetValue(); + } +} + +/*---------------------------------------------------------------------- +| NPT_HttpEntityBodyInputStream ++---------------------------------------------------------------------*/ +class NPT_HttpEntityBodyInputStream : public NPT_InputStream +{ +public: + // constructor and desctructor + NPT_HttpEntityBodyInputStream(NPT_BufferedInputStreamReference& source, + NPT_LargeSize size, + bool size_is_known, + bool chunked, + NPT_HttpClient::Connection* connection, + bool should_persist); + ~NPT_HttpEntityBodyInputStream() override; + + // methods + bool SizeIsKnown() { return m_SizeIsKnown; } + + // NPT_InputStream methods + NPT_Result Read(void* buffer, + NPT_Size bytes_to_read, + NPT_Size* bytes_read = NULL) override; + NPT_Result Seek(NPT_Position /*offset*/) override { + return NPT_ERROR_NOT_SUPPORTED; + } + NPT_Result Tell(NPT_Position& offset) override { + offset = m_Position; + return NPT_SUCCESS; + } + NPT_Result GetSize(NPT_LargeSize& size) override { + size = m_Size; + return NPT_SUCCESS; + } + NPT_Result GetAvailable(NPT_LargeSize& available) override; + +private: + // methods + virtual void OnFullyRead(); + + // members + NPT_LargeSize m_Size; + bool m_SizeIsKnown; + bool m_Chunked; + NPT_HttpClient::Connection* m_Connection; + bool m_ShouldPersist; + NPT_Position m_Position; + NPT_InputStreamReference m_Source; +}; + +/*---------------------------------------------------------------------- +| NPT_HttpEntityBodyInputStream::NPT_HttpEntityBodyInputStream ++---------------------------------------------------------------------*/ +NPT_HttpEntityBodyInputStream::NPT_HttpEntityBodyInputStream( + NPT_BufferedInputStreamReference& source, + NPT_LargeSize size, + bool size_is_known, + bool chunked, + NPT_HttpClient::Connection* connection, + bool should_persist) : + m_Size(size), + m_SizeIsKnown(size_is_known), + m_Chunked(chunked), + m_Connection(connection), + m_ShouldPersist(should_persist), + m_Position(0) +{ + if (size_is_known && size == 0) { + OnFullyRead(); + } else { + if (chunked) { + m_Source = NPT_InputStreamReference(new NPT_HttpChunkedInputStream(source)); + } else { + m_Source = source; + } + } +} + +/*---------------------------------------------------------------------- +| NPT_HttpEntityBodyInputStream::~NPT_HttpEntityBodyInputStream ++---------------------------------------------------------------------*/ +NPT_HttpEntityBodyInputStream::~NPT_HttpEntityBodyInputStream() +{ + delete m_Connection; +} + +/*---------------------------------------------------------------------- +| NPT_HttpEntityBodyInputStream::OnFullyRead ++---------------------------------------------------------------------*/ +void +NPT_HttpEntityBodyInputStream::OnFullyRead() +{ + m_Source = NULL; + if (m_Connection && m_ShouldPersist) { + m_Connection->Recycle(); + m_Connection = NULL; + } +} + +/*---------------------------------------------------------------------- +| NPT_HttpEntityBodyInputStream::Read ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpEntityBodyInputStream::Read(void* buffer, + NPT_Size bytes_to_read, + NPT_Size* bytes_read) +{ + if (bytes_read) *bytes_read = 0; + + // return now if we've already reached the end + if (m_Source.IsNull()) return NPT_ERROR_EOS; + + // clamp to the max possible read size + if (!m_Chunked && m_SizeIsKnown) { + NPT_LargeSize max_can_read = m_Size-m_Position; + if (max_can_read == 0) return NPT_ERROR_EOS; + if (bytes_to_read > max_can_read) bytes_to_read = (NPT_Size)max_can_read; + } + + // read from the source + NPT_Size source_bytes_read = 0; + NPT_Result result = m_Source->Read(buffer, bytes_to_read, &source_bytes_read); + if (NPT_SUCCEEDED(result)) { + m_Position += source_bytes_read; + if (bytes_read) *bytes_read = source_bytes_read; + } + + // check if we've reached the end + if (result == NPT_ERROR_EOS || (m_SizeIsKnown && (m_Position == m_Size))) { + OnFullyRead(); + } + + return result; +} + +/*---------------------------------------------------------------------- +| NPT_HttpEntityBodyInputStream::GetAvaialble ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpEntityBodyInputStream::GetAvailable(NPT_LargeSize& available) +{ + if (m_Source.IsNull()) { + available = 0; + return NPT_SUCCESS; + } + NPT_Result result = m_Source->GetAvailable(available); + if (NPT_FAILED(result)) { + available = 0; + return result; + } + if (available > m_Size-m_Position) { + available = m_Size-m_Position; + } + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpEntity::NPT_HttpEntity ++---------------------------------------------------------------------*/ +NPT_HttpEntity::NPT_HttpEntity() : + m_ContentLength(0), + m_ContentLengthIsKnown(false) +{ +} + +/*---------------------------------------------------------------------- +| NPT_HttpEntity::NPT_HttpEntity ++---------------------------------------------------------------------*/ +NPT_HttpEntity::NPT_HttpEntity(const NPT_HttpHeaders& headers) : + m_ContentLength(0), + m_ContentLengthIsKnown(false) +{ + SetHeaders(headers); +} + +/*---------------------------------------------------------------------- +| NPT_HttpEntity::SetHeaders ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpEntity::SetHeaders(const NPT_HttpHeaders& headers) +{ + NPT_HttpHeader* header; + + // Content-Length + header = headers.GetHeader(NPT_HTTP_HEADER_CONTENT_LENGTH); + if (header != NULL) { + m_ContentLengthIsKnown = true; + NPT_LargeSize length; + if (NPT_SUCCEEDED(header->GetValue().ToInteger64(length))) { + m_ContentLength = length; + } else { + m_ContentLength = 0; + } + } + + // Content-Type + header = headers.GetHeader(NPT_HTTP_HEADER_CONTENT_TYPE); + if (header != NULL) { + m_ContentType = header->GetValue(); + } + + // Content-Encoding + header = headers.GetHeader(NPT_HTTP_HEADER_CONTENT_ENCODING); + if (header != NULL) { + m_ContentEncoding = header->GetValue(); + } + + // Transfer-Encoding + header = headers.GetHeader(NPT_HTTP_HEADER_TRANSFER_ENCODING); + if (header != NULL) { + m_TransferEncoding = header->GetValue(); + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpEntity::~NPT_HttpEntity ++---------------------------------------------------------------------*/ +NPT_HttpEntity::~NPT_HttpEntity() +{ +} + +/*---------------------------------------------------------------------- +| NPT_HttpEntity::GetInputStream ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpEntity::GetInputStream(NPT_InputStreamReference& stream) +{ + // reset output params first + stream = NULL; + + if (m_InputStream.IsNull()) return NPT_FAILURE; + + stream = m_InputStream; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpEntity::SetInputStream ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpEntity::SetInputStream(const NPT_InputStreamReference& stream, + bool update_content_length /* = false */) +{ + m_InputStream = stream; + + // get the content length from the stream + if (update_content_length && !stream.IsNull()) { + NPT_LargeSize length; + if (NPT_SUCCEEDED(stream->GetSize(length))) { + return SetContentLength(length); + } + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpEntity::SetInputStream ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpEntity::SetInputStream(const void* data, NPT_Size data_size) +{ + NPT_MemoryStream* memory_stream = new NPT_MemoryStream(data, data_size); + NPT_InputStreamReference body(memory_stream); + return SetInputStream(body, true); +} + +/*---------------------------------------------------------------------- +| NPT_HttpEntity::SetInputStream ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpEntity::SetInputStream(const char* string) +{ + if (string == NULL) return NPT_ERROR_INVALID_PARAMETERS; + NPT_MemoryStream* memory_stream = new NPT_MemoryStream((const void*)string, + NPT_StringLength(string)); + NPT_InputStreamReference body(memory_stream); + return SetInputStream(body, true); +} + +/*---------------------------------------------------------------------- +| NPT_HttpEntity::SetInputStream ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpEntity::SetInputStream(const NPT_String& string) +{ + NPT_MemoryStream* memory_stream = new NPT_MemoryStream((const void*)string.GetChars(), + string.GetLength()); + NPT_InputStreamReference body(memory_stream); + return SetInputStream(body, true); +} + +/*---------------------------------------------------------------------- +| NPT_HttpEntity::Load ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpEntity::Load(NPT_DataBuffer& buffer) +{ + // check that we have an input stream + if (m_InputStream.IsNull()) return NPT_ERROR_INVALID_STATE; + + // load the stream into the buffer + if (m_ContentLength != (NPT_Size)m_ContentLength) return NPT_ERROR_OUT_OF_RANGE; + return m_InputStream->Load(buffer, (NPT_Size)m_ContentLength); +} + +/*---------------------------------------------------------------------- +| NPT_HttpEntity::SetContentLength ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpEntity::SetContentLength(NPT_LargeSize length) +{ + m_ContentLength = length; + m_ContentLengthIsKnown = true; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpEntity::SetContentType ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpEntity::SetContentType(const char* type) +{ + m_ContentType = type; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpEntity::SetContentEncoding ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpEntity::SetContentEncoding(const char* encoding) +{ + m_ContentEncoding = encoding; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpEntity::SetTransferEncoding ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpEntity::SetTransferEncoding(const char* encoding) +{ + m_TransferEncoding = encoding; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpMessage::NPT_HttpMessage ++---------------------------------------------------------------------*/ +NPT_HttpMessage::NPT_HttpMessage(const char* protocol) : + m_Protocol(protocol), + m_Entity(NULL) +{ +} + +/*---------------------------------------------------------------------- +| NPT_HttpMessage::NPT_HttpMessage ++---------------------------------------------------------------------*/ +NPT_HttpMessage::~NPT_HttpMessage() +{ + delete m_Entity; +} + +/*---------------------------------------------------------------------- +| NPT_HttpMessage::SetEntity ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpMessage::SetEntity(NPT_HttpEntity* entity) +{ + if (entity != m_Entity) { + delete m_Entity; + m_Entity = entity; + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpMessage::ParseHeaders ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpMessage::ParseHeaders(NPT_BufferedInputStream& stream) +{ + return m_Headers.Parse(stream); +} + +/*---------------------------------------------------------------------- +| NPT_HttpRequest::NPT_HttpRequest ++---------------------------------------------------------------------*/ +NPT_HttpRequest::NPT_HttpRequest(const NPT_HttpUrl& url, + const char* method, + const char* protocol) : + NPT_HttpMessage(protocol), + m_Url(url), + m_Method(method) +{ +} + +/*---------------------------------------------------------------------- +| NPT_HttpRequest::NPT_HttpRequest ++---------------------------------------------------------------------*/ +NPT_HttpRequest::NPT_HttpRequest(const char* url, + const char* method, + const char* protocol) : + NPT_HttpMessage(protocol), + m_Url(url), + m_Method(method) +{ +} + +/*---------------------------------------------------------------------- +| NPT_HttpRequest::SetUrl ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpRequest::SetUrl(const char* url) +{ + m_Url = url; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpRequest::SetUrl ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpRequest::SetUrl(const NPT_HttpUrl& url) +{ + m_Url = url; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpRequest::Parse ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpRequest::Parse(NPT_BufferedInputStream& stream, + const NPT_SocketAddress* endpoint, + NPT_HttpRequest*& request) +{ + // default return value + request = NULL; + +skip_first_empty_line: + // read the request line + NPT_String line; + NPT_CHECK_FINER(stream.ReadLine(line, NPT_HTTP_PROTOCOL_MAX_LINE_LENGTH)); + NPT_LOG_FINEST_1("http request: %s", line.GetChars()); + + // cleanup lines that may contain '\0' as first character, clients such + // Spotify desktop app send SSDP M-SEARCH requests followed by an extra + // '\0' character which stays in the buffered stream and messes up parsing + // the next request. + while (line.GetLength() > 0 && line[0] == '\0') { + line = line.Erase(0, 1); + } + + // when using keep-alive connections, clients such as XBox 360 + // incorrectly send a few empty lines as body for GET requests + // so we try to skip them until we find something to parse + if (line.GetLength() == 0) goto skip_first_empty_line; + + // check the request line + int first_space = line.Find(' '); + if (first_space < 0) { + NPT_LOG_FINE_1("http request: %s", line.GetChars()); + return NPT_ERROR_HTTP_INVALID_REQUEST_LINE; + } + int second_space = line.Find(' ', first_space+1); + if (second_space < 0) { + NPT_LOG_FINE_1("http request: %s", line.GetChars()); + return NPT_ERROR_HTTP_INVALID_REQUEST_LINE; + } + + // parse the request line + NPT_String method = line.SubString(0, first_space); + NPT_String uri = line.SubString(first_space+1, second_space-first_space-1); + NPT_String protocol = line.SubString(second_space+1); + + // create a request + bool proxy_style_request = false; + if (uri.StartsWith("http://", true)) { + // proxy-style request with absolute URI + request = new NPT_HttpRequest(uri, method, protocol); + proxy_style_request = true; + } else { + // normal absolute path request + request = new NPT_HttpRequest("http:", method, protocol); + } + + // parse headers + NPT_Result result = request->ParseHeaders(stream); + if (NPT_FAILED(result)) { + delete request; + request = NULL; + return result; + } + + // update the URL + if (!proxy_style_request) { + request->m_Url.SetScheme("http"); + request->m_Url.ParsePathPlus(uri); + request->m_Url.SetPort(NPT_HTTP_DEFAULT_PORT); + + // check for a Host: header + NPT_HttpHeader* host_header = request->GetHeaders().GetHeader(NPT_HTTP_HEADER_HOST); + if (host_header) { + request->m_Url.SetHost(host_header->GetValue()); + + // host sometimes doesn't contain port + if (endpoint) { + request->m_Url.SetPort(endpoint->GetPort()); + } + } else { + // use the endpoint as the host + if (endpoint) { + request->m_Url.SetHost(endpoint->ToString()); + } else { + // use defaults + request->m_Url.SetHost("localhost"); + } + } + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpRequest::~NPT_HttpRequest ++---------------------------------------------------------------------*/ +NPT_HttpRequest::~NPT_HttpRequest() +{ +} + +/*---------------------------------------------------------------------- +| NPT_HttpRequest::Emit ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpRequest::Emit(NPT_OutputStream& stream, bool use_proxy) const +{ + // write the request line + stream.WriteString(m_Method); + stream.WriteFully(" ", 1); + if (use_proxy) { + stream.WriteString(m_Url.ToString(false)); + } else { + stream.WriteString(m_Url.ToRequestString()); + } + stream.WriteFully(" ", 1); + stream.WriteString(m_Protocol); + stream.WriteFully(NPT_HTTP_LINE_TERMINATOR, 2); + + // emit headers + m_Headers.Emit(stream); + + // finish with an empty line + stream.WriteFully(NPT_HTTP_LINE_TERMINATOR, 2); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpResponse::NPT_HttpResponse ++---------------------------------------------------------------------*/ +NPT_HttpResponse::NPT_HttpResponse(NPT_HttpStatusCode status_code, + const char* reason_phrase, + const char* protocol) : + NPT_HttpMessage(protocol), + m_StatusCode(status_code), + m_ReasonPhrase(reason_phrase) +{ +} + +/*---------------------------------------------------------------------- +| NPT_HttpResponse::~NPT_HttpResponse ++---------------------------------------------------------------------*/ +NPT_HttpResponse::~NPT_HttpResponse() +{ +} + +/*---------------------------------------------------------------------- +| NPT_HttpResponse::SetStatus ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpResponse::SetStatus(NPT_HttpStatusCode status_code, + const char* reason_phrase, + const char* protocol) +{ + m_StatusCode = status_code; + m_ReasonPhrase = reason_phrase; + if (protocol) m_Protocol = protocol; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpResponse::SetProtocol ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpResponse::SetProtocol(const char* protocol) +{ + m_Protocol = protocol; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpResponse::Emit ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpResponse::Emit(NPT_OutputStream& stream) const +{ + // write the request line + stream.WriteString(m_Protocol); + stream.WriteFully(" ", 1); + stream.WriteString(NPT_String::FromInteger(m_StatusCode)); + stream.WriteFully(" ", 1); + stream.WriteString(m_ReasonPhrase); + stream.WriteFully(NPT_HTTP_LINE_TERMINATOR, 2); + + // emit headers + m_Headers.Emit(stream); + + // finish with an empty line + stream.WriteFully(NPT_HTTP_LINE_TERMINATOR, 2); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpResponse::Parse ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpResponse::Parse(NPT_BufferedInputStream& stream, + NPT_HttpResponse*& response) +{ + // default return value + response = NULL; + + // read the response line + NPT_String line; + NPT_CHECK_WARNING(stream.ReadLine(line, NPT_HTTP_PROTOCOL_MAX_LINE_LENGTH)); + + NPT_LOG_FINER_1("http response: %s", line.GetChars()); + + // check the response line + // we are lenient here, as we allow the response to deviate slightly from + // strict HTTP (for example, ICY servers response with a method equal to + // ICY insead of HTTP/1.X) + int first_space = line.Find(' '); + if (first_space < 1) return NPT_ERROR_HTTP_INVALID_RESPONSE_LINE; + int second_space = line.Find(' ', first_space+1); + if (second_space < 0) { + // some servers omit (incorrectly) the space and Reason-Code + // but we don't fail them just for that. Just check that the + // status code looks ok + if (line.GetLength() != 12) { + return NPT_ERROR_HTTP_INVALID_RESPONSE_LINE; + } + } else if (second_space-first_space != 4) { + // the status code is not of length 3 + return NPT_ERROR_HTTP_INVALID_RESPONSE_LINE; + } + + // parse the response line + NPT_String protocol = line.SubString(0, first_space); + NPT_String status_code = line.SubString(first_space+1, 3); + NPT_String reason_phrase = line.SubString(first_space+1+3+1, + line.GetLength()-(first_space+1+3+1)); + + // create a response object + NPT_UInt32 status_code_int = 0; + status_code.ToInteger(status_code_int); + response = new NPT_HttpResponse(status_code_int, reason_phrase, protocol); + + // parse headers + NPT_Result result = response->ParseHeaders(stream); + if (NPT_FAILED(result)) { + delete response; + response = NULL; + } + + return result; +} + +/*---------------------------------------------------------------------- +| NPT_HttpEnvProxySelector ++---------------------------------------------------------------------*/ +class NPT_HttpEnvProxySelector : public NPT_HttpProxySelector, + public NPT_AutomaticCleaner::Singleton +{ +public: + static NPT_HttpEnvProxySelector* GetInstance(); + + // NPT_HttpProxySelector methods + NPT_Result GetProxyForUrl(const NPT_HttpUrl& url, NPT_HttpProxyAddress& proxy) override; + +private: + // class variables + static NPT_HttpEnvProxySelector* Instance; + + // class methods + static void ParseProxyEnv(const NPT_String& env, NPT_HttpProxyAddress& proxy); + + // members + NPT_HttpProxyAddress m_HttpProxy; + NPT_HttpProxyAddress m_HttpsProxy; + NPT_List<NPT_String> m_NoProxy; + NPT_HttpProxyAddress m_AllProxy; +}; +NPT_HttpEnvProxySelector* NPT_HttpEnvProxySelector::Instance = NULL; + +/*---------------------------------------------------------------------- +| NPT_HttpEnvProxySelector::GetInstance ++---------------------------------------------------------------------*/ +NPT_HttpEnvProxySelector* +NPT_HttpEnvProxySelector::GetInstance() +{ + if (Instance) return Instance; + + NPT_SingletonLock::GetInstance().Lock(); + if (Instance == NULL) { + // create the shared instance + Instance = new NPT_HttpEnvProxySelector(); + + // prepare for recycling + NPT_AutomaticCleaner::GetInstance()->Register(Instance); + + // parse the http proxy settings + NPT_String http_proxy; + NPT_Environment::Get("http_proxy", http_proxy); + ParseProxyEnv(http_proxy, Instance->m_HttpProxy); + NPT_LOG_FINE_2("http_proxy: %s:%d", Instance->m_HttpProxy.GetHostName().GetChars(), Instance->m_HttpProxy.GetPort()); + + // parse the https proxy settings + NPT_String https_proxy; + if (NPT_FAILED(NPT_Environment::Get("HTTPS_PROXY", https_proxy))) { + NPT_Environment::Get("https_proxy", https_proxy); + } + ParseProxyEnv(https_proxy, Instance->m_HttpsProxy); + NPT_LOG_FINE_2("https_proxy: %s:%d", Instance->m_HttpsProxy.GetHostName().GetChars(), Instance->m_HttpsProxy.GetPort()); + + // parse the all-proxy settings + NPT_String all_proxy; + if (NPT_FAILED(NPT_Environment::Get("ALL_PROXY", all_proxy))) { + NPT_Environment::Get("all_proxy", all_proxy); + } + ParseProxyEnv(all_proxy, Instance->m_AllProxy); + NPT_LOG_FINE_2("all_proxy: %s:%d", Instance->m_AllProxy.GetHostName().GetChars(), Instance->m_AllProxy.GetPort()); + + // parse the no-proxy settings + NPT_String no_proxy; + if (NPT_FAILED(NPT_Environment::Get("NO_PROXY", no_proxy))) { + NPT_Environment::Get("no_proxy", no_proxy); + } + if (no_proxy.GetLength()) { + Instance->m_NoProxy = no_proxy.Split(","); + } + } + NPT_SingletonLock::GetInstance().Unlock(); + + return Instance; +} + +/*---------------------------------------------------------------------- +| NPT_HttpEnvProxySelector::ParseProxyEnv ++---------------------------------------------------------------------*/ +void +NPT_HttpEnvProxySelector::ParseProxyEnv(const NPT_String& env, + NPT_HttpProxyAddress& proxy) +{ + // ignore empty strings + if (env.GetLength() == 0) return; + + NPT_String proxy_spec; + if (env.Find("://") >= 0) { + proxy_spec = env; + } else { + proxy_spec = "http://"+env; + } + NPT_Url url(proxy_spec); + proxy.SetHostName(url.GetHost()); + proxy.SetPort(url.GetPort()); +} + +/*---------------------------------------------------------------------- +| NPT_HttpEnvProxySelector::GetProxyForUrl ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpEnvProxySelector::GetProxyForUrl(const NPT_HttpUrl& url, + NPT_HttpProxyAddress& proxy) +{ + NPT_HttpProxyAddress* protocol_proxy = NULL; + switch (url.GetSchemeId()) { + case NPT_Uri::SCHEME_ID_HTTP: + protocol_proxy = &m_HttpProxy; + break; + + case NPT_Uri::SCHEME_ID_HTTPS: + protocol_proxy = &m_HttpsProxy; + break; + + default: + return NPT_ERROR_HTTP_NO_PROXY; + } + + // check for no-proxy first + if (m_NoProxy.GetItemCount()) { + for (NPT_List<NPT_String>::Iterator i = m_NoProxy.GetFirstItem(); + i; + ++i) { + if ((*i) == "*") { + return NPT_ERROR_HTTP_NO_PROXY; + } + if (url.GetHost().EndsWith(*i, true)) { + if (url.GetHost().GetLength() == (*i).GetLength()) { + // exact match + return NPT_ERROR_HTTP_NO_PROXY; + } + if (url.GetHost().GetChars()[url.GetHost().GetLength()-(*i).GetLength()-1] == '.') { + // subdomain match + return NPT_ERROR_HTTP_NO_PROXY; + } + } + } + } + + // check the protocol proxy + if (protocol_proxy->GetHostName().GetLength()) { + proxy = *protocol_proxy; + return NPT_SUCCESS; + } + + // use the default proxy + proxy = m_AllProxy; + + return proxy.GetHostName().GetLength()?NPT_SUCCESS:NPT_ERROR_HTTP_NO_PROXY; +} + +/*---------------------------------------------------------------------- +| NPT_HttpProxySelector::GetDefault ++---------------------------------------------------------------------*/ +static bool NPT_HttpProxySelector_ConfigChecked = false; +static unsigned int NPT_HttpProxySelector_Config = 0; +const unsigned int NPT_HTTP_PROXY_SELECTOR_CONFIG_NONE = 0; +const unsigned int NPT_HTTP_PROXY_SELECTOR_CONFIG_ENV = 1; +const unsigned int NPT_HTTP_PROXY_SELECTOR_CONFIG_SYSTEM = 2; +NPT_HttpProxySelector* +NPT_HttpProxySelector::GetDefault() +{ + if (!NPT_HttpProxySelector_ConfigChecked) { + NPT_String config; + if (NPT_SUCCEEDED(NPT_Environment::Get("NEPTUNE_NET_CONFIG_PROXY_SELECTOR", config))) { + if (config.Compare("noproxy", true) == 0) { + NPT_HttpProxySelector_Config = NPT_HTTP_PROXY_SELECTOR_CONFIG_NONE; + } else if (config.Compare("env", true) == 0) { + NPT_HttpProxySelector_Config = NPT_HTTP_PROXY_SELECTOR_CONFIG_ENV; + } else if (config.Compare("system", true) == 0) { + NPT_HttpProxySelector_Config = NPT_HTTP_PROXY_SELECTOR_CONFIG_SYSTEM; + } else { + NPT_HttpProxySelector_Config = NPT_HTTP_PROXY_SELECTOR_CONFIG_NONE; + } + } + NPT_HttpProxySelector_ConfigChecked = true; + } + + switch (NPT_HttpProxySelector_Config) { + case NPT_HTTP_PROXY_SELECTOR_CONFIG_NONE: + // no proxy + return NULL; + + case NPT_HTTP_PROXY_SELECTOR_CONFIG_ENV: + // use the shared instance + return NPT_HttpEnvProxySelector::GetInstance(); + + case NPT_HTTP_PROXY_SELECTOR_CONFIG_SYSTEM: + // use the sytem proxy selector + return GetSystemSelector(); + + default: + return NULL; + } +} + +/*---------------------------------------------------------------------- +| NPT_HttpProxySelector::GetSystemSelector ++---------------------------------------------------------------------*/ +#if !defined(NPT_CONFIG_HAVE_SYSTEM_PROXY_SELECTOR) +NPT_HttpProxySelector* +NPT_HttpProxySelector::GetSystemSelector() +{ + return NULL; +} +#endif + +/*---------------------------------------------------------------------- +| NPT_HttpStaticProxySelector ++---------------------------------------------------------------------*/ +class NPT_HttpStaticProxySelector : public NPT_HttpProxySelector +{ +public: + // constructor + NPT_HttpStaticProxySelector(const char* http_propxy_hostname, + NPT_UInt16 http_proxy_port, + const char* https_proxy_hostname, + NPT_UInt16 htts_proxy_port); + + // NPT_HttpProxySelector methods + NPT_Result GetProxyForUrl(const NPT_HttpUrl& url, NPT_HttpProxyAddress& proxy) override; + +private: + // members + NPT_HttpProxyAddress m_HttpProxy; + NPT_HttpProxyAddress m_HttpsProxy; +}; + +/*---------------------------------------------------------------------- +| NPT_HttpStaticProxySelector::NPT_HttpStaticProxySelector ++---------------------------------------------------------------------*/ +NPT_HttpStaticProxySelector::NPT_HttpStaticProxySelector(const char* http_proxy_hostname, + NPT_UInt16 http_proxy_port, + const char* https_proxy_hostname, + NPT_UInt16 https_proxy_port) : + m_HttpProxy( http_proxy_hostname, http_proxy_port), + m_HttpsProxy(https_proxy_hostname, https_proxy_port) +{ +} + +/*---------------------------------------------------------------------- +| NPT_HttpStaticProxySelector::GetProxyForUrl ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpStaticProxySelector::GetProxyForUrl(const NPT_HttpUrl& url, + NPT_HttpProxyAddress& proxy) +{ + switch (url.GetSchemeId()) { + case NPT_Uri::SCHEME_ID_HTTP: + proxy = m_HttpProxy; + break; + + case NPT_Uri::SCHEME_ID_HTTPS: + proxy = m_HttpsProxy; + break; + + default: + return NPT_ERROR_HTTP_NO_PROXY; + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpConnectionManager::NPT_HttpConnectionManager ++---------------------------------------------------------------------*/ +NPT_HttpConnectionManager::NPT_HttpConnectionManager() : + m_Lock(true), + m_MaxConnections(NPT_HTTP_CONNECTION_MANAGER_MAX_CONNECTION_POOL_SIZE), + m_MaxConnectionAge(NPT_HTTP_CONNECTION_MANAGER_MAX_CONNECTION_AGE) +{ +} + +/*---------------------------------------------------------------------- +| NPT_HttpConnectionManager::~NPT_HttpConnectionManager ++---------------------------------------------------------------------*/ +NPT_HttpConnectionManager::~NPT_HttpConnectionManager() +{ + // set abort flag and wait for thread to finish + m_Aborted.SetValue(1); + Wait(); + + m_Connections.Apply(NPT_ObjectDeleter<Connection>()); +} + +/*---------------------------------------------------------------------- +| NPT_HttpConnectionManager::GetInstance ++---------------------------------------------------------------------*/ +NPT_HttpConnectionManager* +NPT_HttpConnectionManager::GetInstance() +{ + if (Instance) return Instance; + + NPT_SingletonLock::GetInstance().Lock(); + if (Instance == NULL) { + // create the shared instance + Instance = new NPT_HttpConnectionManager(); + + // register to for automatic cleanup + NPT_AutomaticCleaner::GetInstance()->RegisterHttpConnectionManager(Instance); + + // Start shared instance + Instance->Start(); + } + NPT_SingletonLock::GetInstance().Unlock(); + + return Instance; +} +NPT_HttpConnectionManager* NPT_HttpConnectionManager::Instance = NULL; + +/*---------------------------------------------------------------------- +| NPT_HttpConnectionManager::Run ++---------------------------------------------------------------------*/ +void +NPT_HttpConnectionManager::Run() +{ + // try to cleanup every 5 secs + while (m_Aborted.WaitUntilEquals(1, 5000) == NPT_ERROR_TIMEOUT) { + NPT_AutoLock lock(m_Lock); + Cleanup(); + } +} + +/*---------------------------------------------------------------------- +| NPT_HttpConnectionManager::Cleanup ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpConnectionManager::Cleanup() +{ + NPT_TimeStamp now; + NPT_System::GetCurrentTimeStamp(now); + NPT_TimeStamp delta((float)m_MaxConnectionAge); + + NPT_List<Connection*>::Iterator tail = m_Connections.GetLastItem(); + while (tail) { + if (now < (*tail)->m_TimeStamp + delta) break; + NPT_LOG_FINE_1("cleaning up connection (%d remain)", m_Connections.GetItemCount()); + delete *tail; + m_Connections.Erase(tail); + tail = m_Connections.GetLastItem(); + } + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpConnectionManager::FindConnection ++---------------------------------------------------------------------*/ +NPT_HttpConnectionManager::Connection* +NPT_HttpConnectionManager::FindConnection(NPT_SocketAddress& address) +{ + NPT_AutoLock lock(m_Lock); + Cleanup(); + + for (NPT_List<Connection*>::Iterator i = m_Connections.GetFirstItem(); + i; + ++i) { + Connection* connection = *i; + + NPT_SocketInfo info; + if (NPT_FAILED(connection->GetInfo(info))) continue; + + if (info.remote_address == address) { + m_Connections.Erase(i); + return connection; + } + } + + // not found + return NULL; +} + +/*---------------------------------------------------------------------- +| NPT_HttpConnectionManager::Track ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpConnectionManager::Track(NPT_HttpClient* client, NPT_HttpClient::Connection* connection) +{ + NPT_AutoLock lock(m_Lock); + + // look if already tracking client connections + ConnectionList* connections = NULL; + if (NPT_SUCCEEDED(m_ClientConnections.Get(client, connections))) { + // return immediately if connection is already associated with client + if (connections->Find(NPT_ObjectComparator<NPT_HttpClient::Connection*>(connection))) { + NPT_LOG_WARNING("Connection already associated to client."); + return NPT_SUCCESS; + } + connections->Add(connection); + return NPT_SUCCESS; + } + + // new client connections + ConnectionList new_connections; + + // add connection to new client connection list + new_connections.Add(connection); + + // track new client connections + m_ClientConnections.Put(client, new_connections); + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpConnectionManager::UntrackConnection ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpConnectionManager::UntrackConnection(NPT_HttpClient::Connection* connection) +{ + NPT_AutoLock lock(m_Lock); + + if (!connection) { + return NPT_ERROR_INVALID_PARAMETERS; + } + + // look for connection by enumerating all client connections + NPT_List<NPT_Map<NPT_HttpClient*, ConnectionList>::Entry*>::Iterator entry = + m_ClientConnections.GetEntries().GetFirstItem(); + while (entry) { + NPT_HttpClient*& client = (NPT_HttpClient*&)(*entry)->GetKey(); + ConnectionList& connections = (ConnectionList&)(*entry)->GetValue(); + + // look for connection in client connection list + NPT_List<NPT_HttpClient::Connection*>::Iterator i = + connections.Find(NPT_ObjectComparator<NPT_HttpClient::Connection*>(connection)); + if (i) { + // remove it + connections.Erase(i); + + // untrack client if no more active connections for it + if (connections.GetItemCount() == 0) { + m_ClientConnections.Erase(client); + } + + return NPT_SUCCESS; + } + ++entry; + } + + return NPT_ERROR_NO_SUCH_ITEM; +} + +/*---------------------------------------------------------------------- +| NPT_HttpConnectionManager::Untrack ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpConnectionManager::Untrack(NPT_HttpClient::Connection* connection) +{ + // check first if ConnectionCanceller Instance has not been released already + // with static finalizers + if (Instance == NULL) return NPT_FAILURE; + + return GetInstance()->UntrackConnection(connection); +} + +/*---------------------------------------------------------------------- +| NPT_HttpConnectionManager::Recycle ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpConnectionManager::Recycle(NPT_HttpConnectionManager::Connection* connection) +{ + // Untrack connection + UntrackConnection(connection); + + { + NPT_AutoLock lock(m_Lock); + Cleanup(); + + // remove older connections to make room + while (m_Connections.GetItemCount() >= m_MaxConnections) { + NPT_List<Connection*>::Iterator head = m_Connections.GetFirstItem(); + if (!head) break; + delete *head; + m_Connections.Erase(head); + NPT_LOG_FINER("removing connection from pool to make some room"); + } + + if (connection) { + + // label this connection with the current timestamp and flag + NPT_System::GetCurrentTimeStamp(connection->m_TimeStamp); + connection->m_IsRecycled = true; + + // add the connection to the pool + m_Connections.Add(connection); + } + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpConnectionManager::AbortConnections ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpConnectionManager::AbortConnections(NPT_HttpClient* client) +{ + NPT_AutoLock lock(m_Lock); + + ConnectionList* connections = NULL; + if (NPT_SUCCEEDED(m_ClientConnections.Get(client, connections))) { + for (NPT_List<NPT_HttpClient::Connection*>::Iterator i = connections->GetFirstItem(); + i; + ++i) { + (*i)->Abort(); + } + } + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpConnectionManager::Connection::Connection ++---------------------------------------------------------------------*/ +NPT_HttpConnectionManager::Connection::Connection(NPT_HttpConnectionManager& manager, + NPT_SocketReference& socket, + NPT_InputStreamReference input_stream, + NPT_OutputStreamReference output_stream) : + m_Manager(manager), + m_IsRecycled(false), + m_Socket(socket), + m_InputStream(input_stream), + m_OutputStream(output_stream) +{ +} + +/*---------------------------------------------------------------------- +| NPT_HttpConnectionManager::Connection::~Connection ++---------------------------------------------------------------------*/ +NPT_HttpConnectionManager::Connection::~Connection() +{ + NPT_HttpConnectionManager::Untrack(this); +} + +/*---------------------------------------------------------------------- +| NPT_HttpConnectionManager::Connection::Recycle ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpConnectionManager::Connection::Recycle() +{ + return m_Manager.Recycle(this); +} + +/*---------------------------------------------------------------------- +| NPT_HttpClient::NPT_HttpClient ++---------------------------------------------------------------------*/ +NPT_HttpClient::NPT_HttpClient(Connector* connector, bool transfer_ownership) : + m_ProxySelector(NPT_HttpProxySelector::GetDefault()), + m_ProxySelectorIsOwned(false), + m_Connector(connector), + m_ConnectorIsOwned(transfer_ownership), + m_Aborted(false) +{ + if (connector == NULL) { + m_Connector = new NPT_HttpTlsConnector(); + m_ConnectorIsOwned = true; + } +} + +/*---------------------------------------------------------------------- +| NPT_HttpClient::~NPT_HttpClient ++---------------------------------------------------------------------*/ +NPT_HttpClient::~NPT_HttpClient() +{ + if (m_ProxySelectorIsOwned) { + delete m_ProxySelector; + } + if (m_ConnectorIsOwned) { + delete m_Connector; + } +} + +/*---------------------------------------------------------------------- +| NPT_HttpClient::SetConfig ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpClient::SetConfig(const Config& config) +{ + m_Config = config; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpClient::SetProxy ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpClient::SetProxy(const char* http_proxy_hostname, + NPT_UInt16 http_proxy_port, + const char* https_proxy_hostname, + NPT_UInt16 https_proxy_port) +{ + if (m_ProxySelectorIsOwned) { + delete m_ProxySelector; + m_ProxySelector = NULL; + m_ProxySelectorIsOwned = false; + } + + // use a static proxy to hold on to the settings + m_ProxySelector = new NPT_HttpStaticProxySelector(http_proxy_hostname, + http_proxy_port, + https_proxy_hostname, + https_proxy_port); + m_ProxySelectorIsOwned = true; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpClient::SetProxySelector ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpClient::SetProxySelector(NPT_HttpProxySelector* selector) +{ + if (m_ProxySelectorIsOwned && m_ProxySelector != selector) { + delete m_ProxySelector; + } + m_ProxySelector = selector; + m_ProxySelectorIsOwned = false; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpClient::SetConnector ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpClient::SetConnector(Connector* connector) +{ + if (m_ConnectorIsOwned && m_Connector != connector) { + delete m_Connector; + } + m_Connector = connector; + m_ConnectorIsOwned = false; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpClient::SetTimeouts ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpClient::SetTimeouts(NPT_Timeout connection_timeout, + NPT_Timeout io_timeout, + NPT_Timeout name_resolver_timeout) +{ + m_Config.m_ConnectionTimeout = connection_timeout; + m_Config.m_IoTimeout = io_timeout; + m_Config.m_NameResolverTimeout = name_resolver_timeout; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpClient::SetUserAgent ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpClient::SetUserAgent(const char* user_agent) +{ + m_Config.m_UserAgent = user_agent; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpClient::TrackConnection ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpClient::TrackConnection(Connection* connection) +{ + NPT_AutoLock lock(m_AbortLock); + if (m_Aborted) return NPT_ERROR_CANCELLED; + return NPT_HttpConnectionManager::GetInstance()->Track(this, connection); +} + +/*---------------------------------------------------------------------- +| NPT_HttpClient::SendRequestOnce ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpClient::SendRequestOnce(NPT_HttpRequest& request, + NPT_HttpResponse*& response, + NPT_HttpRequestContext* context /* = NULL */) +{ + // setup default values + NPT_Result result = NPT_SUCCESS; + response = NULL; + + NPT_LOG_FINE_1("requesting URL %s", request.GetUrl().ToString().GetChars()); + + // get the address and port to which we need to connect + NPT_HttpProxyAddress proxy; + bool use_proxy = false; + if (m_ProxySelector) { + // we have a proxy selector, ask it to select a proxy for this URL + result = m_ProxySelector->GetProxyForUrl(request.GetUrl(), proxy); + if (NPT_FAILED(result) && result != NPT_ERROR_HTTP_NO_PROXY) { + NPT_LOG_WARNING_1("proxy selector failure (%d)", result); + return result; + } + use_proxy = !proxy.GetHostName().IsEmpty(); + } + + // connect to the server or proxy + Connection* connection = NULL; + bool http_1_1 = (request.GetProtocol() == NPT_HTTP_PROTOCOL_1_1); + NPT_Reference<Connection> cref; + + // send the request to the server (in a loop, since we may need to reconnect with 1.1) + bool reconnect = false; + unsigned int watchdog = NPT_HTTP_MAX_RECONNECTS; + do { + cref = NULL; + connection = NULL; + NPT_LOG_FINE_3("calling connector (proxy:%s) (http 1.1:%s) (url:%s)", + use_proxy?"yes":"no", http_1_1?"yes":"no", request.GetUrl().ToStringWithDefaultPort(0).GetChars()); + NPT_CHECK_WARNING(m_Connector->Connect(request.GetUrl(), + *this, + use_proxy?&proxy:NULL, + http_1_1, + connection)); + NPT_LOG_FINE_1("got connection (reused: %s)", connection->IsRecycled()?"true":"false"); + + NPT_InputStreamReference input_stream = connection->GetInputStream(); + NPT_OutputStreamReference output_stream = connection->GetOutputStream(); + + cref = connection; + reconnect = connection->IsRecycled(); + + // update context if any + if (context) { + NPT_SocketInfo info; + cref->GetInfo(info); + context->SetLocalAddress(info.local_address); + context->SetRemoteAddress(info.remote_address); + } + + NPT_HttpEntity* entity = request.GetEntity(); + NPT_InputStreamReference body_stream; + + if (reconnect && entity && NPT_SUCCEEDED(entity->GetInputStream(body_stream)) && NPT_FAILED(body_stream->Seek(0))) { + // if body is not seekable, we can't afford to reuse a connection + // that could fail, so we reconnect a new one instead + NPT_LOG_FINE("rewinding body stream would fail ... create new connection"); + continue; + } + + // decide if this connection should persist + NPT_HttpHeaders& headers = request.GetHeaders(); + bool should_persist = http_1_1; + if (!connection->SupportsPersistence()) { + should_persist = false; + } + if (should_persist) { + const NPT_String* connection_header = headers.GetHeaderValue(NPT_HTTP_HEADER_CONNECTION); + if (connection_header && (*connection_header == "close")) { + should_persist = false; + } + } + + if (m_Config.m_UserAgent.GetLength()) { + headers.SetHeader(NPT_HTTP_HEADER_USER_AGENT, m_Config.m_UserAgent, false); // set but don't replace + } + + result = WriteRequest(*output_stream.AsPointer(), request, should_persist, use_proxy); + if (NPT_FAILED(result)) { + NPT_LOG_FINE_1("failed to write request headers (%d)", result); + if (reconnect && !m_Aborted) { + if (!body_stream.IsNull()) { + // go back to the start of the body so that we can resend + NPT_LOG_FINE("rewinding body stream in order to resend"); + result = body_stream->Seek(0); + if (NPT_FAILED(result)) { + NPT_CHECK_FINE(NPT_ERROR_HTTP_CANNOT_RESEND_BODY); + } + } + continue; + } else { + return result; + } + } + + result = ReadResponse(input_stream, + should_persist, + request.GetMethod() != NPT_HTTP_METHOD_HEAD, + response, + &cref); + if (NPT_FAILED(result)) { + NPT_LOG_FINE_1("failed to parse the response (%d)", result); + if (reconnect && !m_Aborted /*&& + (result == NPT_ERROR_EOS || + result == NPT_ERROR_CONNECTION_ABORTED || + result == NPT_ERROR_CONNECTION_RESET || + result == NPT_ERROR_READ_FAILED) GBG: don't look for specific error codes */) { + NPT_LOG_FINE("error is not fatal, retrying"); + if (!body_stream.IsNull()) { + // go back to the start of the body so that we can resend + NPT_LOG_FINE("rewinding body stream in order to resend"); + result = body_stream->Seek(0); + if (NPT_FAILED(result)) { + NPT_CHECK_FINE(NPT_ERROR_HTTP_CANNOT_RESEND_BODY); + } + } + continue; + } else { + // don't retry + return result; + } + } + break; + } while (reconnect && --watchdog && !m_Aborted); + + // check that we have a valid connection + if (NPT_FAILED(result) && !m_Aborted) { + NPT_LOG_FINE("failed after max reconnection attempts"); + return NPT_ERROR_HTTP_TOO_MANY_RECONNECTS; + } + + return result; +} + +/*---------------------------------------------------------------------- +| NPT_HttpClient::WriteRequest ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpClient::WriteRequest(NPT_OutputStream& output_stream, + NPT_HttpRequest& request, + bool should_persist, + bool use_proxy /* = false */) +{ + NPT_Result result = NPT_SUCCESS; + + // add any headers that may be missing + NPT_HttpHeaders& headers = request.GetHeaders(); + + if (!should_persist) { + headers.SetHeader(NPT_HTTP_HEADER_CONNECTION, "close", false); // set but don't replace + } + + NPT_String host = request.GetUrl().GetHost(); + NPT_UInt16 default_port = 0; + switch (request.GetUrl().GetSchemeId()) { + case NPT_Uri::SCHEME_ID_HTTP: default_port = NPT_HTTP_DEFAULT_PORT; break; + case NPT_Uri::SCHEME_ID_HTTPS: default_port = NPT_HTTPS_DEFAULT_PORT; break; + default: break; + } + if (request.GetUrl().GetPort() != default_port) { + host += ":"; + host += NPT_String::FromInteger(request.GetUrl().GetPort()); + } + headers.SetHeader(NPT_HTTP_HEADER_HOST, host, false); // set but don't replace + + // get the request entity to set additional headers + NPT_InputStreamReference body_stream; + NPT_HttpEntity* entity = request.GetEntity(); + if (entity && NPT_SUCCEEDED(entity->GetInputStream(body_stream))) { + // set the content length if known + if (entity->ContentLengthIsKnown()) { + headers.SetHeader(NPT_HTTP_HEADER_CONTENT_LENGTH, + NPT_String::FromInteger(entity->GetContentLength())); + } + + // content type + NPT_String content_type = entity->GetContentType(); + if (!content_type.IsEmpty()) { + headers.SetHeader(NPT_HTTP_HEADER_CONTENT_TYPE, content_type); + } + + // content encoding + NPT_String content_encoding = entity->GetContentEncoding(); + if (!content_encoding.IsEmpty()) { + headers.SetHeader(NPT_HTTP_HEADER_CONTENT_ENCODING, content_encoding); + } + + // transfer encoding + const NPT_String& transfer_encoding = entity->GetTransferEncoding(); + if (!transfer_encoding.IsEmpty()) { + headers.SetHeader(NPT_HTTP_HEADER_TRANSFER_ENCODING, transfer_encoding); + } + } + + // create a memory stream to buffer the headers + NPT_MemoryStream header_stream; + + // emit the request headers into the header buffer + request.Emit(header_stream, use_proxy && request.GetUrl().GetSchemeId()==NPT_Url::SCHEME_ID_HTTP); + + // send the headers + NPT_CHECK_WARNING(output_stream.WriteFully(header_stream.GetData(), header_stream.GetDataSize())); + + // send request body + if (entity && !body_stream.IsNull()) { + // check for chunked transfer encoding + NPT_OutputStream* dest = &output_stream; + if (entity->GetTransferEncoding() == NPT_HTTP_TRANSFER_ENCODING_CHUNKED) { + dest = new NPT_HttpChunkedOutputStream(output_stream); + } + + NPT_LOG_FINE_1("sending body stream, %lld bytes", entity->GetContentLength()); //FIXME: Would be 0 for chunked encoding + NPT_LargeSize bytes_written = 0; + + // content length = 0 means copy until input returns EOS + result = NPT_StreamToStreamCopy(*body_stream.AsPointer(), *dest, 0, entity->GetContentLength(), &bytes_written); + if (NPT_FAILED(result)) { + NPT_LOG_FINE_3("body stream only partially sent, %lld bytes (%d:%s)", + bytes_written, + result, + NPT_ResultText(result)); + } + + // flush to write out any buffered data left in chunked output if used + dest->Flush(); + + // cleanup (this will send zero size chunk followed by CRLF) + if (dest != &output_stream) delete dest; + } + + // flush the output stream so that everything is sent to the server + output_stream.Flush(); + + return result; +} + +/*---------------------------------------------------------------------- +| NPT_HttpClient::ReadResponse ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpClient::ReadResponse(NPT_InputStreamReference& input_stream, + bool should_persist, + bool expect_entity, + NPT_HttpResponse*& response, + NPT_Reference<Connection>* cref /* = NULL */) +{ + NPT_Result result; + + // setup default values + response = NULL; + + // create a buffered stream for this socket stream + NPT_BufferedInputStreamReference buffered_input_stream(new NPT_BufferedInputStream(input_stream)); + + // parse the response + for (unsigned int watchcat = 0; watchcat < NPT_HTTP_MAX_100_RESPONSES; watchcat++) { + // parse the response + result = NPT_HttpResponse::Parse(*buffered_input_stream, response); + NPT_CHECK_FINE(result); + + if (response->GetStatusCode() >= 100 && response->GetStatusCode() < 200) { + NPT_LOG_FINE_1("got %d response, continuing", response->GetStatusCode()); + delete response; + response = NULL; + continue; + } + NPT_LOG_FINER_2("got response, code=%d, msg=%s", + response->GetStatusCode(), + response->GetReasonPhrase().GetChars()); + break; + } + + // check that we have a valid response + if (response == NULL) { + NPT_LOG_FINE("failed after max continuation attempts"); + return NPT_ERROR_HTTP_TOO_MANY_RECONNECTS; + } + + // unbuffer the stream + buffered_input_stream->SetBufferSize(0); + + // decide if we should still try to reuse this connection later on + if (should_persist) { + const NPT_String* connection_header = response->GetHeaders().GetHeaderValue(NPT_HTTP_HEADER_CONNECTION); + if (response->GetProtocol() == NPT_HTTP_PROTOCOL_1_1) { + if (connection_header && (*connection_header == "close")) { + should_persist = false; + } + } else { + if (!connection_header || (*connection_header != "keep-alive")) { + should_persist = false; + } + } + } + + // create an entity if one is expected in the response + if (expect_entity) { + NPT_HttpEntity* response_entity = new NPT_HttpEntity(response->GetHeaders()); + + // check if the content length is known + bool have_content_length = (response->GetHeaders().GetHeaderValue(NPT_HTTP_HEADER_CONTENT_LENGTH) != NULL); + + // check for chunked Transfer-Encoding + bool chunked = false; + if (response_entity->GetTransferEncoding() == NPT_HTTP_TRANSFER_ENCODING_CHUNKED) { + chunked = true; + response_entity->SetTransferEncoding(NULL); + } + + // prepare to transfer ownership of the connection if needed + Connection* connection = NULL; + if (cref) { + connection = cref->AsPointer(); + cref->Detach(); // release the internal ref + // don't delete connection now so we can abort while readin response body, + // just pass ownership to NPT_HttpEntityBodyInputStream so it can recycle it + // when done if connection should persist + } + + // create the body stream wrapper + NPT_InputStream* response_body_stream = + new NPT_HttpEntityBodyInputStream(buffered_input_stream, + response_entity->GetContentLength(), + have_content_length, + chunked, + connection, + should_persist); + response_entity->SetInputStream(NPT_InputStreamReference(response_body_stream)); + response->SetEntity(response_entity); + } else { + if (should_persist && cref) { + Connection* connection = cref->AsPointer(); + cref->Detach(); // release the internal ref + connection->Recycle(); + } + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpClient::SendRequest ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpClient::SendRequest(NPT_HttpRequest& request, + NPT_HttpResponse*& response, + NPT_HttpRequestContext* context /* = NULL */) +{ + NPT_Cardinal watchdog = m_Config.m_MaxRedirects+1; + bool keep_going; + NPT_Result result; + + // reset aborted flag + m_Aborted = false; + + // default value + response = NULL; + + // check that for GET requests there is no entity + if (request.GetEntity() != NULL && + request.GetMethod() == NPT_HTTP_METHOD_GET) { + return NPT_ERROR_HTTP_INVALID_REQUEST; + } + + do { + keep_going = false; + result = SendRequestOnce(request, response, context); + if (NPT_FAILED(result)) break; + if (response && m_Config.m_MaxRedirects && + (request.GetMethod() == NPT_HTTP_METHOD_GET || + request.GetMethod() == NPT_HTTP_METHOD_HEAD) && + (response->GetStatusCode() == 301 || + response->GetStatusCode() == 302 || + response->GetStatusCode() == 303 || + response->GetStatusCode() == 307)) { + // handle redirect + const NPT_String* location = response->GetHeaders().GetHeaderValue(NPT_HTTP_HEADER_LOCATION); + if (location) { + // check for location fields that are not absolute URLs + // (this is not allowed by the standard, but many web servers do it + if (location->StartsWith("/") || + (!location->StartsWith("http://", true) && + !location->StartsWith("https://", true))) { + NPT_LOG_FINE_1("Location: header (%s) is not an absolute URL, using it as a relative URL", location->GetChars()); + if (location->StartsWith("/")) { + NPT_LOG_FINE_1("redirecting to absolute path %s", location->GetChars()); + request.GetUrl().ParsePathPlus(*location); + } else { + NPT_String redirect_path = request.GetUrl().GetPath(); + int slash_pos = redirect_path.ReverseFind('/'); + if (slash_pos >= 0) { + redirect_path.SetLength(slash_pos+1); + } else { + redirect_path = "/"; + } + redirect_path += *location; + NPT_LOG_FINE_1("redirecting to absolute path %s", redirect_path.GetChars()); + request.GetUrl().ParsePathPlus(redirect_path); + } + } else { + // replace the request url + NPT_LOG_FINE_1("redirecting to %s", location->GetChars()); + request.SetUrl(*location); + // remove host header so it is replaced based on new url + request.GetHeaders().RemoveHeader(NPT_HTTP_HEADER_HOST); + } + keep_going = true; + delete response; + response = NULL; + } + } + } while (keep_going && --watchdog && !m_Aborted); + + // check if we were bitten by the watchdog + if (watchdog == 0) { + NPT_LOG_WARNING("too many HTTP redirects"); + return NPT_ERROR_HTTP_TOO_MANY_REDIRECTS; + } + + return result; +} + +/*---------------------------------------------------------------------- +| NPT_HttpClient::Abort ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpClient::Abort() +{ + NPT_AutoLock lock(m_AbortLock); + m_Aborted = true; + + NPT_HttpConnectionManager::GetInstance()->AbortConnections(this); + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpRequestContext::NPT_HttpRequestContext ++---------------------------------------------------------------------*/ +NPT_HttpRequestContext::NPT_HttpRequestContext(const NPT_SocketAddress* local_address, + const NPT_SocketAddress* remote_address) +{ + if (local_address) m_LocalAddress = *local_address; + if (remote_address) m_RemoteAddress = *remote_address; +} + +/*---------------------------------------------------------------------- +| NPT_HttpServer::NPT_HttpServer ++---------------------------------------------------------------------*/ +NPT_HttpServer::NPT_HttpServer(NPT_UInt16 listen_port, bool cancellable) : + m_Socket(cancellable?NPT_SOCKET_FLAG_CANCELLABLE:0), + m_BoundPort(0), + m_ServerHeader("Neptune/" NPT_NEPTUNE_VERSION_STRING), + m_Run(true) +{ + m_Config.m_ListenAddress = NPT_IpAddress::Any; + m_Config.m_ListenPort = listen_port; + m_Config.m_IoTimeout = NPT_HTTP_SERVER_DEFAULT_IO_TIMEOUT; + m_Config.m_ConnectionTimeout = NPT_HTTP_SERVER_DEFAULT_CONNECTION_TIMEOUT; + m_Config.m_ReuseAddress = true; +} + +/*---------------------------------------------------------------------- +| NPT_HttpServer::NPT_HttpServer ++---------------------------------------------------------------------*/ +NPT_HttpServer::NPT_HttpServer(NPT_IpAddress listen_address, + NPT_UInt16 listen_port, + bool cancellable) : + m_Socket(cancellable?NPT_SOCKET_FLAG_CANCELLABLE:0), + m_BoundPort(0), + m_ServerHeader("Neptune/" NPT_NEPTUNE_VERSION_STRING), + m_Run(true) +{ + m_Config.m_ListenAddress = listen_address; + m_Config.m_ListenPort = listen_port; + m_Config.m_IoTimeout = NPT_HTTP_SERVER_DEFAULT_IO_TIMEOUT; + m_Config.m_ConnectionTimeout = NPT_HTTP_SERVER_DEFAULT_CONNECTION_TIMEOUT; + m_Config.m_ReuseAddress = true; +} + +/*---------------------------------------------------------------------- +| NPT_HttpServer::~NPT_HttpServer ++---------------------------------------------------------------------*/ +NPT_HttpServer::~NPT_HttpServer() +{ + m_RequestHandlers.Apply(NPT_ObjectDeleter<HandlerConfig>()); +} + +/*---------------------------------------------------------------------- +| NPT_HttpServer::Bind ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpServer::Bind() +{ + // check if we're already bound + if (m_BoundPort != 0) return NPT_SUCCESS; + + // bind + NPT_Result result = m_Socket.Bind( + NPT_SocketAddress(m_Config.m_ListenAddress, m_Config.m_ListenPort), + m_Config.m_ReuseAddress); + if (NPT_FAILED(result)) return result; + + // update the bound port info + NPT_SocketInfo info; + m_Socket.GetInfo(info); + m_BoundPort = info.local_address.GetPort(); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpServer::SetConfig ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpServer::SetConfig(const Config& config) +{ + m_Config = config; + + // check that we can bind to this listen port + return Bind(); +} + +/*---------------------------------------------------------------------- +| NPT_HttpServer::SetListenPort ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpServer::SetListenPort(NPT_UInt16 port, bool reuse_address) +{ + m_Config.m_ListenPort = port; + m_Config.m_ReuseAddress = reuse_address; + return Bind(); +} + +/*---------------------------------------------------------------------- +| NPT_HttpServer::SetTimeouts ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpServer::SetTimeouts(NPT_Timeout connection_timeout, + NPT_Timeout io_timeout) +{ + m_Config.m_ConnectionTimeout = connection_timeout; + m_Config.m_IoTimeout = io_timeout; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpServer::SetServerHeader ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpServer::SetServerHeader(const char* server_header) +{ + m_ServerHeader = server_header; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpServer::Abort ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpServer::Abort() +{ + m_Socket.Cancel(); + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpServer::WaitForNewClient ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpServer::WaitForNewClient(NPT_InputStreamReference& input, + NPT_OutputStreamReference& output, + NPT_HttpRequestContext* context, + NPT_Flags socket_flags) +{ + // ensure that we're bound + NPT_CHECK_FINE(Bind()); + + // wait for a connection + NPT_Socket* client; + NPT_LOG_FINE_2("waiting for new connection on %s:%d...", + (const char*)m_Config.m_ListenAddress.ToString(), + m_BoundPort); + NPT_Result result = m_Socket.WaitForNewClient(client, m_Config.m_ConnectionTimeout, socket_flags); + if (result != NPT_ERROR_TIMEOUT) { + NPT_CHECK_WARNING(result); + } else { + NPT_CHECK_FINE(result); + } + if (client == NULL) return NPT_ERROR_INTERNAL; + + // get the client info + if (context) { + NPT_SocketInfo client_info; + client->GetInfo(client_info); + + context->SetLocalAddress(client_info.local_address); + context->SetRemoteAddress(client_info.remote_address); + + NPT_LOG_FINE_2("client connected (%s <- %s)", + client_info.local_address.ToString().GetChars(), + client_info.remote_address.ToString().GetChars()); + } + + // configure the socket + client->SetReadTimeout(m_Config.m_IoTimeout); + client->SetWriteTimeout(m_Config.m_IoTimeout); + + // get the streams + client->GetInputStream(input); + client->GetOutputStream(output); + + // we don't need the socket anymore + delete client; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpServer::Loop ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpServer::Loop(bool cancellable_sockets) +{ + NPT_InputStreamReference input; + NPT_OutputStreamReference output; + NPT_HttpRequestContext context; + NPT_Result result; + + do { + // wait for a client to connect + NPT_Flags flags = cancellable_sockets?NPT_SOCKET_FLAG_CANCELLABLE:0; + result = WaitForNewClient(input, output, &context, flags); + NPT_LOG_FINE_2("WaitForNewClient returned %d (%s)", + result, + NPT_ResultText(result)); + if (!m_Run) break; + if (result == NPT_ERROR_TIMEOUT) continue; + + // respond to the client + if (NPT_SUCCEEDED(result)) { + // send a response + result = RespondToClient(input, output, context); + NPT_LOG_FINE_2("ResponToClient returned %d (%s)", + result, + NPT_ResultText(result)); + } else { + NPT_LOG_FINE_2("WaitForNewClient returned %d (%s)", + result, + NPT_ResultText(result)); + // if there was an error, wait a short time to avoid spinning + if (result != NPT_ERROR_TERMINATED) { + NPT_LOG_FINE("sleeping before restarting the loop"); + NPT_System::Sleep(1.0); + } + } + + // release the stream references so that the socket can be closed + input = NULL; + output = NULL; + } while (m_Run && result != NPT_ERROR_TERMINATED); + + return result; +} + +/*---------------------------------------------------------------------- +| NPT_HttpServer::HandlerConfig::HandlerConfig ++---------------------------------------------------------------------*/ +NPT_HttpServer::HandlerConfig::HandlerConfig(NPT_HttpRequestHandler* handler, + const char* path, + bool include_children, + bool transfer_ownership) : + m_Handler(handler), + m_Path(path), + m_IncludeChildren(include_children), + m_HandlerIsOwned(transfer_ownership) +{ +} + +/*---------------------------------------------------------------------- +| NPT_HttpServer::HandlerConfig::~HandlerConfig ++---------------------------------------------------------------------*/ +NPT_HttpServer::HandlerConfig::~HandlerConfig() +{ + if (m_HandlerIsOwned) delete m_Handler; +} + +/*---------------------------------------------------------------------- +| NPT_HttpServer::AddRequestHandler ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpServer::AddRequestHandler(NPT_HttpRequestHandler* handler, + const char* path, + bool include_children, + bool transfer_ownership) +{ + return m_RequestHandlers.Add(new HandlerConfig(handler, path, include_children, transfer_ownership)); +} + +/*---------------------------------------------------------------------- +| NPT_HttpServer::FindRequestHandler ++---------------------------------------------------------------------*/ +NPT_HttpRequestHandler* +NPT_HttpServer::FindRequestHandler(NPT_HttpRequest& request) +{ + NPT_String path = NPT_Uri::PercentDecode(request.GetUrl().GetPath()); + for (NPT_List<HandlerConfig*>::Iterator it = m_RequestHandlers.GetFirstItem(); + it; + ++it) { + HandlerConfig* config = *it; + if (config->m_IncludeChildren) { + if (path.StartsWith(config->m_Path)) { + return config->m_Handler; + } + } else { + if (path == config->m_Path) { + return config->m_Handler; + } + } + } + + // not found + return NULL; +} + +/*---------------------------------------------------------------------- +| NPT_HttpServer::FindRequestHandlers ++---------------------------------------------------------------------*/ +NPT_List<NPT_HttpRequestHandler*> +NPT_HttpServer::FindRequestHandlers(NPT_HttpRequest& request) +{ + NPT_List<NPT_HttpRequestHandler*> handlers; + + for (NPT_List<HandlerConfig*>::Iterator it = m_RequestHandlers.GetFirstItem(); + it; + ++it) { + HandlerConfig* config = *it; + if (config->m_IncludeChildren) { + if (request.GetUrl().GetPath(true).StartsWith(config->m_Path)) { + handlers.Add(config->m_Handler); + } + } else { + if (request.GetUrl().GetPath(true) == config->m_Path) { + handlers.Insert(handlers.GetFirstItem(), config->m_Handler); + } + } + } + + return handlers; +} + +/*---------------------------------------------------------------------- +| NPT_HttpServer::RespondToClient ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpServer::RespondToClient(NPT_InputStreamReference& input, + NPT_OutputStreamReference& output, + const NPT_HttpRequestContext& context) +{ + NPT_HttpRequest* request; + NPT_HttpResponse* response = NULL; + NPT_Result result = NPT_ERROR_NO_SUCH_ITEM; + bool terminate_server = false; + + NPT_HttpResponder responder(input, output); + NPT_CHECK_WARNING(responder.ParseRequest(request, &context.GetLocalAddress())); + NPT_LOG_FINE_1("request, path=%s", request->GetUrl().ToRequestString(true).GetChars()); + + // prepare the response body + NPT_HttpEntity* body = new NPT_HttpEntity(); + + NPT_HttpRequestHandler* handler = FindRequestHandler(*request); + if (handler) { + // create a response object + response = new NPT_HttpResponse(200, "OK", NPT_HTTP_PROTOCOL_1_0); + response->SetEntity(body); + + // ask the handler to setup the response + result = handler->SetupResponse(*request, context, *response); + } + if (result == NPT_ERROR_NO_SUCH_ITEM || handler == NULL) { + body->SetInputStream(NPT_HTTP_DEFAULT_404_HTML); + body->SetContentType("text/html"); + if (response == NULL) { + response = new NPT_HttpResponse(404, "Not Found", NPT_HTTP_PROTOCOL_1_0); + } else { + response->SetStatus(404, "Not Found"); + } + response->SetEntity(body); + if (handler) { + handler->Completed(NPT_ERROR_NO_SUCH_ITEM); + handler = NULL; + } + } else if (result == NPT_ERROR_PERMISSION_DENIED) { + body->SetInputStream(NPT_HTTP_DEFAULT_403_HTML); + body->SetContentType("text/html"); + response->SetStatus(403, "Forbidden"); + handler->Completed(NPT_ERROR_PERMISSION_DENIED); + handler = NULL; + } else if (result == NPT_ERROR_TERMINATED) { + // mark that we want to exit + terminate_server = true; + } else if (NPT_FAILED(result)) { + body->SetInputStream(NPT_HTTP_DEFAULT_500_HTML); + body->SetContentType("text/html"); + response->SetStatus(500, "Internal Error"); + handler->Completed(result); + handler = NULL; + } + + // augment the headers with server information + if (m_ServerHeader.GetLength()) { + response->GetHeaders().SetHeader(NPT_HTTP_HEADER_SERVER, m_ServerHeader, false); + } + + // send the response headers + result = responder.SendResponseHeaders(*response); + if (NPT_FAILED(result)) { + NPT_LOG_WARNING_2("SendResponseHeaders failed (%d:%s)", result, NPT_ResultText(result)); + goto end; + } + + // send the body + if (request->GetMethod() != NPT_HTTP_METHOD_HEAD) { + if (handler) { + result = handler->SendResponseBody(context, *response, *output); + } else { + // send body manually in case there was an error with the handler or no handler was found + NPT_InputStreamReference body_stream; + body->GetInputStream(body_stream); + if (!body_stream.IsNull()) { + result = NPT_StreamToStreamCopy(*body_stream, *output, 0, body->GetContentLength()); + if (NPT_FAILED(result)) { + NPT_LOG_INFO_2("NPT_StreamToStreamCopy returned %d (%s)", result, NPT_ResultText(result)); + goto end; + } + } + } + } + + // flush + output->Flush(); + + // if we need to die, we return an error code + if (NPT_SUCCEEDED(result) && terminate_server) result = NPT_ERROR_TERMINATED; + +end: + // cleanup + delete response; + delete request; + + if (handler) { + handler->Completed(result); + } + + return result; +} + +/*---------------------------------------------------------------------- +| NPT_HttpResponder::NPT_HttpResponder ++---------------------------------------------------------------------*/ +NPT_HttpResponder::NPT_HttpResponder(NPT_InputStreamReference& input, + NPT_OutputStreamReference& output) : + m_Input(new NPT_BufferedInputStream(input)), + m_Output(output) +{ + m_Config.m_IoTimeout = NPT_HTTP_SERVER_DEFAULT_IO_TIMEOUT; +} + +/*---------------------------------------------------------------------- +| NPT_HttpResponder::~NPT_HttpResponder ++---------------------------------------------------------------------*/ +NPT_HttpResponder::~NPT_HttpResponder() +{ +} + +/*---------------------------------------------------------------------- +| NPT_HttpServer::Terminate ++---------------------------------------------------------------------*/ +void NPT_HttpServer::Terminate() +{ + m_Run = false; +} + +/*---------------------------------------------------------------------- +| NPT_HttpResponder::SetConfig ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpResponder::SetConfig(const Config& config) +{ + m_Config = config; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpResponder::SetTimeout ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpResponder::SetTimeout(NPT_Timeout io_timeout) +{ + m_Config.m_IoTimeout = io_timeout; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpResponder::ParseRequest ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpResponder::ParseRequest(NPT_HttpRequest*& request, + const NPT_SocketAddress* local_address) +{ + // rebuffer the stream in case we're using a keep-alive connection + m_Input->SetBufferSize(NPT_BUFFERED_BYTE_STREAM_DEFAULT_SIZE); + + // parse the request + NPT_CHECK_FINE(NPT_HttpRequest::Parse(*m_Input, local_address, request)); + + // unbuffer the stream + m_Input->SetBufferSize(0); + + // don't create an entity if no body is expected + if (request->GetMethod() == NPT_HTTP_METHOD_GET || + request->GetMethod() == NPT_HTTP_METHOD_HEAD || + request->GetMethod() == NPT_HTTP_METHOD_TRACE) { + return NPT_SUCCESS; + } + + // set the entity info + NPT_HttpEntity* entity = new NPT_HttpEntity(request->GetHeaders()); + if (entity->GetTransferEncoding() == NPT_HTTP_TRANSFER_ENCODING_CHUNKED) { + entity->SetInputStream(NPT_InputStreamReference(new NPT_HttpChunkedInputStream(m_Input))); + } else { + entity->SetInputStream(m_Input); + } + request->SetEntity(entity); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpResponder::SendResponseHeaders ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpResponder::SendResponseHeaders(NPT_HttpResponse& response) +{ + // add default headers + NPT_HttpHeaders& headers = response.GetHeaders(); + if (response.GetProtocol() == NPT_HTTP_PROTOCOL_1_0) { + headers.SetHeader(NPT_HTTP_HEADER_CONNECTION, + "close", false); // set but don't replace + } + + // add computed headers + NPT_HttpEntity* entity = response.GetEntity(); + if (entity) { + // content type + const NPT_String& content_type = entity->GetContentType(); + if (!content_type.IsEmpty()) { + headers.SetHeader(NPT_HTTP_HEADER_CONTENT_TYPE, content_type); + } + + // content encoding + const NPT_String& content_encoding = entity->GetContentEncoding(); + if (!content_encoding.IsEmpty()) { + headers.SetHeader(NPT_HTTP_HEADER_CONTENT_ENCODING, content_encoding); + } + + // transfer encoding + const NPT_String& transfer_encoding = entity->GetTransferEncoding(); + if (!transfer_encoding.IsEmpty()) { + headers.SetHeader(NPT_HTTP_HEADER_TRANSFER_ENCODING, transfer_encoding); + } + + // set the content length if known + if (entity->ContentLengthIsKnown()) { + headers.SetHeader(NPT_HTTP_HEADER_CONTENT_LENGTH, + NPT_String::FromInteger(entity->GetContentLength())); + } else if (transfer_encoding.IsEmpty() || transfer_encoding.Compare(NPT_HTTP_TRANSFER_ENCODING_CHUNKED, true)) { + // no content length, the only way client will know we're done + // is when we'll close the connection unless it's chunked encoding + headers.SetHeader(NPT_HTTP_HEADER_CONNECTION, + "close", true); // set and replace + } + } else { + // force content length to 0 if there is no message body + // (necessary for 1.1 or 1.0 with keep-alive connections) + headers.SetHeader(NPT_HTTP_HEADER_CONTENT_LENGTH, "0"); + } + + // create a memory stream to buffer the response line and headers + NPT_MemoryStream buffer; + + // emit the response line + NPT_CHECK_WARNING(response.Emit(buffer)); + + // send the buffer + NPT_CHECK_WARNING(m_Output->WriteFully(buffer.GetData(), buffer.GetDataSize())); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpRequestHandler Dynamic Cast Anchor ++---------------------------------------------------------------------*/ +NPT_DEFINE_DYNAMIC_CAST_ANCHOR(NPT_HttpRequestHandler) + +/*---------------------------------------------------------------------- +| NPT_HttpRequestHandler::SendResponseBody ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpRequestHandler::SendResponseBody(const NPT_HttpRequestContext& /*context*/, + NPT_HttpResponse& response, + NPT_OutputStream& output) +{ + NPT_HttpEntity* entity = response.GetEntity(); + if (entity == NULL) return NPT_SUCCESS; + + NPT_InputStreamReference body_stream; + entity->GetInputStream(body_stream); + if (body_stream.IsNull()) return NPT_SUCCESS; + + // check for chunked transfer encoding + NPT_OutputStream* dest = &output; + if (entity->GetTransferEncoding() == NPT_HTTP_TRANSFER_ENCODING_CHUNKED) { + dest = new NPT_HttpChunkedOutputStream(output); + } + + // send the body + NPT_LOG_FINE_1("sending body stream, %lld bytes", entity->GetContentLength()); + NPT_LargeSize bytes_written = 0; + NPT_Result result = NPT_StreamToStreamCopy(*body_stream, *dest, 0, entity->GetContentLength(), &bytes_written); + if (NPT_FAILED(result)) { + NPT_LOG_FINE_3("body stream only partially sent, %lld bytes (%d:%s)", + bytes_written, + result, + NPT_ResultText(result)); + } + + // flush to write out any buffered data left in chunked output if used + dest->Flush(); + + // cleanup (this will send zero size chunk followed by CRLF) + if (dest != &output) delete dest; + + return result; +} + +/*---------------------------------------------------------------------- +| NPT_HttpStaticRequestHandler::NPT_HttpStaticRequestHandler ++---------------------------------------------------------------------*/ +NPT_HttpStaticRequestHandler::NPT_HttpStaticRequestHandler(const void* data, + NPT_Size size, + const char* mime_type, + bool copy) : + m_MimeType(mime_type), + m_Buffer(data, size, copy) +{} + +/*---------------------------------------------------------------------- +| NPT_HttpStaticRequestHandler::NPT_HttpStaticRequestHandler ++---------------------------------------------------------------------*/ +NPT_HttpStaticRequestHandler::NPT_HttpStaticRequestHandler(const char* document, + const char* mime_type, + bool copy) : + m_MimeType(mime_type), + m_Buffer(document, NPT_StringLength(document), copy) +{} + +/*---------------------------------------------------------------------- +| NPT_HttpStaticRequestHandler::SetupResponse ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpStaticRequestHandler::SetupResponse(NPT_HttpRequest& /*request*/, + const NPT_HttpRequestContext& /*context*/, + NPT_HttpResponse& response) +{ + NPT_HttpEntity* entity = response.GetEntity(); + if (entity == NULL) return NPT_ERROR_INVALID_STATE; + + entity->SetContentType(m_MimeType); + entity->SetInputStream(m_Buffer.GetData(), m_Buffer.GetDataSize()); + + return NPT_SUCCESS; +} + +const NPT_HttpFileRequestHandler_DefaultFileTypeMapEntry +NPT_HttpFileRequestHandler_DefaultFileTypeMap[] = { + {"xml", "text/xml; charset=\"utf-8\"" }, + {"htm", "text/html" }, + {"html", "text/html" }, + {"c", "text/plain"}, + {"h", "text/plain"}, + {"txt", "text/plain"}, + {"css", "text/css" }, + {"manifest", "text/cache-manifest"}, + {"gif", "image/gif" }, + {"thm", "image/jpeg"}, + {"png", "image/png"}, + {"tif", "image/tiff"}, + {"tiff", "image/tiff"}, + {"jpg", "image/jpeg"}, + {"jpeg", "image/jpeg"}, + {"jpe", "image/jpeg"}, + {"jp2", "image/jp2" }, + {"png", "image/png" }, + {"bmp", "image/bmp" }, + {"aif", "audio/x-aiff"}, + {"aifc", "audio/x-aiff"}, + {"aiff", "audio/x-aiff"}, + {"flac", "audio/x-flac"}, + {"mka", "audio/x-matroska"}, + {"mpa", "audio/mpeg"}, + {"mp2", "audio/mpeg"}, + {"mp3", "audio/mpeg"}, + {"m4a", "audio/mp4"}, + {"wma", "audio/x-ms-wma"}, + {"wav", "audio/x-wav"}, + {"mkv", "video/x-matroska"}, + {"mpeg", "video/mpeg"}, + {"mpg", "video/mpeg"}, + {"mp4", "video/mp4"}, + {"m4v", "video/mp4"}, + {"ts", "video/MP2T"}, // RFC 3555 + {"mpegts", "video/MP2T"}, + {"mov", "video/quicktime"}, + {"qt", "video/quicktime"}, + {"wmv", "video/x-ms-wmv"}, + {"wtv", "video/x-ms-wmv"}, + {"asf", "video/x-ms-asf"}, + {"mkv", "video/x-matroska"}, + {"mk3d", "video/x-matroska-3d"}, + {"flv", "video/x-flv"}, + {"avi", "video/x-msvideo"}, + {"divx", "video/x-msvideo"}, + {"xvid", "video/x-msvideo"}, + {"doc", "application/msword"}, + {"js", "application/javascript"}, + {"m3u8", "application/x-mpegURL"}, + {"pdf", "application/pdf"}, + {"ps", "application/postscript"}, + {"eps", "application/postscript"}, + {"zip", "application/zip"} +}; + +/*---------------------------------------------------------------------- +| NPT_HttpFileRequestHandler::NPT_HttpFileRequestHandler ++---------------------------------------------------------------------*/ +NPT_HttpFileRequestHandler::NPT_HttpFileRequestHandler(const char* url_root, + const char* file_root, + bool auto_dir, + const char* auto_index) : + m_UrlRoot(url_root), + m_FileRoot(file_root), + m_DefaultMimeType("text/html"), + m_UseDefaultFileTypeMap(true), + m_AutoDir(auto_dir), + m_AutoIndex(auto_index) +{ +} + +/*---------------------------------------------------------------------- +| helper functions FIXME: need to move these to a separate module ++---------------------------------------------------------------------*/ +static NPT_UInt32 +_utf8_decode(const char** str) +{ + NPT_UInt32 result; + NPT_UInt32 min_value; + unsigned int bytes_left; + + if (**str == 0) { + return ~0; + } else if ((**str & 0x80) == 0x00) { + result = *(*str)++; + bytes_left = 0; + min_value = 0; + } else if ((**str & 0xE0) == 0xC0) { + result = *(*str)++ & 0x1F; + bytes_left = 1; + min_value = 0x80; + } else if ((**str & 0xF0) == 0xE0) { + result = *(*str)++ & 0x0F; + bytes_left = 2; + min_value = 0x800; + } else if ((**str & 0xF8) == 0xF0) { + result = *(*str)++ & 0x07; + bytes_left = 3; + min_value = 0x10000; + } else { + return ~0; + } + + while (bytes_left--) { + if (**str == 0 || (**str & 0xC0) != 0x80) return ~0; + result = (result << 6) | (*(*str)++ & 0x3F); + } + + if (result < min_value || (result & 0xFFFFF800) == 0xD800 || result > 0x10FFFF) { + return ~0; + } + + return result; +} + +/*---------------------------------------------------------------------- +| NPT_HtmlEncode ++---------------------------------------------------------------------*/ +static NPT_String +NPT_HtmlEncode(const char* str, const char* chars) +{ + NPT_String encoded; + + // check args + if (str == NULL) return encoded; + + // reserve at least the size of the current uri + encoded.Reserve(NPT_StringLength(str)); + + // process each character + while (*str) { + NPT_UInt32 c = _utf8_decode(&str); + bool encode = false; + if (c < ' ' || c > '~') { + encode = true; + } else { + const char* match = chars; + while (*match) { + if (c == (NPT_UInt32)*match) { + encode = true; + break; + } + ++match; + } + } + if (encode) { + // encode + char hex[9]; + encoded += "&#x"; + unsigned int len = 0; + if (c > 0xFFFF) { + NPT_ByteToHex((unsigned char)(c>>24), &hex[0], true); + NPT_ByteToHex((unsigned char)(c>>16), &hex[2], true); + len = 4; + } + NPT_ByteToHex((unsigned char)(c>>8), &hex[len ], true); + NPT_ByteToHex((unsigned char)(c ), &hex[len+2], true); + hex[len+4] = ';'; + encoded.Append(hex, len+5); + } else { + // no encoding required + encoded += (char)c; + } + } + + return encoded; +} + +/*---------------------------------------------------------------------- +| NPT_HttpFileRequestHandler::SetupResponse ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpFileRequestHandler::SetupResponse(NPT_HttpRequest& request, + const NPT_HttpRequestContext& /* context */, + NPT_HttpResponse& response) +{ + NPT_HttpEntity* entity = response.GetEntity(); + if (entity == NULL) return NPT_ERROR_INVALID_STATE; + + // check the method + if (request.GetMethod() != NPT_HTTP_METHOD_GET && + request.GetMethod() != NPT_HTTP_METHOD_HEAD) { + response.SetStatus(405, "Method Not Allowed"); + return NPT_SUCCESS; + } + + // set some default headers + response.GetHeaders().SetHeader(NPT_HTTP_HEADER_ACCEPT_RANGES, "bytes"); + + // declare HTTP/1.1 if the client asked for it + if (request.GetProtocol() == NPT_HTTP_PROTOCOL_1_1) { + response.SetProtocol(NPT_HTTP_PROTOCOL_1_1); + } + + // TODO: we need to normalize the request path + + // check that the request's path is an entry under the url root + if (!request.GetUrl().GetPath(true).StartsWith(m_UrlRoot)) { + return NPT_ERROR_INVALID_PARAMETERS; + } + + // compute the filename + NPT_String filename = m_FileRoot; + NPT_String relative_path = NPT_Url::PercentDecode(request.GetUrl().GetPath().GetChars()+m_UrlRoot.GetLength()); + filename += "/"; + filename += relative_path; + NPT_LOG_FINE_1("filename = %s", filename.GetChars()); + + // get info about the file + NPT_FileInfo info; + NPT_File::GetInfo(filename, &info); + + // check if this is a directory + if (info.m_Type == NPT_FileInfo::FILE_TYPE_DIRECTORY) { + NPT_LOG_FINE("file is a DIRECTORY"); + if (m_AutoDir) { + if (m_AutoIndex.GetLength()) { + NPT_LOG_FINE("redirecting to auto-index"); + filename += NPT_FilePath::Separator; + filename += m_AutoIndex; + if (NPT_File::Exists(filename)) { + NPT_String location = m_UrlRoot+"/"+m_AutoIndex; + response.SetStatus(302, "Found"); + response.GetHeaders().SetHeader(NPT_HTTP_HEADER_LOCATION, location); + } else { + return NPT_ERROR_PERMISSION_DENIED; + } + } else { + NPT_LOG_FINE("doing auto-dir"); + + // get the dir entries + NPT_List<NPT_String> entries; + NPT_File::ListDir(filename, entries); + + NPT_String html; + html.Reserve(1024+128*entries.GetItemCount()); + + NPT_String html_dirname = NPT_HtmlEncode(relative_path, "<>&"); + html += "<hmtl><head><title>Directory Listing for /"; + html += html_dirname; + html += "</title></head><body>"; + html += "<h2>Directory Listing for /"; + html += html_dirname; + html += "</h2><hr><ul>\r\n"; + NPT_String url_base_path = NPT_HtmlEncode(request.GetUrl().GetPath(), "<>&\""); + + for (NPT_List<NPT_String>::Iterator i = entries.GetFirstItem(); + i; + ++i) { + NPT_String url_filename = NPT_HtmlEncode(*i, "<>&"); + html += "<li><a href=\""; + html += url_base_path; + if (!url_base_path.EndsWith("/")) html += "/"; + html += url_filename; + html += "\">"; + html +=url_filename; + + NPT_String full_path = filename; + full_path += "/"; + full_path += *i; + NPT_File::GetInfo(full_path, &info); + if (info.m_Type == NPT_FileInfo::FILE_TYPE_DIRECTORY) html += "/"; + + html += "</a><br>\r\n"; + } + html += "</ul></body></html>"; + + entity->SetContentType("text/html"); + entity->SetInputStream(html); + return NPT_SUCCESS; + } + } else { + return NPT_ERROR_PERMISSION_DENIED; + } + } + + // open the file + NPT_File file(filename); + NPT_Result result = file.Open(NPT_FILE_OPEN_MODE_READ); + if (NPT_FAILED(result)) { + NPT_LOG_FINE("file not found"); + return NPT_ERROR_NO_SUCH_ITEM; + } + NPT_InputStreamReference stream; + file.GetInputStream(stream); + + // check for range requests + const NPT_String* range_spec = request.GetHeaders().GetHeaderValue(NPT_HTTP_HEADER_RANGE); + + // setup entity body + NPT_CHECK(SetupResponseBody(response, stream, range_spec)); + + // set the response body + entity->SetContentType(GetContentType(filename)); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpFileRequestHandler::SetupResponseBody ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpFileRequestHandler::SetupResponseBody(NPT_HttpResponse& response, + NPT_InputStreamReference& stream, + const NPT_String* range_spec /* = NULL */) +{ + NPT_HttpEntity* entity = response.GetEntity(); + if (entity == NULL) return NPT_ERROR_INVALID_STATE; + + if (range_spec) { + const NPT_String* accept_range = response.GetHeaders().GetHeaderValue(NPT_HTTP_HEADER_ACCEPT_RANGES); + + if (response.GetEntity()->GetTransferEncoding() == NPT_HTTP_TRANSFER_ENCODING_CHUNKED || + (accept_range && accept_range->Compare("bytes"))) { + NPT_LOG_FINE("range request not supported"); + response.SetStatus(416, "Requested Range Not Satisfiable"); + return NPT_SUCCESS; + } + + // measure the stream size + bool has_stream_size = false; + NPT_LargeSize stream_size = 0; + NPT_Result result = stream->GetSize(stream_size); + if (NPT_SUCCEEDED(result)) { + has_stream_size = true; + NPT_LOG_FINE_1("body size=%lld", stream_size); + if (stream_size == 0) return NPT_SUCCESS; + } + + if (!range_spec->StartsWith("bytes=")) { + NPT_LOG_FINE("unknown range spec"); + response.SetStatus(400, "Bad Request"); + return NPT_SUCCESS; + } + NPT_String valid_range; + NPT_String range(range_spec->GetChars()+6); + if (range.Find(',') >= 0) { + NPT_LOG_FINE("multi-range requests not supported"); + if (has_stream_size) { + valid_range = "bytes */"; + valid_range += NPT_String::FromInteger(stream_size); + response.GetHeaders().SetHeader(NPT_HTTP_HEADER_CONTENT_RANGE, valid_range.GetChars()); + } + response.SetStatus(416, "Requested Range Not Satisfiable"); + return NPT_SUCCESS; + } + int sep = range.Find('-'); + NPT_UInt64 range_start = 0; + NPT_UInt64 range_end = 0; + bool has_start = false; + bool has_end = false; + bool satisfied = false; + if (sep < 0) { + NPT_LOG_FINE("invalid syntax"); + response.SetStatus(400, "Bad Request"); + return NPT_SUCCESS; + } else { + if ((unsigned int)sep+1 < range.GetLength()) { + result = NPT_ParseInteger64(range.GetChars()+sep+1, range_end); + if (NPT_FAILED(result)) { + NPT_LOG_FINE("failed to parse range end"); + return result; + } + range.SetLength(sep); + has_end = true; + } + if (sep > 0) { + result = range.ToInteger64(range_start); + if (NPT_FAILED(result)) { + NPT_LOG_FINE("failed to parse range start"); + return result; + } + has_start = true; + } + + if (!has_stream_size) { + if (has_start && range_start == 0 && !has_end) { + bool update_content_length = (entity->GetTransferEncoding() != NPT_HTTP_TRANSFER_ENCODING_CHUNKED); + // use the whole file stream as a body + return entity->SetInputStream(stream, update_content_length); + } else { + NPT_LOG_WARNING_2("file.GetSize() failed (%d:%s)", result, NPT_ResultText(result)); + NPT_LOG_FINE("range request not supported"); + response.SetStatus(416, "Requested Range Not Satisfiable"); + return NPT_SUCCESS; + } + } + + if (has_start) { + // some clients sends incorrect range_end equal to size + // we try to handle it + if (!has_end || range_end == stream_size) range_end = stream_size-1; + } else { + if (has_end) { + if (range_end <= stream_size) { + range_start = stream_size-range_end; + range_end = stream_size-1; + } + } + } + NPT_LOG_FINE_2("final range: start=%lld, end=%lld", range_start, range_end); + if (range_start > range_end) { + NPT_LOG_FINE("invalid range"); + response.SetStatus(400, "Bad Request"); + satisfied = false; + } else if (range_end >= stream_size) { + response.SetStatus(416, "Requested Range Not Satisfiable"); + NPT_LOG_FINE("out of range"); + satisfied = false; + } else { + satisfied = true; + } + } + if (satisfied && range_start != 0) { + // seek in the stream + result = stream->Seek(range_start); + if (NPT_FAILED(result)) { + NPT_LOG_WARNING_2("stream.Seek() failed (%d:%s)", result, NPT_ResultText(result)); + satisfied = false; + } + } + if (!satisfied) { + if (!valid_range.IsEmpty()) response.GetHeaders().SetHeader(NPT_HTTP_HEADER_CONTENT_RANGE, valid_range.GetChars()); + response.SetStatus(416, "Requested Range Not Satisfiable"); + return NPT_SUCCESS; + } + + // use a portion of the file stream as a body + entity->SetInputStream(stream, false); + entity->SetContentLength(range_end-range_start+1); + response.SetStatus(206, "Partial Content"); + valid_range = "bytes "; + valid_range += NPT_String::FromInteger(range_start); + valid_range += "-"; + valid_range += NPT_String::FromInteger(range_end); + valid_range += "/"; + valid_range += NPT_String::FromInteger(stream_size); + response.GetHeaders().SetHeader(NPT_HTTP_HEADER_CONTENT_RANGE, valid_range.GetChars()); + } else { + bool update_content_length = (entity->GetTransferEncoding() != NPT_HTTP_TRANSFER_ENCODING_CHUNKED); + // use the whole file stream as a body + entity->SetInputStream(stream, update_content_length); + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpFileRequestHandler::GetContentType ++---------------------------------------------------------------------*/ +const char* +NPT_HttpFileRequestHandler::GetDefaultContentType(const char* extension) +{ + for (unsigned int i=0; i<NPT_ARRAY_SIZE(NPT_HttpFileRequestHandler_DefaultFileTypeMap); i++) { + if (NPT_String::Compare(extension, NPT_HttpFileRequestHandler_DefaultFileTypeMap[i].extension, true) == 0) { + const char* type = NPT_HttpFileRequestHandler_DefaultFileTypeMap[i].mime_type; + NPT_LOG_FINE_1("using type from default list: %s", type); + return type; + } + } + + return NULL; +} + +/*---------------------------------------------------------------------- +| NPT_HttpFileRequestHandler::GetContentType ++---------------------------------------------------------------------*/ +const char* +NPT_HttpFileRequestHandler::GetContentType(const NPT_String& filename) +{ + int last_dot = filename.ReverseFind('.'); + if (last_dot > 0) { + NPT_String extension = filename.GetChars()+last_dot+1; + extension.MakeLowercase(); + + NPT_LOG_FINE_1("extension=%s", extension.GetChars()); + + NPT_String* mime_type; + if (NPT_SUCCEEDED(m_FileTypeMap.Get(extension, mime_type))) { + NPT_LOG_FINE_1("found mime type in map: %s", mime_type->GetChars()); + return mime_type->GetChars(); + } + + // not found, look in the default map if necessary + if (m_UseDefaultFileTypeMap) { + const char* type = NPT_HttpFileRequestHandler::GetDefaultContentType(extension); + if (type) return type; + } + } + + NPT_LOG_FINE("using default mime type"); + return m_DefaultMimeType; +} + +/*---------------------------------------------------------------------- +| NPT_HttpChunkedInputStream::NPT_HttpChunkedInputStream ++---------------------------------------------------------------------*/ +NPT_HttpChunkedInputStream::NPT_HttpChunkedInputStream( + NPT_BufferedInputStreamReference& stream) : + m_Source(stream), + m_CurrentChunkSize(0), + m_Eos(false) +{ +} + +/*---------------------------------------------------------------------- +| NPT_HttpChunkedInputStream::~NPT_HttpChunkedInputStream ++---------------------------------------------------------------------*/ +NPT_HttpChunkedInputStream::~NPT_HttpChunkedInputStream() +{ +} + +/*---------------------------------------------------------------------- +| NPT_HttpChunkedInputStream::NPT_HttpChunkedInputStream ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpChunkedInputStream::Read(void* buffer, + NPT_Size bytes_to_read, + NPT_Size* bytes_read /* = NULL */) +{ + // set the initial state of return values + if (bytes_read) *bytes_read = 0; + + // check for end of stream + if (m_Eos) return NPT_ERROR_EOS; + + // shortcut + if (bytes_to_read == 0) return NPT_SUCCESS; + + // read next chunk size if needed + if (m_CurrentChunkSize == 0) { + // buffered mode + m_Source->SetBufferSize(4096); + + NPT_String size_line; + NPT_CHECK_FINE(m_Source->ReadLine(size_line)); + + // decode size (in hex) + m_CurrentChunkSize = 0; + if (size_line.GetLength() < 1) { + NPT_LOG_WARNING("empty chunk size line"); + return NPT_ERROR_INVALID_FORMAT; + } + const char* size_hex = size_line.GetChars(); + while (*size_hex != '\0' && + *size_hex != ' ' && + *size_hex != ';' && + *size_hex != '\r' && + *size_hex != '\n') { + int nibble = NPT_HexToNibble(*size_hex); + if (nibble < 0) { + NPT_LOG_WARNING_1("invalid chunk size format (%s)", size_line.GetChars()); + return NPT_ERROR_INVALID_FORMAT; + } + m_CurrentChunkSize = (m_CurrentChunkSize<<4)|nibble; + ++size_hex; + } + NPT_LOG_FINEST_1("start of chunk, size=%d", m_CurrentChunkSize); + + // 0 = end of body + if (m_CurrentChunkSize == 0) { + NPT_LOG_FINEST("end of chunked stream, reading trailers"); + + // read footers until empty line + NPT_String footer; + do { + NPT_CHECK_FINE(m_Source->ReadLine(footer)); + } while (!footer.IsEmpty()); + m_Eos = true; + + NPT_LOG_FINEST("end of chunked stream, done"); + return NPT_ERROR_EOS; + } + + // unbuffer source + m_Source->SetBufferSize(0); + } + + // read no more than what's left in chunk + NPT_Size chunk_bytes_read; + if (bytes_to_read > m_CurrentChunkSize) bytes_to_read = m_CurrentChunkSize; + NPT_CHECK_FINE(m_Source->Read(buffer, bytes_to_read, &chunk_bytes_read)); + + // ready to go to next chunk? + m_CurrentChunkSize -= chunk_bytes_read; + if (m_CurrentChunkSize == 0) { + NPT_LOG_FINEST("reading end of chunk"); + + // when a chunk is finished, a \r\n follows + char newline[2]; + NPT_CHECK_FINE(m_Source->ReadFully(newline, 2)); + if (newline[0] != '\r' || newline[1] != '\n') { + NPT_LOG_WARNING("invalid end of chunk (expected \\r\\n)"); + return NPT_ERROR_INVALID_FORMAT; + } + } + + // update output params + if (bytes_read) *bytes_read = chunk_bytes_read; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpChunkedInputStream::Seek ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpChunkedInputStream::Seek(NPT_Position /*offset*/) +{ + return NPT_ERROR_NOT_SUPPORTED; +} + +/*---------------------------------------------------------------------- +| NPT_HttpChunkedInputStream::Tell ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpChunkedInputStream::Tell(NPT_Position& offset) +{ + offset = 0; + return NPT_ERROR_NOT_SUPPORTED; +} + +/*---------------------------------------------------------------------- +| NPT_HttpChunkedInputStream::GetSize ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpChunkedInputStream::GetSize(NPT_LargeSize& size) +{ + return m_Source->GetSize(size); +} + +/*---------------------------------------------------------------------- +| NPT_HttpChunkedInputStream::GetAvailable ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpChunkedInputStream::GetAvailable(NPT_LargeSize& available) +{ + return m_Source->GetAvailable(available); +} + +/*---------------------------------------------------------------------- +| NPT_HttpChunkedOutputStream::NPT_HttpChunkedOutputStream ++---------------------------------------------------------------------*/ +NPT_HttpChunkedOutputStream::NPT_HttpChunkedOutputStream(NPT_OutputStream& stream) : + m_Stream(stream) +{ +} + +/*---------------------------------------------------------------------- +| NPT_HttpChunkedOutputStream::~NPT_HttpChunkedOutputStream ++---------------------------------------------------------------------*/ +NPT_HttpChunkedOutputStream::~NPT_HttpChunkedOutputStream() +{ + // zero size chunk followed by CRLF (no trailer) + m_Stream.WriteFully("0" NPT_HTTP_LINE_TERMINATOR NPT_HTTP_LINE_TERMINATOR, 5); +} + +/*---------------------------------------------------------------------- +| NPT_HttpChunkedOutputStream::Write ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpChunkedOutputStream::Write(const void* buffer, + NPT_Size bytes_to_write, + NPT_Size* bytes_written) +{ + // default values + if (bytes_written) *bytes_written = 0; + + // shortcut + if (bytes_to_write == 0) return NPT_SUCCESS; + + // write the chunk header + char size[16]; + size[15] = '\n'; + size[14] = '\r'; + char* c = &size[14]; + unsigned int char_count = 2; + unsigned int value = bytes_to_write; + do { + unsigned int digit = (unsigned int)(value%16); + if (digit < 10) { + *--c = '0'+digit; + } else { + *--c = 'A'+digit-10; + } + char_count++; + value /= 16; + } while(value); + NPT_Result result = m_Stream.WriteFully(c, char_count); + if (NPT_FAILED(result)) return result; + + // write the chunk data + result = m_Stream.WriteFully(buffer, bytes_to_write); + if (NPT_FAILED(result)) return result; + + // finish the chunk + result = m_Stream.WriteFully(NPT_HTTP_LINE_TERMINATOR, 2); + if (NPT_SUCCEEDED(result) && bytes_written) { + *bytes_written = bytes_to_write; + } + return result; +} diff --git a/lib/libUPnP/Neptune/Source/Core/NptHttp.h b/lib/libUPnP/Neptune/Source/Core/NptHttp.h new file mode 100644 index 0000000..3d2a0d2 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptHttp.h @@ -0,0 +1,866 @@ +/***************************************************************** +| +| Neptune - HTTP Protocol +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +#ifndef _NPT_HTTP_H_ +#define _NPT_HTTP_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptUri.h" +#include "NptTypes.h" +#include "NptList.h" +#include "NptBufferedStreams.h" +#include "NptSockets.h" +#include "NptMap.h" +#include "NptDynamicCast.h" +#include "NptVersion.h" +#include "NptTime.h" +#include "NptThreads.h" +#include "NptAutomaticCleaner.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const unsigned int NPT_HTTP_DEFAULT_PORT = 80; +const unsigned int NPT_HTTPS_DEFAULT_PORT = 443; +const unsigned int NPT_HTTP_INVALID_PORT = 0; + +const NPT_Timeout NPT_HTTP_CLIENT_DEFAULT_CONNECTION_TIMEOUT = 30000; +const NPT_Timeout NPT_HTTP_CLIENT_DEFAULT_IO_TIMEOUT = 30000; +const NPT_Timeout NPT_HTTP_CLIENT_DEFAULT_NAME_RESOLVER_TIMEOUT = 60000; +const unsigned int NPT_HTTP_CLIENT_DEFAULT_MAX_REDIRECTS = 20; + +const NPT_Timeout NPT_HTTP_SERVER_DEFAULT_CONNECTION_TIMEOUT = NPT_TIMEOUT_INFINITE; +const NPT_Timeout NPT_HTTP_SERVER_DEFAULT_IO_TIMEOUT = 60000; + +const unsigned int NPT_HTTP_CONNECTION_MANAGER_MAX_CONNECTION_POOL_SIZE = 5; +const unsigned int NPT_HTTP_CONNECTION_MANAGER_MAX_CONNECTION_AGE = 30; // seconds +const unsigned int NPT_HTTP_MAX_RECONNECTS = 10; +const unsigned int NPT_HTTP_MAX_100_RESPONSES = 10; + +const int NPT_HTTP_PROTOCOL_MAX_LINE_LENGTH = 8192; +const int NPT_HTTP_PROTOCOL_MAX_HEADER_COUNT = 100; + +#define NPT_HTTP_PROTOCOL_1_0 "HTTP/1.0" +#define NPT_HTTP_PROTOCOL_1_1 "HTTP/1.1" +#define NPT_HTTP_METHOD_GET "GET" +#define NPT_HTTP_METHOD_HEAD "HEAD" +#define NPT_HTTP_METHOD_POST "POST" +#define NPT_HTTP_METHOD_PUT "PUT" +#define NPT_HTTP_METHOD_OPTIONS "OPTIONS" +#define NPT_HTTP_METHOD_DELETE "DELETE" +#define NPT_HTTP_METHOD_TRACE "TRACE" + +#define NPT_HTTP_HEADER_HOST "Host" +#define NPT_HTTP_HEADER_CONNECTION "Connection" +#define NPT_HTTP_HEADER_USER_AGENT "User-Agent" +#define NPT_HTTP_HEADER_SERVER "Server" +#define NPT_HTTP_HEADER_CONTENT_LENGTH "Content-Length" +#define NPT_HTTP_HEADER_CONTENT_TYPE "Content-Type" +#define NPT_HTTP_HEADER_CONTENT_ENCODING "Content-Encoding" +#define NPT_HTTP_HEADER_TRANSFER_ENCODING "Transfer-Encoding" +#define NPT_HTTP_HEADER_LOCATION "Location" +#define NPT_HTTP_HEADER_RANGE "Range" +#define NPT_HTTP_HEADER_CONTENT_RANGE "Content-Range" +#define NPT_HTTP_HEADER_COOKIE "Cookie" +#define NPT_HTTP_HEADER_ACCEPT_RANGES "Accept-Ranges" +#define NPT_HTTP_HEADER_CONTENT_RANGE "Content-Range" +#define NPT_HTTP_HEADER_AUTHORIZATION "Authorization" + +#define NPT_HTTP_TRANSFER_ENCODING_CHUNKED "chunked" + + +const int NPT_ERROR_HTTP_INVALID_RESPONSE_LINE = NPT_ERROR_BASE_HTTP - 0; +const int NPT_ERROR_HTTP_INVALID_REQUEST_LINE = NPT_ERROR_BASE_HTTP - 1; +const int NPT_ERROR_HTTP_NO_PROXY = NPT_ERROR_BASE_HTTP - 2; +const int NPT_ERROR_HTTP_INVALID_REQUEST = NPT_ERROR_BASE_HTTP - 3; +const int NPT_ERROR_HTTP_METHOD_NOT_SUPPORTED = NPT_ERROR_BASE_HTTP - 4; +const int NPT_ERROR_HTTP_TOO_MANY_REDIRECTS = NPT_ERROR_BASE_HTTP - 5; +const int NPT_ERROR_HTTP_TOO_MANY_RECONNECTS = NPT_ERROR_BASE_HTTP - 6; +const int NPT_ERROR_HTTP_CANNOT_RESEND_BODY = NPT_ERROR_BASE_HTTP - 7; + +#define NPT_HTTP_LINE_TERMINATOR "\r\n" + +#if !defined(NPT_CONFIG_HTTP_DEFAULT_USER_AGENT) +#define NPT_CONFIG_HTTP_DEFAULT_USER_AGENT "Neptune/" NPT_NEPTUNE_VERSION_STRING +#endif + +/*---------------------------------------------------------------------- +| types ++---------------------------------------------------------------------*/ +typedef unsigned int NPT_HttpStatusCode; +typedef NPT_UrlQuery NPT_HttpUrlQuery; // for backward compatibility + +/*---------------------------------------------------------------------- +| NPT_HttpUrl ++---------------------------------------------------------------------*/ +class NPT_HttpUrl : public NPT_Url { +public: + // constructors + NPT_HttpUrl() {} + NPT_HttpUrl(const char* host, + NPT_UInt16 port, + const char* path, + const char* query = NULL, + const char* fragment = NULL); + NPT_HttpUrl(const char* url, bool ignore_scheme = false); + + // methods + NPT_String ToString(bool with_fragment = true) const override; +}; + +/*---------------------------------------------------------------------- +| NPT_HttpProtocol ++---------------------------------------------------------------------*/ +class NPT_HttpProtocol +{ +public: + // class methods + const char* GetStatusCodeString(NPT_HttpStatusCode status_code); +}; + +/*---------------------------------------------------------------------- +| NPT_HttpHeader ++---------------------------------------------------------------------*/ +class NPT_HttpHeader { +public: + // constructors and destructor + NPT_HttpHeader(const char* name, const char* value); + ~NPT_HttpHeader(); + + // methods + NPT_Result Emit(NPT_OutputStream& stream) const; + const NPT_String& GetName() const { return m_Name; } + const NPT_String& GetValue() const { return m_Value; } + NPT_Result SetName(const char* name); + NPT_Result SetValue(const char* value); + +private: + // members + NPT_String m_Name; + NPT_String m_Value; +}; + +/*---------------------------------------------------------------------- +| NPT_HttpHeaders ++---------------------------------------------------------------------*/ +class NPT_HttpHeaders { +public: + // constructors and destructor + NPT_HttpHeaders(); + ~NPT_HttpHeaders(); + + // methods + NPT_Result Parse(NPT_BufferedInputStream& stream); + NPT_Result Emit(NPT_OutputStream& stream) const; + const NPT_List<NPT_HttpHeader*>& GetHeaders() const { return m_Headers; } + NPT_HttpHeader* GetHeader(const char* name) const; + const NPT_String* GetHeaderValue(const char* name) const; + NPT_Result SetHeader(const char* name, const char* value, bool replace=true); + NPT_Result AddHeader(const char* name, const char* value); + NPT_Result RemoveHeader(const char* name); + +private: + // members + NPT_List<NPT_HttpHeader*> m_Headers; +}; + +/*---------------------------------------------------------------------- +| NPT_HttpEntity ++---------------------------------------------------------------------*/ +class NPT_HttpEntity { +public: + // constructors and destructor + NPT_HttpEntity(); + NPT_HttpEntity(const NPT_HttpHeaders& headers); + virtual ~NPT_HttpEntity(); + + // methods + NPT_Result SetInputStream(const NPT_InputStreamReference& stream, + bool update_content_length = false); + NPT_Result SetInputStream(const void* data, NPT_Size size); + NPT_Result SetInputStream(const NPT_String& string); + NPT_Result SetInputStream(const char* string); + NPT_Result GetInputStream(NPT_InputStreamReference& stream); + NPT_Result Load(NPT_DataBuffer& buffer); + NPT_Result SetHeaders(const NPT_HttpHeaders& headers); + + // field access + NPT_Result SetContentLength(NPT_LargeSize length); + NPT_Result SetContentType(const char* type); + NPT_Result SetContentEncoding(const char* encoding); + NPT_Result SetTransferEncoding(const char* encoding); + NPT_LargeSize GetContentLength() { return m_ContentLength; } + const NPT_String& GetContentType() { return m_ContentType; } + const NPT_String& GetContentEncoding() { return m_ContentEncoding; } + const NPT_String& GetTransferEncoding() { return m_TransferEncoding;} + bool ContentLengthIsKnown() { return m_ContentLengthIsKnown; } + +private: + // members + NPT_InputStreamReference m_InputStream; + NPT_LargeSize m_ContentLength; + NPT_String m_ContentType; + NPT_String m_ContentEncoding; + NPT_String m_TransferEncoding; + bool m_ContentLengthIsKnown; +}; + +/*---------------------------------------------------------------------- +| NPT_HttpMessage ++---------------------------------------------------------------------*/ +class NPT_HttpMessage { +public: + // constructors and destructor + virtual ~NPT_HttpMessage(); + + // methods + const NPT_String& GetProtocol() const { + return m_Protocol; + } + NPT_Result SetProtocol(const char* protocol) { + m_Protocol = protocol; + return NPT_SUCCESS; + } + NPT_HttpHeaders& GetHeaders() { + return m_Headers; + } + const NPT_HttpHeaders& GetHeaders() const { + return m_Headers; + } + NPT_Result SetEntity(NPT_HttpEntity* entity); + NPT_HttpEntity* GetEntity() { + return m_Entity; + } + NPT_HttpEntity* GetEntity() const { + return m_Entity; + } + virtual NPT_Result ParseHeaders(NPT_BufferedInputStream& stream); + +protected: + // constructors + NPT_HttpMessage(const char* protocol); + + // members + NPT_String m_Protocol; + NPT_HttpHeaders m_Headers; + NPT_HttpEntity* m_Entity; +}; + +/*---------------------------------------------------------------------- +| NPT_HttpRequest ++---------------------------------------------------------------------*/ +class NPT_HttpRequest : public NPT_HttpMessage { +public: + // class methods + static NPT_Result Parse(NPT_BufferedInputStream& stream, + const NPT_SocketAddress* endpoint, + NPT_HttpRequest*& request); + + // constructors and destructor + NPT_HttpRequest(const NPT_HttpUrl& url, + const char* method, + const char* protocol = NPT_HTTP_PROTOCOL_1_0); + NPT_HttpRequest(const char* url, + const char* method, + const char* protocol = NPT_HTTP_PROTOCOL_1_0); + ~NPT_HttpRequest() override; + + // methods + const NPT_HttpUrl& GetUrl() const { return m_Url; } + NPT_HttpUrl& GetUrl() { return m_Url; } + NPT_Result SetUrl(const char* url); + NPT_Result SetUrl(const NPT_HttpUrl& url); + const NPT_String& GetMethod() const { return m_Method; } + virtual NPT_Result Emit(NPT_OutputStream& stream, bool use_proxy=false) const; + +protected: + // members + NPT_HttpUrl m_Url; + NPT_String m_Method; +}; + +/*---------------------------------------------------------------------- +| NPT_HttpResponse ++---------------------------------------------------------------------*/ +class NPT_HttpResponse : public NPT_HttpMessage { +public: + // class methods + static NPT_Result Parse(NPT_BufferedInputStream& stream, + NPT_HttpResponse*& response); + + // constructors and destructor + NPT_HttpResponse(NPT_HttpStatusCode status_code, + const char* reason_phrase, + const char* protocol = NPT_HTTP_PROTOCOL_1_0); + ~NPT_HttpResponse() override; + + // methods + NPT_Result SetStatus(NPT_HttpStatusCode status_code, + const char* reason_phrase, + const char* protocol = NULL); + NPT_Result SetProtocol(const char* protocol); + NPT_HttpStatusCode GetStatusCode() const { return m_StatusCode; } + const NPT_String& GetReasonPhrase() const { return m_ReasonPhrase; } + virtual NPT_Result Emit(NPT_OutputStream& stream) const; + +protected: + // members + NPT_HttpStatusCode m_StatusCode; + NPT_String m_ReasonPhrase; +}; + +/*---------------------------------------------------------------------- +| NPT_HttpProxyAddress ++---------------------------------------------------------------------*/ +class NPT_HttpProxyAddress +{ +public: + NPT_HttpProxyAddress() : m_Port(NPT_HTTP_INVALID_PORT) {} + NPT_HttpProxyAddress(const char* hostname, NPT_UInt16 port) : + m_HostName(hostname), m_Port(port) {} + + const NPT_String& GetHostName() const { return m_HostName; } + void SetHostName(const char* hostname) { m_HostName = hostname; } + NPT_UInt16 GetPort() const { return m_Port; } + void SetPort(NPT_UInt16 port) { m_Port = port; } + +private: + NPT_String m_HostName; + NPT_UInt16 m_Port; +}; + +/*---------------------------------------------------------------------- +| NPT_HttpProxySelector ++---------------------------------------------------------------------*/ +class NPT_HttpProxySelector +{ +public: + // class methods + static NPT_HttpProxySelector* GetDefault(); + static NPT_HttpProxySelector* GetSystemSelector(); + + // methods + virtual ~NPT_HttpProxySelector() {}; + virtual NPT_Result GetProxyForUrl(const NPT_HttpUrl& url, NPT_HttpProxyAddress& proxy) = 0; + +private: + // class members + static NPT_HttpProxySelector* m_SystemDefault; +}; + +class NPT_HttpRequestContext; + +/*---------------------------------------------------------------------- +| NPT_HttpClient ++---------------------------------------------------------------------*/ +class NPT_HttpClient { +public: + // types + struct Config { + Config() : m_ConnectionTimeout( NPT_HTTP_CLIENT_DEFAULT_CONNECTION_TIMEOUT), + m_IoTimeout( NPT_HTTP_CLIENT_DEFAULT_CONNECTION_TIMEOUT), + m_NameResolverTimeout(NPT_HTTP_CLIENT_DEFAULT_NAME_RESOLVER_TIMEOUT), + m_MaxRedirects( NPT_HTTP_CLIENT_DEFAULT_MAX_REDIRECTS), + m_UserAgent( NPT_CONFIG_HTTP_DEFAULT_USER_AGENT) {} + NPT_Timeout m_ConnectionTimeout; + NPT_Timeout m_IoTimeout; + NPT_Timeout m_NameResolverTimeout; + NPT_Cardinal m_MaxRedirects; + NPT_String m_UserAgent; + }; + + class Connection { + public: + virtual ~Connection() {} + virtual NPT_InputStreamReference& GetInputStream() = 0; + virtual NPT_OutputStreamReference& GetOutputStream() = 0; + virtual NPT_Result GetInfo(NPT_SocketInfo& info) = 0; + virtual bool SupportsPersistence() { return false; } + virtual bool IsRecycled() { return false; } + virtual NPT_Result Recycle() { delete this; return NPT_SUCCESS; } + virtual NPT_Result Abort() { return NPT_ERROR_NOT_IMPLEMENTED; } + }; + + class Connector { + public: + virtual ~Connector() {} + + virtual NPT_Result Connect(const NPT_HttpUrl& url, + NPT_HttpClient& client, + const NPT_HttpProxyAddress* proxy, + bool reuse, // whether we can reuse a connection or not + Connection*& connection) = 0; + + protected: + NPT_Result TrackConnection(NPT_HttpClient& client, + Connection* connection) { return client.TrackConnection(connection); } + Connector() {} // don't instantiate directly + }; + + // class methods + static NPT_Result WriteRequest(NPT_OutputStream& output_stream, + NPT_HttpRequest& request, + bool should_persist, + bool use_proxy = false); + static NPT_Result ReadResponse(NPT_InputStreamReference& input_stream, + bool should_persist, + bool expect_entity, + NPT_HttpResponse*& response, + NPT_Reference<Connection>* cref = NULL); + + /** + * @param connector Pointer to a connector instance, or NULL to use + * the default (TCP) connector. + * @param transfer_ownership Boolean flag. If true, the NPT_HttpClient object + * becomes the owner of the passed Connector and will delete it when it is + * itself deleted. If false, the caller keeps the ownership of the connector. + * This flag is ignored if the connector parameter is NULL. + */ + NPT_HttpClient(Connector* connector = NULL, bool transfer_ownership = true); + + virtual ~NPT_HttpClient(); + + // methods + NPT_Result SendRequest(NPT_HttpRequest& request, + NPT_HttpResponse*& response, + NPT_HttpRequestContext* context = NULL); + NPT_Result Abort(); + const Config& GetConfig() const { return m_Config; } + NPT_Result SetConfig(const Config& config); + NPT_Result SetProxy(const char* http_proxy_hostname, + NPT_UInt16 http_proxy_port, + const char* https_proxy_hostname = NULL, + NPT_UInt16 https_proxy_port = 0); + NPT_Result SetProxySelector(NPT_HttpProxySelector* selector); + NPT_Result SetConnector(Connector* connector); + NPT_Result SetTimeouts(NPT_Timeout connection_timeout, + NPT_Timeout io_timeout, + NPT_Timeout name_resolver_timeout); + NPT_Result SetUserAgent(const char* user_agent); + NPT_Result SetOptions(NPT_Flags options, bool on); + +protected: + // methods + NPT_Result TrackConnection(Connection* connection); + NPT_Result SendRequestOnce(NPT_HttpRequest& request, + NPT_HttpResponse*& response, + NPT_HttpRequestContext* context = NULL); + + // members + Config m_Config; + NPT_HttpProxySelector* m_ProxySelector; + bool m_ProxySelectorIsOwned; + Connector* m_Connector; + bool m_ConnectorIsOwned; + NPT_Mutex m_AbortLock; + bool m_Aborted; +}; + +/*---------------------------------------------------------------------- +| NPT_HttpConnectionManager ++---------------------------------------------------------------------*/ +class NPT_HttpConnectionManager : public NPT_Thread, + public NPT_AutomaticCleaner::Singleton +{ +public: + // singleton management + static NPT_HttpConnectionManager* GetInstance(); + + class Connection : public NPT_HttpClient::Connection + { + public: + Connection(NPT_HttpConnectionManager& manager, + NPT_SocketReference& socket, + NPT_InputStreamReference input_stream, + NPT_OutputStreamReference output_stream); + ~Connection() override; + + // NPT_HttpClient::Connection methods + NPT_InputStreamReference& GetInputStream() override { return m_InputStream; } + NPT_OutputStreamReference& GetOutputStream() override { return m_OutputStream; } + NPT_Result GetInfo(NPT_SocketInfo& info) override { return m_Socket->GetInfo(info); } + bool SupportsPersistence() override { return true; } + bool IsRecycled() override { return m_IsRecycled; } + NPT_Result Recycle() override; + NPT_Result Abort() override { return m_Socket->Cancel(); } + + // members + NPT_HttpConnectionManager& m_Manager; + bool m_IsRecycled; + NPT_TimeStamp m_TimeStamp; + NPT_SocketReference m_Socket; + NPT_InputStreamReference m_InputStream; + NPT_OutputStreamReference m_OutputStream; + }; + + // destructor + ~NPT_HttpConnectionManager() override; + + // methods + Connection* FindConnection(NPT_SocketAddress& address); + NPT_Result Recycle(Connection* connection); + NPT_Result Track(NPT_HttpClient* client, NPT_HttpClient::Connection* connection); + NPT_Result AbortConnections(NPT_HttpClient* client); + + // class methods + static NPT_Result Untrack(NPT_HttpClient::Connection* connection); + +private: + typedef NPT_List<NPT_HttpClient::Connection*> ConnectionList; + + // class members + static NPT_HttpConnectionManager* Instance; + + // constructor + NPT_HttpConnectionManager(); + + // NPT_Thread methods + void Run() override; + + // methods + NPT_Result UntrackConnection(NPT_HttpClient::Connection* connection); + NPT_Result Cleanup(); + + // members + NPT_Mutex m_Lock; + NPT_Cardinal m_MaxConnections; + NPT_Cardinal m_MaxConnectionAge; + NPT_SharedVariable m_Aborted; + NPT_List<Connection*> m_Connections; + NPT_Map<NPT_HttpClient*, ConnectionList> m_ClientConnections; +}; + +/*---------------------------------------------------------------------- +| NPT_HttpRequestContext ++---------------------------------------------------------------------*/ +class NPT_HttpRequestContext +{ +public: + // constructor + NPT_HttpRequestContext() {} + NPT_HttpRequestContext(const NPT_SocketAddress* local_address, + const NPT_SocketAddress* remote_address); + + // methods + const NPT_SocketAddress& GetLocalAddress() const { return m_LocalAddress; } + const NPT_SocketAddress& GetRemoteAddress() const { return m_RemoteAddress; } + void SetLocalAddress(const NPT_SocketAddress& address) { + m_LocalAddress = address; + } + void SetRemoteAddress(const NPT_SocketAddress& address) { + m_RemoteAddress = address; + } + +private: + // members + NPT_SocketAddress m_LocalAddress; + NPT_SocketAddress m_RemoteAddress; +}; + +/*---------------------------------------------------------------------- +| NPT_HttpRequestHandler ++---------------------------------------------------------------------*/ +class NPT_HttpRequestHandler +{ +public: + NPT_IMPLEMENT_DYNAMIC_CAST(NPT_HttpRequestHandler) + + // destructor + virtual ~NPT_HttpRequestHandler() {} + + // methods + virtual NPT_Result SetupResponse(NPT_HttpRequest& request, + const NPT_HttpRequestContext& context, + NPT_HttpResponse& response) = 0; + + /** + * Override this method if you want to write the body yourself. + * The default implementation will simply write out the entity's + * input stream. + */ + virtual NPT_Result SendResponseBody(const NPT_HttpRequestContext& context, + NPT_HttpResponse& response, + NPT_OutputStream& output); + + /** + * A notification method called by the server upon completing the + * processing of a request. + */ + virtual void Completed(NPT_Result /*result*/) {} +}; + +/*---------------------------------------------------------------------- +| NPT_HttpStaticRequestHandler ++---------------------------------------------------------------------*/ +class NPT_HttpStaticRequestHandler : public NPT_HttpRequestHandler +{ +public: + // constructors + NPT_HttpStaticRequestHandler(const char* document, + const char* mime_type = "text/html", + bool copy = true); + NPT_HttpStaticRequestHandler(const void* data, + NPT_Size size, + const char* mime_type = "text/html", + bool copy = true); + + // NPT_HttpRequestHandler methods + NPT_Result SetupResponse(NPT_HttpRequest& request, + const NPT_HttpRequestContext& context, + NPT_HttpResponse& response) override; + +private: + NPT_String m_MimeType; + NPT_DataBuffer m_Buffer; +}; + +/*---------------------------------------------------------------------- +| NPT_HttpFileRequestHandler_DefaultFileTypeMapEntry ++---------------------------------------------------------------------*/ +typedef struct NPT_HttpFileRequestHandler_DefaultFileTypeMapEntry { + const char* extension; + const char* mime_type; +} NPT_HttpFileRequestHandler_FileTypeMapEntry; + +/*---------------------------------------------------------------------- +| NPT_HttpFileRequestHandler ++---------------------------------------------------------------------*/ +class NPT_HttpFileRequestHandler : public NPT_HttpRequestHandler +{ +public: + // constructors + NPT_HttpFileRequestHandler(const char* url_root, + const char* file_root, + bool auto_dir = false, + const char* auto_index = NULL); + + // NPT_HttpRequestHandler methods + NPT_Result SetupResponse(NPT_HttpRequest& request, + const NPT_HttpRequestContext& context, + NPT_HttpResponse& response) override; + + // class methods + static const char* GetDefaultContentType(const char* extension); + + // accessors + NPT_Map<NPT_String,NPT_String>& GetFileTypeMap() { return m_FileTypeMap; } + void SetDefaultMimeType(const char* mime_type) { + m_DefaultMimeType = mime_type; + } + void SetUseDefaultFileTypeMap(bool use_default) { + m_UseDefaultFileTypeMap = use_default; + } + + static NPT_Result SetupResponseBody(NPT_HttpResponse& response, + NPT_InputStreamReference& stream, + const NPT_String* range_spec = NULL); + +protected: + // methods + const char* GetContentType(const NPT_String& filename); + +private: + NPT_String m_UrlRoot; + NPT_String m_FileRoot; + NPT_Map<NPT_String, NPT_String> m_FileTypeMap; + NPT_String m_DefaultMimeType; + bool m_UseDefaultFileTypeMap; + bool m_AutoDir; + NPT_String m_AutoIndex; +}; + +/*---------------------------------------------------------------------- +| NPT_HttpServer ++---------------------------------------------------------------------*/ +class NPT_HttpServer { +public: + // types + struct Config { + NPT_Timeout m_ConnectionTimeout; + NPT_Timeout m_IoTimeout; + NPT_IpAddress m_ListenAddress; + NPT_UInt16 m_ListenPort; + bool m_ReuseAddress; + }; + + // constructors and destructor + NPT_HttpServer(NPT_UInt16 listen_port = NPT_HTTP_DEFAULT_PORT, bool cancellable = false); + NPT_HttpServer(NPT_IpAddress listen_address, + NPT_UInt16 listen_port = NPT_HTTP_DEFAULT_PORT, + bool cancellable = false); + virtual ~NPT_HttpServer(); + + // methods + NPT_Result SetConfig(const Config& config); + const Config& GetConfig() const { return m_Config; } + NPT_Result SetListenPort(NPT_UInt16 port, bool reuse_address = true); + NPT_Result SetTimeouts(NPT_Timeout connection_timeout, NPT_Timeout io_timeout); + NPT_Result SetServerHeader(const char* server_header); + NPT_Result Abort(); + NPT_Result WaitForNewClient(NPT_InputStreamReference& input, + NPT_OutputStreamReference& output, + NPT_HttpRequestContext* context, + NPT_Flags socket_flags = 0); + NPT_Result Loop(bool cancellable_sockets=true); + NPT_UInt16 GetPort() { return m_BoundPort; } + void Terminate(); + + /** + * Add a request handler. By default the ownership of the handler is NOT transfered to this object, + * so the caller is responsible for the lifetime management of the handler object. + */ + virtual NPT_Result AddRequestHandler(NPT_HttpRequestHandler* handler, + const char* path, + bool include_children = false, + bool transfer_ownership = false); + virtual NPT_HttpRequestHandler* FindRequestHandler(NPT_HttpRequest& request); + virtual NPT_List<NPT_HttpRequestHandler*> FindRequestHandlers(NPT_HttpRequest& request); + + /** + * Parse the request from a new client, form a response, and send it back. + */ + virtual NPT_Result RespondToClient(NPT_InputStreamReference& input, + NPT_OutputStreamReference& output, + const NPT_HttpRequestContext& context); + +protected: + // types + struct HandlerConfig { + HandlerConfig(NPT_HttpRequestHandler* handler, + const char* path, + bool include_children, + bool transfer_ownership = false); + ~HandlerConfig(); + + // methods + bool WillHandle(NPT_HttpRequest& request); + + // members + NPT_HttpRequestHandler* m_Handler; + NPT_String m_Path; + bool m_IncludeChildren; + bool m_HandlerIsOwned; + }; + + // methods + NPT_Result Bind(); + + // members + NPT_TcpServerSocket m_Socket; + NPT_UInt16 m_BoundPort; + Config m_Config; + NPT_List<HandlerConfig*> m_RequestHandlers; + NPT_String m_ServerHeader; + bool m_Run; +}; + +/*---------------------------------------------------------------------- +| NPT_HttpResponder ++---------------------------------------------------------------------*/ +class NPT_HttpResponder { +public: + // types + struct Config { + NPT_Timeout m_IoTimeout; + }; + + // constructors and destructor + NPT_HttpResponder(NPT_InputStreamReference& input, + NPT_OutputStreamReference& output); + virtual ~NPT_HttpResponder(); + + // methods + NPT_Result SetConfig(const Config& config); + NPT_Result SetTimeout(NPT_Timeout io_timeout); + NPT_Result ParseRequest(NPT_HttpRequest*& request, + const NPT_SocketAddress* local_address = NULL); + NPT_Result SendResponseHeaders(NPT_HttpResponse& response); + +protected: + // members + Config m_Config; + NPT_BufferedInputStreamReference m_Input; + NPT_OutputStreamReference m_Output; +}; + +/*---------------------------------------------------------------------- +| NPT_HttpChunkedInputStream ++---------------------------------------------------------------------*/ +class NPT_HttpChunkedInputStream : public NPT_InputStream +{ +public: + // constructors and destructor + NPT_HttpChunkedInputStream(NPT_BufferedInputStreamReference& stream); + ~NPT_HttpChunkedInputStream() override; + + // NPT_InputStream methods + NPT_Result Read(void* buffer, + NPT_Size bytes_to_read, + NPT_Size* bytes_read = NULL) override; + NPT_Result Seek(NPT_Position offset) override; + NPT_Result Tell(NPT_Position& offset) override; + NPT_Result GetSize(NPT_LargeSize& size) override; + NPT_Result GetAvailable(NPT_LargeSize& available) override; + +protected: + // members + NPT_BufferedInputStreamReference m_Source; + NPT_UInt32 m_CurrentChunkSize; + bool m_Eos; +}; + +/*---------------------------------------------------------------------- +| NPT_HttpChunkedOutputStream ++---------------------------------------------------------------------*/ +class NPT_HttpChunkedOutputStream : public NPT_OutputStream +{ +public: + // constructors and destructor + NPT_HttpChunkedOutputStream(NPT_OutputStream& stream); + ~NPT_HttpChunkedOutputStream() override; + + // NPT_OutputStream methods + NPT_Result Write(const void* buffer, + NPT_Size bytes_to_write, + NPT_Size* bytes_written = NULL) override; + NPT_Result Seek(NPT_Position /*offset*/) override { return NPT_ERROR_NOT_SUPPORTED;} + NPT_Result Tell(NPT_Position& offset) override { return m_Stream.Tell(offset); } + NPT_Result Flush() override { return m_Stream.Flush(); } + +protected: + // members + NPT_OutputStream& m_Stream; +}; + +#endif // _NPT_HTTP_H_ + diff --git a/lib/libUPnP/Neptune/Source/Core/NptInterfaces.h b/lib/libUPnP/Neptune/Source/Core/NptInterfaces.h new file mode 100644 index 0000000..b0bb264 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptInterfaces.h @@ -0,0 +1,115 @@ +/***************************************************************** +| +| Neptune - Interfaces +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +#ifndef _NPT_INTERFACES_H_ +#define _NPT_INTERFACES_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptTypes.h" +#include "NptCommon.h" +#include "NptResults.h" +#include "NptConfig.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const int NPT_ERROR_NO_SUCH_INTERFACE = NPT_ERROR_BASE_INTERFACES - 0; + +/*---------------------------------------------------------------------- +| NPT_InterfaceId ++---------------------------------------------------------------------*/ +class NPT_InterfaceId +{ + public: + // methods + bool operator==(const NPT_InterfaceId& id) const { + return ((id.m_Id == m_Id) && (id.m_Version == m_Version)); + } + + // members + unsigned long m_Id; + unsigned long m_Version; +}; + +/*---------------------------------------------------------------------- +| NPT_Polymorphic ++---------------------------------------------------------------------*/ +class NPT_Polymorphic +{ +public: + // destructor + virtual ~NPT_Polymorphic() {} + + // methods + virtual NPT_Result GetInterface(const NPT_InterfaceId& id, + NPT_Interface*& iface) = 0; +}; + +/*---------------------------------------------------------------------- +| NPT_Interruptible ++---------------------------------------------------------------------*/ +class NPT_Interruptible +{ +public: + // destructor + virtual ~NPT_Interruptible() {} + + // methods + virtual NPT_Result Interrupt() = 0; +}; + +/*---------------------------------------------------------------------- +| NPT_Configurable ++---------------------------------------------------------------------*/ +class NPT_Configurable +{ +public: + // destructor + virtual ~NPT_Configurable() {} + + // methods + virtual NPT_Result SetProperty(const char* /*name*/, + const char* /*value*/) { + return NPT_ERROR_NO_SUCH_PROPERTY; + } + virtual NPT_Result SetProperty(const char* /*name*/, + int /*value*/) { + return NPT_ERROR_NO_SUCH_PROPERTY; + } + virtual NPT_Result GetProperty(const char* /*name*/, + NPT_PropertyValue& /*value*/) { + return NPT_ERROR_NO_SUCH_PROPERTY; + } +}; + +#endif // _NPT_INTERFACES_H_ diff --git a/lib/libUPnP/Neptune/Source/Core/NptJson.cpp b/lib/libUPnP/Neptune/Source/Core/NptJson.cpp new file mode 100644 index 0000000..300e210 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptJson.cpp @@ -0,0 +1,37 @@ +/***************************************************************** +| +| Neptune - JSON +| +| Copyright (c) 2002-2012, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptJson.h" +#include "NptUtils.h" + diff --git a/lib/libUPnP/Neptune/Source/Core/NptJson.h b/lib/libUPnP/Neptune/Source/Core/NptJson.h new file mode 100644 index 0000000..699feef --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptJson.h @@ -0,0 +1,42 @@ +/***************************************************************** +| +| Neptune - JSON +| +| Copyright (c) 2002-2012, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +#ifndef _NPT_JSON_H_ +#define _NPT_JSON_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptTypes.h" +#include "NptStrings.h" + + +#endif // _NPT_JSON_H_ diff --git a/lib/libUPnP/Neptune/Source/Core/NptList.cpp b/lib/libUPnP/Neptune/Source/Core/NptList.cpp new file mode 100644 index 0000000..8879756 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptList.cpp @@ -0,0 +1,34 @@ +/***************************************************************** +| +| Neptune - Lists +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ diff --git a/lib/libUPnP/Neptune/Source/Core/NptList.h b/lib/libUPnP/Neptune/Source/Core/NptList.h new file mode 100644 index 0000000..37d1802 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptList.h @@ -0,0 +1,704 @@ +/***************************************************************** +| +| Neptune - Lists +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +#ifndef _NPT_LIST_H_ +#define _NPT_LIST_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptResults.h" +#include "NptTypes.h" +#include "NptConstants.h" +#include "NptCommon.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const int NPT_ERROR_LIST_EMPTY = NPT_ERROR_BASE_LIST - 0; +const int NPT_ERROR_LIST_OPERATION_ABORTED = NPT_ERROR_BASE_LIST - 1; +const int NPT_ERROR_LIST_OPERATION_CONTINUE = NPT_ERROR_BASE_LIST - 2; + +/*---------------------------------------------------------------------- +| NPT_List ++---------------------------------------------------------------------*/ +template <typename T> +class NPT_List +{ +protected: + class Item; + +public: + // types + typedef T Element; + + class Iterator { + public: + Iterator() : m_Item(NULL) {} + explicit Iterator(Item* item) : m_Item(item) {} + Iterator(const Iterator& copy) : m_Item(copy.m_Item) {} + T& operator*() const { return m_Item->m_Data; } + T* operator->() const { return &m_Item->m_Data;} + Iterator& operator++() { // prefix + m_Item = m_Item->m_Next; + return (*this); + } + Iterator operator++(int) { // postfix + Iterator saved_this = *this; + m_Item = m_Item->m_Next; + return saved_this; + } + Iterator& operator--() { // prefix + m_Item = m_Item->m_Prev; + return (*this); + } + Iterator operator--(int) { // postfix + Iterator saved_this = *this; + m_Item = m_Item->m_Prev; + return saved_this; + } + operator bool() const { + return m_Item != NULL; + } + bool operator==(const Iterator& other) const { + return m_Item == other.m_Item; + } + bool operator!=(const Iterator& other) const { + return m_Item != other.m_Item; + } + void operator=(const Iterator& other) { + m_Item = other.m_Item; + } + void operator=(Item* item) { + m_Item = item; + } + + private: + Item* m_Item; + + // friends + friend class NPT_List<T>; + }; + + // methods + NPT_List<T>(); + NPT_List<T>(const NPT_List<T>& list); + ~NPT_List<T>(); + NPT_Result Add(const T& data); + NPT_Result Insert(const Iterator where, const T& data); + NPT_Result Remove(const T& data, bool all=false); + NPT_Result Erase(const Iterator position); + NPT_Result PopHead(T& data); + bool Contains(const T& data) const; + NPT_Result Clear(); + NPT_Result Get(NPT_Ordinal index, T& data) const; + NPT_Result Get(NPT_Ordinal index, T*& data) const; + NPT_Cardinal GetItemCount() const { return m_ItemCount; } + Iterator GetFirstItem() const { return Iterator(m_Head); } + Iterator GetLastItem() const { return Iterator(m_Tail); } + Iterator GetItem(NPT_Ordinal index) const; + + // list manipulation + NPT_Result Add(NPT_List<T>& list); + NPT_Result Remove(const NPT_List<T>& list, bool all=false); + NPT_Result Cut(NPT_Cardinal keep, NPT_List<T>& cut); + + // item manipulation + NPT_Result Add(Item& item); + NPT_Result Detach(Item& item); + NPT_Result Insert(const Iterator where, Item& item); + + // list operations + // keep these template members defined here because MSV6 does not let + // us define them later + template <typename X> + NPT_Result Apply(const X& function) const + { + Item* item = m_Head; + while (item) { + function(item->m_Data); + item = item->m_Next; + } + + return NPT_SUCCESS; + } + + template <typename X, typename P> + NPT_Result ApplyUntil(const X& function, const P& predicate, bool* match = NULL) const + { + Item* item = m_Head; + while (item) { + NPT_Result return_value; + if (predicate(function(item->m_Data), return_value)) { + if (match) *match = true; + return return_value; + } + item = item->m_Next; + } + + if (match) *match = false; + return NPT_SUCCESS; + } + + template <typename P> + Iterator Find(const P& predicate, NPT_Ordinal n=0) const + { + Item* item = m_Head; + while (item) { + if (predicate(item->m_Data)) { + if (n == 0) { + return Iterator(item); + } + --n; + } + item = item->m_Next; + } + + return Iterator(NULL); + } + + // Merge sort algorithm + // http://en.wikipedia.org/wiki/Mergesort + template <typename X> + NPT_Result Sort(const X& function) + { + if (GetItemCount() <= 1) return NPT_SUCCESS; + + NPT_List<T> right; + NPT_CHECK(Cut(GetItemCount() >> 1, right)); + + // sort the left side + Sort(function); + + // sort the right side + right.Sort(function); + + // merge the two back inline + if (function(m_Tail->m_Data, right.m_Head->m_Data) > 0) { + Merge(right, function); + } else { + // append right + right.m_Head->m_Prev = m_Tail; + m_Tail->m_Next = right.m_Head; + m_Tail = right.m_Tail; + m_ItemCount += right.m_ItemCount; + + right.m_ItemCount = 0; + right.m_Head = right.m_Tail = NULL; + } + + return NPT_SUCCESS; + } + + template <typename X> + NPT_Result Merge(NPT_List<T>& other, const X& function) + { + Iterator left = GetFirstItem(); + Iterator right; + while (left && other.m_Head) { + if (function(*left, other.m_Head->m_Data) <= 0) { + ++left; + } else { + // remove head and insert it + Item* head = other.m_Head; + other.Detach(*head); + Insert(left, *head); + } + } + + // add what's left of other if any + if (other.m_Head) { + other.m_Head->m_Prev = m_Tail; + if (m_Tail) m_Tail->m_Next = other.m_Head; + m_Tail = other.m_Tail; + if (!m_Head) m_Head = other.m_Head; + other.m_Head = other.m_Tail = NULL; + } + m_ItemCount += other.m_ItemCount; + other.m_ItemCount = 0; + return NPT_SUCCESS; + } + + // operators + void operator=(const NPT_List<T>& other); + bool operator==(const NPT_List<T>& other) const; + bool operator!=(const NPT_List<T>& other) const; + +protected: + // types + class Item + { + public: + // methods + Item(const T& data) : m_Next(0), m_Prev(0), m_Data(data) {} + + // members + Item* m_Next; + Item* m_Prev; + T m_Data; + + // friends + //friend class NPT_List<T>; + //friend class NPT_List<T>::Iterator; + }; + + // members + NPT_Cardinal m_ItemCount; + Item* m_Head; + Item* m_Tail; +}; + +/*---------------------------------------------------------------------- +| NPT_List<T>::NPT_List ++---------------------------------------------------------------------*/ +template <typename T> +inline +NPT_List<T>::NPT_List() : m_ItemCount(0), m_Head(0), m_Tail(0) +{ +} + +/*---------------------------------------------------------------------- +| NPT_List<T>::NPT_List ++---------------------------------------------------------------------*/ +template <typename T> +inline +NPT_List<T>::NPT_List(const NPT_List<T>& list) : m_ItemCount(0), m_Head(0), m_Tail(0) +{ + *this = list; +} + +/*---------------------------------------------------------------------- +| NPT_List<T>::~NPT_List<T> ++---------------------------------------------------------------------*/ +template <typename T> +inline +NPT_List<T>::~NPT_List() +{ + Clear(); +} + +/*---------------------------------------------------------------------- +| NPT_List<T>::operator= ++---------------------------------------------------------------------*/ +template <typename T> +void +NPT_List<T>::operator=(const NPT_List<T>& list) +{ + // cleanup + Clear(); + + // copy the new list + Item* item = list.m_Head; + while (item) { + Add(item->m_Data); + item = item->m_Next; + } +} + +/*---------------------------------------------------------------------- +| NPT_List<T>::operator== ++---------------------------------------------------------------------*/ +template <typename T> +bool +NPT_List<T>::operator==(const NPT_List<T>& other) const +{ + // quick test + if (m_ItemCount != other.m_ItemCount) return false; + + // compare all elements one by one + Item* our_item = m_Head; + Item* their_item = other.m_Head; + while (our_item && their_item) { + if (our_item->m_Data != their_item->m_Data) return false; + our_item = our_item->m_Next; + their_item = their_item->m_Next; + } + + return our_item == NULL && their_item == NULL; +} + +/*---------------------------------------------------------------------- +| NPT_List<T>::operator!= ++---------------------------------------------------------------------*/ +template <typename T> +inline +bool +NPT_List<T>::operator!=(const NPT_List<T>& other) const +{ + return !(*this == other); +} + +/*---------------------------------------------------------------------- +| NPT_List<T>::Clear ++---------------------------------------------------------------------*/ +template <typename T> +NPT_Result +NPT_List<T>::Clear() +{ + // delete all items + Item* item = m_Head; + while (item) { + Item* next = item->m_Next; + delete item; + item = next; + } + + m_ItemCount = 0; + m_Head = NULL; + m_Tail = NULL; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_List<T>::Add ++---------------------------------------------------------------------*/ +template <typename T> +NPT_Result +NPT_List<T>::Add(Item& item) +{ + // add element at the tail + if (m_Tail) { + item.m_Prev = m_Tail; + item.m_Next = NULL; + m_Tail->m_Next = &item; + m_Tail = &item; + } else { + m_Head = &item; + m_Tail = &item; + item.m_Next = NULL; + item.m_Prev = NULL; + } + + // one more item in the list now + ++m_ItemCount; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_List<T>::Add ++---------------------------------------------------------------------*/ +template <typename T> +NPT_Result +NPT_List<T>::Add(NPT_List<T>& list) +{ + // copy the new list + Item* item = list.m_Head; + while (item) { + Add(item->m_Data); + item = item->m_Next; + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_List<T>::Add ++---------------------------------------------------------------------*/ +template <typename T> +inline +NPT_Result +NPT_List<T>::Add(const T& data) +{ + return Add(*new Item(data)); +} + +/*---------------------------------------------------------------------- +| NPT_List<T>::GetItem ++---------------------------------------------------------------------*/ +template <typename T> +typename NPT_List<T>::Iterator +NPT_List<T>::GetItem(NPT_Ordinal n) const +{ + Iterator result; + if (n >= m_ItemCount) return result; + + result = m_Head; + for (unsigned int i=0; i<n; i++) { + ++result; + } + + return result; +} + +/*---------------------------------------------------------------------- +| NPT_List<T>::Insert ++---------------------------------------------------------------------*/ +template <typename T> +inline +NPT_Result +NPT_List<T>::Insert(Iterator where, const T&data) +{ + return Insert(where, *new Item(data)); +} + +/*---------------------------------------------------------------------- +| NPT_List<T>::Insert ++---------------------------------------------------------------------*/ +template <typename T> +NPT_Result +NPT_List<T>::Insert(Iterator where, Item& item) +{ + // insert the item in the list + Item* position = where.m_Item; + if (position) { + // insert at position + item.m_Next = position; + item.m_Prev = position->m_Prev; + position->m_Prev = &item; + if (item.m_Prev) { + item.m_Prev->m_Next = &item; + } else { + // this is the new head + m_Head = &item; + } + + // one more item in the list now + ++m_ItemCount; + } else { + // insert at tail + return Add(item); + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_List<T>::Erase ++---------------------------------------------------------------------*/ +template <typename T> +NPT_Result +NPT_List<T>::Erase(Iterator position) +{ + if (!position) return NPT_ERROR_NO_SUCH_ITEM; + Detach(*position.m_Item); + delete position.m_Item; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_List<T>::Remove ++---------------------------------------------------------------------*/ +template <typename T> +NPT_Result +NPT_List<T>::Remove(const T& data, bool all) +{ + Item* item = m_Head; + NPT_Cardinal matches = 0; + + while (item) { + Item* next = item->m_Next; + if (item->m_Data == data) { + // we found a match + ++matches; + + // detach item + Detach(*item); + + // destroy the item + delete item; + + if (!all) return NPT_SUCCESS; + } + item = next; + } + + return matches?NPT_SUCCESS:NPT_ERROR_NO_SUCH_ITEM; +} + +/*---------------------------------------------------------------------- +| NPT_List<T>::Remove ++---------------------------------------------------------------------*/ +template <typename T> +NPT_Result +NPT_List<T>::Remove(const NPT_List<T>& list, bool all) +{ + Item* item = list.m_Head; + while (item) { + Remove(item->m_Data, all); + item = item->m_Next; + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_List<T>::Detach ++---------------------------------------------------------------------*/ +template <typename T> +NPT_Result +NPT_List<T>::Detach(Item& item) +{ + // remove item + if (item.m_Prev) { + // item is not the head + if (item.m_Next) { + // item is not the tail + item.m_Next->m_Prev = item.m_Prev; + item.m_Prev->m_Next = item.m_Next; + } else { + // item is the tail + m_Tail = item.m_Prev; + m_Tail->m_Next = NULL; + } + } else { + // item is the head + m_Head = item.m_Next; + if (m_Head) { + // item is not the tail + m_Head->m_Prev = NULL; + } else { + // item is also the tail + m_Tail = NULL; + } + } + + // one less item in the list now + --m_ItemCount; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_List<T>::Get ++---------------------------------------------------------------------*/ +template <typename T> +NPT_Result +NPT_List<T>::Get(NPT_Ordinal index, T& data) const +{ + T* data_pointer; + NPT_CHECK(Get(index, data_pointer)); + data = *data_pointer; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_List<T>::Get ++---------------------------------------------------------------------*/ +template <typename T> +NPT_Result +NPT_List<T>::Get(NPT_Ordinal index, T*& data) const +{ + Item* item = m_Head; + + if (index < m_ItemCount) { + while (index--) item = item->m_Next; + data = &item->m_Data; + return NPT_SUCCESS; + } else { + data = NULL; + return NPT_ERROR_NO_SUCH_ITEM; + } +} + +/*---------------------------------------------------------------------- +| NPT_List<T>::PopHead ++---------------------------------------------------------------------*/ +template <typename T> +NPT_Result +NPT_List<T>::PopHead(T& data) +{ + // check that we have an element + if (m_Head == NULL) return NPT_ERROR_LIST_EMPTY; + + // copy the head item's data + data = m_Head->m_Data; + + // discard the head item + Item* head = m_Head; + m_Head = m_Head->m_Next; + if (m_Head) { + m_Head->m_Prev = NULL; + } else { + m_Tail = NULL; + } + delete head; + + // update the count + --m_ItemCount; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_List<T>::Contains ++---------------------------------------------------------------------*/ +template <typename T> +bool +NPT_List<T>::Contains(const T& data) const +{ + Item* item = m_Head; + while (item) { + if (item->m_Data == data) return true; + item = item->m_Next; + } + + return false; +} + +/*---------------------------------------------------------------------- +| NPT_List<T>::Cut ++---------------------------------------------------------------------*/ +template <typename T> +NPT_Result +NPT_List<T>::Cut(NPT_Cardinal keep, NPT_List<T>& cut) +{ + cut.Clear(); + + // shortcut + if (keep >= GetItemCount()) return NPT_SUCCESS; + + // update new counts first + cut.m_ItemCount = m_ItemCount-keep; + m_ItemCount = keep; + + // look for the cut-point item + Item* item = m_Head; + while (keep--) { item = item->m_Next;} + + // the cut list goes from the cut-point item to the tail + cut.m_Head = item; + cut.m_Tail = m_Tail; + + // update the portion of the list we keep + if (item == m_Head) m_Head = NULL; + m_Tail = item->m_Prev; + + // update the cut list + if (item->m_Prev) item->m_Prev->m_Next = NULL; + item->m_Prev = NULL; + + return NPT_SUCCESS; +} + +#endif // _NPT_LIST_H_ diff --git a/lib/libUPnP/Neptune/Source/Core/NptLogging.cpp b/lib/libUPnP/Neptune/Source/Core/NptLogging.cpp new file mode 100644 index 0000000..51d20e7 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptLogging.cpp @@ -0,0 +1,1555 @@ +/***************************************************************** +| +| Neptune - Logging Support +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| +****************************************************************/ +/** @file +* Implementation file for logging +*/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include <stdarg.h> + +#include "NptLogging.h" +#include "NptList.h" +#include "NptStreams.h" +#include "NptSockets.h" +#include "NptUtils.h" +#include "NptFile.h" +#include "NptSystem.h" +#include "NptConsole.h" +#include "NptDebug.h" + +/*---------------------------------------------------------------------- +| logging ++---------------------------------------------------------------------*/ +//NPT_SET_LOCAL_LOGGER("neptune.logging") + +/*---------------------------------------------------------------------- +| types ++---------------------------------------------------------------------*/ +class NPT_LogConsoleHandler : public NPT_LogHandler { +public: + // enums + enum { + OUTPUT_TO_CONSOLE = 1, + OUTPUT_TO_DEBUG = 2 + }; + + // class methods + static NPT_Result Create(const char* logger_name, NPT_LogHandler*& handler); + + // methods + void Log(const NPT_LogRecord& record) override; + +private: + // members + NPT_UInt32 m_Outputs; + bool m_UseColors; + NPT_Flags m_FormatFilter; +}; + +class NPT_LogFileHandler : public NPT_LogHandler { +public: + // class methods + static NPT_Result Create(const char* logger_name, NPT_LogHandler*& handler); + + // methods + void Log(const NPT_LogRecord& record) override; + +private: + NPT_Result Open(bool append = true); + +private: + // members + bool m_Flush; + bool m_Append; + NPT_String m_Filename; + NPT_Flags m_FormatFilter; + NPT_LargeSize m_MaxFilesize; + NPT_OutputStreamReference m_Stream; +}; + +class NPT_LogTcpHandler : public NPT_LogHandler { +public: + // class methods + static void FormatRecord(const NPT_LogRecord& record, NPT_String& msg); + static NPT_Result Create(const char* logger_name, NPT_LogHandler*& handler); + + // methods + void Log(const NPT_LogRecord& record) override; + +private: + // constructor + NPT_LogTcpHandler() : m_Port(0) {} + + // methods + NPT_Result Connect(); + + // members + NPT_String m_Host; + NPT_UInt16 m_Port; + NPT_OutputStreamReference m_Stream; +}; + +class NPT_LogUdpHandler : public NPT_LogHandler { +public: + // class methods + static NPT_Result Create(const char* logger_name, NPT_LogHandler*& handler); + + // methods + void Log(const NPT_LogRecord& record) override; + +private: + // members + NPT_UdpSocket m_Socket; + NPT_SocketAddress m_Target; +}; + +class NPT_LogNullHandler : public NPT_LogHandler { +public: + // class methods + static NPT_Result Create(NPT_LogHandler*& handler); + + // methods + void Log(const NPT_LogRecord& record) override; +}; + +class NPT_LogCustomHandler : public NPT_LogHandler { +public: + // class methods + static NPT_Result SetCustomHandlerFunction(CustomHandlerExternalFunction function); + static NPT_Result Create(NPT_LogHandler*& handler); + + // methods + void Log(const NPT_LogRecord& record) override; + +private: + static CustomHandlerExternalFunction s_ExternalFunction; +}; + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +#define NPT_LOG_HEAP_BUFFER_INCREMENT 4096 +#define NPT_LOG_STACK_BUFFER_MAX_SIZE 512 +#define NPT_LOG_HEAP_BUFFER_MAX_SIZE 65536 + +#if !defined(NPT_CONFIG_LOG_CONFIG_ENV) +#define NPT_CONFIG_LOG_CONFIG_ENV "NEPTUNE_LOG_CONFIG" +#endif + +#if !defined(NPT_CONFIG_DEFAULT_LOG_CONFIG_SOURCE) +#define NPT_CONFIG_DEFAULT_LOG_CONFIG_SOURCE "file:neptune-logging.properties" +#endif + +#if !defined(NPT_CONFIG_DEFAULT_LOG_LEVEL) +#define NPT_CONFIG_DEFAULT_LOG_LEVEL NPT_LOG_LEVEL_OFF +#endif +#define NPT_LOG_ROOT_DEFAULT_HANDLER "ConsoleHandler" +#if !defined(NPT_CONFIG_DEFAULT_FILE_HANDLER_FILENAME) +#define NPT_CONFIG_DEFAULT_LOG_FILE_HANDLER_FILENAME "_neptune.log" +#endif + +#define NPT_LOG_TCP_HANDLER_DEFAULT_PORT 7723 +#define NPT_LOG_TCP_HANDLER_DEFAULT_CONNECT_TIMEOUT 5000 /* 5 seconds */ + +#define NPT_LOG_UDP_HANDLER_DEFAULT_PORT 7724 + +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__APPLE__) +#define NPT_LOG_CONSOLE_HANDLER_DEFAULT_COLOR_MODE false +#else +#define NPT_LOG_CONSOLE_HANDLER_DEFAULT_COLOR_MODE true +#endif + +#ifndef NPT_CONFIG_DEFAULT_LOG_CONSOLE_HANDLER_OUTPUTS +#define NPT_CONFIG_DEFAULT_LOG_CONSOLE_HANDLER_OUTPUTS OUTPUT_TO_DEBUG +#endif + +#define NPT_LOG_FILE_HANDLER_MIN_RECYCLE_SIZE 1000000 + +#define NPT_LOG_FORMAT_FILTER_NO_SOURCE 1 +#define NPT_LOG_FORMAT_FILTER_NO_TIMESTAMP 2 +#define NPT_LOG_FORMAT_FILTER_NO_FUNCTION_NAME 4 +#define NPT_LOG_FORMAT_FILTER_NO_LOGGER_NAME 8 +#define NPT_LOG_FORMAT_FILTER_NO_SOURCEPATH 16 +#define NPT_LOG_FORMAT_FILTER_NO_THREAD_ID 32 + +/*---------------------------------------------------------------------- +| globals ++---------------------------------------------------------------------*/ +static NPT_LogManager LogManager; + +/*---------------------------------------------------------------------- +| NPT_LogManagerAutoDisabler ++---------------------------------------------------------------------*/ +class NPT_LogManagerAutoDisabler +{ +public: + NPT_LogManagerAutoDisabler() : m_WasEnabled(LogManager.IsEnabled()) { + LogManager.SetEnabled(false); + } + ~NPT_LogManagerAutoDisabler() { + LogManager.SetEnabled(m_WasEnabled); + } +private: + bool m_WasEnabled; +}; + +/*---------------------------------------------------------------------- +| NPT_LogManagerAutoLocker ++---------------------------------------------------------------------*/ +class NPT_LogManagerAutoLocker +{ + public: + // methods + NPT_LogManagerAutoLocker(NPT_LogManager &manager) : m_Manager(manager) { + m_Manager.Lock(); + } + ~NPT_LogManagerAutoLocker() { + m_Manager.Unlock(); + } + + private: + // members + NPT_LogManager& m_Manager; +}; + +/*---------------------------------------------------------------------- +| NPT_GetSystemLogConfig ++---------------------------------------------------------------------*/ +#if !defined(NPT_CONFIG_HAVE_SYSTEM_LOG_CONFIG) +NPT_Result NPT_GetSystemLogConfig(NPT_String& /*config*/) +{ + return NPT_ERROR_NOT_SUPPORTED; +} +#endif + +/*---------------------------------------------------------------------- +| NPT_LogHandler::Create ++---------------------------------------------------------------------*/ +NPT_Result +NPT_LogHandler::Create(const char* logger_name, + const char* handler_name, + NPT_LogHandler*& handler) +{ + handler = NULL; + + if (NPT_StringsEqual(handler_name, "NullHandler")) { + return NPT_LogNullHandler::Create(handler); + } else if (NPT_StringsEqual(handler_name, "FileHandler")) { + return NPT_LogFileHandler::Create(logger_name, handler); + } else if (NPT_StringsEqual(handler_name, "ConsoleHandler")) { + return NPT_LogConsoleHandler::Create(logger_name, handler); + } else if (NPT_StringsEqual(handler_name, "TcpHandler")) { + return NPT_LogTcpHandler::Create(logger_name, handler); + } else if (NPT_StringsEqual(handler_name, "UdpHandler")) { + return NPT_LogUdpHandler::Create(logger_name, handler); + } else if (NPT_StringsEqual(handler_name, "CustomHandler")) { + return NPT_LogCustomHandler::Create(handler); + } + + return NPT_ERROR_NO_SUCH_CLASS; +} + +/*---------------------------------------------------------------------- +| NPT_LogHandler::SetCustomHandlerFunction ++---------------------------------------------------------------------*/ +NPT_Result +NPT_LogHandler::SetCustomHandlerFunction(CustomHandlerExternalFunction function) +{ + return NPT_LogCustomHandler::SetCustomHandlerFunction(function); +} + +/*---------------------------------------------------------------------- +| NPT_Log::GetLogLevel ++---------------------------------------------------------------------*/ +int +NPT_Log::GetLogLevel(const char* name) +{ + if ( NPT_StringsEqual(name, "FATAL")) { + return NPT_LOG_LEVEL_FATAL; + } else if (NPT_StringsEqual(name, "SEVERE")) { + return NPT_LOG_LEVEL_SEVERE; + } else if (NPT_StringsEqual(name, "WARNING")) { + return NPT_LOG_LEVEL_WARNING; + } else if (NPT_StringsEqual(name, "INFO")) { + return NPT_LOG_LEVEL_INFO; + } else if (NPT_StringsEqual(name, "FINE")) { + return NPT_LOG_LEVEL_FINE; + } else if (NPT_StringsEqual(name, "FINER")) { + return NPT_LOG_LEVEL_FINER; + } else if (NPT_StringsEqual(name, "FINEST")) { + return NPT_LOG_LEVEL_FINEST; + } else if (NPT_StringsEqual(name, "ALL")) { + return NPT_LOG_LEVEL_ALL; + } else if (NPT_StringsEqual(name, "OFF")) { + return NPT_LOG_LEVEL_OFF; + } else { + return -1; + } +} + +/*---------------------------------------------------------------------- +| NPT_Log::GetLogLevelName ++---------------------------------------------------------------------*/ +const char* +NPT_Log::GetLogLevelName(int level) +{ + switch (level) { + case NPT_LOG_LEVEL_FATAL: return "FATAL"; + case NPT_LOG_LEVEL_SEVERE: return "SEVERE"; + case NPT_LOG_LEVEL_WARNING: return "WARNING"; + case NPT_LOG_LEVEL_INFO: return "INFO"; + case NPT_LOG_LEVEL_FINE: return "FINE"; + case NPT_LOG_LEVEL_FINER: return "FINER"; + case NPT_LOG_LEVEL_FINEST: return "FINEST"; + case NPT_LOG_LEVEL_OFF: return "OFF"; + default: return ""; + } +} + +/*---------------------------------------------------------------------- +| NPT_Log::GetLogLevelAnsiColor ++---------------------------------------------------------------------*/ +const char* +NPT_Log::GetLogLevelAnsiColor(int level) +{ + switch (level) { + case NPT_LOG_LEVEL_FATAL: return "31"; + case NPT_LOG_LEVEL_SEVERE: return "31"; + case NPT_LOG_LEVEL_WARNING: return "33"; + case NPT_LOG_LEVEL_INFO: return "32"; + case NPT_LOG_LEVEL_FINE: return "34"; + case NPT_LOG_LEVEL_FINER: return "35"; + case NPT_LOG_LEVEL_FINEST: return "36"; + default: return NULL; + } +} + +/*---------------------------------------------------------------------- +| NPT_Log::FormatRecordToStream ++---------------------------------------------------------------------*/ +void +NPT_Log::FormatRecordToStream(const NPT_LogRecord& record, + NPT_OutputStream& stream, + bool use_colors, + NPT_Flags format_filter) +{ + const char* level_name = GetLogLevelName(record.m_Level); + NPT_String level_string; + + /* format and emit the record */ + if (level_name[0] == '\0') { + level_string = NPT_String::FromInteger(record.m_Level); + level_name = level_string; + } + if ((format_filter & NPT_LOG_FORMAT_FILTER_NO_SOURCE) == 0) { + unsigned int start = 0; + /* remove source file path if requested */ + if (format_filter & NPT_LOG_FORMAT_FILTER_NO_SOURCEPATH) { + for (start = NPT_StringLength(record.m_SourceFile); + start; + --start) { + if (record.m_SourceFile[start-1] == '\\' || + record.m_SourceFile[start-1] == '/') { + break; + } + } + } + stream.WriteString(record.m_SourceFile + start); + stream.Write("(", 1, NULL); + stream.WriteString(NPT_String::FromIntegerU(record.m_SourceLine)); + stream.Write("): ", 3, NULL); + } + if ((format_filter & NPT_LOG_FORMAT_FILTER_NO_LOGGER_NAME) == 0) { + stream.Write("[", 1, NULL); + stream.WriteString(record.m_LoggerName); + stream.Write("] ", 2, NULL); + } + if ((format_filter & NPT_LOG_FORMAT_FILTER_NO_TIMESTAMP) == 0) { + NPT_String ts = NPT_DateTime(record.m_TimeStamp, true).ToString(NPT_DateTime::FORMAT_W3C, + NPT_DateTime::FLAG_EMIT_FRACTION | + NPT_DateTime::FLAG_EXTENDED_PRECISION); + stream.WriteString(ts.GetChars()); + stream.Write(" ", 1); + } + if ((format_filter & NPT_LOG_FORMAT_FILTER_NO_FUNCTION_NAME) == 0) { + stream.WriteFully("[",1); + if (record.m_SourceFunction) { + stream.WriteString(record.m_SourceFunction); + } + stream.WriteFully("] ",2); + } + if ((format_filter & NPT_LOG_FORMAT_FILTER_NO_THREAD_ID) == 0) { + stream.Write("(", 1, NULL); + stream.WriteString(NPT_String::FromIntegerU(record.m_ThreadId)); + stream.Write(") ", 2, NULL); + } + const char* ansi_color = NULL; + if (use_colors) { + ansi_color = GetLogLevelAnsiColor(record.m_Level); + if (ansi_color) { + stream.Write("\033[", 2, NULL); + stream.WriteString(ansi_color); + stream.Write(";1m", 3, NULL); + } + } + stream.WriteString(level_name); + if (use_colors && ansi_color) { + stream.Write("\033[0m", 4, NULL); + } + stream.Write(": ", 2, NULL); + stream.WriteString(record.m_Message); + stream.Write("\r\n", 2, NULL); +} + +/*---------------------------------------------------------------------- +| NPT_LogManager::NPT_LogManager ++---------------------------------------------------------------------*/ +NPT_LogManager::NPT_LogManager() : + m_LockOwner(0), + m_LockRecursion(0), + m_Enabled(true), + m_Configured(false), + m_Root(NULL) +{ +} + +/*---------------------------------------------------------------------- +| NPT_LogManager::~NPT_LogManager ++---------------------------------------------------------------------*/ +NPT_LogManager::~NPT_LogManager() +{ + /* destroy everything we've created */ + for (NPT_List<NPT_Logger*>::Iterator i = m_Loggers.GetFirstItem(); + i; + ++i) { + NPT_Logger* logger = *i; + delete logger; + } + + /* destroy the root logger */ + delete m_Root; +} + +/*---------------------------------------------------------------------- +| NPT_LogManager::GetDefault ++---------------------------------------------------------------------*/ +NPT_LogManager& +NPT_LogManager::GetDefault() +{ + return LogManager; +} + +/*---------------------------------------------------------------------- +| NPT_LogManager::Lock ++---------------------------------------------------------------------*/ +void +NPT_LogManager::Lock() +{ + NPT_Thread::ThreadId me = NPT_Thread::GetCurrentThreadId(); + if (m_LockOwner != me) { + m_Lock.Lock(); + m_LockOwner = me; + } + ++m_LockRecursion; +} + +/*---------------------------------------------------------------------- +| NPT_LogManager::Unlock ++---------------------------------------------------------------------*/ +void +NPT_LogManager::Unlock() +{ + if (--m_LockRecursion == 0) { + m_LockOwner = (NPT_Thread::ThreadId)0; + m_Lock.Unlock(); + } +} + +/*---------------------------------------------------------------------- +| NPT_LogManager::Configure ++---------------------------------------------------------------------*/ +NPT_Result +NPT_LogManager::Configure(const char* config_sources) +{ + // exit if we're already initialized + if (m_Configured) return NPT_SUCCESS; + + // prevent multiple threads from configuring at the same time + NPT_LogManagerAutoLocker lock(*this); + if (m_Configured) return NPT_SUCCESS; + + // we need to be disabled while we configure ourselves + NPT_LogManagerAutoDisabler autodisabler; + + // set some default config values + SetConfigValue(".handlers", NPT_LOG_ROOT_DEFAULT_HANDLER); + + // see if the config sources have been set to non-default values + if (config_sources == NULL) { + config_sources = NPT_CONFIG_DEFAULT_LOG_CONFIG_SOURCE; + } + NPT_String config_sources_system; + if (NPT_SUCCEEDED(NPT_GetSystemLogConfig(config_sources_system))) { + config_sources = config_sources_system; + } + NPT_String config_sources_env; + if (NPT_SUCCEEDED(NPT_Environment::Get(NPT_CONFIG_LOG_CONFIG_ENV, config_sources_env))) { + config_sources = config_sources_env; + } + + /* load all configs */ + NPT_String config_source; + const char* cursor = config_sources; + const char* source = config_sources; + for (;;) { + if (*cursor == '\0' || *cursor == '|') { + if (cursor != source) { + config_source.Assign(source, (NPT_Size)(cursor-source)); + config_source.Trim(" \t"); + ParseConfigSource(config_source); + if (*cursor == '|') source = cursor+1; + } + if (*cursor == '\0') break; + } + cursor++; + } + + /* create the root logger */ + LogManager.m_Root = new NPT_Logger("", *this); + LogManager.m_Root->m_Level = NPT_CONFIG_DEFAULT_LOG_LEVEL; + LogManager.m_Root->m_LevelIsInherited = false; + ConfigureLogger(LogManager.m_Root); + + // we're initialized now + m_Configured = true; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_LogManager::ConfigValueIsBooleanTrue ++---------------------------------------------------------------------*/ +bool +NPT_LogManager::ConfigValueIsBooleanTrue(NPT_String& value) +{ + return + value.Compare("true", true) == 0 || + value.Compare("yes", true) == 0 || + value.Compare("on", true) == 0 || + value.Compare("1", true) == 0; +} + +/*---------------------------------------------------------------------- +| NPT_LogManager::ConfigValueIsBooleanFalse ++---------------------------------------------------------------------*/ +bool +NPT_LogManager::ConfigValueIsBooleanFalse(NPT_String& value) +{ + return + value.Compare("false", true) == 0 || + value.Compare("no", true) == 0 || + value.Compare("off", true) == 0 || + value.Compare("0", true) == 0; +} + +/*---------------------------------------------------------------------- +| NPT_LogManager::GetConfigValue ++---------------------------------------------------------------------*/ +NPT_String* +NPT_LogManager::GetConfigValue(const char* prefix, const char* suffix) +{ + NPT_Size prefix_length = prefix?NPT_StringLength(prefix):0; + NPT_Size suffix_length = suffix?NPT_StringLength(suffix):0; + NPT_Size key_length = prefix_length+suffix_length; + for (NPT_List<NPT_LogConfigEntry>::Iterator i = LogManager.m_Config.GetFirstItem(); + i; + ++i) { + NPT_LogConfigEntry& entry = *i; + if ((entry.m_Key.GetLength() == key_length) && + (prefix == NULL || entry.m_Key.StartsWith(prefix)) && + (suffix == NULL || entry.m_Key.EndsWith(suffix )) ) { + return &entry.m_Value; + } + } + + // not found + return NULL; +} + +/*---------------------------------------------------------------------- +| NPT_LogManager::SetConfigValue ++---------------------------------------------------------------------*/ +NPT_Result +NPT_LogManager::SetConfigValue(const char* key, const char* value) +{ + NPT_String* value_string = GetConfigValue(key, NULL); + if (value_string) { + /* the key already exists, replace the value */ + *value_string = value; + } else { + /* the value does not already exist, create a new one */ + NPT_CHECK(LogManager.m_Config.Add(NPT_LogConfigEntry(key, value))); + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_LogManager::ParseConfig ++---------------------------------------------------------------------*/ +NPT_Result +NPT_LogManager::ParseConfig(const char* config, + NPT_Size config_size) +{ + const char* cursor = config; + const char* line = config; + const char* separator = NULL; + NPT_String key; + NPT_String value; + + /* parse all entries */ + while (cursor <= config+config_size) { + /* separators are newlines, ';' or end of buffer */ + if ( cursor == config+config_size || + *cursor == '\n' || + *cursor == '\r' || + *cursor == ';') { + /* newline or end of buffer */ + if (separator && line[0] != '#') { + /* we have a property */ + key.Assign(line, (NPT_Size)(separator-line)); + value.Assign(line+(separator+1-line), (NPT_Size)(cursor-(separator+1))); + key.Trim(" \t"); + value.Trim(" \t"); + + SetConfigValue((const char*)key, (const char*)value); + } + line = cursor+1; + separator = NULL; + } else if (*cursor == '=' && separator == NULL) { + separator = cursor; + } + cursor++; + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_LogManager::ParseConfigFile ++---------------------------------------------------------------------*/ +NPT_Result +NPT_LogManager::ParseConfigFile(const char* filename) +{ + NPT_Result result; + + /* load the file */ + NPT_DataBuffer buffer; + result = NPT_File::Load(filename, buffer); + if (NPT_FAILED(result)) return result; + + /* parse the config */ + return ParseConfig((const char*)buffer.GetData(), buffer.GetDataSize()); +} + +/*---------------------------------------------------------------------- +| NPT_LogManager::ParseConfigSource ++---------------------------------------------------------------------*/ +NPT_Result +NPT_LogManager::ParseConfigSource(NPT_String& source) +{ + if (source.StartsWith("file:")) { + /* file source */ + ParseConfigFile(source.GetChars()+5); + } else if (source.StartsWith("plist:")) { + /* property list source */ + ParseConfig(source.GetChars()+6, source.GetLength()-6); + } else if (source.StartsWith("http:port=")) { + /* http configurator */ + unsigned int port = 0; + NPT_Result result = NPT_ParseInteger(source.GetChars()+10, port, true); + if (NPT_FAILED(result)) return result; + new NPT_HttpLoggerConfigurator(port); + } else { + return NPT_ERROR_INVALID_SYNTAX; + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_LogManager::HaveLoggerConfig ++---------------------------------------------------------------------*/ +bool +NPT_LogManager::HaveLoggerConfig(const char* name) +{ + NPT_Size name_length = NPT_StringLength(name); + for (NPT_List<NPT_LogConfigEntry>::Iterator i = m_Config.GetFirstItem(); + i; + ++i) { + NPT_LogConfigEntry& entry = *i; + if (entry.m_Key.StartsWith(name)) { + const char* suffix = entry.m_Key.GetChars()+name_length; + if (NPT_StringsEqual(suffix, ".level") || + NPT_StringsEqual(suffix, ".handlers") || + NPT_StringsEqual(suffix, ".forward")) { + return true; + } + } + } + + /* no config found */ + return false; +} + +/*---------------------------------------------------------------------- +| NPT_LogManager::ConfigureLogger ++---------------------------------------------------------------------*/ +NPT_Result +NPT_LogManager::ConfigureLogger(NPT_Logger* logger) +{ + /* configure the level */ + NPT_String* level_value = GetConfigValue(logger->m_Name,".level"); + if (level_value) { + NPT_Int32 value; + /* try a symbolic name */ + value = NPT_Log::GetLogLevel(*level_value); + if (value < 0) { + /* try a numeric value */ + if (NPT_FAILED(level_value->ToInteger(value, false))) { + value = -1; + } + } + if (value >= 0) { + logger->m_Level = value; + logger->m_LevelIsInherited = false; + } + } + + /* remove any existing handlers */ + logger->DeleteHandlers(); + + /* configure the handlers */ + NPT_String* handlers = GetConfigValue(logger->m_Name,".handlers"); + if (handlers) { + const char* handlers_list = handlers->GetChars(); + const char* cursor = handlers_list; + const char* name_start = handlers_list; + NPT_String handler_name; + NPT_LogHandler* handler; + for (;;) { + if (*cursor == '\0' || *cursor == ',') { + if (cursor != name_start) { + handler_name.Assign(name_start, (NPT_Size)(cursor-name_start)); + handler_name.Trim(" \t"); + + /* create a handler */ + if (NPT_SUCCEEDED( + NPT_LogHandler::Create(logger->m_Name, handler_name, handler))) { + logger->AddHandler(handler); + } + + } + if (*cursor == '\0') break; + name_start = cursor+1; + } + ++cursor; + } + } + + /* configure the forwarding */ + NPT_String* forward = GetConfigValue(logger->m_Name,".forward"); + if (forward && !ConfigValueIsBooleanTrue(*forward)) { + logger->m_ForwardToParent = false; + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_LogManager::FindLogger ++---------------------------------------------------------------------*/ +NPT_Logger* +NPT_LogManager::FindLogger(const char* name) +{ + for (NPT_List<NPT_Logger*>::Iterator i = LogManager.m_Loggers.GetFirstItem(); + i; + ++i) { + NPT_Logger* logger = *i; + if (logger->m_Name == name) { + return logger; + } + } + + return NULL; +} + +/*---------------------------------------------------------------------- +| NPT_LogManager::GetLogger ++---------------------------------------------------------------------*/ +NPT_Logger* +NPT_LogManager::GetLogger(const char* name) +{ + // exit now if the log manager is disabled + if (!LogManager.m_Enabled) return NULL; + + /* check that the manager is initialized */ + if (!LogManager.m_Configured) { + /* init the manager */ + LogManager.Configure(); + NPT_ASSERT(LogManager.m_Configured); + } + + // auto lock until we return from this method + NPT_LogManagerAutoLocker lock(LogManager); + + /* check if this logger is already configured */ + NPT_Logger* logger = LogManager.FindLogger(name); + if (logger) return logger; + + /* create a new logger */ + logger = new NPT_Logger(name, LogManager); + if (logger == NULL) return NULL; + + /* configure the logger */ + LogManager.ConfigureLogger(logger); + + /* find which parent to attach to */ + NPT_Logger* parent = LogManager.m_Root; + NPT_String parent_name = name; + for (;;) { + NPT_Logger* candidate_parent; + + /* find the last dot */ + int dot = parent_name.ReverseFind('.'); + if (dot < 0) break; + parent_name.SetLength(dot); + + /* see if the parent exists */ + candidate_parent = LogManager.FindLogger(parent_name); + if (candidate_parent) { + parent = candidate_parent; + break; + } + + /* this parent name does not exist, see if we need to create it */ + if (LogManager.HaveLoggerConfig(parent_name)) { + parent = GetLogger(parent_name); + break; + } + } + + /* attach to the parent */ + logger->SetParent(parent); + + /* add this logger to the list */ + LogManager.m_Loggers.Add(logger); + + return logger; +} + +/*---------------------------------------------------------------------- +| NPT_Logger::NPT_Logger ++---------------------------------------------------------------------*/ +NPT_Logger::NPT_Logger(const char* name, NPT_LogManager& manager) : + m_Manager(manager), + m_Name(name), + m_Level(NPT_LOG_LEVEL_OFF), + m_LevelIsInherited(true), + m_ForwardToParent(true), + m_Parent(NULL) +{ +} + +/*---------------------------------------------------------------------- +| NPT_Logger::~NPT_Logger ++---------------------------------------------------------------------*/ +NPT_Logger::~NPT_Logger() +{ + /* remove external handlers before cleaning up */ + m_Handlers.Remove(m_ExternalHandlers, true); + + /* delete all handlers */ + m_Handlers.Apply(NPT_ObjectDeleter<NPT_LogHandler>()); +} + +/*---------------------------------------------------------------------- +| NPT_Logger::DeleteHandlers ++---------------------------------------------------------------------*/ +NPT_Result +NPT_Logger::DeleteHandlers() +{ + /* remove external handlers before cleaning up */ + m_Handlers.Remove(m_ExternalHandlers, true); + + /* delete all handlers and empty the list */ + if (m_Handlers.GetItemCount()) { + m_Handlers.Apply(NPT_ObjectDeleter<NPT_LogHandler>()); + m_Handlers.Clear(); + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_Logger::Log ++---------------------------------------------------------------------*/ +void +NPT_Logger::Log(int level, + const char* source_file, + unsigned int source_line, + const char* source_function, + const char* msg, + ...) +{ + // this is a no-op if the log manager is disabled + if (!LogManager.IsEnabled()) return; + + /* check the log level (in case filtering has not already been done) */ + if (level < m_Level) return; + + /* format the message */ + char buffer[NPT_LOG_STACK_BUFFER_MAX_SIZE]; + NPT_Size buffer_size = sizeof(buffer); + char* message = buffer; + int result; + va_list args; + for(;;) { + /* try to format the message (it might not fit) */ + va_start(args, msg); + result = NPT_FormatStringVN(message, buffer_size-1, msg, args); + va_end(args); + if (result >= (int)(buffer_size-1)) result = -1; + message[buffer_size-1] = 0; /* force a NULL termination */ + if (result >= 0) break; + + /* the buffer was too small, try something bigger */ + buffer_size = (buffer_size+NPT_LOG_HEAP_BUFFER_INCREMENT)*2; + if (buffer_size > NPT_LOG_HEAP_BUFFER_MAX_SIZE) break; + if (message != buffer) delete[] message; + message = new char[buffer_size]; + if (message == NULL) return; + } + + /* the message is formatted, publish it to the handlers */ + NPT_LogRecord record; + NPT_Logger* logger = this; + + /* setup the log record */ + record.m_LoggerName = logger->m_Name, + record.m_Level = level; + record.m_Message = message; + record.m_SourceFile = source_file; + record.m_SourceLine = source_line; + record.m_SourceFunction = source_function; + NPT_System::GetCurrentTimeStamp(record.m_TimeStamp); + record.m_ThreadId = (NPT_UInt64)NPT_Thread::GetCurrentThreadId(); + + /* call all handlers for this logger and parents */ + m_Manager.Lock(); + m_Manager.SetEnabled(false); // prevent recursion + while (logger) { + /* call all handlers for the current logger */ + for (NPT_List<NPT_LogHandler*>::Iterator i = logger->m_Handlers.GetFirstItem(); + i; + ++i) { + NPT_LogHandler* handler = *i; + handler->Log(record); + } + + /* forward to the parent unless this logger does not forward */ + if (logger->m_ForwardToParent) { + logger = logger->m_Parent; + } else { + break; + } + } + m_Manager.SetEnabled(true); + m_Manager.Unlock(); + + /* free anything we may have allocated */ + if (message != buffer) delete[] message; +} + +/*---------------------------------------------------------------------- +| NPT_Logger::AddHandler ++---------------------------------------------------------------------*/ +NPT_Result +NPT_Logger::AddHandler(NPT_LogHandler* handler, bool transfer_ownership /* = true */) +{ + /* check parameters */ + if (handler == NULL) return NPT_ERROR_INVALID_PARAMETERS; + + /* keep track of what handlers we won't cleanup */ + if (!transfer_ownership) m_ExternalHandlers.Add(handler); + + return m_Handlers.Add(handler); +} + +/*---------------------------------------------------------------------- +| NPT_Logger::SetParent ++---------------------------------------------------------------------*/ +NPT_Result +NPT_Logger::SetParent(NPT_Logger* parent) +{ + /* set our new parent */ + m_Parent = parent; + + /* find the first ancestor with its own log level */ + NPT_Logger* logger = this; + while (logger->m_LevelIsInherited && logger->m_Parent) { + logger = logger->m_Parent; + } + if (logger != this) m_Level = logger->m_Level; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_LogNullHandler::Create ++---------------------------------------------------------------------*/ +NPT_Result +NPT_LogNullHandler::Create(NPT_LogHandler*& handler) +{ + handler = new NPT_LogNullHandler(); + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_LogNullHandler::Log ++---------------------------------------------------------------------*/ +void +NPT_LogNullHandler::Log(const NPT_LogRecord& /*record*/) +{ +} + + +NPT_LogHandler::CustomHandlerExternalFunction NPT_LogCustomHandler::s_ExternalFunction = NULL; +/*---------------------------------------------------------------------- +| NPT_LogCustomHandler::SetCustomHandlerFunction ++---------------------------------------------------------------------*/ +NPT_Result +NPT_LogCustomHandler::SetCustomHandlerFunction(CustomHandlerExternalFunction function) +{ + s_ExternalFunction = function; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_LogCustomHandler::Create ++---------------------------------------------------------------------*/ +NPT_Result +NPT_LogCustomHandler::Create(NPT_LogHandler*& handler) +{ + /* allocate a new object */ + NPT_LogCustomHandler* instance = new NPT_LogCustomHandler(); + handler = instance; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_LogCustomHandler::Log ++---------------------------------------------------------------------*/ +void +NPT_LogCustomHandler::Log(const NPT_LogRecord& record) +{ + if (s_ExternalFunction) { + (*s_ExternalFunction)(&record); + } +} + +/*---------------------------------------------------------------------- +| NPT_LogConsoleHandler::Create ++---------------------------------------------------------------------*/ +NPT_Result +NPT_LogConsoleHandler::Create(const char* logger_name, + NPT_LogHandler*& handler) +{ + /* compute a prefix for the configuration of this handler */ + NPT_String logger_prefix = logger_name; + logger_prefix += ".ConsoleHandler"; + + /* allocate a new object */ + NPT_LogConsoleHandler* instance = new NPT_LogConsoleHandler(); + handler = instance; + + /* configure the object */ + NPT_String* colors; + instance->m_UseColors = NPT_LOG_CONSOLE_HANDLER_DEFAULT_COLOR_MODE; + colors = LogManager.GetConfigValue(logger_prefix,".colors"); + if (colors) { + if (NPT_LogManager::ConfigValueIsBooleanTrue(*colors)) { + instance->m_UseColors = true; + } else if (NPT_LogManager::ConfigValueIsBooleanFalse(*colors)) { + instance->m_UseColors = false; + } + } + + NPT_String* outputs; + instance->m_Outputs = NPT_CONFIG_DEFAULT_LOG_CONSOLE_HANDLER_OUTPUTS; + outputs = LogManager.GetConfigValue(logger_prefix,".outputs"); + if (outputs) { + outputs->ToInteger(instance->m_Outputs, true); + } + + NPT_String* filter; + instance->m_FormatFilter = 0; + filter = LogManager.GetConfigValue(logger_prefix,".filter"); + if (filter) { + filter->ToInteger(instance->m_FormatFilter, true); + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_LogConsoleHandler::Log ++---------------------------------------------------------------------*/ +void +NPT_LogConsoleHandler::Log(const NPT_LogRecord& record) +{ + NPT_MemoryStream memory_stream(4096); + + NPT_Log::FormatRecordToStream(record, memory_stream, m_UseColors, m_FormatFilter); + memory_stream.Write("\0", 1); + if (m_Outputs & OUTPUT_TO_CONSOLE) { + NPT_Console::Output((const char*)memory_stream.GetData()); + } + if (m_Outputs & OUTPUT_TO_DEBUG) { + NPT_DebugOutput((const char*)memory_stream.GetData()); + } +} + +/*---------------------------------------------------------------------- +| NPT_LogFileHandler::Log ++---------------------------------------------------------------------*/ +void +NPT_LogFileHandler::Log(const NPT_LogRecord& record) +{ + if (m_MaxFilesize > 0) { + /* get current file size */ + NPT_LargeSize size; + NPT_File::GetSize(m_Filename, size); + + /* time to recycle ? */ + if (size > m_MaxFilesize) { + /* release stream to force a reopen later + and to be able to rename file */ + m_Stream = NULL; + + /* rename file using current time */ + NPT_TimeStamp now; + NPT_System::GetCurrentTimeStamp(now); + NPT_String suffix = NPT_DateTime(now, true).ToString(NPT_DateTime::FORMAT_W3C); + suffix.Replace(':', '_'); + NPT_String new_name = NPT_FilePath::Create( + NPT_FilePath::DirName(m_Filename), + NPT_FilePath::BaseName(m_Filename, false) + + "-" + + suffix + + NPT_FilePath::FileExtension(m_Filename)); + + NPT_File::Rename(m_Filename, new_name); + } + } + + /* try to reopen the file if it failed to open + previously or if we rotated it */ + if (m_Stream.IsNull()) { + Open(m_Append); + } + + if (m_Stream.AsPointer()) { + NPT_Log::FormatRecordToStream(record, *m_Stream, false, m_FormatFilter); + if (m_Flush) m_Stream->Flush(); + } +} + +/*---------------------------------------------------------------------- +| NPT_LogFileHandler::Open ++---------------------------------------------------------------------*/ +NPT_Result +NPT_LogFileHandler::Open(bool append /* = true */) +{ + /* reset stream just in case */ + m_Stream = NULL; + + /* open the log file */ + NPT_File file(m_Filename); + NPT_Result result = file.Open(NPT_FILE_OPEN_MODE_CREATE | + NPT_FILE_OPEN_MODE_READ | + NPT_FILE_OPEN_MODE_WRITE | + (append?NPT_FILE_OPEN_MODE_APPEND:NPT_FILE_OPEN_MODE_TRUNCATE)); + if (NPT_FAILED(result)) return result; + + NPT_CHECK(file.GetOutputStream(m_Stream)); + /* seek to end */ + if (append) { + NPT_LargeSize size; + NPT_CHECK(NPT_File::GetSize(m_Filename, size)); + NPT_CHECK(m_Stream->Seek(size)); + } + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_LogFileHandler::Create ++---------------------------------------------------------------------*/ +NPT_Result +NPT_LogFileHandler::Create(const char* logger_name, + NPT_LogHandler*& handler) +{ + /* compute a prefix for the configuration of this handler */ + NPT_String logger_prefix = logger_name; + logger_prefix += ".FileHandler"; + + /* allocate a new object */ + NPT_LogFileHandler* instance = new NPT_LogFileHandler(); + handler = instance; + + /* filename */ + NPT_String* filename_conf = LogManager.GetConfigValue(logger_prefix, ".filename"); + if (filename_conf) { + instance->m_Filename = *filename_conf; + } else if (logger_name[0]) { + NPT_String filename_synth = logger_name; + filename_synth += ".log"; + instance->m_Filename = filename_synth; + } else { + /* default name for the root logger */ + instance->m_Filename = NPT_CONFIG_DEFAULT_LOG_FILE_HANDLER_FILENAME; + } + + /* always flush flag */ + NPT_String* flush = LogManager.GetConfigValue(logger_prefix, ".flush"); + if (flush && NPT_LogManager::ConfigValueIsBooleanTrue(*flush)) { + instance->m_Flush = true; + } else { + instance->m_Flush = false; + } + + /* append mode */ + instance->m_Append = true; + NPT_String* append_mode = LogManager.GetConfigValue(logger_prefix, ".append"); + if (append_mode && NPT_LogManager::ConfigValueIsBooleanFalse(*append_mode)) { + instance->m_Append = false; + } + + /* filter */ + NPT_String* filter; + instance->m_FormatFilter = 0; + filter = LogManager.GetConfigValue(logger_prefix,".filter"); + if (filter) { + filter->ToInteger(instance->m_FormatFilter, true); + } + + /* recycle */ + NPT_String* recycle; + instance->m_MaxFilesize = 0; + recycle = LogManager.GetConfigValue(logger_prefix,".recycle"); + if (recycle) { + NPT_ParseInteger64(*recycle, instance->m_MaxFilesize, true); + if (instance->m_MaxFilesize < NPT_LOG_FILE_HANDLER_MIN_RECYCLE_SIZE) { + instance->m_MaxFilesize = NPT_LOG_FILE_HANDLER_MIN_RECYCLE_SIZE; + } + } + + /* open the log file */ + return instance->Open(instance->m_Append); +} + +/*---------------------------------------------------------------------- +| NPT_LogTcpHandler::Create ++---------------------------------------------------------------------*/ +NPT_Result +NPT_LogTcpHandler::Create(const char* logger_name, NPT_LogHandler*& handler) +{ + /* compute a prefix for the configuration of this handler */ + NPT_String logger_prefix = logger_name; + logger_prefix += ".TcpHandler"; + + /* allocate a new object */ + NPT_LogTcpHandler* instance = new NPT_LogTcpHandler(); + handler = instance; + + /* configure the object */ + const NPT_String* hostname = LogManager.GetConfigValue(logger_prefix, ".hostname"); + if (hostname) { + instance->m_Host = *hostname; + } else { + /* default hostname */ + instance->m_Host = "localhost"; + } + const NPT_String* port = LogManager.GetConfigValue(logger_prefix, ".port"); + if (port) { + NPT_UInt32 port_int; + if (NPT_SUCCEEDED(port->ToInteger(port_int, true))) { + instance->m_Port = (NPT_UInt16)port_int; + } else { + instance->m_Port = NPT_LOG_TCP_HANDLER_DEFAULT_PORT; + } + } else { + /* default port */ + instance->m_Port = NPT_LOG_TCP_HANDLER_DEFAULT_PORT; + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_LogTcpHandler::Connect ++---------------------------------------------------------------------*/ +NPT_Result +NPT_LogTcpHandler::Connect() +{ + /* create a socket */ + NPT_TcpClientSocket tcp_socket; + + /* connect to the host */ + NPT_IpAddress ip_address; + NPT_CHECK(ip_address.ResolveName(m_Host)); + NPT_Result result = tcp_socket.Connect(NPT_SocketAddress(ip_address, m_Port), + NPT_LOG_TCP_HANDLER_DEFAULT_CONNECT_TIMEOUT); + if (NPT_FAILED(result)) { + return result; + } + + /* get the stream */ + return tcp_socket.GetOutputStream(m_Stream); +} + +/*---------------------------------------------------------------------- +| NPT_LogTcpHandler::Log ++---------------------------------------------------------------------*/ +void +NPT_LogTcpHandler::FormatRecord(const NPT_LogRecord& record, NPT_String& msg) +{ + /* format the record */ + const char* level_name = NPT_Log::GetLogLevelName(record.m_Level); + NPT_String level_string; + + /* format and emit the record */ + if (level_name[0] == '\0') { + level_string = NPT_String::FromIntegerU(record.m_Level); + level_name = level_string; + } + msg.Reserve(2048); + msg += "Logger: "; + msg += record.m_LoggerName; + msg += "\r\nLevel: "; + msg += level_name; + msg += "\r\nSource-File: "; + msg += record.m_SourceFile; + msg += "\r\nSource-Function: "; + msg += record.m_SourceFunction; + msg += "\r\nSource-Line: "; + msg += NPT_String::FromIntegerU(record.m_SourceLine); + msg += "\r\nThread-Id: "; + msg += NPT_String::FromIntegerU(record.m_ThreadId); + msg += "\r\nTimeStamp: "; + msg += NPT_DateTime(record.m_TimeStamp, true).ToString(NPT_DateTime::FORMAT_W3C, + NPT_DateTime::FLAG_EMIT_FRACTION | + NPT_DateTime::FLAG_EXTENDED_PRECISION); + msg += "\r\nContent-Length: "; + msg += NPT_String::FromIntegerU(NPT_StringLength(record.m_Message)); + msg += "\r\n\r\n"; + msg += record.m_Message; +} + +/*---------------------------------------------------------------------- +| NPT_LogTcpHandler::Log ++---------------------------------------------------------------------*/ +void +NPT_LogTcpHandler::Log(const NPT_LogRecord& record) +{ + // ensure we're connected + if (m_Stream.IsNull()) { + if (NPT_FAILED(Connect())) return; + } + + // format the record + NPT_String msg; + FormatRecord(record, msg); + + // log, and disconnect if this fails + if (NPT_FAILED(m_Stream->WriteString(msg))) { + m_Stream = NULL; + } +} + +/*---------------------------------------------------------------------- +| NPT_LogUdpHandler::Create ++---------------------------------------------------------------------*/ +NPT_Result +NPT_LogUdpHandler::Create(const char* logger_name, NPT_LogHandler*& handler) +{ + /* compute a prefix for the configuration of this handler */ + NPT_String logger_prefix = logger_name; + logger_prefix += ".UdpHandler"; + + /* allocate a new object */ + NPT_LogUdpHandler* instance = new NPT_LogUdpHandler(); + handler = instance; + + /* configure the object */ + const char* hostname = "localhost"; + const NPT_String* hostname_prop = LogManager.GetConfigValue(logger_prefix, ".hostname"); + if (hostname_prop) { + hostname = hostname_prop->GetChars(); + } + NPT_UInt32 port = NPT_LOG_UDP_HANDLER_DEFAULT_PORT; + const NPT_String* port_prop = LogManager.GetConfigValue(logger_prefix, ".port"); + if (port_prop) { + if (NPT_FAILED(port_prop->ToInteger(port, true))) { + port = NPT_LOG_UDP_HANDLER_DEFAULT_PORT; + } + } + + // resolve the target hostname + NPT_IpAddress target_ip; + target_ip.ResolveName(hostname); + instance->m_Target.SetIpAddress(target_ip); + instance->m_Target.SetPort(port); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_LogUdpHandler::Log ++---------------------------------------------------------------------*/ +void +NPT_LogUdpHandler::Log(const NPT_LogRecord& record) +{ + // format the record + NPT_String msg; + NPT_LogTcpHandler::FormatRecord(record, msg); + + // send it in a datagram + NPT_DataBuffer buffer(msg.GetChars(), msg.GetLength()+1, false); + m_Socket.Send(buffer, &m_Target); +} + +/*---------------------------------------------------------------------- +| NPT_HttpLoggerConfigurator::NPT_HttpLoggerConfigurator ++---------------------------------------------------------------------*/ +NPT_HttpLoggerConfigurator::NPT_HttpLoggerConfigurator(NPT_UInt16 port, bool detached) : + NPT_Thread(detached) +{ + // create the server + m_Server = new NPT_HttpServer(port); + + // attach a handler to response to the requests + m_Server->AddRequestHandler(this, "/", true); +} + +/*---------------------------------------------------------------------- +| NPT_HttpLoggerConfigurator::~NPT_HttpLoggerConfigurator ++---------------------------------------------------------------------*/ +NPT_HttpLoggerConfigurator::~NPT_HttpLoggerConfigurator() +{ + // TODO: send a command to the server to tell it to abort + + // cleanup + delete m_Server; +} + +/*---------------------------------------------------------------------- +| NPT_HttpLoggerConfigurator::SetupResponse ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpLoggerConfigurator::SetupResponse(NPT_HttpRequest& request, + const NPT_HttpRequestContext& /*context*/, + NPT_HttpResponse& response) +{ + // we only support GET here + if (request.GetMethod() != NPT_HTTP_METHOD_GET) return NPT_ERROR_HTTP_METHOD_NOT_SUPPORTED; + + // construct the response message + NPT_String msg; + + msg = "<ul>"; + NPT_List<NPT_LogConfigEntry>& config = LogManager.GetConfig(); + NPT_List<NPT_LogConfigEntry>::Iterator cit = config.GetFirstItem(); + for (; cit; ++cit) { + NPT_LogConfigEntry& entry = (*cit); + msg += "<li>"; + msg += entry.m_Key; + msg += "="; + msg += entry.m_Value; + msg += "</li>"; + } + msg += "</ul>"; + + msg += "<ul>"; + NPT_List<NPT_Logger*>& loggers = LogManager.GetLoggers(); + NPT_List<NPT_Logger*>::Iterator lit = loggers.GetFirstItem(); + for (;lit;++lit) { + NPT_Logger* logger = (*lit); + msg += "<li>"; + msg += logger->GetName(); + msg += ", level="; + msg += NPT_String::FromInteger(logger->GetLevel()); + + NPT_List<NPT_LogHandler*>& handlers = logger->GetHandlers(); + NPT_List<NPT_LogHandler*>::Iterator hit = handlers.GetFirstItem(); + msg += ", handlers="; + for (;hit;++hit) { + NPT_LogHandler* handler = (*hit); + msg += handler->ToString(); + } + msg += "</li>"; + } + msg += "</ul>"; + + // setup the response body + NPT_HttpEntity* entity = response.GetEntity(); + entity->SetContentType("text/html"); + entity->SetInputStream(msg); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HttpLoggerConfigurator::Run ++---------------------------------------------------------------------*/ +void +NPT_HttpLoggerConfigurator::Run() +{ + for (;;) { + NPT_Result result; + result = m_Server->Loop(); + if (NPT_FAILED(result)) { + break; + } + } +} diff --git a/lib/libUPnP/Neptune/Source/Core/NptLogging.h b/lib/libUPnP/Neptune/Source/Core/NptLogging.h new file mode 100644 index 0000000..cbd98ca --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptLogging.h @@ -0,0 +1,524 @@ +/***************************************************************** +| +| Neptune - Logging Support +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| +****************************************************************/ +/** @file +* Header file for logging +*/ + +#ifndef _NPT_LOGGING_H_ +#define _NPT_LOGGING_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptConfig.h" +#include "NptTypes.h" +#include "NptTime.h" +#include "NptStrings.h" +#include "NptList.h" +#include "NptStreams.h" +#include "NptThreads.h" +#include "NptHttp.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class NPT_LogManager; + +/*---------------------------------------------------------------------- +| types ++---------------------------------------------------------------------*/ +class NPT_LogRecord { +public: + const char* m_LoggerName; + int m_Level; + const char* m_Message; + NPT_TimeStamp m_TimeStamp; + const char* m_SourceFile; + unsigned int m_SourceLine; + const char* m_SourceFunction; + NPT_UInt64 m_ThreadId; +}; + +class NPT_LogHandler { +public: + typedef void(*CustomHandlerExternalFunction)(const NPT_LogRecord* record); + + // class methods + static NPT_Result SetCustomHandlerFunction(CustomHandlerExternalFunction function); + static NPT_Result Create(const char* logger_name, + const char* handler_name, + NPT_LogHandler*& handler); + + // methods + virtual ~NPT_LogHandler() {} + virtual void Log(const NPT_LogRecord& record) = 0; + virtual NPT_String ToString() { return ""; } +}; + +class NPT_Logger { +public: + // methods + NPT_Logger(const char* name, NPT_LogManager& manager); + ~NPT_Logger(); + void Log(int level, + const char* source_file, + unsigned int source_line, + const char* source_function, + const char* msg, + ...) +#ifdef __GNUC__ + __attribute__ ((format (printf, 6, 7))) +#endif + ; + + NPT_Result AddHandler(NPT_LogHandler* handler, bool transfer_ownership = true); + NPT_Result DeleteHandlers(); + NPT_Result SetParent(NPT_Logger* parent); + const NPT_String& GetName() const { return m_Name; } + int GetLevel() const { return m_Level; } + bool GetForwardToParent() const { return m_ForwardToParent; } + NPT_List<NPT_LogHandler*>& GetHandlers() { return m_Handlers; } + +private: + // members + NPT_LogManager& m_Manager; + NPT_String m_Name; + int m_Level; + bool m_LevelIsInherited; + bool m_ForwardToParent; + NPT_Logger* m_Parent; + NPT_List<NPT_LogHandler*> m_Handlers; + NPT_List<NPT_LogHandler*> m_ExternalHandlers; + + // friends + friend class NPT_LogManager; +}; + +typedef struct { + NPT_Logger* logger; + const char* name; +} NPT_LoggerReference; + +class NPT_Log { +public: + // class methods + static int GetLogLevel(const char* name); + static const char* GetLogLevelName(int level); + static const char* GetLogLevelAnsiColor(int level); + static void FormatRecordToStream(const NPT_LogRecord& record, + NPT_OutputStream& stream, + bool use_colors, + NPT_Flags format_filter); +}; + +class NPT_LogConfigEntry { +public: + NPT_LogConfigEntry(const char* key, const char* value) : + m_Key(key), m_Value(value) {} + NPT_String m_Key; + NPT_String m_Value; +}; + +class NPT_LogManager { +public: + // class methods + static NPT_LogManager& GetDefault(); + static bool ConfigValueIsBooleanTrue(NPT_String& value); + static bool ConfigValueIsBooleanFalse(NPT_String& value); + static NPT_Logger* GetLogger(const char* name); + + // methods + NPT_LogManager(); + ~NPT_LogManager(); + NPT_Result Configure(const char* config_sources = NULL); + NPT_String* GetConfigValue(const char* prefix, const char* suffix); + NPT_List<NPT_Logger*>& GetLoggers() { return m_Loggers; } + NPT_List<NPT_LogConfigEntry>& GetConfig() { return m_Config; } + void SetEnabled(bool enabled) { m_Enabled = enabled; } + bool IsEnabled() { return m_Enabled; } + void Lock(); + void Unlock(); + +private: + // methods + NPT_Result SetConfigValue(const char* key, const char* value); + NPT_Result ParseConfig(const char* config, NPT_Size config_size); + NPT_Result ParseConfigSource(NPT_String& source); + NPT_Result ParseConfigFile(const char* filename); + bool HaveLoggerConfig(const char* name); + NPT_Logger* FindLogger(const char* name); + NPT_Result ConfigureLogger(NPT_Logger* logger); + + // members + NPT_Mutex m_Lock; + NPT_Thread::ThreadId m_LockOwner; + unsigned int m_LockRecursion; + bool m_Enabled; + bool m_Configured; + NPT_List<NPT_LogConfigEntry> m_Config; + NPT_List<NPT_Logger*> m_Loggers; + NPT_Logger* m_Root; +}; + +const unsigned short NPT_HTTP_LOGGER_CONFIGURATOR_DEFAULT_PORT = 6378; +class NPT_HttpLoggerConfigurator : NPT_HttpRequestHandler, public NPT_Thread { +public: + // constructor and destructor + NPT_HttpLoggerConfigurator(NPT_UInt16 port = NPT_HTTP_LOGGER_CONFIGURATOR_DEFAULT_PORT, + bool detached = true); + ~NPT_HttpLoggerConfigurator() override; + + // NPT_Runnable (NPT_Thread) methods + void Run() override; + +private: + // NPT_HttpRequestHandler methods + NPT_Result SetupResponse(NPT_HttpRequest& request, + const NPT_HttpRequestContext& context, + NPT_HttpResponse& response) override; + + // members + NPT_HttpServer* m_Server; +}; + +NPT_Result NPT_GetSystemLogConfig(NPT_String& config); + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +#define NPT_LOG_LEVEL_FATAL 700 +#define NPT_LOG_LEVEL_SEVERE 600 +#define NPT_LOG_LEVEL_WARNING 500 +#define NPT_LOG_LEVEL_INFO 400 +#define NPT_LOG_LEVEL_FINE 300 +#define NPT_LOG_LEVEL_FINER 200 +#define NPT_LOG_LEVEL_FINEST 100 + +#define NPT_LOG_LEVEL_OFF 32767 +#define NPT_LOG_LEVEL_ALL 0 + +/*---------------------------------------------------------------------- +| macros ++---------------------------------------------------------------------*/ +#define NPT_LOG_GET_LOGGER(_logger) \ + if ((_logger).logger == NULL) { \ + (_logger).logger = NPT_LogManager::GetLogger((_logger).name); \ + } + +#if defined(NPT_CONFIG_ENABLE_LOGGING) + +#define NPT_DEFINE_LOGGER(_logger, _name) static volatile NPT_LoggerReference _logger = { NULL, (_name) }; + +#define NPT_LOG_X(_logger, _level, _argsx) \ +do { \ + NPT_LOG_GET_LOGGER((_logger)) \ + if ((_logger).logger && (_level) >= (_logger).logger->GetLevel()) { \ + (_logger).logger->Log _argsx; \ + } \ +} while(0) + +#define NPT_CHECK_LL(_logger, _level, _result) do { \ + NPT_Result _x = (_result); \ + if (_x != NPT_SUCCESS) { \ + NPT_LOG_X((_logger),(_level),((_level),__FILE__,__LINE__,(NPT_LocalFunctionName),"NPT_CHECK failed, result=%d (%s) [%s]", _x, NPT_ResultText(_x), #_result)); \ + return _x; \ + } \ +} while(0) + +#define NPT_CHECK_LABEL_LL(_logger, _level, _result, _label) do { \ + NPT_Result _x = (_result); \ + if (_x != NPT_SUCCESS) { \ + NPT_LOG_X((_logger),(_level),((_level),__FILE__,__LINE__,(NPT_LocalFunctionName),"NPT_CHECK failed, result=%d (%s) [%s]", _x, NPT_ResultText(_x), #_result)); \ + goto _label; \ + } \ +} while(0) +#define NPT_CHECK_POINTER_LL(_logger, _level, _p) do { \ + if ((_p) == NULL) { \ + NPT_LOG_X((_logger),(_level),((_level),__FILE__,__LINE__,(NPT_LocalFunctionName),"@@@ NULL pointer parameter")); \ + return NPT_ERROR_INVALID_PARAMETERS; \ + } \ +} while(0) +#define NPT_CHECK_POINTER_LABEL_LL(_logger, _level, _p, _label) do { \ + if ((_p) == NULL) { \ + NPT_LOG_X((_logger),(_level),((_level),__FILE__,__LINE__,(NPT_LocalFunctionName),"@@@ NULL pointer parameter")); \ + goto _label; \ + } \ +} while(0) + +#else /* NPT_CONFIG_ENABLE_LOGGING */ + +#define NPT_DEFINE_LOGGER(_logger, _name) +#define NPT_LOG_X(_logger, _level, _argsx) +#define NPT_CHECK_LL(_logger, _level, _result) NPT_CHECK(_result) +#define NPT_CHECK_LABEL_LL(_logger, _level, _result, _label) NPT_CHECK_LABEL((_result), _label) +#define NPT_CHECK_POINTER_LL(_logger, _level, _p) NPT_CHECK_POINTER((_p)) +#define NPT_CHECK_POINTER_LABEL_LL(_logger, _level, _p, _label) NPT_CHECK_POINTER_LABEL((_p), _label) + +#endif /* NPT_CONFIG_ENABLE_LOGGING */ + +#define NPT_SET_LOCAL_LOGGER(_name) NPT_DEFINE_LOGGER(_NPT_LocalLogger, (_name)) +#define NPT_CHECK_L(_level, _result) NPT_CHECK_LL(_NPT_LocalLogger, (_level), (_result)) +#define NPT_CHECK_LABEL_L(_level, _result, _label) NPT_CHECK_LABEL_LL(_NPT_LocalLogger, (_level), NULL, (_result), _label) + +/* NOTE: the following are machine-generated, do not edit */ +#define NPT_LOG_LL(_logger,_level,_msg) NPT_LOG_X((_logger),(_level),((_level),__FILE__,__LINE__,(NPT_LocalFunctionName),(_msg))) +#define NPT_LOG(_level,_msg) NPT_LOG_LL((_NPT_LocalLogger),(_level),(_msg)) +#define NPT_LOG_L(_logger,_level,_msg) NPT_LOG_LL((_logger),(_level),(_msg)) +#define NPT_LOG_LL1(_logger,_level,_msg,_arg1) NPT_LOG_X((_logger),(_level),((_level),__FILE__,__LINE__,(NPT_LocalFunctionName),(_msg),(_arg1))) +#define NPT_LOG_1(_level,_msg,_arg1) NPT_LOG_LL1((_NPT_LocalLogger),(_level),(_msg),(_arg1)) +#define NPT_LOG_L1(_logger,_level,_msg,_arg1) NPT_LOG_LL1((_logger),(_level),(_msg),(_arg1)) +#define NPT_LOG_LL2(_logger,_level,_msg,_arg1,_arg2) NPT_LOG_X((_logger),(_level),((_level),__FILE__,__LINE__,(NPT_LocalFunctionName),(_msg),(_arg1),(_arg2))) +#define NPT_LOG_2(_level,_msg,_arg1,_arg2) NPT_LOG_LL2((_NPT_LocalLogger),(_level),(_msg),(_arg1),(_arg2)) +#define NPT_LOG_L2(_logger,_level,_msg,_arg1,_arg2) NPT_LOG_LL2((_logger),(_level),(_msg),(_arg1),(_arg2)) +#define NPT_LOG_LL3(_logger,_level,_msg,_arg1,_arg2,_arg3) NPT_LOG_X((_logger),(_level),((_level),__FILE__,__LINE__,(NPT_LocalFunctionName),(_msg),(_arg1),(_arg2),(_arg3))) +#define NPT_LOG_3(_level,_msg,_arg1,_arg2,_arg3) NPT_LOG_LL3((_NPT_LocalLogger),(_level),(_msg),(_arg1),(_arg2),(_arg3)) +#define NPT_LOG_L3(_logger,_level,_msg,_arg1,_arg2,_arg3) NPT_LOG_LL3((_logger),(_level),(_msg),(_arg1),(_arg2),(_arg3)) +#define NPT_LOG_LL4(_logger,_level,_msg,_arg1,_arg2,_arg3,_arg4) NPT_LOG_X((_logger),(_level),((_level),__FILE__,__LINE__,(NPT_LocalFunctionName),(_msg),(_arg1),(_arg2),(_arg3),(_arg4))) +#define NPT_LOG_4(_level,_msg,_arg1,_arg2,_arg3,_arg4) NPT_LOG_LL4((_NPT_LocalLogger),(_level),(_msg),(_arg1),(_arg2),(_arg3),(_arg4)) +#define NPT_LOG_L4(_logger,_level,_msg,_arg1,_arg2,_arg3,_arg4) NPT_LOG_LL4((_logger),(_level),(_msg),(_arg1),(_arg2),(_arg3),(_arg4)) +#define NPT_LOG_LL5(_logger,_level,_msg,_arg1,_arg2,_arg3,_arg4,_arg5) NPT_LOG_X((_logger),(_level),((_level),__FILE__,__LINE__,(NPT_LocalFunctionName),(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5))) +#define NPT_LOG_5(_level,_msg,_arg1,_arg2,_arg3,_arg4,_arg5) NPT_LOG_LL5((_NPT_LocalLogger),(_level),(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5)) +#define NPT_LOG_L5(_logger,_level,_msg,_arg1,_arg2,_arg3,_arg4,_arg5) NPT_LOG_LL5((_logger),(_level),(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5)) +#define NPT_LOG_LL6(_logger,_level,_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6) NPT_LOG_X((_logger),(_level),((_level),__FILE__,__LINE__,(NPT_LocalFunctionName),(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6))) +#define NPT_LOG_6(_level,_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6) NPT_LOG_LL6((_NPT_LocalLogger),(_level),(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6)) +#define NPT_LOG_L6(_logger,_level,_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6) NPT_LOG_LL6((_logger),(_level),(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6)) +#define NPT_LOG_LL7(_logger,_level,_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7) NPT_LOG_X((_logger),(_level),((_level),__FILE__,__LINE__,(NPT_LocalFunctionName),(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7))) +#define NPT_LOG_7(_level,_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7) NPT_LOG_LL7((_NPT_LocalLogger),(_level),(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7)) +#define NPT_LOG_L7(_logger,_level,_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7) NPT_LOG_LL7((_logger),(_level),(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7)) +#define NPT_LOG_LL8(_logger,_level,_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7,_arg8) NPT_LOG_X((_logger),(_level),((_level),__FILE__,__LINE__,(NPT_LocalFunctionName),(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7),(_arg8))) +#define NPT_LOG_8(_level,_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7,_arg8) NPT_LOG_LL8((_NPT_LocalLogger),(_level),(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7),(_arg8)) +#define NPT_LOG_L8(_logger,_level,_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7,_arg8) NPT_LOG_LL8((_logger),(_level),(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7),(_arg8)) +#define NPT_LOG_LL9(_logger,_level,_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7,_arg8,_arg9) NPT_LOG_X((_logger),(_level),((_level),__FILE__,__LINE__,(NPT_LocalFunctionName),(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7),(_arg8),(_arg9))) +#define NPT_LOG_9(_level,_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7,_arg8,_arg9) NPT_LOG_LL9((_NPT_LocalLogger),(_level),(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7),(_arg8),(_arg9)) +#define NPT_LOG_L9(_logger,_level,_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7,_arg8,_arg9) NPT_LOG_LL9((_logger),(_level),(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7),(_arg8),(_arg9)) + +#define NPT_LOG_FATAL(_msg) NPT_LOG_LL((_NPT_LocalLogger),NPT_LOG_LEVEL_FATAL,(_msg)) +#define NPT_LOG_FATAL_L(_logger,_msg) NPT_LOG_LL((_logger),NPT_LOG_LEVEL_FATAL,(_msg)) +#define NPT_LOG_FATAL_1(_msg,_arg1) NPT_LOG_LL1((_NPT_LocalLogger),NPT_LOG_LEVEL_FATAL,(_msg),(_arg1)) +#define NPT_LOG_FATAL_L1(_logger,_msg,_arg1) NPT_LOG_LL1((_logger),NPT_LOG_LEVEL_FATAL,(_msg),(_arg1)) +#define NPT_LOG_FATAL_2(_msg,_arg1,_arg2) NPT_LOG_LL2((_NPT_LocalLogger),NPT_LOG_LEVEL_FATAL,(_msg),(_arg1),(_arg2)) +#define NPT_LOG_FATAL_L2(_logger,_msg,_arg1,_arg2) NPT_LOG_LL2((_logger),NPT_LOG_LEVEL_FATAL,(_msg),(_arg1),(_arg2)) +#define NPT_LOG_FATAL_3(_msg,_arg1,_arg2,_arg3) NPT_LOG_LL3((_NPT_LocalLogger),NPT_LOG_LEVEL_FATAL,(_msg),(_arg1),(_arg2),(_arg3)) +#define NPT_LOG_FATAL_L3(_logger,_msg,_arg1,_arg2,_arg3) NPT_LOG_LL3((_logger),NPT_LOG_LEVEL_FATAL,(_msg),(_arg1),(_arg2),(_arg3)) +#define NPT_LOG_FATAL_4(_msg,_arg1,_arg2,_arg3,_arg4) NPT_LOG_LL4((_NPT_LocalLogger),NPT_LOG_LEVEL_FATAL,(_msg),(_arg1),(_arg2),(_arg3),(_arg4)) +#define NPT_LOG_FATAL_L4(_logger,_msg,_arg1,_arg2,_arg3,_arg4) NPT_LOG_LL4((_logger),NPT_LOG_LEVEL_FATAL,(_msg),(_arg1),(_arg2),(_arg3),(_arg4)) +#define NPT_LOG_FATAL_5(_msg,_arg1,_arg2,_arg3,_arg4,_arg5) NPT_LOG_LL5((_NPT_LocalLogger),NPT_LOG_LEVEL_FATAL,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5)) +#define NPT_LOG_FATAL_L5(_logger,_msg,_arg1,_arg2,_arg3,_arg4,_arg5) NPT_LOG_LL5((_logger),NPT_LOG_LEVEL_FATAL,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5)) +#define NPT_LOG_FATAL_6(_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6) NPT_LOG_LL6((_NPT_LocalLogger),NPT_LOG_LEVEL_FATAL,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6)) +#define NPT_LOG_FATAL_L6(_logger,_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6) NPT_LOG_LL6((_logger),NPT_LOG_LEVEL_FATAL,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6)) +#define NPT_LOG_FATAL_7(_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7) NPT_LOG_LL7((_NPT_LocalLogger),NPT_LOG_LEVEL_FATAL,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7)) +#define NPT_LOG_FATAL_L7(_logger,_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7) NPT_LOG_LL7((_logger),NPT_LOG_LEVEL_FATAL,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7)) +#define NPT_LOG_FATAL_8(_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7,_arg8) NPT_LOG_LL8((_NPT_LocalLogger),NPT_LOG_LEVEL_FATAL,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7),(_arg8)) +#define NPT_LOG_FATAL_L8(_logger,_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7,_arg8) NPT_LOG_LL8((_logger),NPT_LOG_LEVEL_FATAL,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7),(_arg8)) +#define NPT_LOG_FATAL_9(_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7,_arg8,_arg9) NPT_LOG_LL9((_NPT_LocalLogger),NPT_LOG_LEVEL_FATAL,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7),(_arg8),(_arg9)) +#define NPT_LOG_FATAL_L9(_logger,_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7,_arg8,_arg9) NPT_LOG_LL9((_logger),NPT_LOG_LEVEL_FATAL,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7),(_arg8),(_arg9)) +#define NPT_LOG_SEVERE(_msg) NPT_LOG_LL((_NPT_LocalLogger),NPT_LOG_LEVEL_SEVERE,(_msg)) +#define NPT_LOG_SEVERE_L(_logger,_msg) NPT_LOG_LL((_logger),NPT_LOG_LEVEL_SEVERE,(_msg)) +#define NPT_LOG_SEVERE_1(_msg,_arg1) NPT_LOG_LL1((_NPT_LocalLogger),NPT_LOG_LEVEL_SEVERE,(_msg),(_arg1)) +#define NPT_LOG_SEVERE_L1(_logger,_msg,_arg1) NPT_LOG_LL1((_logger),NPT_LOG_LEVEL_SEVERE,(_msg),(_arg1)) +#define NPT_LOG_SEVERE_2(_msg,_arg1,_arg2) NPT_LOG_LL2((_NPT_LocalLogger),NPT_LOG_LEVEL_SEVERE,(_msg),(_arg1),(_arg2)) +#define NPT_LOG_SEVERE_L2(_logger,_msg,_arg1,_arg2) NPT_LOG_LL2((_logger),NPT_LOG_LEVEL_SEVERE,(_msg),(_arg1),(_arg2)) +#define NPT_LOG_SEVERE_3(_msg,_arg1,_arg2,_arg3) NPT_LOG_LL3((_NPT_LocalLogger),NPT_LOG_LEVEL_SEVERE,(_msg),(_arg1),(_arg2),(_arg3)) +#define NPT_LOG_SEVERE_L3(_logger,_msg,_arg1,_arg2,_arg3) NPT_LOG_LL3((_logger),NPT_LOG_LEVEL_SEVERE,(_msg),(_arg1),(_arg2),(_arg3)) +#define NPT_LOG_SEVERE_4(_msg,_arg1,_arg2,_arg3,_arg4) NPT_LOG_LL4((_NPT_LocalLogger),NPT_LOG_LEVEL_SEVERE,(_msg),(_arg1),(_arg2),(_arg3),(_arg4)) +#define NPT_LOG_SEVERE_L4(_logger,_msg,_arg1,_arg2,_arg3,_arg4) NPT_LOG_LL4((_logger),NPT_LOG_LEVEL_SEVERE,(_msg),(_arg1),(_arg2),(_arg3),(_arg4)) +#define NPT_LOG_SEVERE_5(_msg,_arg1,_arg2,_arg3,_arg4,_arg5) NPT_LOG_LL5((_NPT_LocalLogger),NPT_LOG_LEVEL_SEVERE,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5)) +#define NPT_LOG_SEVERE_L5(_logger,_msg,_arg1,_arg2,_arg3,_arg4,_arg5) NPT_LOG_LL5((_logger),NPT_LOG_LEVEL_SEVERE,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5)) +#define NPT_LOG_SEVERE_6(_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6) NPT_LOG_LL6((_NPT_LocalLogger),NPT_LOG_LEVEL_SEVERE,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6)) +#define NPT_LOG_SEVERE_L6(_logger,_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6) NPT_LOG_LL6((_logger),NPT_LOG_LEVEL_SEVERE,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6)) +#define NPT_LOG_SEVERE_7(_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7) NPT_LOG_LL7((_NPT_LocalLogger),NPT_LOG_LEVEL_SEVERE,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7)) +#define NPT_LOG_SEVERE_L7(_logger,_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7) NPT_LOG_LL7((_logger),NPT_LOG_LEVEL_SEVERE,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7)) +#define NPT_LOG_SEVERE_8(_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7,_arg8) NPT_LOG_LL8((_NPT_LocalLogger),NPT_LOG_LEVEL_SEVERE,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7),(_arg8)) +#define NPT_LOG_SEVERE_L8(_logger,_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7,_arg8) NPT_LOG_LL8((_logger),NPT_LOG_LEVEL_SEVERE,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7),(_arg8)) +#define NPT_LOG_SEVERE_9(_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7,_arg8,_arg9) NPT_LOG_LL9((_NPT_LocalLogger),NPT_LOG_LEVEL_SEVERE,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7),(_arg8),(_arg9)) +#define NPT_LOG_SEVERE_L9(_logger,_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7,_arg8,_arg9) NPT_LOG_LL9((_logger),NPT_LOG_LEVEL_SEVERE,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7),(_arg8),(_arg9)) +#define NPT_LOG_WARNING(_msg) NPT_LOG_LL((_NPT_LocalLogger),NPT_LOG_LEVEL_WARNING,(_msg)) +#define NPT_LOG_WARNING_L(_logger,_msg) NPT_LOG_LL((_logger),NPT_LOG_LEVEL_WARNING,(_msg)) +#define NPT_LOG_WARNING_1(_msg,_arg1) NPT_LOG_LL1((_NPT_LocalLogger),NPT_LOG_LEVEL_WARNING,(_msg),(_arg1)) +#define NPT_LOG_WARNING_L1(_logger,_msg,_arg1) NPT_LOG_LL1((_logger),NPT_LOG_LEVEL_WARNING,(_msg),(_arg1)) +#define NPT_LOG_WARNING_2(_msg,_arg1,_arg2) NPT_LOG_LL2((_NPT_LocalLogger),NPT_LOG_LEVEL_WARNING,(_msg),(_arg1),(_arg2)) +#define NPT_LOG_WARNING_L2(_logger,_msg,_arg1,_arg2) NPT_LOG_LL2((_logger),NPT_LOG_LEVEL_WARNING,(_msg),(_arg1),(_arg2)) +#define NPT_LOG_WARNING_3(_msg,_arg1,_arg2,_arg3) NPT_LOG_LL3((_NPT_LocalLogger),NPT_LOG_LEVEL_WARNING,(_msg),(_arg1),(_arg2),(_arg3)) +#define NPT_LOG_WARNING_L3(_logger,_msg,_arg1,_arg2,_arg3) NPT_LOG_LL3((_logger),NPT_LOG_LEVEL_WARNING,(_msg),(_arg1),(_arg2),(_arg3)) +#define NPT_LOG_WARNING_4(_msg,_arg1,_arg2,_arg3,_arg4) NPT_LOG_LL4((_NPT_LocalLogger),NPT_LOG_LEVEL_WARNING,(_msg),(_arg1),(_arg2),(_arg3),(_arg4)) +#define NPT_LOG_WARNING_L4(_logger,_msg,_arg1,_arg2,_arg3,_arg4) NPT_LOG_LL4((_logger),NPT_LOG_LEVEL_WARNING,(_msg),(_arg1),(_arg2),(_arg3),(_arg4)) +#define NPT_LOG_WARNING_5(_msg,_arg1,_arg2,_arg3,_arg4,_arg5) NPT_LOG_LL5((_NPT_LocalLogger),NPT_LOG_LEVEL_WARNING,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5)) +#define NPT_LOG_WARNING_L5(_logger,_msg,_arg1,_arg2,_arg3,_arg4,_arg5) NPT_LOG_LL5((_logger),NPT_LOG_LEVEL_WARNING,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5)) +#define NPT_LOG_WARNING_6(_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6) NPT_LOG_LL6((_NPT_LocalLogger),NPT_LOG_LEVEL_WARNING,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6)) +#define NPT_LOG_WARNING_L6(_logger,_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6) NPT_LOG_LL6((_logger),NPT_LOG_LEVEL_WARNING,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6)) +#define NPT_LOG_WARNING_7(_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7) NPT_LOG_LL7((_NPT_LocalLogger),NPT_LOG_LEVEL_WARNING,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7)) +#define NPT_LOG_WARNING_L7(_logger,_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7) NPT_LOG_LL7((_logger),NPT_LOG_LEVEL_WARNING,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7)) +#define NPT_LOG_WARNING_8(_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7,_arg8) NPT_LOG_LL8((_NPT_LocalLogger),NPT_LOG_LEVEL_WARNING,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7),(_arg8)) +#define NPT_LOG_WARNING_L8(_logger,_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7,_arg8) NPT_LOG_LL8((_logger),NPT_LOG_LEVEL_WARNING,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7),(_arg8)) +#define NPT_LOG_WARNING_9(_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7,_arg8,_arg9) NPT_LOG_LL9((_NPT_LocalLogger),NPT_LOG_LEVEL_WARNING,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7),(_arg8),(_arg9)) +#define NPT_LOG_WARNING_L9(_logger,_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7,_arg8,_arg9) NPT_LOG_LL9((_logger),NPT_LOG_LEVEL_WARNING,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7),(_arg8),(_arg9)) +#define NPT_LOG_INFO(_msg) NPT_LOG_LL((_NPT_LocalLogger),NPT_LOG_LEVEL_INFO,(_msg)) +#define NPT_LOG_INFO_L(_logger,_msg) NPT_LOG_LL((_logger),NPT_LOG_LEVEL_INFO,(_msg)) +#define NPT_LOG_INFO_1(_msg,_arg1) NPT_LOG_LL1((_NPT_LocalLogger),NPT_LOG_LEVEL_INFO,(_msg),(_arg1)) +#define NPT_LOG_INFO_L1(_logger,_msg,_arg1) NPT_LOG_LL1((_logger),NPT_LOG_LEVEL_INFO,(_msg),(_arg1)) +#define NPT_LOG_INFO_2(_msg,_arg1,_arg2) NPT_LOG_LL2((_NPT_LocalLogger),NPT_LOG_LEVEL_INFO,(_msg),(_arg1),(_arg2)) +#define NPT_LOG_INFO_L2(_logger,_msg,_arg1,_arg2) NPT_LOG_LL2((_logger),NPT_LOG_LEVEL_INFO,(_msg),(_arg1),(_arg2)) +#define NPT_LOG_INFO_3(_msg,_arg1,_arg2,_arg3) NPT_LOG_LL3((_NPT_LocalLogger),NPT_LOG_LEVEL_INFO,(_msg),(_arg1),(_arg2),(_arg3)) +#define NPT_LOG_INFO_L3(_logger,_msg,_arg1,_arg2,_arg3) NPT_LOG_LL3((_logger),NPT_LOG_LEVEL_INFO,(_msg),(_arg1),(_arg2),(_arg3)) +#define NPT_LOG_INFO_4(_msg,_arg1,_arg2,_arg3,_arg4) NPT_LOG_LL4((_NPT_LocalLogger),NPT_LOG_LEVEL_INFO,(_msg),(_arg1),(_arg2),(_arg3),(_arg4)) +#define NPT_LOG_INFO_L4(_logger,_msg,_arg1,_arg2,_arg3,_arg4) NPT_LOG_LL4((_logger),NPT_LOG_LEVEL_INFO,(_msg),(_arg1),(_arg2),(_arg3),(_arg4)) +#define NPT_LOG_INFO_5(_msg,_arg1,_arg2,_arg3,_arg4,_arg5) NPT_LOG_LL5((_NPT_LocalLogger),NPT_LOG_LEVEL_INFO,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5)) +#define NPT_LOG_INFO_L5(_logger,_msg,_arg1,_arg2,_arg3,_arg4,_arg5) NPT_LOG_LL5((_logger),NPT_LOG_LEVEL_INFO,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5)) +#define NPT_LOG_INFO_6(_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6) NPT_LOG_LL6((_NPT_LocalLogger),NPT_LOG_LEVEL_INFO,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6)) +#define NPT_LOG_INFO_L6(_logger,_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6) NPT_LOG_LL6((_logger),NPT_LOG_LEVEL_INFO,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6)) +#define NPT_LOG_INFO_7(_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7) NPT_LOG_LL7((_NPT_LocalLogger),NPT_LOG_LEVEL_INFO,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7)) +#define NPT_LOG_INFO_L7(_logger,_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7) NPT_LOG_LL7((_logger),NPT_LOG_LEVEL_INFO,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7)) +#define NPT_LOG_INFO_8(_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7,_arg8) NPT_LOG_LL8((_NPT_LocalLogger),NPT_LOG_LEVEL_INFO,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7),(_arg8)) +#define NPT_LOG_INFO_L8(_logger,_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7,_arg8) NPT_LOG_LL8((_logger),NPT_LOG_LEVEL_INFO,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7),(_arg8)) +#define NPT_LOG_INFO_9(_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7,_arg8,_arg9) NPT_LOG_LL9((_NPT_LocalLogger),NPT_LOG_LEVEL_INFO,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7),(_arg8),(_arg9)) +#define NPT_LOG_INFO_L9(_logger,_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7,_arg8,_arg9) NPT_LOG_LL9((_logger),NPT_LOG_LEVEL_INFO,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7),(_arg8),(_arg9)) +#define NPT_LOG_FINE(_msg) NPT_LOG_LL((_NPT_LocalLogger),NPT_LOG_LEVEL_FINE,(_msg)) +#define NPT_LOG_FINE_L(_logger,_msg) NPT_LOG_LL((_logger),NPT_LOG_LEVEL_FINE,(_msg)) +#define NPT_LOG_FINE_1(_msg,_arg1) NPT_LOG_LL1((_NPT_LocalLogger),NPT_LOG_LEVEL_FINE,(_msg),(_arg1)) +#define NPT_LOG_FINE_L1(_logger,_msg,_arg1) NPT_LOG_LL1((_logger),NPT_LOG_LEVEL_FINE,(_msg),(_arg1)) +#define NPT_LOG_FINE_2(_msg,_arg1,_arg2) NPT_LOG_LL2((_NPT_LocalLogger),NPT_LOG_LEVEL_FINE,(_msg),(_arg1),(_arg2)) +#define NPT_LOG_FINE_L2(_logger,_msg,_arg1,_arg2) NPT_LOG_LL2((_logger),NPT_LOG_LEVEL_FINE,(_msg),(_arg1),(_arg2)) +#define NPT_LOG_FINE_3(_msg,_arg1,_arg2,_arg3) NPT_LOG_LL3((_NPT_LocalLogger),NPT_LOG_LEVEL_FINE,(_msg),(_arg1),(_arg2),(_arg3)) +#define NPT_LOG_FINE_L3(_logger,_msg,_arg1,_arg2,_arg3) NPT_LOG_LL3((_logger),NPT_LOG_LEVEL_FINE,(_msg),(_arg1),(_arg2),(_arg3)) +#define NPT_LOG_FINE_4(_msg,_arg1,_arg2,_arg3,_arg4) NPT_LOG_LL4((_NPT_LocalLogger),NPT_LOG_LEVEL_FINE,(_msg),(_arg1),(_arg2),(_arg3),(_arg4)) +#define NPT_LOG_FINE_L4(_logger,_msg,_arg1,_arg2,_arg3,_arg4) NPT_LOG_LL4((_logger),NPT_LOG_LEVEL_FINE,(_msg),(_arg1),(_arg2),(_arg3),(_arg4)) +#define NPT_LOG_FINE_5(_msg,_arg1,_arg2,_arg3,_arg4,_arg5) NPT_LOG_LL5((_NPT_LocalLogger),NPT_LOG_LEVEL_FINE,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5)) +#define NPT_LOG_FINE_L5(_logger,_msg,_arg1,_arg2,_arg3,_arg4,_arg5) NPT_LOG_LL5((_logger),NPT_LOG_LEVEL_FINE,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5)) +#define NPT_LOG_FINE_6(_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6) NPT_LOG_LL6((_NPT_LocalLogger),NPT_LOG_LEVEL_FINE,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6)) +#define NPT_LOG_FINE_L6(_logger,_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6) NPT_LOG_LL6((_logger),NPT_LOG_LEVEL_FINE,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6)) +#define NPT_LOG_FINE_7(_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7) NPT_LOG_LL7((_NPT_LocalLogger),NPT_LOG_LEVEL_FINE,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7)) +#define NPT_LOG_FINE_L7(_logger,_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7) NPT_LOG_LL7((_logger),NPT_LOG_LEVEL_FINE,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7)) +#define NPT_LOG_FINE_8(_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7,_arg8) NPT_LOG_LL8((_NPT_LocalLogger),NPT_LOG_LEVEL_FINE,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7),(_arg8)) +#define NPT_LOG_FINE_L8(_logger,_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7,_arg8) NPT_LOG_LL8((_logger),NPT_LOG_LEVEL_FINE,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7),(_arg8)) +#define NPT_LOG_FINE_9(_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7,_arg8,_arg9) NPT_LOG_LL9((_NPT_LocalLogger),NPT_LOG_LEVEL_FINE,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7),(_arg8),(_arg9)) +#define NPT_LOG_FINE_L9(_logger,_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7,_arg8,_arg9) NPT_LOG_LL9((_logger),NPT_LOG_LEVEL_FINE,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7),(_arg8),(_arg9)) +#define NPT_LOG_FINER(_msg) NPT_LOG_LL((_NPT_LocalLogger),NPT_LOG_LEVEL_FINER,(_msg)) +#define NPT_LOG_FINER_L(_logger,_msg) NPT_LOG_LL((_logger),NPT_LOG_LEVEL_FINER,(_msg)) +#define NPT_LOG_FINER_1(_msg,_arg1) NPT_LOG_LL1((_NPT_LocalLogger),NPT_LOG_LEVEL_FINER,(_msg),(_arg1)) +#define NPT_LOG_FINER_L1(_logger,_msg,_arg1) NPT_LOG_LL1((_logger),NPT_LOG_LEVEL_FINER,(_msg),(_arg1)) +#define NPT_LOG_FINER_2(_msg,_arg1,_arg2) NPT_LOG_LL2((_NPT_LocalLogger),NPT_LOG_LEVEL_FINER,(_msg),(_arg1),(_arg2)) +#define NPT_LOG_FINER_L2(_logger,_msg,_arg1,_arg2) NPT_LOG_LL2((_logger),NPT_LOG_LEVEL_FINER,(_msg),(_arg1),(_arg2)) +#define NPT_LOG_FINER_3(_msg,_arg1,_arg2,_arg3) NPT_LOG_LL3((_NPT_LocalLogger),NPT_LOG_LEVEL_FINER,(_msg),(_arg1),(_arg2),(_arg3)) +#define NPT_LOG_FINER_L3(_logger,_msg,_arg1,_arg2,_arg3) NPT_LOG_LL3((_logger),NPT_LOG_LEVEL_FINER,(_msg),(_arg1),(_arg2),(_arg3)) +#define NPT_LOG_FINER_4(_msg,_arg1,_arg2,_arg3,_arg4) NPT_LOG_LL4((_NPT_LocalLogger),NPT_LOG_LEVEL_FINER,(_msg),(_arg1),(_arg2),(_arg3),(_arg4)) +#define NPT_LOG_FINER_L4(_logger,_msg,_arg1,_arg2,_arg3,_arg4) NPT_LOG_LL4((_logger),NPT_LOG_LEVEL_FINER,(_msg),(_arg1),(_arg2),(_arg3),(_arg4)) +#define NPT_LOG_FINER_5(_msg,_arg1,_arg2,_arg3,_arg4,_arg5) NPT_LOG_LL5((_NPT_LocalLogger),NPT_LOG_LEVEL_FINER,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5)) +#define NPT_LOG_FINER_L5(_logger,_msg,_arg1,_arg2,_arg3,_arg4,_arg5) NPT_LOG_LL5((_logger),NPT_LOG_LEVEL_FINER,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5)) +#define NPT_LOG_FINER_6(_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6) NPT_LOG_LL6((_NPT_LocalLogger),NPT_LOG_LEVEL_FINER,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6)) +#define NPT_LOG_FINER_L6(_logger,_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6) NPT_LOG_LL6((_logger),NPT_LOG_LEVEL_FINER,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6)) +#define NPT_LOG_FINER_7(_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7) NPT_LOG_LL7((_NPT_LocalLogger),NPT_LOG_LEVEL_FINER,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7)) +#define NPT_LOG_FINER_L7(_logger,_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7) NPT_LOG_LL7((_logger),NPT_LOG_LEVEL_FINER,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7)) +#define NPT_LOG_FINER_8(_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7,_arg8) NPT_LOG_LL8((_NPT_LocalLogger),NPT_LOG_LEVEL_FINER,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7),(_arg8)) +#define NPT_LOG_FINER_L8(_logger,_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7,_arg8) NPT_LOG_LL8((_logger),NPT_LOG_LEVEL_FINER,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7),(_arg8)) +#define NPT_LOG_FINER_9(_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7,_arg8,_arg9) NPT_LOG_LL9((_NPT_LocalLogger),NPT_LOG_LEVEL_FINER,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7),(_arg8),(_arg9)) +#define NPT_LOG_FINER_L9(_logger,_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7,_arg8,_arg9) NPT_LOG_LL9((_logger),NPT_LOG_LEVEL_FINER,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7),(_arg8),(_arg9)) +#define NPT_LOG_FINEST(_msg) NPT_LOG_LL((_NPT_LocalLogger),NPT_LOG_LEVEL_FINEST,(_msg)) +#define NPT_LOG_FINEST_L(_logger,_msg) NPT_LOG_LL((_logger),NPT_LOG_LEVEL_FINEST,(_msg)) +#define NPT_LOG_FINEST_1(_msg,_arg1) NPT_LOG_LL1((_NPT_LocalLogger),NPT_LOG_LEVEL_FINEST,(_msg),(_arg1)) +#define NPT_LOG_FINEST_L1(_logger,_msg,_arg1) NPT_LOG_LL1((_logger),NPT_LOG_LEVEL_FINEST,(_msg),(_arg1)) +#define NPT_LOG_FINEST_2(_msg,_arg1,_arg2) NPT_LOG_LL2((_NPT_LocalLogger),NPT_LOG_LEVEL_FINEST,(_msg),(_arg1),(_arg2)) +#define NPT_LOG_FINEST_L2(_logger,_msg,_arg1,_arg2) NPT_LOG_LL2((_logger),NPT_LOG_LEVEL_FINEST,(_msg),(_arg1),(_arg2)) +#define NPT_LOG_FINEST_3(_msg,_arg1,_arg2,_arg3) NPT_LOG_LL3((_NPT_LocalLogger),NPT_LOG_LEVEL_FINEST,(_msg),(_arg1),(_arg2),(_arg3)) +#define NPT_LOG_FINEST_L3(_logger,_msg,_arg1,_arg2,_arg3) NPT_LOG_LL3((_logger),NPT_LOG_LEVEL_FINEST,(_msg),(_arg1),(_arg2),(_arg3)) +#define NPT_LOG_FINEST_4(_msg,_arg1,_arg2,_arg3,_arg4) NPT_LOG_LL4((_NPT_LocalLogger),NPT_LOG_LEVEL_FINEST,(_msg),(_arg1),(_arg2),(_arg3),(_arg4)) +#define NPT_LOG_FINEST_L4(_logger,_msg,_arg1,_arg2,_arg3,_arg4) NPT_LOG_LL4((_logger),NPT_LOG_LEVEL_FINEST,(_msg),(_arg1),(_arg2),(_arg3),(_arg4)) +#define NPT_LOG_FINEST_5(_msg,_arg1,_arg2,_arg3,_arg4,_arg5) NPT_LOG_LL5((_NPT_LocalLogger),NPT_LOG_LEVEL_FINEST,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5)) +#define NPT_LOG_FINEST_L5(_logger,_msg,_arg1,_arg2,_arg3,_arg4,_arg5) NPT_LOG_LL5((_logger),NPT_LOG_LEVEL_FINEST,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5)) +#define NPT_LOG_FINEST_6(_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6) NPT_LOG_LL6((_NPT_LocalLogger),NPT_LOG_LEVEL_FINEST,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6)) +#define NPT_LOG_FINEST_L6(_logger,_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6) NPT_LOG_LL6((_logger),NPT_LOG_LEVEL_FINEST,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6)) +#define NPT_LOG_FINEST_7(_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7) NPT_LOG_LL7((_NPT_LocalLogger),NPT_LOG_LEVEL_FINEST,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7)) +#define NPT_LOG_FINEST_L7(_logger,_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7) NPT_LOG_LL7((_logger),NPT_LOG_LEVEL_FINEST,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7)) +#define NPT_LOG_FINEST_8(_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7,_arg8) NPT_LOG_LL8((_NPT_LocalLogger),NPT_LOG_LEVEL_FINEST,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7),(_arg8)) +#define NPT_LOG_FINEST_L8(_logger,_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7,_arg8) NPT_LOG_LL8((_logger),NPT_LOG_LEVEL_FINEST,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7),(_arg8)) +#define NPT_LOG_FINEST_9(_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7,_arg8,_arg9) NPT_LOG_LL9((_NPT_LocalLogger),NPT_LOG_LEVEL_FINEST,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7),(_arg8),(_arg9)) +#define NPT_LOG_FINEST_L9(_logger,_msg,_arg1,_arg2,_arg3,_arg4,_arg5,_arg6,_arg7,_arg8,_arg9) NPT_LOG_LL9((_logger),NPT_LOG_LEVEL_FINEST,(_msg),(_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6),(_arg7),(_arg8),(_arg9)) + +#define NPT_CHECK_FATAL(_result) NPT_CHECK_LL((_NPT_LocalLogger),NPT_LOG_LEVEL_FATAL,(_result)) +#define NPT_CHECK_FATAL_L(_logger,_result) NPT_CHECK_LL((_logger),NPT_LOG_LEVEL_FATAL,(_result)) +#define NPT_CHECK_SEVERE(_result) NPT_CHECK_LL((_NPT_LocalLogger),NPT_LOG_LEVEL_SEVERE,(_result)) +#define NPT_CHECK_SEVERE_L(_logger,_result) NPT_CHECK_LL((_logger),NPT_LOG_LEVEL_SEVERE,(_result)) +#define NPT_CHECK_WARNING(_result) NPT_CHECK_LL((_NPT_LocalLogger),NPT_LOG_LEVEL_WARNING,(_result)) +#define NPT_CHECK_WARNING_L(_logger,_result) NPT_CHECK_LL((_logger),NPT_LOG_LEVEL_WARNING,(_result)) +#define NPT_CHECK_INFO(_result) NPT_CHECK_LL((_NPT_LocalLogger),NPT_LOG_LEVEL_INFO,(_result)) +#define NPT_CHECK_INFO_L(_logger,_result) NPT_CHECK_LL((_logger),NPT_LOG_LEVEL_INFO,(_result)) +#define NPT_CHECK_FINE(_result) NPT_CHECK_LL((_NPT_LocalLogger),NPT_LOG_LEVEL_FINE,(_result)) +#define NPT_CHECK_FINE_L(_logger,_result) NPT_CHECK_LL((_logger),NPT_LOG_LEVEL_FINE,(_result)) +#define NPT_CHECK_FINER(_result) NPT_CHECK_LL((_NPT_LocalLogger),NPT_LOG_LEVEL_FINER,(_result)) +#define NPT_CHECK_FINER_L(_logger,_result) NPT_CHECK_LL((_logger),NPT_LOG_LEVEL_FINER,(_result)) +#define NPT_CHECK_FINEST(_result) NPT_CHECK_LL((_NPT_LocalLogger),NPT_LOG_LEVEL_FINEST,(_result)) +#define NPT_CHECK_FINEST_L(_logger,_result) NPT_CHECK_LL((_logger),NPT_LOG_LEVEL_FINEST,(_result)) + +#define NPT_CHECK_LABEL_FATAL(_result,_label) NPT_CHECK_LABEL_LL((_NPT_LocalLogger),NPT_LOG_LEVEL_FATAL,(_result),_label) +#define NPT_CHECK_LABEL_FATAL_L(_logger,_result,_label) NPT_CHECK_LABEL_LL((_logger),NPT_LOG_LEVEL_FATAL,(_result),_label) +#define NPT_CHECK_LABEL_SEVERE(_result,_label) NPT_CHECK_LABEL_LL((_NPT_LocalLogger),NPT_LOG_LEVEL_SEVERE,(_result),_label) +#define NPT_CHECK_LABEL_SEVERE_L(_logger,_result,_label) NPT_CHECK_LABEL_LL((_logger),NPT_LOG_LEVEL_SEVERE,(_result),_label) +#define NPT_CHECK_LABEL_WARNING(_result,_label) NPT_CHECK_LABEL_LL((_NPT_LocalLogger),NPT_LOG_LEVEL_WARNING,(_result),_label) +#define NPT_CHECK_LABEL_WARNING_L(_logger,_result,_label) NPT_CHECK_LABEL_LL((_logger),NPT_LOG_LEVEL_WARNING,(_result),_label) +#define NPT_CHECK_LABEL_INFO(_result,_label) NPT_CHECK_LABEL_LL((_NPT_LocalLogger),NPT_LOG_LEVEL_INFO,(_result),_label) +#define NPT_CHECK_LABEL_INFO_L(_logger,_result,_label) NPT_CHECK_LABEL_LL((_logger),NPT_LOG_LEVEL_INFO,(_result),_label) +#define NPT_CHECK_LABEL_FINE(_result,_label) NPT_CHECK_LABEL_LL((_NPT_LocalLogger),NPT_LOG_LEVEL_FINE,(_result),_label) +#define NPT_CHECK_LABEL_FINE_L(_logger,_result,_label) NPT_CHECK_LABEL_LL((_logger),NPT_LOG_LEVEL_FINE,(_result),_label) +#define NPT_CHECK_LABEL_FINER(_result,_label) NPT_CHECK_LABEL_LL((_NPT_LocalLogger),NPT_LOG_LEVEL_FINER,(_result),_label) +#define NPT_CHECK_LABEL_FINER_L(_logger,_result,_label) NPT_CHECK_LABEL_LL((_logger),NPT_LOG_LEVEL_FINER,(_result),_label) +#define NPT_CHECK_LABEL_FINEST(_result,_label) NPT_CHECK_LABEL_LL((_NPT_LocalLogger),NPT_LOG_LEVEL_FINEST,(_result),_label) +#define NPT_CHECK_LABEL_FINEST_L(_logger,_result,_label) NPT_CHECK_LABEL_LL((_logger),NPT_LOG_LEVEL_FINEST,(_result),_label) + +#define NPT_CHECK_POINTER_FATAL(_p) NPT_CHECK_POINTER_LL((_NPT_LocalLogger),NPT_LOG_LEVEL_FATAL,(_p)) +#define NPT_CHECK_POINTER_FATAL_L(_logger,_p) NPT_CHECK_POINTER_LL(_logger,NPT_LOG_LEVEL_FATAL,(_p)) +#define NPT_CHECK_POINTER_SEVERE(_p) NPT_CHECK_POINTER_LL((_NPT_LocalLogger),NPT_LOG_LEVEL_SEVERE,(_p)) +#define NPT_CHECK_POINTER_SEVERE_L(_logger,_p) NPT_CHECK_POINTER_LL(_logger,NPT_LOG_LEVEL_SEVERE,(_p)) +#define NPT_CHECK_POINTER_WARNING(_p) NPT_CHECK_POINTER_LL((_NPT_LocalLogger),NPT_LOG_LEVEL_WARNING,(_p)) +#define NPT_CHECK_POINTER_WARNING_L(_logger,_p) NPT_CHECK_POINTER_LL(_logger,NPT_LOG_LEVEL_WARNING,(_p)) +#define NPT_CHECK_POINTER_INFO(_p) NPT_CHECK_POINTER_LL((_NPT_LocalLogger),NPT_LOG_LEVEL_INFO,(_p)) +#define NPT_CHECK_POINTER_INFO_L(_logger,_p) NPT_CHECK_POINTER_LL(_logger,NPT_LOG_LEVEL_INFO,(_p)) +#define NPT_CHECK_POINTER_FINE(_p) NPT_CHECK_POINTER_LL((_NPT_LocalLogger),NPT_LOG_LEVEL_FINE,(_p)) +#define NPT_CHECK_POINTER_FINE_L(_logger,_p) NPT_CHECK_POINTER_LL(_logger,NPT_LOG_LEVEL_FINE,(_p)) +#define NPT_CHECK_POINTER_FINER(_p) NPT_CHECK_POINTER_LL((_NPT_LocalLogger),NPT_LOG_LEVEL_FINER,(_p)) +#define NPT_CHECK_POINTER_FINER_L(_logger,_p) NPT_CHECK_POINTER_LL(_logger,NPT_LOG_LEVEL_FINER,(_p)) +#define NPT_CHECK_POINTER_FINEST(_p) NPT_CHECK_POINTER_LL((_NPT_LocalLogger),NPT_LOG_LEVEL_FINEST,(_p)) +#define NPT_CHECK_POINTER_FINEST_L(_logger,_p) NPT_CHECK_POINTER_LL(_logger,NPT_LOG_LEVEL_FINEST,(_p)) + +#define NPT_CHECK_POINTER_LABEL_FATAL(_p,_label) NPT_CHECK_POINTER_LABEL_LL((_NPT_LocalLogger),NPT_LOG_LEVEL_FATAL,(_p),_label) +#define NPT_CHECK_POINTER_LABEL_FATAL_L(_logger,_p,_label) NPT_CHECK_POINTER_LABEL_LL(_logger,NPT_LOG_LEVEL_FATAL,(_p),_label) +#define NPT_CHECK_POINTER_LABEL_SEVERE(_p,_label) NPT_CHECK_POINTER_LABEL_LL((_NPT_LocalLogger),NPT_LOG_LEVEL_SEVERE,(_p),_label) +#define NPT_CHECK_POINTER_LABEL_SEVERE_L(_logger,_p,_label) NPT_CHECK_POINTER_LABEL_LL(_logger,NPT_LOG_LEVEL_SEVERE,(_p),_label) +#define NPT_CHECK_POINTER_LABEL_WARNING(_p,_label) NPT_CHECK_POINTER_LABEL_LL((_NPT_LocalLogger),NPT_LOG_LEVEL_WARNING,(_p),_label) +#define NPT_CHECK_POINTER_LABEL_WARNING_L(_logger,_p,_label) NPT_CHECK_POINTER_LABEL_LL(_logger,NPT_LOG_LEVEL_WARNING,(_p),_label) +#define NPT_CHECK_POINTER_LABEL_INFO(_p,_label) NPT_CHECK_POINTER_LABEL_LL((_NPT_LocalLogger),NPT_LOG_LEVEL_INFO,(_p),_label) +#define NPT_CHECK_POINTER_LABEL_INFO_L(_logger,_p,_label) NPT_CHECK_POINTER_LABEL_LL(_logger,NPT_LOG_LEVEL_INFO,(_p),_label) +#define NPT_CHECK_POINTER_LABEL_FINE(_p, _label) NPT_CHECK_POINTER_LABEL_LL((_NPT_LocalLogger),NPT_LOG_LEVEL_FINE,(_p),_label) +#define NPT_CHECK_POINTER_LABEL_FINE_L(_logger,_p,_label) NPT_CHECK_POINTER_LABEL_LL(_logger,NPT_LOG_LEVEL_FINE,(_p),_label) +#define NPT_CHECK_POINTER_LABEL_FINER(_p,_label) NPT_CHECK_POINTER_LABEL_LL((_NPT_LocalLogger),NPT_LOG_LEVEL_FINER,(_p),_label) +#define NPT_CHECK_POINTER_LABEL_FINER_L(_logger,_p,_label) NPT_CHECK_POINTER_LABEL_LL(_logger,NPT_LOG_LEVEL_FINER,(_p),_label) +#define NPT_CHECK_POINTER_LABEL_FINEST(_p,_label) NNPT_CHECK_POINTER_LABEL_LL((_NPT_LocalLogger),NPT_LOG_LEVEL_FINEST,(_p),_label) +#define NPT_CHECK_POINTER_LABEL_FINEST_L(_logger,_p,_label) NPT_CHECK_POINTER_LABEL_LL(_logger,NPT_LOG_LEVEL_FINEST,(_p),_label) + +#endif /* _NPT_LOGGING_H_ */ diff --git a/lib/libUPnP/Neptune/Source/Core/NptMap.h b/lib/libUPnP/Neptune/Source/Core/NptMap.h new file mode 100644 index 0000000..75acbbe --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptMap.h @@ -0,0 +1,807 @@ +/***************************************************************** +| +| Neptune - Maps +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| +****************************************************************/ + +#ifndef _NPT_MAP_H_ +#define _NPT_MAP_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptTypes.h" +#include "NptResults.h" +#include "NptList.h" +#include "NptHash.h" + +/*---------------------------------------------------------------------- +| NPT_Map ++---------------------------------------------------------------------*/ +template <typename K, typename V> +class NPT_Map +{ +public: + // types + class Entry { + public: + // constructor + Entry(const K& key, const V& value) : m_Key(key), m_Value(value) {} + Entry(const K& key) : m_Key(key), m_Value() {} + + // accessors + const K& GetKey() const { return m_Key; } + const V& GetValue() const { return m_Value; } + + // operators + bool operator==(const Entry& other) const { + return m_Key == other.m_Key && m_Value == other.m_Value; + } + + protected: + // methods + void SetValue(const V& value) { m_Value = value; } + + // members + K m_Key; + V m_Value; + + // friends + friend class NPT_Map<K,V>; + }; + + // constructors + NPT_Map<K,V>() {} + NPT_Map<K,V>(const NPT_Map<K,V>& copy); + + // destructor + ~NPT_Map<K,V>(); + + // methods + NPT_Result Put(const K& key, const V& value); + NPT_Result Get(const K& key, V*& value) const; // WARNING: the second parameter is a POINTER on the value type!!! + bool HasKey(const K& key) const { return GetEntry(key) != NULL; } + bool HasValue(const V& value) const; + NPT_Result Erase(const K& key); + NPT_Cardinal GetEntryCount() const { return m_Entries.GetItemCount(); } + const NPT_List<Entry*>& GetEntries() const { return m_Entries; } + NPT_Result Clear(); + + // operators + V& operator[](const K& key); + const NPT_Map<K,V>& operator=(const NPT_Map<K,V>& copy); + bool operator==(const NPT_Map<K,V>& other) const; + bool operator!=(const NPT_Map<K,V>& other) const; + +private: + // types + typedef typename NPT_List<Entry*>::Iterator ListIterator; + + // methods + Entry* GetEntry(const K& key) const; + + // members + NPT_List<Entry*> m_Entries; +}; + +/*---------------------------------------------------------------------- +| NPT_Map<K,V>::NPT_Map<K,V> ++---------------------------------------------------------------------*/ +template <typename K, typename V> +NPT_Map<K,V>::NPT_Map(const NPT_Map<K,V>& copy) +{ + *this = copy; +} + +/*---------------------------------------------------------------------- +| NPT_Map<K,V>::~NPT_Map<K,V> ++---------------------------------------------------------------------*/ +template <typename K, typename V> +NPT_Map<K,V>::~NPT_Map() +{ + // call Clear to ensure we delete all entry objects + Clear(); +} + +/*---------------------------------------------------------------------- +| NPT_Map<K,V>::Clear ++---------------------------------------------------------------------*/ +template <typename K, typename V> +NPT_Result +NPT_Map<K,V>::Clear() +{ + m_Entries.Apply(NPT_ObjectDeleter<Entry>()); + m_Entries.Clear(); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_Map<K,V>::GetEntry ++---------------------------------------------------------------------*/ +template <typename K, typename V> +typename NPT_Map<K,V>::Entry* +NPT_Map<K,V>::GetEntry(const K& key) const +{ + typename NPT_List<Entry*>::Iterator entry = m_Entries.GetFirstItem(); + while (entry) { + if ((*entry)->GetKey() == key) { + return *entry; + } + ++entry; + } + + return NULL; +} + +/*---------------------------------------------------------------------- +| NPT_Map<K,V>::Put ++---------------------------------------------------------------------*/ +template <typename K, typename V> +NPT_Result +NPT_Map<K,V>::Put(const K& key, const V& value) +{ + Entry* entry = GetEntry(key); + if (entry == NULL) { + // no existing entry for that key, create one + m_Entries.Add(new Entry(key, value)); + } else { + // replace the existing entry for that key + entry->SetValue(value); + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_Map<K,V>::Get ++---------------------------------------------------------------------*/ +template <typename K, typename V> +NPT_Result +NPT_Map<K,V>::Get(const K& key, V*& value) const +{ + Entry* entry = GetEntry(key); + if (entry == NULL) { + // no existing entry for that key + value = NULL; + return NPT_ERROR_NO_SUCH_ITEM; + } else { + // found an entry with that key + value = &entry->m_Value; + return NPT_SUCCESS; + } +} + +/*---------------------------------------------------------------------- +| NPT_Map<K,V>::HasValue ++---------------------------------------------------------------------*/ +template <typename K, typename V> +bool +NPT_Map<K,V>::HasValue(const V& value) const +{ + ListIterator entry = m_Entries.GetFirstItem(); + while (entry) { + if (value == (*entry)->m_Value) { + return true; + } + ++entry; + } + + return false; +} + +/*---------------------------------------------------------------------- +| NPT_Map<K,V>::operator= ++---------------------------------------------------------------------*/ +template <typename K, typename V> +const NPT_Map<K,V>& +NPT_Map<K,V>::operator=(const NPT_Map<K,V>& copy) +{ + // do nothing if we're assigning to ourselves + if (this == ©) return copy; + + // destroy all entries + Clear(); + + // copy all entries one by one + ListIterator entry = copy.m_Entries.GetFirstItem(); + while (entry) { + m_Entries.Add(new Entry((*entry)->GetKey(), (*entry)->GetValue())); + ++entry; + } + + return *this; +} + +/*---------------------------------------------------------------------- +| NPT_Map<K,V>::Erase ++---------------------------------------------------------------------*/ +template <typename K, typename V> +NPT_Result +NPT_Map<K,V>::Erase(const K& key) +{ + ListIterator entry = m_Entries.GetFirstItem(); + while (entry) { + if ((*entry)->GetKey() == key) { + delete *entry; // do this before removing the entry from the + // list, because Erase() will invalidate the + // iterator item + m_Entries.Erase(entry); + return NPT_SUCCESS; + } + ++entry; + } + + return NPT_ERROR_NO_SUCH_ITEM; +} + +/*---------------------------------------------------------------------- +| NPT_Map<K,V>::operator== ++---------------------------------------------------------------------*/ +template <typename K, typename V> +bool +NPT_Map<K,V>::operator==(const NPT_Map<K,V>& other) const +{ + // quick test + if (m_Entries.GetItemCount() != other.m_Entries.GetItemCount()) return false; + + // compare all entries to all other entries + ListIterator entry = m_Entries.GetFirstItem(); + while (entry) { + V* value; + if (NPT_SUCCEEDED(other.Get((*entry)->m_Key, value))) { + // the other map has an entry for this key, check the value + if (!(*value == (*entry)->m_Value)) return false; + } else { + // the other map does not have an entry for this key + return false; + } + ++entry; + } + + return true; +} + +/*---------------------------------------------------------------------- +| NPT_Map<K,V>::operator!= ++---------------------------------------------------------------------*/ +template <typename K, typename V> +bool +NPT_Map<K,V>::operator!=(const NPT_Map<K,V>& other) const +{ + return !(*this == other); +} + +/*---------------------------------------------------------------------- +| NPT_Map<K,V>::operator[] ++---------------------------------------------------------------------*/ +template <typename K, typename V> +V& +NPT_Map<K,V>::operator[](const K& key) +{ + Entry* entry = GetEntry(key); + if (entry == NULL) { + // create a new "default" entry for this key + entry = new Entry(key); + m_Entries.Add(entry); + } + + return entry->m_Value; +} + +/*---------------------------------------------------------------------- +| NPT_HashMap ++---------------------------------------------------------------------*/ +template <typename K, typename V, typename HF = NPT_Hash<K> > +class NPT_HashMap +{ +public: + // types + class Entry { + public: + // constructor + Entry(NPT_UInt32 hash_value, const K& key, const V& value) : m_HashValue(hash_value), m_Key(key), m_Value(value) {} + Entry(NPT_UInt32 hash_value, const K& key) : m_HashValue(hash_value), m_Key(key), m_Value() {} + + // accessors + const K& GetKey() const { return m_Key; } + const V& GetValue() const { return m_Value; } + NPT_UInt32 GetHashValue() const { return m_HashValue; } + + // operators + bool operator==(const Entry& other) const { + return m_HashValue == other.m_HashValue && m_Key == other.m_Key && m_Value == other.m_Value; + } + + protected: + // methods + void SetValue(const V& value) { m_Value = value; } + + // members + NPT_UInt32 m_HashValue; + K m_Key; + V m_Value; + + // friends + friend class NPT_HashMap<K,V,HF>; + }; + + class Iterator { + public: + Iterator() : m_Entry(NULL), m_Map(NULL) {} + Iterator(Entry** entry, const NPT_HashMap<K,V,HF>* map) : m_Entry(entry), m_Map(map) {} + Iterator(const Iterator& copy) : m_Entry(copy.m_Entry), m_Map(copy.m_Map) {} + const Entry& operator*() const { return **m_Entry; } + Iterator& operator++() { // prefix + if (m_Map && m_Entry) { + do { + ++m_Entry; + if (m_Entry >= &m_Map->m_Buckets[1<<m_Map->m_BucketCountLog]) { + m_Entry = NULL; + } else { + if (*m_Entry) break; + } + } while (m_Entry); + } + return (*this); + } + Iterator operator++(int) { // postfix + Iterator saved_this = *this; + ++(*this); + return saved_this; + } + operator bool() const { + return m_Entry != NULL; + } + bool operator==(const Iterator& other) const { + return m_Map == other.m_Map && m_Entry == other.m_Entry; + } + bool operator!=(const Iterator& other) const { + return !(*this == other); + } + void operator=(const Iterator& other) { + m_Entry = other.m_Entry; + m_Map = other.m_Map; + } + + private: + // friends + friend class NPT_HashMap<K,V,HF>; + + // members + Entry** m_Entry; + const NPT_HashMap<K,V,HF>* m_Map; + }; + + // constructors + NPT_HashMap<K,V,HF>(); + NPT_HashMap<K,V,HF>(const HF& hasher); + NPT_HashMap<K,V,HF>(const NPT_HashMap<K,V,HF>& copy); + + // destructor + ~NPT_HashMap<K,V,HF>(); + + // methods + NPT_Result Put(const K& key, const V& value); + NPT_Result Get(const K& key, V*& value) const; // WARNING: the second parameter is a POINTER on the value type!!! + bool HasKey(const K& key) const { return GetEntry(key) != NULL; } + bool HasValue(const V& value) const; + NPT_Result Erase(const K& key); + NPT_Cardinal GetEntryCount() const { return m_EntryCount; } + Iterator GetEntries() const; + NPT_Result Clear(); + + // list operations + // keep these template members defined here because MSV6 does not let + // us define them later + template <typename X> + NPT_Result Apply(const X& function) const + { + for (int i=0; i<(1<<m_BucketCountLog); i++) { + if (m_Buckets[i]) { + function(m_Buckets[i]); + } + } + return NPT_SUCCESS; + } + + // operators + V& operator[](const K& key); + const NPT_HashMap<K,V,HF>& operator=(const NPT_HashMap<K,V,HF>& copy); + bool operator==(const NPT_HashMap<K,V,HF>& other) const; + bool operator!=(const NPT_HashMap<K,V,HF>& other) const; + +private: + // methods + Entry* GetEntry(const K& key, NPT_UInt32* position=NULL) const; + NPT_Result AddEntry(Entry* entry); + void AllocateBuckets(unsigned int count_log); + void AdjustBuckets(NPT_Cardinal entry_count, bool allow_shrink=false); + + // members + HF m_Hasher; + Entry** m_Buckets; + NPT_Cardinal m_BucketCountLog; + NPT_Cardinal m_EntryCount; +}; + +/*---------------------------------------------------------------------- +| NPT_HashMap<K,V>::NPT_HashMap ++---------------------------------------------------------------------*/ +template <typename K, typename V, typename HF> +NPT_HashMap<K,V,HF>::NPT_HashMap() : + m_Buckets(NULL), + m_EntryCount(0) +{ + AllocateBuckets(4); +} + +/*---------------------------------------------------------------------- +| NPT_HashMap<K,V>::NPT_HashMap ++---------------------------------------------------------------------*/ +template <typename K, typename V, typename HF> +NPT_HashMap<K,V,HF>::NPT_HashMap(const HF& hasher) : + m_Hasher(hasher), + m_Buckets(NULL), + m_EntryCount(0) +{ + AllocateBuckets(4); +} + +/*---------------------------------------------------------------------- +| NPT_HashMap<K,V>::NPT_HashMap ++---------------------------------------------------------------------*/ +template <typename K, typename V, typename HF> +NPT_HashMap<K,V,HF>::NPT_HashMap(const NPT_HashMap<K,V,HF>& copy) : + m_Buckets(NULL), + m_BucketCountLog(0), + m_EntryCount(0) +{ + *this = copy; +} + +/*---------------------------------------------------------------------- +| NPT_MapMap<K,V,HF>::NPT_HashMap ++---------------------------------------------------------------------*/ +template <typename K, typename V, typename HF> +NPT_HashMap<K,V,HF>::~NPT_HashMap() +{ + for (int i=0; i<(1<<m_BucketCountLog); i++) { + delete m_Buckets[i]; + } + delete[] m_Buckets; +} + +/*---------------------------------------------------------------------- +| NPT_HashMap<K,V,HF>::AllocateBuckets ++---------------------------------------------------------------------*/ +template <typename K, typename V, typename HF> +void +NPT_HashMap<K,V,HF>::AllocateBuckets(unsigned int count_log) +{ + m_Buckets = new Entry*[1<<count_log]; + m_BucketCountLog = count_log; + for (int i=0; i<(1<<count_log); i++) { + m_Buckets[i] = NULL; + } +} + +/*---------------------------------------------------------------------- +| NPT_HashMap<K,V,HF>::AdjustBuckets ++---------------------------------------------------------------------*/ +template <typename K, typename V, typename HF> +void +NPT_HashMap<K,V,HF>::AdjustBuckets(NPT_Cardinal entry_count, bool allow_shrink) +{ + Entry** buckets = NULL; + unsigned int bucket_count = 1<<m_BucketCountLog; + if (2*entry_count >= bucket_count) { + // we need to grow + buckets = m_Buckets; + AllocateBuckets(m_BucketCountLog+1); + } else if (allow_shrink && (5*entry_count < bucket_count) && m_BucketCountLog > 4) { + // we need to shrink + buckets = m_Buckets; + AllocateBuckets(m_BucketCountLog-1); + } + if (buckets) { + m_EntryCount = 0; + for (unsigned int i=0; i<bucket_count; i++) { + if (buckets[i]) AddEntry(buckets[i]); + } + delete[] buckets; + } +} + +/*---------------------------------------------------------------------- +| NPT_HashMap<K,V,HF>::Clear ++---------------------------------------------------------------------*/ +template <typename K, typename V, typename HF> +NPT_Result +NPT_HashMap<K,V,HF>::Clear() +{ + if (m_Buckets) { + for (int i=0; i<(1<<m_BucketCountLog); i++) { + delete m_Buckets[i]; + } + delete[] m_Buckets; + } + m_EntryCount = 0; + AllocateBuckets(4); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HashMap<K,V,HF>::GetEntries ++---------------------------------------------------------------------*/ +template <typename K, typename V, typename HF> +typename NPT_HashMap<K,V,HF>::Iterator +NPT_HashMap<K,V,HF>::GetEntries() const +{ + for (int i=0; i<(1<<m_BucketCountLog); i++) { + if (m_Buckets[i]) { + return Iterator(&m_Buckets[i], this); + } + } + return Iterator(NULL, this); +} + +/*---------------------------------------------------------------------- +| NPT_HashMap<K,V,HF>::GetEntry ++---------------------------------------------------------------------*/ +template <typename K, typename V, typename HF> +typename NPT_HashMap<K,V,HF>::Entry* +NPT_HashMap<K,V,HF>::GetEntry(const K& key, NPT_UInt32* position) const +{ + NPT_UInt32 hash_value = m_Hasher(key); + NPT_UInt32 mask = (1<<m_BucketCountLog)-1; + NPT_UInt32 cursor = hash_value & mask; + while (m_Buckets[cursor]) { + Entry* entry = m_Buckets[cursor]; + if (entry->m_HashValue == hash_value && + entry->m_Key == key) { + if (position) *position = cursor; + return entry; + } + cursor = (cursor + 1) & mask; + } + + return NULL; +} + +/*---------------------------------------------------------------------- +| NPT_HashMap<K,V,HF>::AddEntry ++---------------------------------------------------------------------*/ +template <typename K, typename V, typename HF> +NPT_Result +NPT_HashMap<K,V,HF>::AddEntry(Entry* entry) +{ + AdjustBuckets(m_EntryCount+1); + + NPT_UInt32 hash_value = entry->m_HashValue; + NPT_UInt32 mask = (1<<m_BucketCountLog)-1; + NPT_UInt32 cursor = hash_value & mask; + while (m_Buckets[cursor]) { + cursor = (cursor + 1) & mask; + } + m_Buckets[cursor] = entry; + ++m_EntryCount; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HashMap<K,V,HF>::Put ++---------------------------------------------------------------------*/ +template <typename K, typename V, typename HF> +NPT_Result +NPT_HashMap<K,V,HF>::Put(const K& key, const V& value) +{ + Entry* entry = GetEntry(key); + if (entry == NULL) { + // no existing entry for that key, create one + return AddEntry(new Entry(m_Hasher(key), key, value)); + } else { + // replace the existing entry for that key + entry->SetValue(value); + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HashMap<K,V,HF>::Get ++---------------------------------------------------------------------*/ +template <typename K, typename V, typename HF> +NPT_Result +NPT_HashMap<K,V,HF>::Get(const K& key, V*& value) const +{ + Entry* entry = GetEntry(key); + if (entry == NULL) { + // no existing entry for that key + value = NULL; + return NPT_ERROR_NO_SUCH_ITEM; + } else { + // found an entry with that key + value = &entry->m_Value; + return NPT_SUCCESS; + } +} + +/*---------------------------------------------------------------------- +| NPT_HashMap<K,V,HF>::HasValue ++---------------------------------------------------------------------*/ +template <typename K, typename V, typename HF> +bool +NPT_HashMap<K,V,HF>::HasValue(const V& value) const +{ + for (int i=0; i<(1<<m_BucketCountLog); i++) { + if (m_Buckets[i] && m_Buckets[i]->m_Value == value) { + return true; + } + } + + return false; +} + +/*---------------------------------------------------------------------- +| NPT_HashMap<K,V,HF>::Erase ++---------------------------------------------------------------------*/ +template <typename K, typename V, typename HF> +NPT_Result +NPT_HashMap<K,V,HF>::Erase(const K& key) +{ + NPT_UInt32 position; + Entry* entry = GetEntry(key, &position); + if (entry == NULL) { + return NPT_ERROR_NO_SUCH_ITEM; + } + + // mark the bucket as unoccupied + m_Buckets[position] = NULL; + + // look for buckets that need to be relocated: + // there should be no empty bucket between an entry's ideal hash bucket + // and its actual bucket. + NPT_UInt32 mask = (1<<m_BucketCountLog)-1; + for (NPT_UInt32 cursor = (position+1) & mask; m_Buckets[cursor]; cursor = (cursor + 1) & mask) { + NPT_UInt32 target = m_Buckets[cursor]->m_HashValue & mask; + // check if target is between position and cursor (modulo the bucket array size) + // | position.target.cursor | + // |....cursor position.target.| or |.target..cursor position...| + if ( (position <= cursor) ? + ((position < target) && (target <= cursor)) : + ((position < target) || (target <= cursor)) ) { + continue; + } + + // move the bucket back + m_Buckets[position] = m_Buckets[cursor]; + m_Buckets[cursor] = NULL; + position = cursor; + } + + // cleanup and adjust the counter and buckets + delete entry; + --m_EntryCount; + AdjustBuckets(m_EntryCount, true); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HashMap<K,V,HF>::operator= ++---------------------------------------------------------------------*/ +template <typename K, typename V, typename HF> +const NPT_HashMap<K,V,HF>& +NPT_HashMap<K,V,HF>::operator=(const NPT_HashMap<K,V,HF>& copy) +{ + // do nothing if we're assigning to ourselves + if (this == ©) return copy; + + // destroy all entries + Clear(); + + // prepare to receive all the entries + AdjustBuckets(copy.m_EntryCount); + + // copy all entries + for (int i=0; i<1<<copy.m_BucketCountLog; i++) { + if (copy.m_Buckets[i]) { + AddEntry(new Entry(m_Hasher(copy.m_Buckets[i]->GetKey()), + copy.m_Buckets[i]->GetKey(), + copy.m_Buckets[i]->GetValue())); + } + } + + return *this; +} + +/*---------------------------------------------------------------------- +| NPT_HashMap<K,V,HF>::operator== ++---------------------------------------------------------------------*/ +template <typename K, typename V, typename HF> +bool +NPT_HashMap<K,V,HF>::operator==(const NPT_HashMap<K,V,HF>& other) const +{ + // quick check + if (m_EntryCount != other.m_EntryCount) return false; + + // compare all entries to all other entries + for (int i=0; i<(1<<m_BucketCountLog); i++) { + Entry* entry = m_Buckets[i]; + if (entry == NULL) continue; + Entry* other_entry = other.GetEntry(entry->m_Key); + if (other_entry == NULL || !(other_entry->m_Value == entry->m_Value)) { + return false; + } + } + + return true; +} + +/*---------------------------------------------------------------------- +| NPT_HashMap<K,V,HF>::operator!= ++---------------------------------------------------------------------*/ +template <typename K, typename V, typename HF> +bool +NPT_HashMap<K,V,HF>::operator!=(const NPT_HashMap<K,V,HF>& other) const +{ + return !(*this == other); +} + +/*---------------------------------------------------------------------- +| NPT_HashMap<K,V>::operator[] ++---------------------------------------------------------------------*/ +template <typename K, typename V, typename HF> +V& +NPT_HashMap<K,V,HF>::operator[](const K& key) +{ + Entry* entry = GetEntry(key); + if (entry == NULL) { + // create a new "default" entry for this key + entry = new Entry(m_Hasher(key), key); + AddEntry(entry); + } + + return entry->m_Value; +} + +/*---------------------------------------------------------------------- +| NPT_MapEntryValueDeleter ++---------------------------------------------------------------------*/ +template <class T> +class NPT_MapEntryValueDeleter { +public: + void operator()(T* entry) const { + delete entry->GetValue(); + } +}; + +#endif // _NPT_MAP_H_ diff --git a/lib/libUPnP/Neptune/Source/Core/NptMessaging.cpp b/lib/libUPnP/Neptune/Source/Core/NptMessaging.cpp new file mode 100644 index 0000000..cffe1d1 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptMessaging.cpp @@ -0,0 +1,127 @@ +/***************************************************************** +| +| Neptune - Messaging System +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptMessaging.h" +#include "NptDynamicCast.h" + +/*---------------------------------------------------------------------- +| globals ++---------------------------------------------------------------------*/ +NPT_DEFINE_DYNAMIC_CAST_ANCHOR(NPT_MessageHandler) +const NPT_Message::Type NPT_Message::MessageType = "Generic Message"; + +/*---------------------------------------------------------------------- +| NPT_MessageHandler::HandleMessage ++---------------------------------------------------------------------*/ +NPT_Result +NPT_MessageHandler::HandleMessage(NPT_Message* message) +{ + return message->Dispatch(this); +} + +/*---------------------------------------------------------------------- +| NPT_MessageHandlerProxy::NPT_MessageHandlerProxy ++---------------------------------------------------------------------*/ +NPT_DEFINE_DYNAMIC_CAST_ANCHOR(NPT_MessageHandlerProxy) +NPT_MessageHandlerProxy::NPT_MessageHandlerProxy(NPT_MessageHandler* handler) : + m_Handler(handler), + m_ReferenceCount(1) +{} + +/*---------------------------------------------------------------------- +| NPT_MessageHandlerProxy::NPT_MessageHandlerProxy ++---------------------------------------------------------------------*/ +NPT_MessageHandlerProxy::~NPT_MessageHandlerProxy() +{ +} + +/*---------------------------------------------------------------------- +| NPT_MessageHandlerProxy::OnMessage ++---------------------------------------------------------------------*/ +void +NPT_MessageHandlerProxy::OnMessage(NPT_Message* message) +{ + m_Lock.Lock(); + if (m_Handler) m_Handler->OnMessage(message); + m_Lock.Unlock(); +} + +/*---------------------------------------------------------------------- +| NPT_MessageHandlerProxy::HandleMessage ++---------------------------------------------------------------------*/ +NPT_Result +NPT_MessageHandlerProxy::HandleMessage(NPT_Message* message) +{ + NPT_Result result = NPT_SUCCESS; + m_Lock.Lock(); + if (m_Handler) result = m_Handler->HandleMessage(message); + m_Lock.Unlock(); + + return result; +} + +/*---------------------------------------------------------------------- +| NPT_MessageHandlerProxy::DetachHandler ++---------------------------------------------------------------------*/ +void +NPT_MessageHandlerProxy::DetachHandler() +{ + m_Lock.Lock(); + m_Handler = NULL; + m_Lock.Unlock(); +} + +/*---------------------------------------------------------------------- +| NPT_MessageHandlerProxy::AddReference ++---------------------------------------------------------------------*/ +void +NPT_MessageHandlerProxy::AddReference() +{ + m_Lock.Lock(); + ++m_ReferenceCount; + m_Lock.Unlock(); +} + +/*---------------------------------------------------------------------- +| NPT_MessageHandlerProxy::Release ++---------------------------------------------------------------------*/ +void +NPT_MessageHandlerProxy::Release() +{ + m_Lock.Lock(); + bool must_delete = (--m_ReferenceCount == 0); + m_Lock.Unlock(); + + if (must_delete) delete this; +} diff --git a/lib/libUPnP/Neptune/Source/Core/NptMessaging.h b/lib/libUPnP/Neptune/Source/Core/NptMessaging.h new file mode 100644 index 0000000..3da21a0 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptMessaging.h @@ -0,0 +1,230 @@ +/***************************************************************** +| +| Neptune - Messaging System +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +#ifndef _NPT_MESSAGING_H_ +#define _NPT_MESSAGING_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptConstants.h" +#include "NptTypes.h" +#include "NptResults.h" +#include "NptList.h" +#include "NptThreads.h" +#include "NptDynamicCast.h" + +/*---------------------------------------------------------------------- +| forward references ++---------------------------------------------------------------------*/ +class NPT_Message; + +/*---------------------------------------------------------------------- +| NPT_MessageHandler ++---------------------------------------------------------------------*/ +class NPT_MessageHandler +{ +public: + NPT_IMPLEMENT_DYNAMIC_CAST(NPT_MessageHandler) + + // methods + virtual ~NPT_MessageHandler() {} + + // default message handler + virtual void OnMessage(NPT_Message*) {} + + // this method is a central point of handling for received messages. + // it can be overloaded by subclasses that wish to process all + // incoming messages + virtual NPT_Result HandleMessage(NPT_Message* message); +}; + +/*---------------------------------------------------------------------- +| NPT_MessageHandlerProxy ++---------------------------------------------------------------------*/ +class NPT_MessageHandlerProxy : public NPT_MessageHandler +{ +public: + NPT_IMPLEMENT_DYNAMIC_CAST_D(NPT_MessageHandlerProxy, NPT_MessageHandler) + + /** + * Create a proxy for a message handler. + * All calls to HandleMessage() and OnMessage() on the proxy + * are automatically forwarded to the handler. + * This class is useful in cases where a handler is passed + * asynchronously (for example in a message queue) and one wishes + * to guarantee right away that no more calls to the handler will be + * made (because, for example, the handler needs to be deleted). + * + * The proxy object keeps a pointer to the handler, but does not own it. + */ + NPT_MessageHandlerProxy(NPT_MessageHandler* handler); + + // destructor + ~NPT_MessageHandlerProxy() override; + + // NPT_MessageHandler methods + void OnMessage(NPT_Message*) override; + NPT_Result HandleMessage(NPT_Message* message) override; + + /** + * Detach the proxy from the handler implementation. + * After this call returns, calls will no longer be + * forwarded to the handler object. It is then safe, for example, + * to delete the handler. + */ + void DetachHandler(); + + /** + * Increment the reference count + */ + void AddReference(); + + /** + * Decrement the reference count and delete if 0 + */ + void Release(); + +private: + // members + NPT_MessageHandler* m_Handler; + NPT_Cardinal m_ReferenceCount; + NPT_Mutex m_Lock; +}; + +/*---------------------------------------------------------------------- +| NPT_Messsage ++---------------------------------------------------------------------*/ +class NPT_Message +{ +public: + // types + typedef const char* Type; + + // static members + static Type const MessageType; + + // methods + virtual ~NPT_Message() {} + virtual Type GetType() { return MessageType; } + virtual NPT_Result Dispatch(NPT_MessageHandler* handler) { + return DefaultDeliver(handler); + } + // this method should really be called 'Deliver', but this would + // cause a problem when subclasses overload it + virtual NPT_Result DefaultDeliver(NPT_MessageHandler* handler) { + handler->OnMessage(this); + return NPT_SUCCESS; + } +}; + +/*---------------------------------------------------------------------- +| NPT_TerminateMesssage ++---------------------------------------------------------------------*/ +class NPT_TerminateMessage : public NPT_Message +{ +public: + // methods + NPT_Result Dispatch(NPT_MessageHandler* /*handler*/) override { + return NPT_ERROR_TERMINATED; + } +}; + +/*---------------------------------------------------------------------- +| NPT_MessageQueue ++---------------------------------------------------------------------*/ +class NPT_MessageQueue +{ +public: + // methods + virtual ~NPT_MessageQueue() {} + virtual NPT_Result PumpMessage(NPT_Timeout timeout = NPT_TIMEOUT_INFINITE) = 0; + virtual NPT_Result QueueMessage(NPT_Message* message, + NPT_MessageHandler* handler) = 0; +}; + +/*---------------------------------------------------------------------- +| NPT_MessageReceiver ++---------------------------------------------------------------------*/ +class NPT_MessageReceiver +{ +public: + // methods + NPT_MessageReceiver() : m_Queue(NULL), m_Handler(NULL) {} + NPT_MessageReceiver(NPT_MessageHandler* handler) : + m_Queue(NULL), m_Handler(handler) {} + NPT_MessageReceiver(NPT_MessageQueue* queue) : + m_Queue(queue), m_Handler(NULL) {} + NPT_MessageReceiver(NPT_MessageHandler* handler, + NPT_MessageQueue* queue) : + m_Queue(queue), m_Handler(handler) {} + virtual ~NPT_MessageReceiver() {} + NPT_Result SetQueue(NPT_MessageQueue* queue) { + m_Queue = queue; + return NPT_SUCCESS; + } + NPT_Result SetHandler(NPT_MessageHandler* handler) { + m_Handler = handler; + return NPT_SUCCESS; + } + virtual NPT_Result PostMessage(NPT_Message* message) { + if (m_Queue) { + return m_Queue->QueueMessage(message, m_Handler); + } else { + return NPT_FAILURE; + } + } + +protected: + // members + NPT_MessageQueue* m_Queue; + NPT_MessageHandler* m_Handler; +}; + +/*---------------------------------------------------------------------- +| NPT_MessageBroadcaster ++---------------------------------------------------------------------*/ +class NPT_MessageBroadcaster +{ +public: + // methods + NPT_MessageBroadcaster(NPT_Message* message) : m_Message(message) {} + NPT_Result operator()(NPT_MessageReceiver*& receiver) const { + receiver->PostMessage(m_Message); + return NPT_SUCCESS; + } + +private: + // members + NPT_Message* m_Message; +}; + +#endif // _NPT_MESSAGING_H_ diff --git a/lib/libUPnP/Neptune/Source/Core/NptNetwork.cpp b/lib/libUPnP/Neptune/Source/Core/NptNetwork.cpp new file mode 100644 index 0000000..1b8bde7 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptNetwork.cpp @@ -0,0 +1,438 @@ +/***************************************************************** +| +| Neptune - Network +| +| Copyright (c) 2002-2016, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptSockets.h" +#include "NptUtils.h" + +/*---------------------------------------------------------------------- +| NPT_IpAddress::NPT_IpAddress ++---------------------------------------------------------------------*/ +NPT_IpAddress::NPT_IpAddress() : + m_Type(IPV4), + m_ScopeId(0) +{ + NPT_SetMemory(m_Address, 0, sizeof(m_Address)); +} + +/*---------------------------------------------------------------------- +| NPT_IpAddress::NPT_IpAddress ++---------------------------------------------------------------------*/ +NPT_IpAddress::NPT_IpAddress(Type type) : + m_Type(type), + m_ScopeId(0) +{ + NPT_SetMemory(m_Address, 0, sizeof(m_Address)); +} + +/*---------------------------------------------------------------------- +| NPT_IpAddress::NPT_IpAddress ++---------------------------------------------------------------------*/ +NPT_IpAddress::NPT_IpAddress(unsigned long address) : + m_Type(IPV4), + m_ScopeId(0) +{ + Set(address); +} + +/*---------------------------------------------------------------------- +| NPT_IpAddress::NPT_IpAddress ++---------------------------------------------------------------------*/ +NPT_IpAddress::NPT_IpAddress(unsigned char a, + unsigned char b, + unsigned char c, + unsigned char d) : + m_Type(IPV4), + m_ScopeId(0) +{ + NPT_SetMemory(&m_Address[0], 0, sizeof(m_Address)); + m_Address[0] = a; + m_Address[1] = b; + m_Address[2] = c; + m_Address[3] = d; +} + +/*---------------------------------------------------------------------- +| NPT_IpAddress::NPT_IpAddress ++---------------------------------------------------------------------*/ +NPT_IpAddress::NPT_IpAddress(Type type, const unsigned char* address, unsigned int size, NPT_UInt32 scope_id) : + m_Type(type), + m_ScopeId(scope_id) +{ + if (type == IPV6 && size == 16) { + NPT_CopyMemory(&m_Address[0], address, 16); + } else if (type == IPV4 && size == 4) { + NPT_CopyMemory(&m_Address[0], address, 4); + NPT_SetMemory(&m_Address[4], 0, 12); + m_ScopeId = 0; + } else { + NPT_SetMemory(&m_Address[0], 0, 16); + m_ScopeId = 0; + } +} + +/*---------------------------------------------------------------------- +| NPT_IpAddress::AsLong ++---------------------------------------------------------------------*/ +unsigned long +NPT_IpAddress::AsLong() const +{ + return + (((unsigned long)m_Address[0])<<24) | + (((unsigned long)m_Address[1])<<16) | + (((unsigned long)m_Address[2])<< 8) | + (((unsigned long)m_Address[3])); +} + +/*---------------------------------------------------------------------- +| NPT_IpAddress::AsBytes ++---------------------------------------------------------------------*/ +const unsigned char* +NPT_IpAddress::AsBytes() const +{ + return m_Address; +} + +/*---------------------------------------------------------------------- +| NPT_IpAddress::Set ++---------------------------------------------------------------------*/ +NPT_Result +NPT_IpAddress::Set(const unsigned char bytes[4]) +{ + m_Type = IPV4; + m_Address[0] = bytes[0]; + m_Address[1] = bytes[1]; + m_Address[2] = bytes[2]; + m_Address[3] = bytes[3]; + NPT_SetMemory(&m_Address[4], 0, sizeof(m_Address)-4); + m_ScopeId = 0; // always 0 for IPv4 + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_IpAddress::Set ++---------------------------------------------------------------------*/ +NPT_Result +NPT_IpAddress::Set(unsigned long address) +{ + m_Type = IPV4; + m_Address[0] = (unsigned char)((address >> 24) & 0xFF); + m_Address[1] = (unsigned char)((address >> 16) & 0xFF); + m_Address[2] = (unsigned char)((address >> 8) & 0xFF); + m_Address[3] = (unsigned char)((address ) & 0xFF); + NPT_SetMemory(&m_Address[4], 0, sizeof(m_Address)-4); + m_ScopeId = 0; // always 0 for IPv4 + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_IpAddress::Set ++---------------------------------------------------------------------*/ +NPT_Result +NPT_IpAddress::Set(const unsigned char* bytes, unsigned int size, NPT_UInt32 scope_id) +{ + NPT_SetMemory(&m_Address[0], 0, sizeof(m_Address)); + if (size == 4) { + m_Type = IPV4; + NPT_CopyMemory(&m_Address[0], bytes, 4); + m_ScopeId = 0; // always 0 for IPv4 + } else if (size == 16) { + m_Type = IPV6; + NPT_CopyMemory(&m_Address[0], bytes, 16); + m_ScopeId = scope_id; + } else { + return NPT_ERROR_INVALID_PARAMETERS; + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_IpAddress::operator== ++---------------------------------------------------------------------*/ +bool +NPT_IpAddress::operator==(const NPT_IpAddress& other) const +{ + unsigned int bytes_to_check = (m_Type == IPV4)?4:16; + for (unsigned int i=0; i<bytes_to_check; i++) { + if (m_Address[i] != other.m_Address[i]) { + return false; + } + } + return m_Type == other.m_Type; +} + +/*---------------------------------------------------------------------- +| NPT_IpAddress::ToUrlHost ++---------------------------------------------------------------------*/ +NPT_String +NPT_IpAddress::ToUrlHost() const +{ + if (m_Type == IPV6) { + NPT_String result = "["; + result += ToString(); + return result+"]"; + } else { + return ToString(); + } +} + +/*---------------------------------------------------------------------- +| NPT_IpAddress::IsUnspecified ++---------------------------------------------------------------------*/ +bool +NPT_IpAddress::IsUnspecified() const +{ + for (unsigned int i=0; i<(unsigned int)(m_Type==IPV4?4:16); i++) { + if (m_Address[i]) return false; + } + return true; +} + +/*---------------------------------------------------------------------- +| NPT_IpAddress::IsLooppack ++---------------------------------------------------------------------*/ +bool +NPT_IpAddress::IsLooppack() const +{ + if (m_Type == IPV4) { + return m_Address[0] == 127 && + m_Address[1] == 0 && + m_Address[2] == 0 && + m_Address[3] == 1; + } else { + return m_Address[ 0] == 0 && + m_Address[ 1] == 0 && + m_Address[ 2] == 0 && + m_Address[ 3] == 0 && + m_Address[ 4] == 0 && + m_Address[ 5] == 0 && + m_Address[ 6] == 0 && + m_Address[ 7] == 0 && + m_Address[ 8] == 0 && + m_Address[ 9] == 0 && + m_Address[10] == 0 && + m_Address[11] == 0 && + m_Address[12] == 0 && + m_Address[13] == 0 && + m_Address[14] == 0 && + m_Address[15] == 1; + } +} + +/*---------------------------------------------------------------------- +| NPT_IpAddress::IsV4Compatible ++---------------------------------------------------------------------*/ +bool +NPT_IpAddress::IsV4Compatible() const +{ + if (m_Type == IPV4) return true; + return m_Address[ 0] == 0 && + m_Address[ 1] == 0 && + m_Address[ 2] == 0 && + m_Address[ 3] == 0 && + m_Address[ 4] == 0 && + m_Address[ 5] == 0 && + m_Address[ 6] == 0 && + m_Address[ 7] == 0 && + m_Address[ 8] == 0 && + m_Address[ 9] == 0 && + m_Address[10] == 0 && + m_Address[11] == 0 && + !(m_Address[12] == 0 && + m_Address[13] == 0 && + m_Address[14] == 0 && + m_Address[15] == 0) && + !(m_Address[12] == 0 && + m_Address[13] == 0 && + m_Address[14] == 0 && + m_Address[15] == 1); +} + +/*---------------------------------------------------------------------- +| NPT_IpAddress::IsV4Mapped ++---------------------------------------------------------------------*/ +bool +NPT_IpAddress::IsV4Mapped() const +{ + if (m_Type == IPV4) return false; + return m_Address[ 0] == 0 && + m_Address[ 1] == 0 && + m_Address[ 2] == 0 && + m_Address[ 3] == 0 && + m_Address[ 4] == 0 && + m_Address[ 5] == 0 && + m_Address[ 6] == 0 && + m_Address[ 7] == 0 && + m_Address[ 8] == 0 && + m_Address[ 9] == 0 && + m_Address[10] == 0xFF && + m_Address[11] == 0xFF; +} + +/*---------------------------------------------------------------------- +| NPT_IpAddress::IsLinkLocal ++---------------------------------------------------------------------*/ +bool +NPT_IpAddress::IsLinkLocal() const +{ + if (m_Type == IPV4) { + return m_Address[0] == 169 && m_Address[1] == 254; + } else { + return m_Address[0] == 0xFE && ((m_Address[1]&0xC0) == 0x80); + } +} + +/*---------------------------------------------------------------------- +| NPT_IpAddress::IsSiteLocal ++---------------------------------------------------------------------*/ +bool +NPT_IpAddress::IsSiteLocal() const +{ + if (m_Type == IPV4) return false; + return m_Address[0] == 0xFE && ((m_Address[1]&0xC0) == 0xC0); +} + +/*---------------------------------------------------------------------- +| NPT_IpAddress::IsUniqueLocal ++---------------------------------------------------------------------*/ +bool +NPT_IpAddress::IsUniqueLocal() const +{ + if (m_Type == IPV4) { + return (m_Address[0] == 10) || + (m_Address[0] == 172 && (m_Address[1]&0xF0) == 16) || + (m_Address[0] == 192 && m_Address[1] == 168); + } else { + return ((m_Address[0] & 0xFE) == 0xFC); + } +} + +/*---------------------------------------------------------------------- +| NPT_IpAddress::IsMulticast ++---------------------------------------------------------------------*/ +bool +NPT_IpAddress::IsMulticast() const +{ + if (m_Type == IPV4) { + return (m_Address[0] & 0xF0) == 224; + } else { + return m_Address[0] == 0xFF; + } +} + +/*---------------------------------------------------------------------- +| NPT_MacAddress::NPT_MacAddress ++---------------------------------------------------------------------*/ +NPT_MacAddress::NPT_MacAddress(Type type, + const unsigned char* address, + unsigned int length) +{ + SetAddress(type, address, length); +} + +/*---------------------------------------------------------------------- +| NPT_MacAddress::SetAddress ++---------------------------------------------------------------------*/ +void +NPT_MacAddress::SetAddress(Type type, + const unsigned char* address, + unsigned int length) +{ + m_Type = type; + if (length > NPT_NETWORK_MAX_MAC_ADDRESS_LENGTH) { + length = NPT_NETWORK_MAX_MAC_ADDRESS_LENGTH; + } + m_Length = length; + for (unsigned int i=0; i<length; i++) { + m_Address[i] = address[i]; + } +} + +/*---------------------------------------------------------------------- +| NPT_MacAddress::ToString ++---------------------------------------------------------------------*/ +NPT_String +NPT_MacAddress::ToString() const +{ + NPT_String result; + + if (m_Length) { + char s[3*NPT_NETWORK_MAX_MAC_ADDRESS_LENGTH]; + const char hex[17] = "0123456789abcdef"; + for (unsigned int i=0; i<m_Length; i++) { + s[i*3 ] = hex[m_Address[i]>>4]; + s[i*3+1] = hex[m_Address[i]&0xf]; + s[i*3+2] = ':'; + } + s[3*m_Length-1] = '\0'; + result = s; + } + + return result; +} + +/*---------------------------------------------------------------------- +| NPT_NetworkInterface::NPT_NetworkInterface ++---------------------------------------------------------------------*/ +NPT_NetworkInterface::NPT_NetworkInterface(const char* name, + const NPT_MacAddress& mac, + NPT_Flags flags) : + m_Name(name), + m_MacAddress(mac), + m_Flags(flags) +{ +} + +/*---------------------------------------------------------------------- +| NPT_NetworkInterface::NPT_NetworkInterface ++---------------------------------------------------------------------*/ +NPT_NetworkInterface::NPT_NetworkInterface(const char* name, + NPT_Flags flags) : + m_Name(name), + m_Flags(flags) +{ +} + +/*---------------------------------------------------------------------- +| NPT_NetworkInterface::AddAddress ++---------------------------------------------------------------------*/ +NPT_Result +NPT_NetworkInterface::AddAddress(const NPT_NetworkInterfaceAddress& address) +{ + return m_Addresses.Add(address); +} + + diff --git a/lib/libUPnP/Neptune/Source/Core/NptNetwork.h b/lib/libUPnP/Neptune/Source/Core/NptNetwork.h new file mode 100644 index 0000000..fb37f44 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptNetwork.h @@ -0,0 +1,277 @@ +/***************************************************************** +| +| Neptune - Network +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +#ifndef _NPT_NETWORK_H_ +#define _NPT_NETWORK_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptTypes.h" +#include "NptConstants.h" +#include "NptStrings.h" +#include "NptList.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const unsigned int NPT_NETWORK_MAX_MAC_ADDRESS_LENGTH = 8; + +/*---------------------------------------------------------------------- +| flags ++---------------------------------------------------------------------*/ +#define NPT_NETWORK_INTERFACE_FLAG_LOOPBACK 0x01 +#define NPT_NETWORK_INTERFACE_FLAG_PROMISCUOUS 0x02 +#define NPT_NETWORK_INTERFACE_FLAG_BROADCAST 0x04 +#define NPT_NETWORK_INTERFACE_FLAG_MULTICAST 0x08 +#define NPT_NETWORK_INTERFACE_FLAG_POINT_TO_POINT 0x10 + +/*---------------------------------------------------------------------- +| workarounds ++---------------------------------------------------------------------*/ +#if defined(_WIN32) +#if defined(SetPort) +#undef SetPort +#endif +#endif + +/*---------------------------------------------------------------------- +| types ++---------------------------------------------------------------------*/ +typedef unsigned int NPT_IpPort; + +/*---------------------------------------------------------------------- +| NPT_IpAddress ++---------------------------------------------------------------------*/ +class NPT_IpAddress +{ +public: + // constants + typedef enum { + IPV4, + IPV6 + } Type; + + // class members + static const NPT_IpAddress Any; + static const NPT_IpAddress Loopback; + + // constructors and destructor + NPT_IpAddress(); + NPT_IpAddress(Type type); + NPT_IpAddress(unsigned long address); + NPT_IpAddress(unsigned char a, unsigned char b, unsigned char c, unsigned char d); + NPT_IpAddress(Type type, const unsigned char* address, unsigned int size, NPT_UInt32 scope_id = 0); + + // accessors + Type GetType() const { return m_Type; } + NPT_UInt32 GetScopeId() const { return m_ScopeId; } + + // methods + NPT_Result ResolveName(const char* name, + NPT_Timeout timeout = NPT_TIMEOUT_INFINITE); + NPT_Result Parse(const char* name); + NPT_Result Set(unsigned long address); + NPT_Result Set(const unsigned char bytes[4]); + NPT_Result Set(const unsigned char* bytes, unsigned int size, NPT_UInt32 scope_id = 0); + const unsigned char* AsBytes() const; + unsigned long AsLong() const; + NPT_String ToString() const; + NPT_String ToUrlHost() const; + + // address properties + bool IsUnspecified() const; + bool IsLooppack() const; + bool IsV4Compatible() const; + bool IsV4Mapped() const; + bool IsLinkLocal() const; + bool IsSiteLocal() const; + bool IsUniqueLocal() const; + bool IsMulticast() const; + + // operators + bool operator==(const NPT_IpAddress& other) const; + + // FIXME: temporary + NPT_String m_HostName; + +private: + // members + Type m_Type; + unsigned char m_Address[16]; + NPT_UInt32 m_ScopeId; // IPv6 only +}; + +/*---------------------------------------------------------------------- +| NPT_MacAddress ++---------------------------------------------------------------------*/ +class NPT_MacAddress +{ +public: + // typedef enum + typedef enum { + TYPE_UNKNOWN, + TYPE_LOOPBACK, + TYPE_ETHERNET, + TYPE_PPP, + TYPE_IEEE_802_11 + } Type; + + // constructors and destructor + NPT_MacAddress() : m_Type(TYPE_UNKNOWN), m_Length(0) {} + NPT_MacAddress(Type type, + const unsigned char* addr, + unsigned int length); + + // methods + void SetAddress(Type type, const unsigned char* addr, + unsigned int length); + Type GetType() const { return m_Type; } + const unsigned char* GetAddress() const { return m_Address; } + unsigned int GetLength() const { return m_Length; } + NPT_String ToString() const; + +private: + // members + Type m_Type; + unsigned char m_Address[NPT_NETWORK_MAX_MAC_ADDRESS_LENGTH]; + unsigned int m_Length; +}; + +/*---------------------------------------------------------------------- +| NPT_NetworkInterfaceAddress ++---------------------------------------------------------------------*/ +class NPT_NetworkInterfaceAddress +{ +public: + // constructors and destructor + NPT_NetworkInterfaceAddress(const NPT_IpAddress& primary, + const NPT_IpAddress& broadcast, + const NPT_IpAddress& destination, + const NPT_IpAddress& netmask) : + m_PrimaryAddress(primary), + m_BroadcastAddress(broadcast), + m_DestinationAddress(destination), + m_NetMask(netmask) {} + + // methods + const NPT_IpAddress& GetPrimaryAddress() const { + return m_PrimaryAddress; + } + const NPT_IpAddress& GetBroadcastAddress() const { + return m_BroadcastAddress; + } + const NPT_IpAddress& GetDestinationAddress() const { + return m_DestinationAddress; + } + const NPT_IpAddress& GetNetMask() const { + return m_NetMask; + } + + bool IsAddressInNetwork(const NPT_IpAddress& address) { + if (m_PrimaryAddress.AsLong() == address.AsLong()) return true; + if (m_NetMask.AsLong() == 0) return false; + return (m_PrimaryAddress.AsLong() & m_NetMask.AsLong()) == (address.AsLong() & m_NetMask.AsLong()); + } + +private: + // members + NPT_IpAddress m_PrimaryAddress; + NPT_IpAddress m_BroadcastAddress; + NPT_IpAddress m_DestinationAddress; + NPT_IpAddress m_NetMask; +}; + +/*---------------------------------------------------------------------- +| NPT_NetworkInterface ++---------------------------------------------------------------------*/ +class NPT_NetworkInterface +{ +public: + // class methods + static NPT_Result GetNetworkInterfaces(NPT_List<NPT_NetworkInterface*>& interfaces); + + // constructors and destructor + NPT_NetworkInterface(const char* name, + const NPT_MacAddress& mac, + NPT_Flags flags); + NPT_NetworkInterface(const char* name, + NPT_Flags flags); + ~NPT_NetworkInterface() {} + + // methods + NPT_Result AddAddress(const NPT_NetworkInterfaceAddress& address); + const NPT_String& GetName() const { + return m_Name; + } + const NPT_MacAddress& GetMacAddress() const { + return m_MacAddress; + } + void SetMacAddress(NPT_MacAddress::Type type, + const unsigned char* addr, + unsigned int length) { + m_MacAddress.SetAddress(type, addr, length); + } + NPT_Flags GetFlags() const { return m_Flags; } + const NPT_List<NPT_NetworkInterfaceAddress>& GetAddresses() const { + return m_Addresses; + } + + bool IsAddressInNetwork(const NPT_IpAddress& address) { + NPT_List<NPT_NetworkInterfaceAddress>::Iterator iter = m_Addresses.GetFirstItem(); + while (iter) { + if ((*iter).IsAddressInNetwork(address)) return true; + ++iter; + } + return false; + } + +private: + // members + NPT_String m_Name; + NPT_MacAddress m_MacAddress; + NPT_Flags m_Flags; + NPT_List<NPT_NetworkInterfaceAddress> m_Addresses; +}; + +/*---------------------------------------------------------------------- +| NPT_NetworkNameResolver ++---------------------------------------------------------------------*/ +class NPT_NetworkNameResolver +{ +public: + // class methods + static NPT_Result Resolve(const char* name, + NPT_List<NPT_IpAddress>& addresses, + NPT_Timeout timeout = NPT_TIMEOUT_INFINITE); +}; + +#endif // _NPT_NETWORK_H_ diff --git a/lib/libUPnP/Neptune/Source/Core/NptQueue.cpp b/lib/libUPnP/Neptune/Source/Core/NptQueue.cpp new file mode 100644 index 0000000..bd68ad2 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptQueue.cpp @@ -0,0 +1,36 @@ +/***************************************************************** +| +| Neptune - Queue +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptQueue.h" + diff --git a/lib/libUPnP/Neptune/Source/Core/NptQueue.h b/lib/libUPnP/Neptune/Source/Core/NptQueue.h new file mode 100644 index 0000000..ecfe1a9 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptQueue.h @@ -0,0 +1,94 @@ +/***************************************************************** +| +| Neptune - Queue +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +#ifndef _NPT_QUEUE_H_ +#define _NPT_QUEUE_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptTypes.h" +#include "NptConstants.h" + +/*---------------------------------------------------------------------- +| NPT_QueueItem ++---------------------------------------------------------------------*/ +class NPT_QueueItem; + +/*---------------------------------------------------------------------- +| NPT_GenericQueue ++---------------------------------------------------------------------*/ +class NPT_GenericQueue +{ + public: + // class methods + static NPT_GenericQueue* CreateInstance(NPT_Cardinal max_items = 0); + + // methods + virtual ~NPT_GenericQueue() {} + virtual NPT_Result Push(NPT_QueueItem* item, + NPT_Timeout timeout = NPT_TIMEOUT_INFINITE) = 0; + virtual NPT_Result Pop(NPT_QueueItem*& item, + NPT_Timeout timeout = NPT_TIMEOUT_INFINITE) = 0; + virtual NPT_Result Peek(NPT_QueueItem*& item, + NPT_Timeout timeout = NPT_TIMEOUT_INFINITE) = 0; + protected: + // methods + NPT_GenericQueue() {} +}; + +/*---------------------------------------------------------------------- +| NPT_Queue ++---------------------------------------------------------------------*/ +template <class T> +class NPT_Queue +{ + public: + // methods + NPT_Queue(NPT_Cardinal max_items = 0) : + m_Delegate(NPT_GenericQueue::CreateInstance(max_items)) {} + virtual ~NPT_Queue<T>() { delete m_Delegate; } + virtual NPT_Result Push(T* item, NPT_Timeout timeout = NPT_TIMEOUT_INFINITE) { + return m_Delegate->Push(reinterpret_cast<NPT_QueueItem*>(item), timeout); + } + virtual NPT_Result Pop(T*& item, NPT_Timeout timeout = NPT_TIMEOUT_INFINITE) { + return m_Delegate->Pop(reinterpret_cast<NPT_QueueItem*&>(item), timeout); + } + virtual NPT_Result Peek(T*& item, NPT_Timeout timeout = NPT_TIMEOUT_INFINITE) { + return m_Delegate->Peek(reinterpret_cast<NPT_QueueItem*&>(item), timeout); + } + + protected: + // members + NPT_GenericQueue* m_Delegate; +}; + +#endif // _NPT_QUEUE_H_ diff --git a/lib/libUPnP/Neptune/Source/Core/NptReferences.h b/lib/libUPnP/Neptune/Source/Core/NptReferences.h new file mode 100644 index 0000000..c8e1f5a --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptReferences.h @@ -0,0 +1,173 @@ +/***************************************************************** +| +| Neptune - References +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| +****************************************************************/ + +#ifndef _NPT_REFERENCES_H_ +#define _NPT_REFERENCES_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptConstants.h" +#include "NptThreads.h" + +/*---------------------------------------------------------------------- +| NPT_Reference ++---------------------------------------------------------------------*/ +template <typename T> +class NPT_Reference +{ +public: + // constructors and destructor + NPT_Reference() : m_Object(NULL), m_Counter(NULL), m_Mutex(NULL), m_ThreadSafe(true) {} + explicit NPT_Reference(T* object, bool thread_safe = true) : + m_Object(object), + m_Counter(object?new NPT_Cardinal(1):NULL), + m_Mutex((object && thread_safe)?new NPT_Mutex():NULL), + m_ThreadSafe(thread_safe) {} + + NPT_Reference(const NPT_Reference<T>& ref) : + m_Object(ref.m_Object), m_Counter(ref.m_Counter), m_Mutex(ref.m_Mutex), m_ThreadSafe(ref.m_ThreadSafe) { + if (m_Mutex) m_Mutex->Lock(); + if (m_Counter) ++(*m_Counter); + if (m_Mutex) m_Mutex->Unlock(); + } + + // this methods should be private, but this causes a problem on some + // compilers, because we need this function in order to implement + // the cast operator operator NPT_Reference<U>() below, which would + // have to be marked as a friend, and friend declarations with the + // same class name confuses some compilers + NPT_Reference(T* object, NPT_Cardinal* counter, NPT_Mutex* mutex, bool thread_safe) : + m_Object(object), m_Counter(counter), m_Mutex(mutex), m_ThreadSafe(thread_safe) { + if (m_Mutex) m_Mutex->Lock(); + if (m_Counter) ++(*m_Counter); + if (m_Mutex) m_Mutex->Unlock(); + } + + ~NPT_Reference() { + Release(); + } + + // overloaded operators + NPT_Reference<T>& operator=(const NPT_Reference<T>& ref) { + if (this != &ref) { + Release(); + m_Object = ref.m_Object; + m_Counter = ref.m_Counter; + m_Mutex = ref.m_Mutex; + m_ThreadSafe = ref.m_ThreadSafe; + + if (m_Mutex) m_Mutex->Lock(); + if (m_Counter) ++(*m_Counter); + if (m_Mutex) m_Mutex->Unlock(); + } + return *this; + } + NPT_Reference<T>& operator=(T* object) { + Release(); + m_Object = object; + m_Counter = object?new NPT_Cardinal(1):NULL; + m_Mutex = (object && m_ThreadSafe)?new NPT_Mutex():NULL; + return *this; + } + T& operator*() const { return *m_Object; } + T* operator->() const { return m_Object; } + + bool operator==(const NPT_Reference<T>& ref) const { + return m_Object == ref.m_Object; + } + bool operator!=(const NPT_Reference<T>& ref) const { + return m_Object != ref.m_Object; + } + + // overloaded cast operators + template <typename U> operator NPT_Reference<U>() { + return NPT_Reference<U>(m_Object, m_Counter, m_Mutex, m_ThreadSafe); + } + + // methods + /** + * Returns the naked pointer value. + */ + T* AsPointer() const { return m_Object; } + + /** + * Returns the reference counter value. + */ + NPT_Cardinal GetCounter() const { return *m_Counter; } + + /** + * Returns whether this references a NULL object. + */ + bool IsNull() const { return m_Object == NULL; } + + /** + * Detach the reference from the shared object. + * The reference count is decremented, but the object is not deleted if the + * reference count becomes 0. + * After the method returns, this reference does not point to any shared object. + */ + void Detach() { + Release(true); + } + +private: + // methods + void Release(bool detach_only = false) { + bool last_reference = false; + if (m_Mutex) m_Mutex->Lock(); + + if (m_Counter && --(*m_Counter) == 0) { + delete m_Counter; + if (!detach_only) delete m_Object; + last_reference = true; + } + + m_Counter = NULL; + m_Object = NULL; + + if (m_Mutex) { + NPT_Mutex* mutex = m_Mutex; + m_Mutex = NULL; + mutex->Unlock(); + if (last_reference) delete mutex; + } + + } + + // members + T* m_Object; + NPT_Cardinal* m_Counter; + NPT_Mutex* m_Mutex; + bool m_ThreadSafe; +}; + +#endif // _NPT_REFERENCES_H_ diff --git a/lib/libUPnP/Neptune/Source/Core/NptResults.cpp b/lib/libUPnP/Neptune/Source/Core/NptResults.cpp new file mode 100644 index 0000000..cf87793 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptResults.cpp @@ -0,0 +1,153 @@ +/***************************************************************** +| +| Neptune - Result Code Map +| +| This file is automatically generated by a script, do not edit! +| +| Copyright (c) 2002-2010, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "Neptune.h" + +/*---------------------------------------------------------------------- +| NPT_ResultText ++---------------------------------------------------------------------*/ +const char* +NPT_ResultText(NPT_Result result) +{ + switch (result) { + case NPT_SUCCESS: return "SUCCESS"; + case NPT_FAILURE: return "FAILURE"; + + case NPT_ERROR_INVALID_PARAMETERS: return "NPT_ERROR_INVALID_PARAMETERS"; + case NPT_ERROR_PERMISSION_DENIED: return "NPT_ERROR_PERMISSION_DENIED"; + case NPT_ERROR_OUT_OF_MEMORY: return "NPT_ERROR_OUT_OF_MEMORY"; + case NPT_ERROR_NO_SUCH_NAME: return "NPT_ERROR_NO_SUCH_NAME"; + case NPT_ERROR_NO_SUCH_PROPERTY: return "NPT_ERROR_NO_SUCH_PROPERTY"; + case NPT_ERROR_NO_SUCH_ITEM: return "NPT_ERROR_NO_SUCH_ITEM"; + case NPT_ERROR_NO_SUCH_CLASS: return "NPT_ERROR_NO_SUCH_CLASS"; + case NPT_ERROR_OVERFLOW: return "NPT_ERROR_OVERFLOW"; + case NPT_ERROR_INTERNAL: return "NPT_ERROR_INTERNAL"; + case NPT_ERROR_INVALID_STATE: return "NPT_ERROR_INVALID_STATE"; + case NPT_ERROR_INVALID_FORMAT: return "NPT_ERROR_INVALID_FORMAT"; + case NPT_ERROR_INVALID_SYNTAX: return "NPT_ERROR_INVALID_SYNTAX"; + case NPT_ERROR_NOT_IMPLEMENTED: return "NPT_ERROR_NOT_IMPLEMENTED"; + case NPT_ERROR_NOT_SUPPORTED: return "NPT_ERROR_NOT_SUPPORTED"; + case NPT_ERROR_TIMEOUT: return "NPT_ERROR_TIMEOUT"; + case NPT_ERROR_WOULD_BLOCK: return "NPT_ERROR_WOULD_BLOCK"; + case NPT_ERROR_TERMINATED: return "NPT_ERROR_TERMINATED"; + case NPT_ERROR_OUT_OF_RANGE: return "NPT_ERROR_OUT_OF_RANGE"; + case NPT_ERROR_OUT_OF_RESOURCES: return "NPT_ERROR_OUT_OF_RESOURCES"; + case NPT_ERROR_NOT_ENOUGH_SPACE: return "NPT_ERROR_NOT_ENOUGH_SPACE"; + case NPT_ERROR_INTERRUPTED: return "NPT_ERROR_INTERRUPTED"; + case NPT_ERROR_CANCELLED: return "NPT_ERROR_CANCELLED"; + case NPT_ERROR_LIST_EMPTY: return "NPT_ERROR_LIST_EMPTY"; + case NPT_ERROR_LIST_OPERATION_ABORTED: return "NPT_ERROR_LIST_OPERATION_ABORTED"; + case NPT_ERROR_LIST_OPERATION_CONTINUE: return "NPT_ERROR_LIST_OPERATION_CONTINUE"; + case NPT_ERROR_NO_SUCH_FILE: return "NPT_ERROR_NO_SUCH_FILE"; + case NPT_ERROR_FILE_NOT_OPEN: return "NPT_ERROR_FILE_NOT_OPEN"; + case NPT_ERROR_FILE_BUSY: return "NPT_ERROR_FILE_BUSY"; + case NPT_ERROR_FILE_ALREADY_OPEN: return "NPT_ERROR_FILE_ALREADY_OPEN"; + case NPT_ERROR_FILE_NOT_READABLE: return "NPT_ERROR_FILE_NOT_READABLE"; + case NPT_ERROR_FILE_NOT_WRITABLE: return "NPT_ERROR_FILE_NOT_WRITABLE"; + case NPT_ERROR_FILE_NOT_DIRECTORY: return "NPT_ERROR_FILE_NOT_DIRECTORY"; + case NPT_ERROR_FILE_ALREADY_EXISTS: return "NPT_ERROR_FILE_ALREADY_EXISTS"; + case NPT_ERROR_FILE_NOT_ENOUGH_SPACE: return "NPT_ERROR_FILE_NOT_ENOUGH_SPACE"; + case NPT_ERROR_DIRECTORY_NOT_EMPTY: return "NPT_ERROR_DIRECTORY_NOT_EMPTY"; + case NPT_ERROR_READ_FAILED: return "NPT_ERROR_READ_FAILED"; + case NPT_ERROR_WRITE_FAILED: return "NPT_ERROR_WRITE_FAILED"; + case NPT_ERROR_EOS: return "NPT_ERROR_EOS"; + case NPT_ERROR_CONNECTION_RESET: return "NPT_ERROR_CONNECTION_RESET"; + case NPT_ERROR_CONNECTION_ABORTED: return "NPT_ERROR_CONNECTION_ABORTED"; + case NPT_ERROR_CONNECTION_REFUSED: return "NPT_ERROR_CONNECTION_REFUSED"; + case NPT_ERROR_CONNECTION_FAILED: return "NPT_ERROR_CONNECTION_FAILED"; + case NPT_ERROR_HOST_UNKNOWN: return "NPT_ERROR_HOST_UNKNOWN"; + case NPT_ERROR_SOCKET_FAILED: return "NPT_ERROR_SOCKET_FAILED"; + case NPT_ERROR_GETSOCKOPT_FAILED: return "NPT_ERROR_GETSOCKOPT_FAILED"; + case NPT_ERROR_SETSOCKOPT_FAILED: return "NPT_ERROR_SETSOCKOPT_FAILED"; + case NPT_ERROR_SOCKET_CONTROL_FAILED: return "NPT_ERROR_SOCKET_CONTROL_FAILED"; + case NPT_ERROR_BIND_FAILED: return "NPT_ERROR_BIND_FAILED"; + case NPT_ERROR_LISTEN_FAILED: return "NPT_ERROR_LISTEN_FAILED"; + case NPT_ERROR_ACCEPT_FAILED: return "NPT_ERROR_ACCEPT_FAILED"; + case NPT_ERROR_ADDRESS_IN_USE: return "NPT_ERROR_ADDRESS_IN_USE"; + case NPT_ERROR_NETWORK_DOWN: return "NPT_ERROR_NETWORK_DOWN"; + case NPT_ERROR_NETWORK_UNREACHABLE: return "NPT_ERROR_NETWORK_UNREACHABLE"; + case NPT_ERROR_HOST_UNREACHABLE: return "NPT_ERROR_HOST_UNREACHABLE"; + case NPT_ERROR_NO_SUCH_INTERFACE: return "NPT_ERROR_NO_SUCH_INTERFACE"; + case NPT_ERROR_XML_INVALID_NESTING: return "NPT_ERROR_XML_INVALID_NESTING"; + case NPT_ERROR_XML_TAG_MISMATCH: return "NPT_ERROR_XML_TAG_MISMATCH"; + case NPT_ERROR_HTTP_INVALID_RESPONSE_LINE: return "NPT_ERROR_HTTP_INVALID_RESPONSE_LINE"; + case NPT_ERROR_HTTP_INVALID_REQUEST_LINE: return "NPT_ERROR_HTTP_INVALID_REQUEST_LINE"; + case NPT_ERROR_HTTP_NO_PROXY: return "NPT_ERROR_HTTP_NO_PROXY"; + case NPT_ERROR_HTTP_INVALID_REQUEST: return "NPT_ERROR_HTTP_INVALID_REQUEST"; + case NPT_ERROR_HTTP_METHOD_NOT_SUPPORTED: return "NPT_ERROR_HTTP_METHOD_NOT_SUPPORTED"; + case NPT_ERROR_HTTP_TOO_MANY_REDIRECTS: return "NPT_ERROR_HTTP_TOO_MANY_REDIRECTS"; + case NPT_ERROR_HTTP_TOO_MANY_RECONNECTS: return "NPT_ERROR_HTTP_TOO_MANY_RECONNECTS"; + case NPT_ERROR_HTTP_CANNOT_RESEND_BODY: return "NPT_ERROR_HTTP_CANNOT_RESEND_BODY"; + case NPT_ERROR_CALLBACK_HANDLER_SHUTDOWN: return "NPT_ERROR_CALLBACK_HANDLER_SHUTDOWN"; + case NPT_ERROR_CALLBACK_NOTHING_PENDING: return "NPT_ERROR_CALLBACK_NOTHING_PENDING"; + case NPT_ERROR_NO_SUCH_SERIAL_PORT: return "NPT_ERROR_NO_SUCH_SERIAL_PORT"; + case NPT_ERROR_SERIAL_PORT_NOT_OPEN: return "NPT_ERROR_SERIAL_PORT_NOT_OPEN"; + case NPT_ERROR_SERIAL_PORT_ALREADY_OPEN: return "NPT_ERROR_SERIAL_PORT_ALREADY_OPEN"; + case NPT_ERROR_SERIAL_PORT_BUSY: return "NPT_ERROR_SERIAL_PORT_BUSY"; + case NPT_ERROR_INVALID_PASSWORD: return "NPT_ERROR_INVALID_PASSWORD"; + case NPT_ERROR_TLS_INVALID_HANDSHAKE: return "NPT_ERROR_TLS_INVALID_HANDSHAKE"; + case NPT_ERROR_TLS_INVALID_PROTOCOL_MESSAGE: return "NPT_ERROR_TLS_INVALID_PROTOCOL_MESSAGE"; + case NPT_ERROR_TLS_INVALID_HMAC: return "NPT_ERROR_TLS_INVALID_HMAC"; + case NPT_ERROR_TLS_INVALID_VERSION: return "NPT_ERROR_TLS_INVALID_VERSION"; + case NPT_ERROR_TLS_INVALID_SESSION: return "NPT_ERROR_TLS_INVALID_SESSION"; + case NPT_ERROR_TLS_NO_CIPHER: return "NPT_ERROR_TLS_NO_CIPHER"; + case NPT_ERROR_TLS_BAD_CERTIFICATE: return "NPT_ERROR_TLS_BAD_CERTIFICATE"; + case NPT_ERROR_TLS_INVALID_KEY: return "NPT_ERROR_TLS_INVALID_KEY"; + case NPT_ERROR_TLS_NO_CLIENT_RENEGOTIATION: return "NPT_ERROR_TLS_NO_CLIENT_RENEGOTIATION"; + case NPT_ERROR_TLS_INVALID_FINISHED_MESSAGE: return "NPT_ERROR_TLS_INVALID_FINISHED_MESSAGE"; + case NPT_ERROR_TLS_NO_CERTIFICATE_DEFINED: return "NPT_ERROR_TLS_NO_CERTIFICATE_DEFINED"; + case NPT_ERROR_TLS_ALERT_HANDSHAKE_FAILED: return "NPT_ERROR_TLS_ALERT_HANDSHAKE_FAILED"; + case NPT_ERROR_TLS_ALERT_BAD_CERTIFICATE: return "NPT_ERROR_TLS_ALERT_BAD_CERTIFICATE"; + case NPT_ERROR_TLS_ALERT_INVALID_VERSION: return "NPT_ERROR_TLS_ALERT_INVALID_VERSION"; + case NPT_ERROR_TLS_ALERT_BAD_RECORD_MAC: return "NPT_ERROR_TLS_ALERT_BAD_RECORD_MAC"; + case NPT_ERROR_TLS_ALERT_DECODE_ERROR: return "NPT_ERROR_TLS_ALERT_DECODE_ERROR"; + case NPT_ERROR_TLS_ALERT_DECRYPT_ERROR: return "NPT_ERROR_TLS_ALERT_DECRYPT_ERROR"; + case NPT_ERROR_TLS_ALERT_ILLEGAL_PARAMETER: return "NPT_ERROR_TLS_ALERT_ILLEGAL_PARAMETER"; + case NPT_ERROR_TLS_ALERT_UNEXPECTED_MESSAGE: return "NPT_ERROR_TLS_ALERT_UNEXPECTED_MESSAGE"; + case NPT_ERROR_TLS_CERTIFICATE_FAILURE: return "NPT_ERROR_TLS_CERTIFICATE_FAILURE"; + case NPT_ERROR_TLS_CERTIFICATE_NO_TRUST_ANCHOR: return "NPT_ERROR_TLS_CERTIFICATE_NO_TRUST_ANCHOR"; + case NPT_ERROR_TLS_CERTIFICATE_BAD_SIGNATURE: return "NPT_ERROR_TLS_CERTIFICATE_BAD_SIGNATURE"; + case NPT_ERROR_TLS_CERTIFICATE_NOT_YET_VALID: return "NPT_ERROR_TLS_CERTIFICATE_NOT_YET_VALID"; + case NPT_ERROR_TLS_CERTIFICATE_EXPIRED: return "NPT_ERROR_TLS_CERTIFICATE_EXPIRED"; + case NPT_ERROR_TLS_CERTIFICATE_SELF_SIGNED: return "NPT_ERROR_TLS_CERTIFICATE_SELF_SIGNED"; + case NPT_ERROR_TLS_CERTIFICATE_INVALID_CHAIN: return "NPT_ERROR_TLS_CERTIFICATE_INVALID_CHAIN"; + case NPT_ERROR_TLS_CERTIFICATE_UNSUPPORTED_DIGEST: return "NPT_ERROR_TLS_CERTIFICATE_UNSUPPORTED_DIGEST"; + case NPT_ERROR_TLS_CERTIFICATE_INVALID_PRIVATE_KEY: return "NPT_ERROR_TLS_CERTIFICATE_INVALID_PRIVATE_KEY"; + case NPT_ERROR_TLS_DNS_NAME_MISMATCH: return "NPT_ERROR_TLS_DNS_NAME_MISMATCH"; + + default: return "UNKNOWN"; + } +} diff --git a/lib/libUPnP/Neptune/Source/Core/NptResults.h b/lib/libUPnP/Neptune/Source/Core/NptResults.h new file mode 100644 index 0000000..274c545 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptResults.h @@ -0,0 +1,163 @@ +/***************************************************************** +| +| Neptune - Result Codes +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +#ifndef _NPT_RESULTS_H_ +#define _NPT_RESULTS_H_ + +/*---------------------------------------------------------------------- +| macros ++---------------------------------------------------------------------*/ +#if defined(NPT_DEBUG) +#include "NptDebug.h" +#define NPT_CHECK(_x) \ +do { \ + NPT_Result _result = (_x); \ + if (_result != NPT_SUCCESS) { \ + NPT_Debug("%s(%d): @@@ NPT_CHECK failed, result=%d (%s)\n", __FILE__, __LINE__, _result, NPT_ResultText(_result)); \ + return _result; \ + } \ +} while(0) +#define NPT_CHECK_POINTER(_p) \ +do { \ + if ((_p) == NULL) { \ + NPT_Debug("%s(%d): @@@ NULL pointer parameter\n", __FILE__, __LINE__); \ + return NPT_ERROR_INVALID_PARAMETERS; \ + } \ +} while(0) +#define NPT_CHECK_LABEL(_x, label) \ +do { \ + NPT_Result _result = (_x); \ + if (_result != NPT_SUCCESS) { \ + NPT_Debug("%s(%d): @@@ NPT_CHECK failed, result=%d (%s)\n", __FILE__, __LINE__, _result, NPT_ResultText(_result)); \ + goto label; \ + } \ +} while(0) +#define NPT_CHECK_POINTER_LABEL(_p, label) \ +do { \ + if (_p == NULL) { \ + NPT_Debug("%s(%d): @@@ NULL pointer parameter\n", __FILE__, __LINE__); \ + goto label; \ + } \ +} while(0) +#else +#define NPT_CHECK(_x) \ +do { \ + NPT_Result _result = (_x); \ + if (_result != NPT_SUCCESS) { \ + return _result; \ + } \ +} while(0) +#define NPT_CHECK_POINTER(_p) \ +do { \ + if ((_p) == NULL) return NPT_ERROR_INVALID_PARAMETERS; \ +} while(0) +#define NPT_CHECK_LABEL(_x, label) \ +do { \ + NPT_Result _result = (_x); \ + if (_result != NPT_SUCCESS) { \ + goto label; \ + } \ +} while(0) +#define NPT_CHECK_POINTER_LABEL(_p, label) \ +do { \ + if ((_p) == NULL) { \ + goto label; \ + } \ +} while(0) +#endif + +#define NPT_FAILED(result) ((result) != NPT_SUCCESS) +#define NPT_SUCCEEDED(result) ((result) == NPT_SUCCESS) + +/*---------------------------------------------------------------------- +| result codes ++---------------------------------------------------------------------*/ +/** Result indicating that the operation or call succeeded */ +#define NPT_SUCCESS 0 + +/** Result indicating an unspecififed failure condition */ +#define NPT_FAILURE (-1) + +#if !defined(NPT_ERROR_BASE) +#define NPT_ERROR_BASE -20000 +#endif + +// error bases +const int NPT_ERROR_BASE_GENERAL = NPT_ERROR_BASE-0; +const int NPT_ERROR_BASE_LIST = NPT_ERROR_BASE-100; +const int NPT_ERROR_BASE_FILE = NPT_ERROR_BASE-200; +const int NPT_ERROR_BASE_IO = NPT_ERROR_BASE-300; +const int NPT_ERROR_BASE_SOCKET = NPT_ERROR_BASE-400; +const int NPT_ERROR_BASE_INTERFACES = NPT_ERROR_BASE-500; +const int NPT_ERROR_BASE_XML = NPT_ERROR_BASE-600; +const int NPT_ERROR_BASE_UNIX = NPT_ERROR_BASE-700; +const int NPT_ERROR_BASE_HTTP = NPT_ERROR_BASE-800; +const int NPT_ERROR_BASE_THREADS = NPT_ERROR_BASE-900; +const int NPT_ERROR_BASE_SERIAL_PORT = NPT_ERROR_BASE-1000; +const int NPT_ERROR_BASE_TLS = NPT_ERROR_BASE-1100; + +// general errors +const int NPT_ERROR_INVALID_PARAMETERS = NPT_ERROR_BASE_GENERAL - 0; +const int NPT_ERROR_PERMISSION_DENIED = NPT_ERROR_BASE_GENERAL - 1; +const int NPT_ERROR_OUT_OF_MEMORY = NPT_ERROR_BASE_GENERAL - 2; +const int NPT_ERROR_NO_SUCH_NAME = NPT_ERROR_BASE_GENERAL - 3; +const int NPT_ERROR_NO_SUCH_PROPERTY = NPT_ERROR_BASE_GENERAL - 4; +const int NPT_ERROR_NO_SUCH_ITEM = NPT_ERROR_BASE_GENERAL - 5; +const int NPT_ERROR_NO_SUCH_CLASS = NPT_ERROR_BASE_GENERAL - 6; +const int NPT_ERROR_OVERFLOW = NPT_ERROR_BASE_GENERAL - 7; +const int NPT_ERROR_INTERNAL = NPT_ERROR_BASE_GENERAL - 8; +const int NPT_ERROR_INVALID_STATE = NPT_ERROR_BASE_GENERAL - 9; +const int NPT_ERROR_INVALID_FORMAT = NPT_ERROR_BASE_GENERAL - 10; +const int NPT_ERROR_INVALID_SYNTAX = NPT_ERROR_BASE_GENERAL - 11; +const int NPT_ERROR_NOT_IMPLEMENTED = NPT_ERROR_BASE_GENERAL - 12; +const int NPT_ERROR_NOT_SUPPORTED = NPT_ERROR_BASE_GENERAL - 13; +const int NPT_ERROR_TIMEOUT = NPT_ERROR_BASE_GENERAL - 14; +const int NPT_ERROR_WOULD_BLOCK = NPT_ERROR_BASE_GENERAL - 15; +const int NPT_ERROR_TERMINATED = NPT_ERROR_BASE_GENERAL - 16; +const int NPT_ERROR_OUT_OF_RANGE = NPT_ERROR_BASE_GENERAL - 17; +const int NPT_ERROR_OUT_OF_RESOURCES = NPT_ERROR_BASE_GENERAL - 18; +const int NPT_ERROR_NOT_ENOUGH_SPACE = NPT_ERROR_BASE_GENERAL - 19; +const int NPT_ERROR_INTERRUPTED = NPT_ERROR_BASE_GENERAL - 20; +const int NPT_ERROR_CANCELLED = NPT_ERROR_BASE_GENERAL - 21; + +/* standard error codes */ +/* these are special codes to convey an errno */ +/* the error code is (SHI_ERROR_BASE_ERRNO - errno) */ +/* where errno is the positive integer from errno.h */ +const int NPT_ERROR_BASE_ERRNO = NPT_ERROR_BASE-2000; +#define NPT_ERROR_ERRNO(e) (NPT_ERROR_BASE_ERRNO - (e)) + +/*---------------------------------------------------------------------- +| functions ++---------------------------------------------------------------------*/ +const char* NPT_ResultText(int result); + +#endif // _NPT_RESULTS_H_ diff --git a/lib/libUPnP/Neptune/Source/Core/NptRingBuffer.cpp b/lib/libUPnP/Neptune/Source/Core/NptRingBuffer.cpp new file mode 100644 index 0000000..798176d --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptRingBuffer.cpp @@ -0,0 +1,269 @@ +/***************************************************************** +| +| Neptune - Ring Buffer +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptRingBuffer.h" +#include "NptResults.h" +#include "NptUtils.h" +#include "NptStreams.h" + +/*---------------------------------------------------------------------- +| NPT_RingBuffer::NPT_RingBuffer ++---------------------------------------------------------------------*/ +NPT_RingBuffer::NPT_RingBuffer(NPT_Size size) : + m_BufferIsLocal(true), + m_Closed(false) +{ + m_Data.start = new unsigned char[size]; + m_Data.end = m_Data.start + size; + + m_In = m_Out = m_Data.start; +} + +/*---------------------------------------------------------------------- +| NPT_RingBuffer::NPT_RingBuffer ++---------------------------------------------------------------------*/ +NPT_RingBuffer::NPT_RingBuffer(void* buffer, NPT_Size size) : + m_BufferIsLocal(false), + m_Closed(false) +{ + m_Data.start = (unsigned char*)buffer; + m_Data.end = m_Data.start + size; + + m_In = m_Out = m_Data.start; +} + +/*---------------------------------------------------------------------- +| NPT_RingBuffer::~NPT_RingBuffer ++---------------------------------------------------------------------*/ +NPT_RingBuffer::~NPT_RingBuffer() +{ + if (m_BufferIsLocal) delete[] m_Data.start; +} + +/*---------------------------------------------------------------------- +| NPT_RingBuffer::GetContiguousSpace ++---------------------------------------------------------------------*/ +NPT_Size +NPT_RingBuffer::GetContiguousSpace() const +{ + return + (m_In < m_Out) ? + (NPT_Size)(m_Out - m_In - 1) : + ((m_Out == m_Data.start) ? + (NPT_Size)(m_Data.end - m_In - 1) : + (NPT_Size)(m_Data.end - m_In)); +} + +/*---------------------------------------------------------------------- +| NPT_RingBuffer::GetSpace ++---------------------------------------------------------------------*/ +NPT_Size +NPT_RingBuffer::GetSpace() const +{ + return + (m_In < m_Out) ? + (NPT_Size)(m_Out - m_In - 1) : + (NPT_Size)(m_Data.end - m_In + m_Out - m_Data.start - 1); +} + +/*----------------------------------------------------------------------+ +| NPT_RingBuffer::Write ++----------------------------------------------------------------------*/ +NPT_Result +NPT_RingBuffer::Write(const void* buffer, NPT_Size byte_count) +{ + if (m_Closed) return NPT_ERROR_WRITE_FAILED; + + if (byte_count == 0) return NPT_SUCCESS; + if (m_In < m_Out) { + if (buffer) NPT_CopyMemory(m_In, buffer, byte_count); + m_In += byte_count; + if (m_In == m_Data.end) m_In = m_Data.start; + } else { + unsigned int chunk = (unsigned int)(m_Data.end - m_In); + if (chunk >= byte_count) chunk = byte_count; + + if (buffer) NPT_CopyMemory(m_In, buffer, chunk); + m_In += chunk; + if (m_In == m_Data.end) m_In = m_Data.start; + if (chunk != byte_count) { + if (buffer) { + NPT_CopyMemory(m_In, + ((const char*)buffer)+chunk, + byte_count-chunk); + } + m_In += byte_count-chunk; + if (m_In == m_Data.end) m_In = m_Data.start; + } + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_RingBuffer::GetContiguousAvailable ++---------------------------------------------------------------------*/ +NPT_Size +NPT_RingBuffer::GetContiguousAvailable() const +{ + return + (m_Out <= m_In) ? + (NPT_Size)(m_In-m_Out) : + (NPT_Size)(m_Data.end - m_Out); +} + +/*---------------------------------------------------------------------- +| NPT_RingBuffer::GetAvailable ++---------------------------------------------------------------------*/ +NPT_Size +NPT_RingBuffer::GetAvailable() const +{ + return + (m_Out <= m_In) ? + (NPT_Size)(m_In-m_Out) : + (NPT_Size)(m_Data.end - m_Out + m_In - m_Data.start); +} + +/*----------------------------------------------------------------------+ +| NPT_RingBuffer::Read ++----------------------------------------------------------------------*/ +NPT_Result +NPT_RingBuffer::Read(void* buffer, NPT_Size byte_count) +{ + if (m_Closed) return NPT_ERROR_READ_FAILED; + + if (byte_count == 0) return NPT_SUCCESS; + if (m_In > m_Out) { + if (buffer) NPT_CopyMemory(buffer, m_Out, byte_count); + m_Out += byte_count; + if (m_Out == m_Data.end) m_Out = m_Data.start; + } else { + unsigned int chunk = (unsigned int)(m_Data.end - m_Out); + if (chunk >= byte_count) chunk = byte_count; + + if (buffer) NPT_CopyMemory(buffer, m_Out, chunk); + m_Out += chunk; + if (m_Out == m_Data.end) m_Out = m_Data.start; + if (chunk != byte_count) { + if (buffer) { + NPT_CopyMemory(((char*)buffer)+chunk, m_Out, byte_count-chunk); + } + m_Out += byte_count-chunk; + if (m_Out == m_Data.end) m_Out = m_Data.start; + } + } + + return NPT_SUCCESS; +} + +/*----------------------------------------------------------------------+ +| NPT_RingBuffer::ReadByte ++----------------------------------------------------------------------*/ +unsigned char +NPT_RingBuffer::ReadByte() +{ + unsigned char result = *m_Out++; + if (m_Out == m_Data.end) m_Out = m_Data.start; + return result; +} + +/*----------------------------------------------------------------------+ +| NPT_RingBuffer::PeekByte ++----------------------------------------------------------------------*/ +unsigned char +NPT_RingBuffer::PeekByte(NPT_Position offset) +{ + unsigned char *where; + + where = m_Out+offset; + if (where >= m_Data.end) where -= (m_Data.end - m_Data.start); + + return *where; +} + +/*----------------------------------------------------------------------+ +| NPT_RingBuffer::MoveIn ++----------------------------------------------------------------------*/ +NPT_Result +NPT_RingBuffer::MoveIn(NPT_Position offset) +{ + int fold; + + m_In += offset; + fold = (int)(m_In - m_Data.end); + if (fold >= 0) { + m_In = m_Data.start + fold; + } + + return NPT_SUCCESS; +} + +/*----------------------------------------------------------------------+ +| NPT_RingBuffer::MoveOut ++----------------------------------------------------------------------*/ +NPT_Result +NPT_RingBuffer::MoveOut(NPT_Position offset) +{ + int fold; + + m_Out += offset; + fold = (int)(m_Out - m_Data.end); + if (fold >= 0) { + m_Out = m_Data.start + fold; + } + + return NPT_SUCCESS; +} + +/*----------------------------------------------------------------------+ +| NPT_RingBuffer::Flush ++----------------------------------------------------------------------*/ +NPT_Result +NPT_RingBuffer::Flush() +{ + m_In = m_Out = m_Data.start; + + return NPT_SUCCESS; +} + +/*----------------------------------------------------------------------+ +| NPT_RingBuffer::Close ++----------------------------------------------------------------------*/ +NPT_Result +NPT_RingBuffer::Close() +{ + m_Closed = true; + return NPT_SUCCESS; +} + diff --git a/lib/libUPnP/Neptune/Source/Core/NptRingBuffer.h b/lib/libUPnP/Neptune/Source/Core/NptRingBuffer.h new file mode 100644 index 0000000..971e4a5 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptRingBuffer.h @@ -0,0 +1,83 @@ +/***************************************************************** +| +| Neptune - Ring Buffer +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +#ifndef _NPT_RING_BUFFER_H_ +#define _NPT_RING_BUFFER_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptTypes.h" +#include "NptReferences.h" + +/*---------------------------------------------------------------------- +| NPT_RingBuffer ++---------------------------------------------------------------------*/ +class NPT_RingBuffer +{ + public: + // methods + NPT_RingBuffer(NPT_Size size); + NPT_RingBuffer(void* buffer, NPT_Size size); + virtual ~NPT_RingBuffer(); + NPT_Size GetSpace() const; + NPT_Size GetContiguousSpace() const; + NPT_Result Write(const void* buffer, NPT_Size byte_count); + NPT_Size GetAvailable() const; + NPT_Size GetContiguousAvailable() const; + NPT_Result Read(void* buffer, NPT_Size byte_count); + unsigned char ReadByte(); + unsigned char PeekByte(NPT_Position offset); + NPT_Result MoveIn(NPT_Position offset); + NPT_Result MoveOut(NPT_Position offset); + NPT_Result Flush(); + NPT_Result Close(); + bool IsClosed() { return m_Closed; } + + // accessors + unsigned char* GetWritePointer() { return m_In; } + unsigned char* GetReadPointer() { return m_Out;} + + private: + // members + struct { + unsigned char* start; + unsigned char* end; + } m_Data; + unsigned char* m_In; + unsigned char* m_Out; + bool m_BufferIsLocal; + bool m_Closed; +}; + +typedef NPT_Reference<NPT_RingBuffer> NPT_RingBufferReference; + +#endif // _NPT_RING_BUFFER_H_ diff --git a/lib/libUPnP/Neptune/Source/Core/NptSelectableMessageQueue.h b/lib/libUPnP/Neptune/Source/Core/NptSelectableMessageQueue.h new file mode 100644 index 0000000..56b55d0 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptSelectableMessageQueue.h @@ -0,0 +1,68 @@ +/***************************************************************** +| +| Neptune - Selectable Message Queue +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +#ifndef _NPT_SELECTABLE_MESSAGE_QUEUE_H_ +#define _NPT_SELECTABLE_MESSAGE_QUEUE_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptMessaging.h" +#include "NptSimpleMessageQueue.h" + +/*---------------------------------------------------------------------- +| NPT_SelectableMessageQueue ++---------------------------------------------------------------------*/ +class NPT_SelectableMessageQueue : public NPT_SimpleMessageQueue +{ +public: + // methods + NPT_SelectableMessageQueue(); + ~NPT_SelectableMessageQueue() override; + + // NPT_MessageQueue methods + NPT_Result PumpMessage(NPT_Timeout timeout = NPT_TIMEOUT_INFINITE) override; + NPT_Result QueueMessage(NPT_Message* message, + NPT_MessageHandler* handler) override; + + // methods + int GetEventFd() { return m_Pipe[0]; } + +private: + // methods + NPT_Result FlushEvent(); + + // members + int m_Pipe[2]; +}; + + +#endif /* _NPT_SELECTABLE_MESSAGE_QUEUE_H_ */ diff --git a/lib/libUPnP/Neptune/Source/Core/NptSerialPort.h b/lib/libUPnP/Neptune/Source/Core/NptSerialPort.h new file mode 100644 index 0000000..b543c11 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptSerialPort.h @@ -0,0 +1,119 @@ +/***************************************************************** +| +| Neptune - Serial Ports +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +#ifndef _NPT_SERIAL_PORT_H_ +#define _NPT_SERIAL_PORT_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptTypes.h" +#include "NptStreams.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const int NPT_ERROR_NO_SUCH_SERIAL_PORT = NPT_ERROR_BASE_SERIAL_PORT - 0; +const int NPT_ERROR_SERIAL_PORT_NOT_OPEN = NPT_ERROR_BASE_SERIAL_PORT - 1; +const int NPT_ERROR_SERIAL_PORT_ALREADY_OPEN = NPT_ERROR_BASE_SERIAL_PORT - 2; +const int NPT_ERROR_SERIAL_PORT_BUSY = NPT_ERROR_BASE_SERIAL_PORT - 3; + +typedef enum { + NPT_SERIAL_PORT_PARITY_NONE, + NPT_SERIAL_PORT_PARITY_EVEN, + NPT_SERIAL_PORT_PARITY_ODD, + NPT_SERIAL_PORT_PARITY_MARK +} NPT_SerialPortParity; + +typedef enum { + NPT_SERIAL_PORT_STOP_BITS_1, + NPT_SERIAL_PORT_STOP_BITS_1_5, + NPT_SERIAL_PORT_STOP_BITS_2 +} NPT_SerialPortStopBits; + +typedef enum { + NPT_SERIAL_PORT_FLOW_CONTROL_NONE, + NPT_SERIAL_PORT_FLOW_CONTROL_HARDWARE, + NPT_SERIAL_PORT_FLOW_CONTROL_XON_XOFF +} NPT_SerialPortFlowControl; + +/*---------------------------------------------------------------------- +| NPT_SerialPortInterface ++---------------------------------------------------------------------*/ +class NPT_SerialPortInterface +{ +public: + // constructors and destructor + virtual ~NPT_SerialPortInterface() {} + + // methods + virtual NPT_Result Open(unsigned int speed, + NPT_SerialPortStopBits stop_bits, + NPT_SerialPortFlowControl flow_control, + NPT_SerialPortParity parity) = 0; + virtual NPT_Result Close() = 0; + virtual NPT_Result GetInputStream(NPT_InputStreamReference& stream) = 0; + virtual NPT_Result GetOutputStream(NPT_OutputStreamReference& stream) = 0; +}; + +/*---------------------------------------------------------------------- +| NPT_SerialPort ++---------------------------------------------------------------------*/ +class NPT_SerialPort : public NPT_SerialPortInterface +{ +public: + // constructors and destructor + NPT_SerialPort(const char* name); + ~NPT_SerialPort() override { delete m_Delegate; } + + // NPT_SerialPortInterface methods + NPT_Result Open(unsigned int speed, + NPT_SerialPortStopBits stop_bits = NPT_SERIAL_PORT_STOP_BITS_1, + NPT_SerialPortFlowControl flow_control = NPT_SERIAL_PORT_FLOW_CONTROL_NONE, + NPT_SerialPortParity parity = NPT_SERIAL_PORT_PARITY_NONE) override { + return m_Delegate->Open(speed, stop_bits, flow_control, parity); + } + NPT_Result Close() override { + return m_Delegate->Close(); + } + NPT_Result GetInputStream(NPT_InputStreamReference& stream) override { + return m_Delegate->GetInputStream(stream); + } + NPT_Result GetOutputStream(NPT_OutputStreamReference& stream) override { + return m_Delegate->GetOutputStream(stream); + } + +protected: + // members + NPT_SerialPortInterface* m_Delegate; +}; + +#endif // _NPT_SERIAL_PORT_H_ diff --git a/lib/libUPnP/Neptune/Source/Core/NptSimpleMessageQueue.cpp b/lib/libUPnP/Neptune/Source/Core/NptSimpleMessageQueue.cpp new file mode 100644 index 0000000..ef2298b --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptSimpleMessageQueue.cpp @@ -0,0 +1,128 @@ +/***************************************************************** +| +| Neptune - Simple Message Queue +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptSimpleMessageQueue.h" +#include "NptDebug.h" +#include "NptLogging.h" + +/*---------------------------------------------------------------------- +| logging ++---------------------------------------------------------------------*/ +NPT_SET_LOCAL_LOGGER("neptune.message-queue") + +/*---------------------------------------------------------------------- +| NPT_SimpleMessageCapsule ++---------------------------------------------------------------------*/ +struct NPT_SimpleMessageCapsule +{ + NPT_SimpleMessageCapsule(NPT_Message* message, + NPT_MessageHandler* handler); + ~NPT_SimpleMessageCapsule(); + NPT_Message* m_Message; + NPT_MessageHandler* m_Handler; + NPT_MessageHandlerProxy* m_Proxy; +}; + +/*---------------------------------------------------------------------- +| NPT_SimpleMessageCapsule::NPT_SimpleMessageCapsule ++---------------------------------------------------------------------*/ +NPT_SimpleMessageCapsule::NPT_SimpleMessageCapsule(NPT_Message* message, + NPT_MessageHandler* handler) : + m_Message(message), + m_Handler(handler), + m_Proxy(NPT_DYNAMIC_CAST(NPT_MessageHandlerProxy, handler)) +{ + if (m_Proxy) m_Proxy->AddReference(); +} + +/*---------------------------------------------------------------------- +| NPT_SimpleMessageCapsule::~NPT_SimpleMessageCapsule ++---------------------------------------------------------------------*/ +NPT_SimpleMessageCapsule::~NPT_SimpleMessageCapsule() +{ + if (m_Proxy) m_Proxy->Release(); +} + +/*---------------------------------------------------------------------- +| NPT_SimpleMessageQueue::NPT_SimpleMessageQueue ++---------------------------------------------------------------------*/ +NPT_SimpleMessageQueue::NPT_SimpleMessageQueue() +{ +} + +/*---------------------------------------------------------------------- +| NPT_SimpleMessageQueue::~NPT_SimpleMessageQueue ++---------------------------------------------------------------------*/ +NPT_SimpleMessageQueue::~NPT_SimpleMessageQueue() +{ + // empty the queue + // TBD +} + +/*---------------------------------------------------------------------- +| NPT_SimpleMessageQueue::QueueMessage ++---------------------------------------------------------------------*/ +NPT_Result +NPT_SimpleMessageQueue::QueueMessage(NPT_Message* message, + NPT_MessageHandler* handler) +{ + // push the message on the queue, with the handler reference + NPT_SimpleMessageCapsule* capsule = new NPT_SimpleMessageCapsule(message, handler); + NPT_Result result = m_Queue.Push(capsule); + if (NPT_FAILED(result)) delete capsule; + return result; +} + +/*---------------------------------------------------------------------- +| NPT_SimpleMessageQueue::PumpMessage ++---------------------------------------------------------------------*/ +NPT_Result +NPT_SimpleMessageQueue::PumpMessage(NPT_Timeout timeout /* = NPT_TIMEOUT_INFINITE */) +{ + NPT_SimpleMessageCapsule* capsule; + + NPT_LOG_FINEST_1("popping message from queue, timeout=%d", timeout); + NPT_Result result = m_Queue.Pop(capsule, timeout); + if (NPT_SUCCEEDED(result) && capsule) { + if (capsule->m_Handler && capsule->m_Message) { + result = capsule->m_Handler->HandleMessage(capsule->m_Message); + } + delete capsule->m_Message; + delete capsule; + } else { + NPT_LOG_FINEST_1("m_Queue.Pop() returned %d", result); + } + + return result; +} diff --git a/lib/libUPnP/Neptune/Source/Core/NptSimpleMessageQueue.h b/lib/libUPnP/Neptune/Source/Core/NptSimpleMessageQueue.h new file mode 100644 index 0000000..ca43e89 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptSimpleMessageQueue.h @@ -0,0 +1,68 @@ +/***************************************************************** +| +| Neptune - Simple Message Queue +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +#ifndef _NPT_SIMPLE_MESSAGE_QUEUE_H_ +#define _NPT_SIMPLE_MESSAGE_QUEUE_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptTypes.h" +#include "NptThreads.h" +#include "NptMessaging.h" +#include "NptQueue.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +struct NPT_SimpleMessageCapsule; + +/*---------------------------------------------------------------------- +| NPT_SimpleMessageQueue ++---------------------------------------------------------------------*/ +class NPT_SimpleMessageQueue : public NPT_MessageQueue +{ + public: + // members + NPT_SimpleMessageQueue(); + ~NPT_SimpleMessageQueue() override; + + // NPT_MessageQueue methods + NPT_Result QueueMessage(NPT_Message* message, + NPT_MessageHandler* handler) override; + NPT_Result PumpMessage(NPT_Timeout timeout = NPT_TIMEOUT_INFINITE) override; + + private: + // members + NPT_Queue<NPT_SimpleMessageCapsule> m_Queue; +}; + +#endif // _NPT_SIMPLE_MESSAGE_QUEUE_H_ diff --git a/lib/libUPnP/Neptune/Source/Core/NptSockets.cpp b/lib/libUPnP/Neptune/Source/Core/NptSockets.cpp new file mode 100644 index 0000000..7958f61 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptSockets.cpp @@ -0,0 +1,59 @@ +/***************************************************************** +| +| Neptune - Sockets +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptSockets.h" +#include "NptUtils.h" + +/*---------------------------------------------------------------------- +| NPT_SocketAddress::ToString ++---------------------------------------------------------------------*/ +NPT_String +NPT_SocketAddress::ToString() const +{ + NPT_String s = m_IpAddress.ToString(); + s += ':'; + s += NPT_String::FromInteger(m_Port); + return s; +} + +/*---------------------------------------------------------------------- +| NPT_SocketAddress::operator== ++---------------------------------------------------------------------*/ +bool +NPT_SocketAddress::operator==(const NPT_SocketAddress& other) const +{ + return (other.GetIpAddress().AsLong() == m_IpAddress.AsLong() && + other.GetPort() == m_Port); +} + diff --git a/lib/libUPnP/Neptune/Source/Core/NptSockets.h b/lib/libUPnP/Neptune/Source/Core/NptSockets.h new file mode 100644 index 0000000..899e1bf --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptSockets.h @@ -0,0 +1,340 @@ +/***************************************************************** +| +| Neptune - Network Sockets +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +#ifndef _NPT_SOCKETS_H_ +#define _NPT_SOCKETS_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptTypes.h" +#include "NptConstants.h" +#include "NptStreams.h" +#include "NptStrings.h" +#include "NptDataBuffer.h" +#include "NptNetwork.h" +#include "NptThreads.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const int NPT_ERROR_CONNECTION_RESET = NPT_ERROR_BASE_SOCKET - 0; +const int NPT_ERROR_CONNECTION_ABORTED = NPT_ERROR_BASE_SOCKET - 1; +const int NPT_ERROR_CONNECTION_REFUSED = NPT_ERROR_BASE_SOCKET - 2; +const int NPT_ERROR_CONNECTION_FAILED = NPT_ERROR_BASE_SOCKET - 3; +const int NPT_ERROR_HOST_UNKNOWN = NPT_ERROR_BASE_SOCKET - 4; +const int NPT_ERROR_SOCKET_FAILED = NPT_ERROR_BASE_SOCKET - 5; +const int NPT_ERROR_GETSOCKOPT_FAILED = NPT_ERROR_BASE_SOCKET - 6; +const int NPT_ERROR_SETSOCKOPT_FAILED = NPT_ERROR_BASE_SOCKET - 7; +const int NPT_ERROR_SOCKET_CONTROL_FAILED = NPT_ERROR_BASE_SOCKET - 8; +const int NPT_ERROR_BIND_FAILED = NPT_ERROR_BASE_SOCKET - 9; +const int NPT_ERROR_LISTEN_FAILED = NPT_ERROR_BASE_SOCKET - 10; +const int NPT_ERROR_ACCEPT_FAILED = NPT_ERROR_BASE_SOCKET - 11; +const int NPT_ERROR_ADDRESS_IN_USE = NPT_ERROR_BASE_SOCKET - 12; +const int NPT_ERROR_NETWORK_DOWN = NPT_ERROR_BASE_SOCKET - 13; +const int NPT_ERROR_NETWORK_UNREACHABLE = NPT_ERROR_BASE_SOCKET - 14; +const int NPT_ERROR_HOST_UNREACHABLE = NPT_ERROR_BASE_SOCKET - 15; +const int NPT_ERROR_NOT_CONNECTED = NPT_ERROR_BASE_SOCKET - 16; + +const unsigned int NPT_SOCKET_FLAG_CANCELLABLE = 1; // make the socket cancellable + +/*---------------------------------------------------------------------- +| forward references ++---------------------------------------------------------------------*/ +class NPT_Socket; + +/*---------------------------------------------------------------------- +| NPT_SocketAddress ++---------------------------------------------------------------------*/ +class NPT_SocketAddress +{ +public: + // constructors and destructor + NPT_SocketAddress() : m_Port(0) {} + NPT_SocketAddress(const NPT_IpAddress& address, NPT_IpPort port) : + m_IpAddress(address), + m_Port(port) {} + + // methods + NPT_Result SetIpAddress(const NPT_IpAddress& address) { + m_IpAddress = address; + return NPT_SUCCESS; + } + const NPT_IpAddress& GetIpAddress() const { + return m_IpAddress; + } + NPT_Result SetPort(NPT_IpPort port) { + m_Port = port; + return NPT_SUCCESS; + } + NPT_IpPort GetPort() const { + return m_Port; + } + NPT_String ToString() const; + + // operators + bool operator==(const NPT_SocketAddress& other) const; + +private: + // members + NPT_IpAddress m_IpAddress; + NPT_IpPort m_Port; +}; + +/*---------------------------------------------------------------------- +| NPT_SocketInfo ++---------------------------------------------------------------------*/ +typedef struct { + NPT_SocketAddress local_address; + NPT_SocketAddress remote_address; +} NPT_SocketInfo; + +/*---------------------------------------------------------------------- +| NPT_SocketInterface ++---------------------------------------------------------------------*/ +class NPT_SocketInterface +{ + public: + virtual ~NPT_SocketInterface() {} + + // interface methods + virtual NPT_Result Bind(const NPT_SocketAddress& address, bool reuse_address = true) = 0; + virtual NPT_Result Connect(const NPT_SocketAddress& address, NPT_Timeout timeout) = 0; + virtual NPT_Result WaitForConnection(NPT_Timeout timeout) = 0; + virtual NPT_Result GetInputStream(NPT_InputStreamReference& stream) = 0; + virtual NPT_Result GetOutputStream(NPT_OutputStreamReference& stream) = 0; + virtual NPT_Result GetInfo(NPT_SocketInfo& info) = 0; + virtual NPT_Result SetReadTimeout(NPT_Timeout timeout) = 0; + virtual NPT_Result SetWriteTimeout(NPT_Timeout timeout) = 0; + virtual NPT_Result Cancel(bool shutdown=true) = 0; +}; + +/*---------------------------------------------------------------------- +| NPT_UdpSocketInterface ++---------------------------------------------------------------------*/ +class NPT_UdpSocketInterface +{ + public: + virtual ~NPT_UdpSocketInterface() {} + + // methods + virtual NPT_Result Send(const NPT_DataBuffer& packet, + const NPT_SocketAddress* address = NULL) = 0; + virtual NPT_Result Receive(NPT_DataBuffer& packet, + NPT_SocketAddress* address = NULL) = 0; +}; + +/*---------------------------------------------------------------------- +| NPT_UdpMulticastSocketInterface ++---------------------------------------------------------------------*/ +class NPT_UdpMulticastSocketInterface +{ + public: + virtual ~NPT_UdpMulticastSocketInterface() {} + + // methods + virtual NPT_Result JoinGroup(const NPT_IpAddress& group, + const NPT_IpAddress& iface) = 0; + virtual NPT_Result LeaveGroup(const NPT_IpAddress& group, + const NPT_IpAddress& iface) = 0; + virtual NPT_Result SetTimeToLive(unsigned char ttl) = 0; + virtual NPT_Result SetInterface(const NPT_IpAddress& iface) = 0; +}; + +/*---------------------------------------------------------------------- +| NPT_TcpServerSocketInterface ++---------------------------------------------------------------------*/ +class NPT_TcpServerSocketInterface +{ + public: + virtual ~NPT_TcpServerSocketInterface() {} + + // interface methods + virtual NPT_Result Listen(unsigned int max_clients) = 0; + virtual NPT_Result WaitForNewClient(NPT_Socket*& client, + NPT_Timeout timeout, + NPT_Flags flags) = 0; +}; + +/*---------------------------------------------------------------------- +| NPT_Socket ++---------------------------------------------------------------------*/ +class NPT_Socket : public NPT_SocketInterface +{ +public: + // static methods + static NPT_Result CancelBlockerSocket(NPT_Thread::ThreadId thread_id); + + // constructor and destructor + explicit NPT_Socket(NPT_SocketInterface* delegate) : m_SocketDelegate(delegate) {} + ~NPT_Socket() override; + + // delegate NPT_SocketInterface methods + NPT_Result Bind(const NPT_SocketAddress& address, bool reuse_address = true) override { + return m_SocketDelegate->Bind(address, reuse_address); + } + NPT_Result Connect(const NPT_SocketAddress& address, + NPT_Timeout timeout = NPT_TIMEOUT_INFINITE) override { + return m_SocketDelegate->Connect(address, timeout); + } + NPT_Result WaitForConnection(NPT_Timeout timeout = NPT_TIMEOUT_INFINITE) override { + return m_SocketDelegate->WaitForConnection(timeout); + } + NPT_Result GetInputStream(NPT_InputStreamReference& stream) override { + return m_SocketDelegate->GetInputStream(stream); + } + NPT_Result GetOutputStream(NPT_OutputStreamReference& stream) override { + return m_SocketDelegate->GetOutputStream(stream); + } + NPT_Result GetInfo(NPT_SocketInfo& info) override { + return m_SocketDelegate->GetInfo(info); + } + NPT_Result SetReadTimeout(NPT_Timeout timeout) override { + return m_SocketDelegate->SetReadTimeout(timeout); + } + NPT_Result SetWriteTimeout(NPT_Timeout timeout) override { + return m_SocketDelegate->SetWriteTimeout(timeout); + } + NPT_Result Cancel(bool shutdown=true) override { + return m_SocketDelegate->Cancel(shutdown); + } + +protected: + // constructor + NPT_Socket() : m_SocketDelegate(NULL) {} + + // members + NPT_SocketInterface* m_SocketDelegate; +}; + +typedef NPT_Reference<NPT_Socket> NPT_SocketReference; + +/*---------------------------------------------------------------------- +| NPT_UdpSocket ++---------------------------------------------------------------------*/ +class NPT_UdpSocket : public NPT_Socket, + public NPT_UdpSocketInterface +{ + public: + // constructor and destructor + NPT_UdpSocket(NPT_Flags flags=0); + ~NPT_UdpSocket() override; + + // delegate NPT_UdpSocketInterface methods + NPT_Result Send(const NPT_DataBuffer& packet, + const NPT_SocketAddress* address = NULL) override { + return m_UdpSocketDelegate->Send(packet, address); + } + NPT_Result Receive(NPT_DataBuffer& packet, + NPT_SocketAddress* address = NULL) override { + return m_UdpSocketDelegate->Receive(packet, address); + } + +protected: + // constructor + NPT_UdpSocket(NPT_UdpSocketInterface* delegate); + + // members + NPT_UdpSocketInterface* m_UdpSocketDelegate; +}; + +/*---------------------------------------------------------------------- +| NPT_UdpMulticastSocket ++---------------------------------------------------------------------*/ +class NPT_UdpMulticastSocket : public NPT_UdpSocket, + public NPT_UdpMulticastSocketInterface +{ +public: + // constructor and destructor + NPT_UdpMulticastSocket(NPT_Flags flags=0); + ~NPT_UdpMulticastSocket() override; + + // delegate NPT_UdpMulticastSocketInterface methods + NPT_Result JoinGroup(const NPT_IpAddress& group, + const NPT_IpAddress& iface = + NPT_IpAddress::Any) override { + return m_UdpMulticastSocketDelegate->JoinGroup(group, iface); + } + NPT_Result LeaveGroup(const NPT_IpAddress& group, + const NPT_IpAddress& iface = + NPT_IpAddress::Any) override { + return m_UdpMulticastSocketDelegate->LeaveGroup(group, iface); + } + NPT_Result SetTimeToLive(unsigned char ttl) override { + return m_UdpMulticastSocketDelegate->SetTimeToLive(ttl); + } + NPT_Result SetInterface(const NPT_IpAddress& iface) override { + return m_UdpMulticastSocketDelegate->SetInterface(iface); + } + +protected: + // members + NPT_UdpMulticastSocketInterface* m_UdpMulticastSocketDelegate; +}; + +/*---------------------------------------------------------------------- +| NPT_TcpClientSocket ++---------------------------------------------------------------------*/ +class NPT_TcpClientSocket : public NPT_Socket +{ +public: + // constructors and destructor + NPT_TcpClientSocket(NPT_Flags flags=0); + ~NPT_TcpClientSocket() override; +}; + +/*---------------------------------------------------------------------- +| NPT_TcpServerSocket ++---------------------------------------------------------------------*/ +class NPT_TcpServerSocket : public NPT_Socket, + public NPT_TcpServerSocketInterface +{ +public: + // constructors and destructor + NPT_TcpServerSocket(NPT_Flags flags=0); + ~NPT_TcpServerSocket() override; + + // delegate NPT_TcpServerSocketInterface methods + NPT_Result Listen(unsigned int max_clients) override { + return m_TcpServerSocketDelegate->Listen(max_clients); + } + NPT_Result WaitForNewClient(NPT_Socket*& client, + NPT_Timeout timeout = NPT_TIMEOUT_INFINITE, + NPT_Flags flags = 0) override { + return m_TcpServerSocketDelegate->WaitForNewClient(client, timeout, flags); + } + +protected: + // members + NPT_TcpServerSocketInterface* m_TcpServerSocketDelegate; +}; + +#endif // _NPT_SOCKETS_H_ diff --git a/lib/libUPnP/Neptune/Source/Core/NptStack.h b/lib/libUPnP/Neptune/Source/Core/NptStack.h new file mode 100644 index 0000000..5078805 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptStack.h @@ -0,0 +1,74 @@ +/***************************************************************** +| +| Neptune - Stack +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| +****************************************************************/ + +#ifndef _NPT_STACK_H_ +#define _NPT_STACK_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptResults.h" +#include "NptTypes.h" +#include "NptList.h" + +/*---------------------------------------------------------------------- +| NPT_Stack ++---------------------------------------------------------------------*/ +template <typename T> +class NPT_Stack : public NPT_List<T> +{ +public: + // methods + NPT_Result Push(const T& value) { + // NOTE: we must use the this-> accessor here because the standard + // requires it when the member to look up is in a parent template + return this->Add(value); + } + + NPT_Result Peek(T& value) { + // NOTE: we must use the this-> accessor here because the standard + // requires it when the member to look up is in a parent template + if (this->m_ItemCount == 0) return NPT_ERROR_NO_SUCH_ITEM; + value = this->m_Tail->m_Data; + return NPT_SUCCESS; + } + + NPT_Result Pop(T& value) { + // NOTE: we must use the this-> accessor here because the standard + // requires it when the member to look up is in a parent template + if (this->m_ItemCount == 0) return NPT_ERROR_NO_SUCH_ITEM; + typename NPT_List<T>::Iterator tail = this->GetLastItem(); + value = *tail; + return this->Erase(tail); + } +}; + +#endif // _NPT_STACK_H_ diff --git a/lib/libUPnP/Neptune/Source/Core/NptStreams.cpp b/lib/libUPnP/Neptune/Source/Core/NptStreams.cpp new file mode 100644 index 0000000..79909fa --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptStreams.cpp @@ -0,0 +1,724 @@ +/***************************************************************** +| +| Neptune - Byte Streams +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptStreams.h" +#include "NptUtils.h" +#include "NptConstants.h" +#include "NptStrings.h" +#include "NptDebug.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const NPT_Size NPT_INPUT_STREAM_LOAD_DEFAULT_READ_CHUNK = 4096; +const NPT_LargeSize NPT_INPUT_STREAM_LOAD_MAX_SIZE = 0x40000000; // 1GB + +/*---------------------------------------------------------------------- +| NPT_InputStream::Load ++---------------------------------------------------------------------*/ +NPT_Result +NPT_InputStream::Load(NPT_DataBuffer& buffer, NPT_Size max_read /* = 0 */) +{ + NPT_Result result; + NPT_LargeSize total_bytes_read; + + // reset the buffer + buffer.SetDataSize(0); + + // check the limits + if (max_read > NPT_INPUT_STREAM_LOAD_MAX_SIZE) { + return NPT_ERROR_INVALID_PARAMETERS; + } + + // try to get the stream size + NPT_LargeSize size; + if (NPT_SUCCEEDED(GetSize(size))) { + // make sure we don't read more than max_read + if (max_read && max_read < size) size = max_read; + if (size > NPT_INPUT_STREAM_LOAD_MAX_SIZE) { + return NPT_ERROR_OUT_OF_RANGE; + } + } else { + size = max_read; + } + + // pre-allocate the buffer + if (size) NPT_CHECK(buffer.Reserve((NPT_Size)size)); + + // read the data from the file + total_bytes_read = 0; + do { + NPT_LargeSize available = 0; + NPT_LargeSize bytes_to_read; + NPT_Size bytes_read; + NPT_Byte* data; + + // check if we know how much data is available + result = GetAvailable(available); + if (NPT_SUCCEEDED(result) && available) { + // we know how much is available + bytes_to_read = available; + } else { + bytes_to_read = NPT_INPUT_STREAM_LOAD_DEFAULT_READ_CHUNK; + } + + // make sure we don't read more than what was asked + if (size != 0 && total_bytes_read+bytes_to_read>size) { + bytes_to_read = size-total_bytes_read; + } + + // stop if we've read everything + if (bytes_to_read == 0) break; + + // ensure that the buffer has enough space + if (total_bytes_read+bytes_to_read > NPT_INPUT_STREAM_LOAD_MAX_SIZE) { + buffer.SetBufferSize(0); + return NPT_ERROR_OUT_OF_RANGE; + } + NPT_CHECK(buffer.Reserve((NPT_Size)(total_bytes_read+bytes_to_read))); + + // read the data + data = buffer.UseData()+total_bytes_read; + result = Read((void*)data, (NPT_Size)bytes_to_read, &bytes_read); + if (NPT_SUCCEEDED(result) && bytes_read != 0) { + total_bytes_read += bytes_read; + buffer.SetDataSize((NPT_Size)total_bytes_read); + } + } while(NPT_SUCCEEDED(result) && (size==0 || total_bytes_read < size)); + + if (result == NPT_ERROR_EOS) { + return NPT_SUCCESS; + } else { + return result; + } +} + +/*---------------------------------------------------------------------- +| NPT_InputStream::ReadFully ++---------------------------------------------------------------------*/ +NPT_Result +NPT_InputStream::ReadFully(void* buffer, NPT_Size bytes_to_read) +{ + // shortcut + if (bytes_to_read == 0) return NPT_SUCCESS; + + // read until failure + NPT_Size bytes_read; + while (bytes_to_read) { + NPT_Result result = Read(buffer, bytes_to_read, &bytes_read); + if (NPT_FAILED(result)) return result; + if (bytes_read == 0) return NPT_ERROR_INTERNAL; + NPT_ASSERT(bytes_read <= bytes_to_read); + bytes_to_read -= bytes_read; + buffer = (void*)(((NPT_Byte*)buffer)+bytes_read); + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_InputStream::ReadUI64 ++---------------------------------------------------------------------*/ +NPT_Result +NPT_InputStream::ReadUI64(NPT_UInt64& value) +{ + unsigned char buffer[8]; + + // read bytes from the stream + NPT_Result result; + result = ReadFully((void*)buffer, 8); + if (NPT_FAILED(result)) { + value = 0; + return result; + } + + // convert bytes to value + value = NPT_BytesToInt64Be(buffer); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_InputStream::ReadUI32 ++---------------------------------------------------------------------*/ +NPT_Result +NPT_InputStream::ReadUI32(NPT_UInt32& value) +{ + unsigned char buffer[4]; + + // read bytes from the stream + NPT_Result result; + result = ReadFully((void*)buffer, 4); + if (NPT_FAILED(result)) { + value = 0; + return result; + } + + // convert bytes to value + value = NPT_BytesToInt32Be(buffer); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_InputStream::ReadUI24 ++---------------------------------------------------------------------*/ +NPT_Result +NPT_InputStream::ReadUI24(NPT_UInt32& value) +{ + unsigned char buffer[3]; + + // read bytes from the stream + NPT_Result result; + result = ReadFully((void*)buffer, 3); + if (NPT_FAILED(result)) { + value = 0; + return result; + } + + // convert bytes to value + value = NPT_BytesToInt24Be(buffer); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_InputStream::ReadUI16 ++---------------------------------------------------------------------*/ +NPT_Result +NPT_InputStream::ReadUI16(NPT_UInt16& value) +{ + unsigned char buffer[2]; + + // read bytes from the stream + NPT_Result result; + result = ReadFully((void*)buffer, 2); + if (NPT_FAILED(result)) { + value = 0; + return result; + } + + // convert bytes to value + value = NPT_BytesToInt16Be(buffer); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_InputStream::ReadUI08 ++---------------------------------------------------------------------*/ +NPT_Result +NPT_InputStream::ReadUI08(NPT_UInt8& value) +{ + unsigned char buffer[1]; + + // read bytes from the stream + NPT_Result result; + result = ReadFully((void*)buffer, 1); + if (NPT_FAILED(result)) { + value = 0; + return result; + } + + // convert bytes to value + value = buffer[0]; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_InputStream::Skip ++---------------------------------------------------------------------*/ +NPT_Result +NPT_InputStream::Skip(NPT_Size count) +{ + // get the current location + NPT_Position position; + NPT_CHECK(Tell(position)); + + // seek ahead + return Seek(position+count); +} + +/*---------------------------------------------------------------------- +| NPT_OutputStream::WriteFully ++---------------------------------------------------------------------*/ +NPT_Result +NPT_OutputStream::WriteFully(const void* buffer, NPT_Size bytes_to_write) +{ + // shortcut + if (bytes_to_write == 0) return NPT_SUCCESS; + + // write until failure + NPT_Size bytes_written; + while (bytes_to_write) { + NPT_Result result = Write(buffer, bytes_to_write, &bytes_written); + if (NPT_FAILED(result)) return result; + if (bytes_written == 0) return NPT_ERROR_INTERNAL; + NPT_ASSERT(bytes_written <= bytes_to_write); + bytes_to_write -= bytes_written; + buffer = (const void*)(((const NPT_Byte*)buffer)+bytes_written); + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_OutputStream::WriteString ++---------------------------------------------------------------------*/ +NPT_Result +NPT_OutputStream::WriteString(const char* buffer) +{ + // shortcut + NPT_Size string_length; + if (buffer == NULL || (string_length = NPT_StringLength(buffer)) == 0) { + return NPT_SUCCESS; + } + + // write the string + return WriteFully((const void*)buffer, string_length); +} + +/*---------------------------------------------------------------------- +| NPT_OutputStream::WriteLine ++---------------------------------------------------------------------*/ +NPT_Result +NPT_OutputStream::WriteLine(const char* buffer) +{ + NPT_CHECK(WriteString(buffer)); + NPT_CHECK(WriteFully((const void*)"\r\n", 2)); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_OutputStream::WriteUI64 ++---------------------------------------------------------------------*/ +NPT_Result +NPT_OutputStream::WriteUI64(NPT_UInt64 value) +{ + unsigned char buffer[8]; + + // convert value to bytes + NPT_BytesFromInt64Be(buffer, value); + + // write bytes to the stream + return WriteFully((void*)buffer, 8); +} + +/*---------------------------------------------------------------------- +| NPT_OutputStream::WriteUI32 ++---------------------------------------------------------------------*/ +NPT_Result +NPT_OutputStream::WriteUI32(NPT_UInt32 value) +{ + unsigned char buffer[4]; + + // convert value to bytes + NPT_BytesFromInt32Be(buffer, value); + + // write bytes to the stream + return WriteFully((void*)buffer, 4); +} + +/*---------------------------------------------------------------------- +| NPT_OutputStream::WriteUI24 ++---------------------------------------------------------------------*/ +NPT_Result +NPT_OutputStream::WriteUI24(NPT_UInt32 value) +{ + unsigned char buffer[3]; + + // convert value to bytes + NPT_BytesFromInt24Be(buffer, value); + + // write bytes to the stream + return WriteFully((void*)buffer, 3); +} + +/*---------------------------------------------------------------------- +| NPT_OutputStream::WriteUI16 ++---------------------------------------------------------------------*/ +NPT_Result +NPT_OutputStream::WriteUI16(NPT_UInt16 value) +{ + unsigned char buffer[2]; + + // convert value to bytes + NPT_BytesFromInt16Be(buffer, value); + + // write bytes to the stream + return WriteFully((void*)buffer, 2); +} + +/*---------------------------------------------------------------------- +| NPT_OutputStream::WriteUI08 ++---------------------------------------------------------------------*/ +NPT_Result +NPT_OutputStream::WriteUI08(NPT_UInt8 value) +{ + return WriteFully((void*)&value, 1); +} + +/*---------------------------------------------------------------------- +| NPT_MemoryStream::NPT_MemoryStream ++---------------------------------------------------------------------*/ +NPT_MemoryStream::NPT_MemoryStream(NPT_Size initial_capacity) : + m_Buffer(initial_capacity), + m_ReadOffset(0), + m_WriteOffset(0) +{ +} + +/*---------------------------------------------------------------------- +| NPT_MemoryStream::NPT_MemoryStream ++---------------------------------------------------------------------*/ +NPT_MemoryStream::NPT_MemoryStream(const void* data, NPT_Size size) : + m_Buffer(data, size), + m_ReadOffset(0), + m_WriteOffset(0) +{ +} + +/*---------------------------------------------------------------------- +| NPT_MemoryStream::Read ++---------------------------------------------------------------------*/ +NPT_Result +NPT_MemoryStream::Read(void* buffer, + NPT_Size bytes_to_read, + NPT_Size* bytes_read) +{ + // check for shortcut + if (bytes_to_read == 0) { + if (bytes_read) *bytes_read = 0; + return NPT_SUCCESS; + } + + // clip to what's available + NPT_Size available = m_Buffer.GetDataSize(); + if (m_ReadOffset+bytes_to_read > available) { + bytes_to_read = available-m_ReadOffset; + } + + // copy the data + if (bytes_to_read) { + NPT_CopyMemory(buffer, (void*)(((char*)m_Buffer.UseData())+m_ReadOffset), bytes_to_read); + m_ReadOffset += bytes_to_read; + } + if (bytes_read) *bytes_read = bytes_to_read; + + return bytes_to_read?NPT_SUCCESS:NPT_ERROR_EOS; +} + +/*---------------------------------------------------------------------- +| NPT_MemoryStream::InputSeek ++---------------------------------------------------------------------*/ +NPT_Result +NPT_MemoryStream::InputSeek(NPT_Position offset) +{ + if (offset > m_Buffer.GetDataSize()) { + return NPT_ERROR_OUT_OF_RANGE; + } else { + m_ReadOffset = (NPT_Size)offset; + return NPT_SUCCESS; + } +} + +/*---------------------------------------------------------------------- +| NPT_MemoryStream::Write ++---------------------------------------------------------------------*/ +NPT_Result +NPT_MemoryStream::Write(const void* data, + NPT_Size bytes_to_write, + NPT_Size* bytes_written) +{ + NPT_CHECK(m_Buffer.Reserve(m_WriteOffset+bytes_to_write)); + + NPT_CopyMemory(m_Buffer.UseData()+m_WriteOffset, data, bytes_to_write); + m_WriteOffset += bytes_to_write; + if (m_WriteOffset > m_Buffer.GetDataSize()) { + m_Buffer.SetDataSize(m_WriteOffset); + } + if (bytes_written) *bytes_written = bytes_to_write; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_MemoryStream::OutputSeek ++---------------------------------------------------------------------*/ +NPT_Result +NPT_MemoryStream::OutputSeek(NPT_Position offset) +{ + if (offset <= m_Buffer.GetDataSize()) { + m_WriteOffset = (NPT_Size)offset; + return NPT_SUCCESS; + } else { + return NPT_ERROR_OUT_OF_RANGE; + } +} + +/*---------------------------------------------------------------------- +| NPT_MemoryStream::SetDataSize ++---------------------------------------------------------------------*/ +NPT_Result +NPT_MemoryStream::SetDataSize(NPT_Size size) +{ + // update data amount in buffer + NPT_CHECK(m_Buffer.SetDataSize(size)); + + // adjust the read and write offsets + if (m_ReadOffset > size) m_ReadOffset = size; + if (m_WriteOffset > size) m_WriteOffset = size; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_StreamToStreamCopy ++---------------------------------------------------------------------*/ +const unsigned int NPT_STREAM_COPY_BUFFER_SIZE = 65536; // copy 64k at a time +NPT_Result +NPT_StreamToStreamCopy(NPT_InputStream& from, + NPT_OutputStream& to, + NPT_Position offset /* = 0 */, + NPT_LargeSize size /* = 0, 0 means the entire stream */, + NPT_LargeSize* bytes_written /* = NULL */) +{ + // default values + if (bytes_written) *bytes_written = 0; + + // seek into the input if required + if (offset) { + NPT_CHECK(from.Seek(offset)); + } + + // allocate a buffer for the transfer + NPT_LargeSize bytes_transfered = 0; + NPT_Byte* buffer = new NPT_Byte[NPT_STREAM_COPY_BUFFER_SIZE]; + NPT_Result result = NPT_SUCCESS; + if (buffer == NULL) return NPT_ERROR_OUT_OF_MEMORY; + + // copy until an error occurs or the end of stream is reached + for (;;) { + // read some data + NPT_Size bytes_to_read = NPT_STREAM_COPY_BUFFER_SIZE; + NPT_Size bytes_read = 0; + if (size) { + // a max size was specified + if (size-bytes_transfered < NPT_STREAM_COPY_BUFFER_SIZE) { + bytes_to_read = (NPT_Size)(size-bytes_transfered); + } + } + result = from.Read(buffer, bytes_to_read, &bytes_read); + if (NPT_FAILED(result)) { + if (result == NPT_ERROR_EOS) result = NPT_SUCCESS; + break; + } + if (bytes_read == 0) continue; + + NPT_Size buffer_bytes_to_write = bytes_read; + NPT_Byte* buffer_bytes = (NPT_Byte*)buffer; + while (buffer_bytes_to_write) { + NPT_Size buffer_bytes_written = 0; + result = to.Write(buffer_bytes, buffer_bytes_to_write, &buffer_bytes_written); + if (NPT_FAILED(result)) goto end; + NPT_ASSERT(buffer_bytes_written <= buffer_bytes_to_write); + buffer_bytes_to_write -= buffer_bytes_written; + if (bytes_written) *bytes_written += buffer_bytes_written; + buffer_bytes += buffer_bytes_written; + } + + // update the counts + if (size) { + bytes_transfered += bytes_read; + if (bytes_transfered >= size) break; + } + } + +end: + // free the buffer and return + delete[] buffer; + return result; +} + +/*---------------------------------------------------------------------- +| NPT_StringOutputStream::NPT_StringOutputStream ++---------------------------------------------------------------------*/ +NPT_StringOutputStream::NPT_StringOutputStream(NPT_Size size) : + m_String(new NPT_String), + m_StringIsOwned(true) +{ + m_String->Reserve(size); +} + + +/*---------------------------------------------------------------------- +| NPT_StringOutputStream::NPT_StringOutputStream ++---------------------------------------------------------------------*/ +NPT_StringOutputStream::NPT_StringOutputStream(NPT_String* storage) : + m_String(storage), + m_StringIsOwned(false) +{ +} + +/*---------------------------------------------------------------------- +| NPT_StringOutputStream::~NPT_StringOutputStream ++---------------------------------------------------------------------*/ +NPT_StringOutputStream::~NPT_StringOutputStream() +{ + if (m_StringIsOwned) delete m_String; +} + +/*---------------------------------------------------------------------- +| NPT_StringOutputStream::Write ++---------------------------------------------------------------------*/ +NPT_Result +NPT_StringOutputStream::Write(const void* buffer, NPT_Size bytes_to_write, NPT_Size* bytes_written /* = NULL */) +{ + m_String->Append((const char*)buffer, bytes_to_write); + if (bytes_written) *bytes_written = bytes_to_write; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_SubInputStream::NPT_SubInputStream ++---------------------------------------------------------------------*/ +NPT_SubInputStream::NPT_SubInputStream(NPT_InputStreamReference& source, + NPT_Position start, + NPT_LargeSize size) : + m_Source(source), + m_Position(0), + m_Start(start), + m_Size(size) +{ +} + +/*---------------------------------------------------------------------- +| NPT_SubInputStream::Read ++---------------------------------------------------------------------*/ +NPT_Result +NPT_SubInputStream::Read(void* buffer, + NPT_Size bytes_to_read, + NPT_Size* bytes_read) +{ + // default values + if (bytes_read) *bytes_read = 0; + + // shortcut + if (bytes_to_read == 0) { + return NPT_SUCCESS; + } + + // clamp to range + if (m_Position+bytes_to_read > m_Size) { + bytes_to_read = (NPT_Size)(m_Size - m_Position); + } + + // check for end of substream + if (bytes_to_read == 0) { + return NPT_ERROR_EOS; + } + + // seek inside the source + NPT_Result result; + result = m_Source->Seek(m_Start+m_Position); + if (NPT_FAILED(result)) { + return result; + } + + // read from the source + NPT_Size source_bytes_read = 0; + result = m_Source->Read(buffer, bytes_to_read, &source_bytes_read); + if (NPT_SUCCEEDED(result)) { + m_Position += source_bytes_read; + if (bytes_read) *bytes_read = source_bytes_read; + } + return result; +} + +/*---------------------------------------------------------------------- +| NPT_SubInputStream::Seek ++---------------------------------------------------------------------*/ +NPT_Result +NPT_SubInputStream::Seek(NPT_Position position) +{ + if (position == m_Position) return NPT_SUCCESS; + if (position > m_Size) return NPT_ERROR_OUT_OF_RANGE; + m_Position = position; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_SubInputStream::Tell ++---------------------------------------------------------------------*/ +NPT_Result +NPT_SubInputStream::Tell(NPT_Position& position) +{ + position = m_Position; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_SubInputStream::GetSize ++---------------------------------------------------------------------*/ +NPT_Result +NPT_SubInputStream::GetSize(NPT_LargeSize& size) +{ + size = m_Size; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_SubInputStream::GetAvailable ++---------------------------------------------------------------------*/ +NPT_Result +NPT_SubInputStream::GetAvailable(NPT_LargeSize& available) +{ + available = m_Size-m_Position; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_NullOutputStream::Write ++---------------------------------------------------------------------*/ +NPT_Result +NPT_NullOutputStream::Write(const void* /*buffer*/, + NPT_Size bytes_to_write, + NPT_Size* bytes_written /* = NULL */) +{ + if (bytes_written) *bytes_written = bytes_to_write; + return NPT_SUCCESS; +} + diff --git a/lib/libUPnP/Neptune/Source/Core/NptStreams.h b/lib/libUPnP/Neptune/Source/Core/NptStreams.h new file mode 100644 index 0000000..bb22903 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptStreams.h @@ -0,0 +1,321 @@ +/***************************************************************** +| +| Neptune - Byte Streams +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +#ifndef _NPT_STREAMS_H_ +#define _NPT_STREAMS_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptTypes.h" +#include "NptReferences.h" +#include "NptConstants.h" +#include "NptResults.h" +#include "NptDataBuffer.h" +#include "NptStrings.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class NPT_String; + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const int NPT_ERROR_READ_FAILED = NPT_ERROR_BASE_IO - 0; +const int NPT_ERROR_WRITE_FAILED = NPT_ERROR_BASE_IO - 1; +const int NPT_ERROR_EOS = NPT_ERROR_BASE_IO - 2; + +/*---------------------------------------------------------------------- +| NPT_InputStream ++---------------------------------------------------------------------*/ +class NPT_InputStream +{ + public: + // constructor and destructor + virtual ~NPT_InputStream() {}; + + // methods + virtual NPT_Result Load(NPT_DataBuffer& buffer, NPT_Size max_read = 0); + virtual NPT_Result Read(void* buffer, + NPT_Size bytes_to_read, + NPT_Size* bytes_read = NULL) = 0; + virtual NPT_Result ReadFully(void* buffer, + NPT_Size bytes_to_read); + virtual NPT_Result Seek(NPT_Position offset) = 0; + virtual NPT_Result Skip(NPT_Size offset); + virtual NPT_Result Tell(NPT_Position& offset) = 0; + virtual NPT_Result GetSize(NPT_LargeSize& size) = 0; + virtual NPT_Result GetAvailable(NPT_LargeSize& available) = 0; + + // data access methods + NPT_Result ReadUI64(NPT_UInt64& value); + NPT_Result ReadUI32(NPT_UInt32& value); + NPT_Result ReadUI24(NPT_UInt32& value); + NPT_Result ReadUI16(NPT_UInt16& value); + NPT_Result ReadUI08(NPT_UInt8& value); +}; + +typedef NPT_Reference<NPT_InputStream> NPT_InputStreamReference; + +/*---------------------------------------------------------------------- +| NPT_OutputStream ++---------------------------------------------------------------------*/ +class NPT_OutputStream +{ +public: + // constructor and destructor + virtual ~NPT_OutputStream() {}; + + // methods + virtual NPT_Result Write(const void* buffer, + NPT_Size bytes_to_write, + NPT_Size* bytes_written = NULL) = 0; + virtual NPT_Result WriteFully(const void* buffer, + NPT_Size bytes_to_write); + virtual NPT_Result WriteString(const char* string_buffer); + virtual NPT_Result WriteLine(const char* line_buffer); + virtual NPT_Result Seek(NPT_Position offset) = 0; + virtual NPT_Result Tell(NPT_Position& offset) = 0; + virtual NPT_Result Flush() { return NPT_SUCCESS; } + + // data access methods + NPT_Result WriteUI64(NPT_UInt64 value); + NPT_Result WriteUI32(NPT_UInt32 value); + NPT_Result WriteUI24(NPT_UInt32 value); + NPT_Result WriteUI16(NPT_UInt16 value); + NPT_Result WriteUI08(NPT_UInt8 value); +}; + +typedef NPT_Reference<NPT_OutputStream> NPT_OutputStreamReference; + +/*---------------------------------------------------------------------- +| NPT_StreamToStreamCopy ++---------------------------------------------------------------------*/ +NPT_Result NPT_StreamToStreamCopy(NPT_InputStream& from, + NPT_OutputStream& to, + NPT_Position offset = 0, + NPT_LargeSize size = 0, /* 0 means the entire stream */ + NPT_LargeSize* bytes_written = NULL); + +/*---------------------------------------------------------------------- +| NPT_DelegatingInputStream +| +| Use this class as a base class if you need to inherit both from +| NPT_InputStream and NPT_OutputStream which share the Seek and Tell +| method. In this case, you override the base-specific version of +| those methods, InputSeek, InputTell, instead of the Seek and Tell +| methods. ++---------------------------------------------------------------------*/ +class NPT_DelegatingInputStream : public NPT_InputStream +{ +public: + // NPT_InputStream methods + NPT_Result Seek(NPT_Position offset) override { + return InputSeek(offset); + } + NPT_Result Tell(NPT_Position& offset) override { + return InputTell(offset); + } + +private: + // methods + virtual NPT_Result InputSeek(NPT_Position offset) = 0; + virtual NPT_Result InputTell(NPT_Position& offset) = 0; +}; + +/*---------------------------------------------------------------------- +| NPT_DelegatingOutputStream +| +| Use this class as a base class if you need to inherit both from +| NPT_InputStream and NPT_OutputStream which share the Seek and Tell +| method. In this case, you override the base-specific version of +| those methods, OutputSeek and OutputTell, instead of the Seek and +| Tell methods. ++---------------------------------------------------------------------*/ +class NPT_DelegatingOutputStream : public NPT_OutputStream +{ +public: + // NPT_OutputStream methods + NPT_Result Seek(NPT_Position offset) override { + return OutputSeek(offset); + } + NPT_Result Tell(NPT_Position& offset) override { + return OutputTell(offset); + } + +private: + // methods + virtual NPT_Result OutputSeek(NPT_Position offset) = 0; + virtual NPT_Result OutputTell(NPT_Position& offset) = 0; +}; + +/*---------------------------------------------------------------------- +| NPT_MemoryStream ++---------------------------------------------------------------------*/ +class NPT_MemoryStream : + public NPT_DelegatingInputStream, + public NPT_DelegatingOutputStream +{ +public: + // constructor and destructor + NPT_MemoryStream(NPT_Size initial_capacity = 0); + NPT_MemoryStream(const void* data, NPT_Size size); + ~NPT_MemoryStream() override {} + + // accessors + const NPT_DataBuffer& GetBuffer() const { return m_Buffer; } + + // NPT_InputStream methods + NPT_Result Read(void* buffer, + NPT_Size bytes_to_read, + NPT_Size* bytes_read = NULL) override; + NPT_Result GetSize(NPT_LargeSize& size) override { + size = m_Buffer.GetDataSize(); + return NPT_SUCCESS; + } + NPT_Result GetAvailable(NPT_LargeSize& available) override { + available = (NPT_LargeSize)m_Buffer.GetDataSize()-m_ReadOffset; + return NPT_SUCCESS; + } + + // NPT_OutputStream methods + NPT_Result Write(const void* buffer, + NPT_Size bytes_to_write, + NPT_Size* bytes_written = NULL) override; + + // methods delegated to m_Buffer + const NPT_Byte* GetData() const { return m_Buffer.GetData(); } + NPT_Byte* UseData() { return m_Buffer.UseData(); } + NPT_Size GetDataSize() const { return m_Buffer.GetDataSize(); } + NPT_Size GetBufferSize() const { return m_Buffer.GetBufferSize();} + + // methods + NPT_Result SetDataSize(NPT_Size size); + +private: + // NPT_DelegatingInputStream methods + NPT_Result InputSeek(NPT_Position offset) override; + NPT_Result InputTell(NPT_Position& offset) override { + offset = m_ReadOffset; + return NPT_SUCCESS; + } + + // NPT_DelegatingOutputStream methods + NPT_Result OutputSeek(NPT_Position offset) override; + NPT_Result OutputTell(NPT_Position& offset) override { + offset = m_WriteOffset; + return NPT_SUCCESS; + } + +protected: + // members + NPT_DataBuffer m_Buffer; + NPT_Size m_ReadOffset; + NPT_Size m_WriteOffset; +}; + +typedef NPT_Reference<NPT_MemoryStream> NPT_MemoryStreamReference; + +/*---------------------------------------------------------------------- +| NPT_StringOutputStream ++---------------------------------------------------------------------*/ +class NPT_StringOutputStream : public NPT_OutputStream +{ +public: + // methods + NPT_StringOutputStream(NPT_Size size = 4096); + NPT_StringOutputStream(NPT_String* storage); + ~NPT_StringOutputStream() override ; + + const NPT_String& GetString() const { return *m_String; } + NPT_Result Reset() { if (m_String) m_String->SetLength(0); return NPT_SUCCESS; } + + // NPT_OutputStream methods + NPT_Result Write(const void* buffer, NPT_Size bytes_to_write, NPT_Size* bytes_written = NULL) override; + + NPT_Result Seek(NPT_Position /*offset*/) override { return NPT_ERROR_NOT_SUPPORTED; } + NPT_Result Tell(NPT_Position& offset) override { offset = m_String->GetLength(); return NPT_SUCCESS; } + +protected: + NPT_String* m_String; + bool m_StringIsOwned; +}; + +typedef NPT_Reference<NPT_StringOutputStream> NPT_StringOutputStreamReference; + +/*---------------------------------------------------------------------- +| NPT_SubInputStream ++---------------------------------------------------------------------*/ +class NPT_SubInputStream : public NPT_InputStream +{ +public: + // constructor and destructor + NPT_SubInputStream(NPT_InputStreamReference& source, + NPT_Position start, + NPT_LargeSize size); + + // methods + NPT_Result Read(void* buffer, + NPT_Size bytes_to_read, + NPT_Size* bytes_read = NULL) override; + NPT_Result Seek(NPT_Position offset) override; + NPT_Result Tell(NPT_Position& offset) override; + NPT_Result GetSize(NPT_LargeSize& size) override; + NPT_Result GetAvailable(NPT_LargeSize& available) override; + +private: + NPT_InputStreamReference m_Source; + NPT_Position m_Position; + NPT_Position m_Start; + NPT_LargeSize m_Size; +}; + +/*---------------------------------------------------------------------- +| NPT_NullOutputStream ++---------------------------------------------------------------------*/ +class NPT_NullOutputStream : public NPT_OutputStream +{ +public: + // methods + NPT_NullOutputStream() {} + ~NPT_NullOutputStream() override {} + + // NPT_OutputStream methods + NPT_Result Write(const void* buffer, NPT_Size bytes_to_write, NPT_Size* bytes_written = NULL) override; + + NPT_Result Seek(NPT_Position /*offset*/) override { return NPT_ERROR_NOT_SUPPORTED; } + NPT_Result Tell(NPT_Position& /*offset*/) override { return NPT_ERROR_NOT_SUPPORTED; } +}; + +typedef NPT_Reference<NPT_NullOutputStream> NPT_NullOutputStreamReference; + +#endif // _NPT_STREAMS_H_ diff --git a/lib/libUPnP/Neptune/Source/Core/NptStrings.cpp b/lib/libUPnP/Neptune/Source/Core/NptStrings.cpp new file mode 100644 index 0000000..819d9a2 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptStrings.cpp @@ -0,0 +1,1205 @@ +/***************************************************************** +| +| Neptune - String Objects +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptConfig.h" +#include "NptTypes.h" +#include "NptConstants.h" +#include "NptStrings.h" +#include "NptResults.h" +#include "NptUtils.h" +#include "NptDebug.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +#define NPT_STRINGS_WHITESPACE_CHARS "\r\n\t " + +const unsigned int NPT_STRING_FORMAT_BUFFER_DEFAULT_SIZE = 256; +const unsigned int NPT_STRING_FORMAT_BUFFER_MAX_SIZE = 0x80000; // 512k + +/*---------------------------------------------------------------------- +| helpers ++---------------------------------------------------------------------*/ +inline char NPT_Uppercase(char x) { + return (x >= 'a' && x <= 'z') ? x&0xdf : x; +} + +inline char NPT_Lowercase(char x) { + return (x >= 'A' && x <= 'Z') ? x^32 : x; +} + +/*---------------------------------------------------------------------- +| NPT_String::EmptyString ++---------------------------------------------------------------------*/ +char NPT_String::EmptyString = '\0'; + +/*---------------------------------------------------------------------- +| NPT_String::FromInteger ++---------------------------------------------------------------------*/ +NPT_String +NPT_String::FromInteger(NPT_Int64 value) +{ + char str[32]; + char* c = &str[31]; + *c-- = '\0'; + + // handle the sign + bool negative = false; + if (value < 0) { + negative = true; + value = -value; + } + + // process the digits + do { + int digit = (int)(value%10); + *c-- = '0'+digit; + value /= 10; + } while(value); + + if (negative) { + *c = '-'; + } else { + ++c; + } + + return NPT_String(c); +} + +/*---------------------------------------------------------------------- +| NPT_String::FromIntegerU ++---------------------------------------------------------------------*/ +NPT_String +NPT_String::FromIntegerU(NPT_UInt64 value) +{ + char str[32]; + char* c = &str[31]; + *c = '\0'; + + // process the digits + do { + int digit = (int)(value%10); + *--c = '0'+digit; + value /= 10; + } while(value); + + return NPT_String(c); +} + +/*---------------------------------------------------------------------- +| NPT_String::Format ++---------------------------------------------------------------------*/ +NPT_String +NPT_String::Format(const char* format, ...) +{ + NPT_String result; + NPT_Size buffer_size = NPT_STRING_FORMAT_BUFFER_DEFAULT_SIZE; // default value + + va_list args; + + for(;;) { + /* try to format (it might not fit) */ + result.Reserve(buffer_size); + char* buffer = result.UseChars(); + va_start(args, format); + int f_result = NPT_FormatStringVN(buffer, buffer_size, format, args); + va_end(args); + if (f_result >= (int)(buffer_size)) f_result = -1; + if (f_result >= 0) { + result.SetLength(f_result); + break; + } + + /* the buffer was too small, try something bigger */ + /* (we don't trust the return value of NPT_FormatStringVN */ + /* for the actual size needed) */ + buffer_size *= 2; + if (buffer_size > NPT_STRING_FORMAT_BUFFER_MAX_SIZE) break; + } + + return result; +} + +/*---------------------------------------------------------------------- +| NPT_String::NPT_String ++---------------------------------------------------------------------*/ +NPT_String::NPT_String(const char* str) +{ + if (str == NULL) { + m_Chars = NULL; + } else { + m_Chars = Buffer::Create(str); + } +} + +/*---------------------------------------------------------------------- +| NPT_String::NPT_String ++---------------------------------------------------------------------*/ +NPT_String::NPT_String(const char* str, NPT_Size length) +{ + if (str == NULL || length == 0) { + m_Chars = NULL; + } else { + for (unsigned int i=0; i<length-1; i++) { + if (str[i] == '\0') { + if (i == 0) { + m_Chars = NULL; + return; + } + length = i; + break; + } + } + m_Chars = Buffer::Create(str, length); + } +} + +/*---------------------------------------------------------------------- +| NPT_String::NPT_String ++---------------------------------------------------------------------*/ +NPT_String::NPT_String(const NPT_String& str) +{ + if (str.GetLength() == 0) { + m_Chars = NULL; + } else { + m_Chars = Buffer::Create(str.GetChars(), str.GetLength()); + } +} + +/*---------------------------------------------------------------------- +| NPT_String::NPT_String ++---------------------------------------------------------------------*/ +NPT_String::NPT_String(char c, NPT_Cardinal repeat) +{ + if (repeat != 0) { + m_Chars = Buffer::Create(c, repeat); + } else { + m_Chars = NULL; + } +} + +/*---------------------------------------------------------------------- +| NPT_String::SetLength ++---------------------------------------------------------------------*/ +NPT_Result +NPT_String::SetLength(NPT_Size length, bool pad) +{ + // special case for 0 + if (length == 0) { + Reset(); + return NPT_SUCCESS; + } + + // reserve the space + Reserve(length); + + // pad with spaces if necessary + char* chars = UseChars(); + if (pad) { + unsigned int current_length = GetLength(); + if (length > current_length) { + unsigned int pad_length = length-current_length; + NPT_SetMemory(chars+current_length, ' ', pad_length); + } + } + + // update the length and terminate the buffer + GetBuffer()->SetLength(length); + chars[length] = '\0'; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_String::PrepareToWrite ++---------------------------------------------------------------------*/ +inline char* +NPT_String::PrepareToWrite(NPT_Size length) +{ + NPT_ASSERT(length != 0); + if (m_Chars == NULL || GetBuffer()->GetAllocated() < length) { + // the buffer is too small, we need to allocate a new one. + NPT_Size needed = length; + if (m_Chars != NULL) { + NPT_Size grow = GetBuffer()->GetAllocated()*2; + if (grow > length) needed = grow; + delete GetBuffer(); + } + m_Chars = Buffer::Create(needed); + } + GetBuffer()->SetLength(length); + return m_Chars; +} + +/*---------------------------------------------------------------------- +| NPT_String::Reserve ++---------------------------------------------------------------------*/ +void +NPT_String::Reserve(NPT_Size allocate) +{ + if (m_Chars == NULL || GetBuffer()->GetAllocated() < allocate) { + // the buffer is too small, we need to allocate a new one. + NPT_Size needed = allocate; + if (m_Chars != NULL) { + NPT_Size grow = GetBuffer()->GetAllocated()*2; + if (grow > allocate) needed = grow; + } + NPT_Size length = GetLength(); + char* copy = Buffer::Create(needed, length); + if (m_Chars != NULL) { + CopyString(copy, m_Chars); + delete GetBuffer(); + } else { + copy[0] = '\0'; + } + m_Chars = copy; + } +} + +/*---------------------------------------------------------------------- +| NPT_String::Assign ++---------------------------------------------------------------------*/ +void +NPT_String::Assign(const char* str, NPT_Size length) +{ + if (str == NULL || length == 0) { + Reset(); + } else { + for (unsigned int i=0; i<length-1; i++) { + if (str[i] == '\0') { + if (i == 0) { + Reset(); + return; + } else { + length = i; + break; + } + } + } + PrepareToWrite(length); + CopyBuffer(m_Chars, str, length); + m_Chars[length] = '\0'; + } +} + +/*---------------------------------------------------------------------- +| NPT_String::operator= ++---------------------------------------------------------------------*/ +NPT_String& +NPT_String::operator=(const char* str) +{ + if (str == NULL) { + Reset(); + } else { + NPT_Size length = StringLength(str); + if (length == 0) { + Reset(); + } else { + CopyString(PrepareToWrite(length), str); + } + } + + return *this; +} + +/*---------------------------------------------------------------------- +| NPT_String::operator= ++---------------------------------------------------------------------*/ +NPT_String& +NPT_String::operator=(const NPT_String& str) +{ + // do nothing if we're assigning to ourselves + if (this != &str) { + Assign(str.GetChars(), str.GetLength()); + } + return *this; +} + +/*---------------------------------------------------------------------- +| NPT_String::GetHash32 ++---------------------------------------------------------------------*/ +NPT_UInt32 +NPT_String::GetHash32() const +{ + return NPT_Fnv1aHashStr32(GetChars()); +} + +/*---------------------------------------------------------------------- +| NPT_String::GetHash64 ++---------------------------------------------------------------------*/ +NPT_UInt64 +NPT_String::GetHash64() const +{ + return NPT_Fnv1aHashStr64(GetChars()); +} + +/*---------------------------------------------------------------------- +| NPT_String::Append ++---------------------------------------------------------------------*/ +void +NPT_String::Append(const char* str, NPT_Size length) +{ + // shortcut + if (str == NULL || length == 0) return; + + // compute the new length + NPT_Size old_length = GetLength(); + NPT_Size new_length = old_length + length; + + // allocate enough space + Reserve(new_length); + + // append the new string at the end of the current one + CopyBuffer(m_Chars+old_length, str, length); + m_Chars[new_length] = '\0'; + + // update the length + GetBuffer()->SetLength(new_length); +} + +/*---------------------------------------------------------------------- +| NPT_String::Compare ++---------------------------------------------------------------------*/ +int +NPT_String::Compare(const char *s, bool ignore_case) const +{ + return NPT_String::Compare(GetChars(), s, ignore_case); +} + +/*---------------------------------------------------------------------- +| NPT_String::Compare ++---------------------------------------------------------------------*/ +int +NPT_String::Compare(const char *s1, const char *s2, bool ignore_case) +{ + const char *r1 = s1; + const char *r2 = s2; + + if (ignore_case) { + while (NPT_Uppercase(*r1) == NPT_Uppercase(*r2)) { + if (*r1++ == '\0') { + return 0; + } + r2++; + } + return NPT_Uppercase(*r1) - NPT_Uppercase(*r2); + } else { + while (*r1 == *r2) { + if (*r1++ == '\0') { + return 0; + } + r2++; + } + return (*r1 - *r2); + } +} + +/*---------------------------------------------------------------------- +| NPT_String::CompareN ++---------------------------------------------------------------------*/ +int +NPT_String::CompareN(const char *s, NPT_Size count, bool ignore_case) const +{ + return NPT_String::CompareN(GetChars(), s, count, ignore_case); +} + +/*---------------------------------------------------------------------- +| NPT_String::CompareN ++---------------------------------------------------------------------*/ +int +NPT_String::CompareN(const char* s1, const char *s2, NPT_Size count, bool ignore_case) +{ + const char* me = s1; + + if (ignore_case) { + for (unsigned int i=0; i<count; i++) { + if (NPT_Uppercase(me[i]) != NPT_Uppercase(s2[i])) { + return NPT_Uppercase(me[i]) - NPT_Uppercase(s2[i]); + } + } + return 0; + } else { + for (unsigned int i=0; i<count; i++) { + if (me[i] != s2[i]) { + return (me[i] - s2[i]); + } + } + return 0; + } +} + +/*---------------------------------------------------------------------- +| NPT_String::Split ++---------------------------------------------------------------------*/ +NPT_List<NPT_String> +NPT_String::Split(const char* separator) const +{ + NPT_List<NPT_String> result; + NPT_Size separator_length = NPT_StringLength(separator); + + // sepcial case for empty separators + if (separator_length == 0) { + result.Add(*this); + return result; + } + + int current = 0; + int next; + do { + next = Find(separator, current); + unsigned int end = (next>=0?(unsigned int)next:GetLength()); + result.Add(SubString(current, end-current)); + current = next+separator_length; + } while (next >= 0); + + return result; +} + +/*---------------------------------------------------------------------- +| NPT_String::SplitAny ++---------------------------------------------------------------------*/ +NPT_Array<NPT_String> +NPT_String::SplitAny(const char* separator) const +{ + NPT_Array<NPT_String> result((GetLength()>>1)+1); + + // sepcial case for empty separators + if (NPT_StringLength(separator) == 0) { + result.Add(*this); + return result; + } + + int current = 0; + int next; + do { + next = FindAny(separator, current); + unsigned int end = (next>=0?(unsigned int)next:GetLength()); + result.Add(SubString(current, end-current)); + current = next+1; + } while (next >= 0); + + return result; +} + +/*---------------------------------------------------------------------- +| NPT_String::Join ++---------------------------------------------------------------------*/ +NPT_String +NPT_String::Join(NPT_List<NPT_String>& args, const char* separator) +{ + NPT_String output; + NPT_List<NPT_String>::Iterator arg = args.GetFirstItem(); + while (arg) { + output += *arg; + if (++arg) output += separator; + } + + return output; +} + +/*---------------------------------------------------------------------- +| NPT_String::SubString ++---------------------------------------------------------------------*/ +NPT_String +NPT_String::SubString(NPT_Ordinal first, NPT_Size length) const +{ + if (first >= GetLength()) { + first = GetLength(); + length = 0; + } else if (first+length >= GetLength()) { + length = GetLength()-first; + } + return NPT_String(GetChars()+first, length); +} + +/*---------------------------------------------------------------------- +| NPT_StringStartsWith +| +| returns: +| 1 if str starts with sub, +| 0 if str is large enough but does not start with sub +| -1 if str is too short to start with sub ++---------------------------------------------------------------------*/ +static inline int +NPT_StringStartsWith(const char* str, const char* sub, bool ignore_case) +{ + if (ignore_case) { + while (NPT_Uppercase(*str) == NPT_Uppercase(*sub)) { + if (*str++ == '\0') { + return 1; + } + sub++; + } + } else { + while (*str == *sub) { + if (*str++ == '\0') { + return 1; + } + sub++; + } + } + return (*sub == '\0') ? 1 : (*str == '\0' ? -1 : 0); +} + +/*---------------------------------------------------------------------- +| NPT_String::StartsWith ++---------------------------------------------------------------------*/ +bool +NPT_String::StartsWith(const char *s, bool ignore_case) const +{ + if (s == NULL) return false; + return NPT_StringStartsWith(GetChars(), s, ignore_case) == 1; +} + +/*---------------------------------------------------------------------- +| NPT_String::EndsWith ++---------------------------------------------------------------------*/ +bool +NPT_String::EndsWith(const char *s, bool ignore_case) const +{ + if (s == NULL) return false; + NPT_Size str_length = NPT_StringLength(s); + if (str_length > GetLength()) return false; + return NPT_StringStartsWith(GetChars()+GetLength()-str_length, s, ignore_case) == 1; +} + +/*---------------------------------------------------------------------- +| NPT_String::Find ++---------------------------------------------------------------------*/ +int +NPT_String::Find(const char* str, NPT_Ordinal start, bool ignore_case) const +{ + // check args + if (str == NULL || start >= GetLength()) return -1; + + // skip to start position + const char* src = m_Chars + start; + + // look for a substring + while (*src) { + int cmp = NPT_StringStartsWith(src, str, ignore_case); + switch (cmp) { + case -1: + // ref is too short, abort + return -1; + case 1: + // match + return (int)(src-m_Chars); + } + src++; + } + + return -1; +} + +/*---------------------------------------------------------------------- +| NPT_String::Find ++---------------------------------------------------------------------*/ +int +NPT_String::Find(char c, NPT_Ordinal start, bool ignore_case) const +{ + // check args + if (start >= GetLength()) return -1; + + // skip to start position + const char* src = m_Chars + start; + + // look for the character + if (ignore_case) { + while (*src) { + if (NPT_Uppercase(*src) == NPT_Uppercase(c)) { + return (int)(src-m_Chars); + } + src++; + } + } else { + while (*src) { + if (*src == c) return (int)(src-m_Chars); + src++; + } + } + + return -1; +} + +/*---------------------------------------------------------------------- +| NPT_String::FindAny ++---------------------------------------------------------------------*/ +int +NPT_String::FindAny(const char* s, NPT_Ordinal start, bool ignore_case) const +{ + // check args + if (start >= GetLength()) return -1; + + // skip to start position + const char* src = m_Chars + start; + + // look for the character + if (ignore_case) { + while (*src) { + for (NPT_Size i=0; i<NPT_StringLength(s); i++) { + if (NPT_Uppercase(*src) == NPT_Uppercase(s[i])) { + return (int)(src-m_Chars); + } + } + src++; + } + } else { + while (*src) { + for (NPT_Size i=0; i<NPT_StringLength(s); i++) { + if (*src == s[i]) return (int)(src-m_Chars); + } + src++; + } + } + + return -1; +} + +/*---------------------------------------------------------------------- +| NPT_String::ReverseFind ++---------------------------------------------------------------------*/ +int +NPT_String::ReverseFind(const char* str, NPT_Ordinal start, bool ignore_case) const +{ + // check args + if (str == NULL || *str == '\0') return -1; + + // look for a substring + NPT_Size my_length = GetLength(); + NPT_Size str_length = NPT_StringLength(str); + int i=my_length-start-str_length; + const char* src = GetChars(); + if (i<0) return -1; + for (;i>=0; i--) { + int cmp = NPT_StringStartsWith(src+i, str, ignore_case); + if (cmp == 1) { + // match + return i; + } + } + + return -1; +} + +/*---------------------------------------------------------------------- +| NPT_String::ReverseFind ++---------------------------------------------------------------------*/ +int +NPT_String::ReverseFind(char c, NPT_Ordinal start, bool ignore_case) const +{ + // check args + NPT_Size length = GetLength(); + int i = length-start-1; + if (i < 0) return -1; + + // look for the character + const char* src = GetChars(); + if (ignore_case) { + for (;i>=0;i--) { + if (NPT_Uppercase(src[i]) == NPT_Uppercase(c)) { + return i; + } + } + } else { + for (;i>=0;i--) { + if (src[i] == c) return i; + } + } + + return -1; +} + +/*---------------------------------------------------------------------- +| NPT_String::MakeLowercase ++---------------------------------------------------------------------*/ +void +NPT_String::MakeLowercase() +{ + // the source is the current buffer + const char* src = GetChars(); + + // convert all the characters of the existing buffer + char* dst = const_cast<char*>(src); + while (*dst != '\0') { + *dst = NPT_Lowercase(*dst); + dst++; + } +} + +/*---------------------------------------------------------------------- +| NPT_String::MakeUppercase ++---------------------------------------------------------------------*/ +void +NPT_String::MakeUppercase() +{ + // the source is the current buffer + const char* src = GetChars(); + + // convert all the characters of the existing buffer + char* dst = const_cast<char*>(src); + while (*dst != '\0') { + *dst = NPT_Uppercase(*dst); + dst++; + } +} + +/*---------------------------------------------------------------------- +| NPT_String::ToLowercase ++---------------------------------------------------------------------*/ +NPT_String +NPT_String::ToLowercase() const +{ + NPT_String result(*this); + result.MakeLowercase(); + return result; +} + +/*---------------------------------------------------------------------- +| NPT_String::ToUppercase ++---------------------------------------------------------------------*/ +NPT_String +NPT_String::ToUppercase() const +{ + NPT_String result(*this); + result.MakeUppercase(); + return result; +} + +/*---------------------------------------------------------------------- +| NPT_String::Replace ++---------------------------------------------------------------------*/ +const NPT_String& +NPT_String::Replace(char a, char b) +{ + // check args + if (m_Chars == NULL || a == '\0' || b == '\0') return *this; + + // we are going to modify the characters + char* src = m_Chars; + + // process the buffer in place + while (*src) { + if (*src == a) *src = b; + src++; + } + return *this; +} + +/*---------------------------------------------------------------------- +| NPT_String::Replace ++---------------------------------------------------------------------*/ +const NPT_String& +NPT_String::Replace(char a, const char* str) +{ + // check args + if (m_Chars == NULL || a == '\0' || str == NULL || str[0] == '\0') return *this; + + // optimization + if (NPT_StringLength(str) == 1) return Replace(a, str[0]); + + // we are going to create a new string + NPT_String dst; + char* src = m_Chars; + + // reserve at least as much as input + dst.Reserve(GetLength()); + + // process the buffer + while (*src) { + if (*src == a) { + dst += str; + } else { + dst += *src; + } + src++; + } + + Assign(dst.GetChars(), dst.GetLength()); + return *this; +} + +/*---------------------------------------------------------------------- +| NPT_String::Replace ++---------------------------------------------------------------------*/ +const NPT_String& +NPT_String::Replace(const char* before, const char* after) +{ + NPT_Size size_before = NPT_StringLength(before); + NPT_Size size_after = NPT_StringLength(after); + int index = Find(before); + while (index != NPT_STRING_SEARCH_FAILED) { + Erase(index, size_before); + Insert(after, index); + index = Find(before, index+size_after); + } + return *this; +} + +/*---------------------------------------------------------------------- +| NPT_String::Insert ++---------------------------------------------------------------------*/ +const NPT_String& +NPT_String::Insert(const char* str, NPT_Ordinal where) +{ + // check args + if (str == NULL || where > GetLength()) return *this; + + // measure the string to insert + NPT_Size str_length = StringLength(str); + if (str_length == 0) return *this; + + // compute the size of the new string + NPT_Size old_length = GetLength(); + NPT_Size new_length = str_length + GetLength(); + + // prepare to write the new string + char* src = m_Chars; + char* nst = Buffer::Create(new_length, new_length); + char* dst = nst; + + // copy the beginning of the old string + if (where > 0) { + CopyBuffer(dst, src, where); + src += where; + dst += where; + } + + // copy the inserted string + CopyString(dst, str); + dst += str_length; + + // copy the end of the old string + if (old_length > where) { + CopyString(dst, src); + } + + // use the new string + if (m_Chars) delete GetBuffer(); + m_Chars = nst; + return *this; +} + +/*---------------------------------------------------------------------- +| NPT_String::Erase ++---------------------------------------------------------------------*/ +const NPT_String& +NPT_String::Erase(NPT_Ordinal start, NPT_Cardinal count /* = 1 */) +{ + // check bounds + NPT_Size length = GetLength(); + if (start+count > length) { + if (start >= length) return *this; + count = length-start; + } + if (count == 0) return *this; + + CopyString(m_Chars+start, m_Chars+start+count); + GetBuffer()->SetLength(length-count); + return *this; +} + +/*---------------------------------------------------------------------- +| NPT_String::ToInteger ++---------------------------------------------------------------------*/ +NPT_Result +NPT_String::ToInteger(int& value, bool relaxed) const +{ + return NPT_ParseInteger(GetChars(), value, relaxed); +} + +/*---------------------------------------------------------------------- +| NPT_String::ToInteger ++---------------------------------------------------------------------*/ +NPT_Result +NPT_String::ToInteger(unsigned int& value, bool relaxed) const +{ + return NPT_ParseInteger(GetChars(), value, relaxed); +} + +/*---------------------------------------------------------------------- +| NPT_String::ToInteger ++---------------------------------------------------------------------*/ +NPT_Result +NPT_String::ToInteger(long& value, bool relaxed) const +{ + return NPT_ParseInteger(GetChars(), value, relaxed); +} + +/*---------------------------------------------------------------------- +| NPT_String::ToInteger ++---------------------------------------------------------------------*/ +NPT_Result +NPT_String::ToInteger(unsigned long& value, bool relaxed) const +{ + return NPT_ParseInteger(GetChars(), value, relaxed); +} + +/*---------------------------------------------------------------------- +| NPT_String::ToInteger32 ++---------------------------------------------------------------------*/ +NPT_Result +NPT_String::ToInteger32(NPT_Int32& value, bool relaxed) const +{ + return NPT_ParseInteger32(GetChars(), value, relaxed); +} + +/*---------------------------------------------------------------------- +| NPT_String::ToInteger32 ++---------------------------------------------------------------------*/ +NPT_Result +NPT_String::ToInteger32(NPT_UInt32& value, bool relaxed) const +{ + return NPT_ParseInteger32(GetChars(), value, relaxed); +} + +/*---------------------------------------------------------------------- +| NPT_String::ToInteger64 ++---------------------------------------------------------------------*/ +NPT_Result +NPT_String::ToInteger64(NPT_Int64& value, bool relaxed) const +{ + return NPT_ParseInteger64(GetChars(), value, relaxed); +} + +/*---------------------------------------------------------------------- +| NPT_String::ToInteger64 ++---------------------------------------------------------------------*/ +NPT_Result +NPT_String::ToInteger64(NPT_UInt64& value, bool relaxed) const +{ + return NPT_ParseInteger64(GetChars(), value, relaxed); +} + +/*---------------------------------------------------------------------- +| NPT_String::ToFloat ++---------------------------------------------------------------------*/ +NPT_Result +NPT_String::ToFloat(float& value, bool relaxed) const +{ + return NPT_ParseFloat(GetChars(), value, relaxed); +} + +/*---------------------------------------------------------------------- +| NPT_String::TrimLeft ++---------------------------------------------------------------------*/ +const NPT_String& +NPT_String::TrimLeft() +{ + return TrimLeft(NPT_STRINGS_WHITESPACE_CHARS); +} + +/*---------------------------------------------------------------------- +| NPT_String::TrimLeft ++---------------------------------------------------------------------*/ +const NPT_String& +NPT_String::TrimLeft(char c) +{ + char s[2] = {c, 0}; + return TrimLeft((const char*)s); +} + +/*---------------------------------------------------------------------- +| NPT_String::TrimLeft ++---------------------------------------------------------------------*/ +const NPT_String& +NPT_String::TrimLeft(const char* chars) +{ + if (m_Chars == NULL) return *this; + const char* s = m_Chars; + while (char c = *s) { + const char* x = chars; + while (*x) { + if (*x == c) break; + x++; + } + if (*x == 0) break; // not found + s++; + } + if (s == m_Chars) { + // nothing was trimmed + return *this; + } + + // shift chars to the left + char* d = m_Chars; + GetBuffer()->SetLength(GetLength()-(NPT_Size)(s-d)); + while ((*d++ = *s++)) {}; + return *this; +} + +/*---------------------------------------------------------------------- +| NPT_String::TrimRight ++---------------------------------------------------------------------*/ +const NPT_String& +NPT_String::TrimRight() +{ + return TrimRight(NPT_STRINGS_WHITESPACE_CHARS); +} + +/*---------------------------------------------------------------------- +| NPT_String::TrimRight ++---------------------------------------------------------------------*/ +const NPT_String& +NPT_String::TrimRight(char c) +{ + char s[2] = {c, 0}; + return TrimRight((const char*)s); +} + +/*---------------------------------------------------------------------- +| NPT_String::TrimRight ++---------------------------------------------------------------------*/ +const NPT_String& +NPT_String::TrimRight(const char* chars) +{ + if (m_Chars == NULL || m_Chars[0] == '\0') return *this; + char* tail = m_Chars+GetLength()-1; + char* s = tail; + while (s != m_Chars-1) { + const char* x = chars; + while (*x) { + if (*x == *s) { + *s = '\0'; + break; + } + x++; + } + if (*x == 0) break; // not found + s--; + } + if (s == tail) { + // nothing was trimmed + return *this; + } + GetBuffer()->SetLength(1+(int)(s-m_Chars)); + return *this; +} + +/*---------------------------------------------------------------------- +| NPT_String::Trim ++---------------------------------------------------------------------*/ +const NPT_String& +NPT_String::Trim() +{ + TrimLeft(); + return TrimRight(); +} + +/*---------------------------------------------------------------------- +| NPT_String::Trim ++---------------------------------------------------------------------*/ +const NPT_String& +NPT_String::Trim(char c) +{ + char s[2] = {c, 0}; + TrimLeft((const char*)s); + return TrimRight((const char*)s); +} + +/*---------------------------------------------------------------------- +| NPT_String::Trim ++---------------------------------------------------------------------*/ +const NPT_String& +NPT_String::Trim(const char* chars) +{ + TrimLeft(chars); + return TrimRight(chars); +} + +/*---------------------------------------------------------------------- +| NPT_String::operator+(const NPT_String&, const char*) ++---------------------------------------------------------------------*/ +NPT_String +operator+(const NPT_String& s1, const char* s2) +{ + // shortcut + if (s2 == NULL) return NPT_String(s1); + + // measure strings + NPT_Size s1_length = s1.GetLength(); + NPT_Size s2_length = NPT_String::StringLength(s2); + + // allocate space for the new string + NPT_String result; + char* start = result.PrepareToWrite(s1_length+s2_length); + + // concatenate the two strings into the result + NPT_String::CopyBuffer(start, s1, s1_length); + NPT_String::CopyString(start+s1_length, s2); + + return result; +} + +/*---------------------------------------------------------------------- +| NPT_String::operator+(const NPT_String& , const char*) ++---------------------------------------------------------------------*/ +NPT_String +operator+(const char* s1, const NPT_String& s2) +{ + // shortcut + if (s1 == NULL) return NPT_String(s2); + + // measure strings + NPT_Size s1_length = NPT_String::StringLength(s1); + NPT_Size s2_length = s2.GetLength(); + + // allocate space for the new string + NPT_String result; + char* start = result.PrepareToWrite(s1_length+s2_length); + + // concatenate the two strings into the result + NPT_String::CopyBuffer(start, s1, s1_length); + NPT_String::CopyString(start+s1_length, s2.GetChars()); + + return result; +} + +/*---------------------------------------------------------------------- +| NPT_String::operator+(const NPT_String& , char) ++---------------------------------------------------------------------*/ +NPT_String +operator+(const NPT_String& s1, char c) +{ + // allocate space for the new string + NPT_String result; + result.Reserve(s1.GetLength()+1); + + // append + result = s1; + result += c; + + return result; +} + diff --git a/lib/libUPnP/Neptune/Source/Core/NptStrings.h b/lib/libUPnP/Neptune/Source/Core/NptStrings.h new file mode 100644 index 0000000..c445b33 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptStrings.h @@ -0,0 +1,358 @@ +/***************************************************************** +| +| Neptune - String Objects +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +#ifndef _NPT_STRINGS_H_ +#define _NPT_STRINGS_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptConfig.h" +#if defined(NPT_CONFIG_HAVE_NEW_H) +#include <new> +#endif +#include "NptTypes.h" +#include "NptConstants.h" +#include "NptList.h" +#include "NptArray.h" +#include "NptDebug.h" +#include "NptHash.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const int NPT_STRING_SEARCH_FAILED = -1; + +/*---------------------------------------------------------------------- +| NPT_String ++---------------------------------------------------------------------*/ +class NPT_String +{ +public: + // factories + static NPT_String FromInteger(NPT_Int64 value); + static NPT_String FromIntegerU(NPT_UInt64 value); + static NPT_String Format(const char* format, ...); + + // constructors + NPT_String(const NPT_String& str); + NPT_String(const char* str); + NPT_String(const char* str, NPT_Size length); + NPT_String(char c, NPT_Cardinal repeat = 1); + NPT_String() : m_Chars(NULL) {} + ~NPT_String() { if (m_Chars) GetBuffer()->Destroy(); } + + // string info and manipulations + bool IsEmpty() const { return m_Chars == NULL || GetBuffer()->GetLength() == 0; } + NPT_Size GetLength() const { return m_Chars ? GetBuffer()->GetLength() : 0; } + NPT_Size GetCapacity() const { return m_Chars ? GetBuffer()->GetAllocated() : 0; } + NPT_Result SetLength(NPT_Size length, bool pad = false); + void Assign(const char* chars, NPT_Size size); + void Append(const char* chars, NPT_Size size); + void Append(const char* s) { Append(s, StringLength(s)); } + int Compare(const char* s, bool ignore_case = false) const; + static int Compare(const char* s1, const char* s2, bool ignore_case = false); + int CompareN(const char* s, NPT_Size count, bool ignore_case = false) const; + static int CompareN(const char* s1, const char* s2, NPT_Size count, bool ignore_case = false); + + // substrings + NPT_String SubString(NPT_Ordinal first, NPT_Size length) const; + NPT_String SubString(NPT_Ordinal first) const { + return SubString(first, GetLength()); + } + NPT_String Left(NPT_Size length) const { + return SubString(0, length); + } + NPT_String Right(NPT_Size length) const { + return length >= GetLength() ? + *this : + SubString(GetLength()-length, length); + } + NPT_List<NPT_String> Split(const char* separator) const; + NPT_Array<NPT_String> SplitAny(const char* separator) const; + static NPT_String Join(NPT_List<NPT_String>& args, const char* separator); + + // buffer management + void Reserve(NPT_Size length); + + // hashing + NPT_UInt32 GetHash32() const; + NPT_UInt64 GetHash64() const; + + // conversions + NPT_String ToLowercase() const; + NPT_String ToUppercase() const; + NPT_Result ToInteger(int& value, bool relaxed = true) const; + NPT_Result ToInteger(unsigned int& value, bool relaxed = true) const; + NPT_Result ToInteger(long& value, bool relaxed = true) const; + NPT_Result ToInteger(unsigned long& value, bool relaxed = true) const; + NPT_Result ToInteger32(NPT_Int32& value, bool relaxed = true) const; + NPT_Result ToInteger32(NPT_UInt32& value, bool relaxed = true) const; + NPT_Result ToInteger64(NPT_Int64& value, bool relaxed = true) const; + NPT_Result ToInteger64(NPT_UInt64& value, bool relaxed = true) const; + NPT_Result ToFloat(float& value, bool relaxed = true) const; + + // processing + void MakeLowercase(); + void MakeUppercase(); + const NPT_String& Replace(char a, char b); + const NPT_String& Replace(char a, const char* b); + + // search + int Find(char c, NPT_Ordinal start = 0, bool ignore_case = false) const; + int Find(const char* s, NPT_Ordinal start = 0, bool ignore_case = false) const; + int FindAny(const char* s, NPT_Ordinal start, bool ignore_case = false) const; + int ReverseFind(char c, NPT_Ordinal start = 0, bool ignore_case = false) const; + int ReverseFind(const char* s, NPT_Ordinal start = 0, bool ignore_case = false) const; + bool StartsWith(const char* s, bool ignore_case = false) const; + bool EndsWith(const char* s, bool ignore_case = false) const; + + // editing + const NPT_String& Insert(const char* s, NPT_Ordinal where = 0); + const NPT_String& Erase(NPT_Ordinal start, NPT_Cardinal count = 1); + const NPT_String& Replace(const char* before, const char* after); + // void Replace(NPT_Ordinal start, NPT_Cardinal count, const char* s); + const NPT_String& TrimLeft(); + const NPT_String& TrimLeft(char c); + const NPT_String& TrimLeft(const char* chars); + const NPT_String& TrimRight(); + const NPT_String& TrimRight(char c); + const NPT_String& TrimRight(const char* chars); + const NPT_String& Trim(); + const NPT_String& Trim(char c); + const NPT_String& Trim(const char* chars); + + // type casting + operator char*() const { return m_Chars ? m_Chars: &EmptyString; } + operator const char* () const { return m_Chars ? m_Chars: &EmptyString; } + const char* GetChars() const { return m_Chars ? m_Chars: &EmptyString; } + char* UseChars() { return m_Chars ? m_Chars: &EmptyString; } + + // operator overloading + NPT_String& operator=(const char* str); + NPT_String& operator=(const NPT_String& str); + NPT_String& operator=(char c); + const NPT_String& operator+=(const NPT_String& s) { + Append(s.GetChars(), s.GetLength()); + return *this; + } + const NPT_String& operator+=(const char* s) { + Append(s); + return *this; + } + const NPT_String& operator+=(char c) { + Append(&c, 1); + return *this; + } + char operator[](int index) const { + NPT_ASSERT((unsigned int)index < GetLength()); + return GetChars()[index]; + } + char& operator[](int index) { + NPT_ASSERT((unsigned int)index < GetLength()); + return UseChars()[index]; + } + + // friend operators + friend NPT_String operator+(const NPT_String& s1, const NPT_String& s2) { + return s1+s2.GetChars(); + } + friend NPT_String operator+(const NPT_String& s1, const char* s2); + friend NPT_String operator+(const char* s1, const NPT_String& s2); + friend NPT_String operator+(const NPT_String& s, char c); + friend NPT_String operator+(char c, const NPT_String& s); + +protected: + // inner classes + class Buffer { + public: + // class methods + static Buffer* Allocate(NPT_Size allocated, NPT_Size length) { + void* mem = ::operator new(sizeof(Buffer)+allocated+1); + return new(mem) Buffer(allocated, length); + } + static char* Create(NPT_Size allocated, NPT_Size length=0) { + Buffer* shared = Allocate(allocated, length); + return shared->GetChars(); + } + static char* Create(const char* copy) { + NPT_Size length = StringLength(copy); + Buffer* shared = Allocate(length, length); + CopyString(shared->GetChars(), copy); + return shared->GetChars(); + } + static char* Create(const char* copy, NPT_Size length) { + Buffer* shared = Allocate(length, length); + CopyBuffer(shared->GetChars(), copy, length); + shared->GetChars()[length] = '\0'; + return shared->GetChars(); + } + static char* Create(char c, NPT_Cardinal repeat) { + Buffer* shared = Allocate(repeat, repeat); + char* s = shared->GetChars(); + while (repeat--) { + *s++ = c; + } + *s = '\0'; + return shared->GetChars(); + } + + // methods + char* GetChars() { + // return a pointer to the first char + return reinterpret_cast<char*>(this+1); + } + NPT_Size GetLength() const { return m_Length; } + void SetLength(NPT_Size length) { m_Length = length; } + NPT_Size GetAllocated() const { return m_Allocated; } + void Destroy() { ::operator delete((void*)this); } + + private: + // methods + Buffer(NPT_Size allocated, NPT_Size length = 0) : + m_Length(length), + m_Allocated(allocated) {} + + // members + NPT_Cardinal m_Length; + NPT_Cardinal m_Allocated; + // the actual string data follows + + }; + + // members + char* m_Chars; + +private: + // friends + friend class Buffer; + + // static members + static char EmptyString; + + // methods + Buffer* GetBuffer() const { + return reinterpret_cast<Buffer*>(m_Chars)-1; + } + void Reset() { + if (m_Chars != NULL) { + delete GetBuffer(); + m_Chars = NULL; + } + } + char* PrepareToWrite(NPT_Size length); + void PrepareToAppend(NPT_Size length, NPT_Size allocate); + + // static methods + static void CopyString(char* dst, const char* src) { + while ((*dst++ = *src++)){} + } + + static void CopyBuffer(char* dst, const char* src, NPT_Size size) { + while (size--) *dst++ = *src++; + } + + static NPT_Size StringLength(const char* str) { + NPT_Size length = 0; + while (*str++) length++; + return length; + } +}; + +/*---------------------------------------------------------------------- +| external operators ++---------------------------------------------------------------------*/ +inline bool operator==(const NPT_String& s1, const NPT_String& s2) { + return s1.Compare(s2) == 0; +} +inline bool operator==(const NPT_String& s1, const char* s2) { + return s1.Compare(s2) == 0; +} +inline bool operator==(const char* s1, const NPT_String& s2) { + return s2.Compare(s1) == 0; +} +inline bool operator!=(const NPT_String& s1, const NPT_String& s2) { + return s1.Compare(s2) != 0; +} +inline bool operator!=(const NPT_String& s1, const char* s2) { + return s1.Compare(s2) != 0; +} +inline bool operator!=(const char* s1, const NPT_String& s2) { + return s2.Compare(s1) != 0; +} +inline bool operator<(const NPT_String& s1, const NPT_String& s2) { + return s1.Compare(s2) < 0; +} +inline bool operator<(const NPT_String& s1, const char* s2) { + return s1.Compare(s2) < 0; +} +inline bool operator<(const char* s1, const NPT_String& s2) { + return s2.Compare(s1) > 0; +} +inline bool operator>(const NPT_String& s1, const NPT_String& s2) { + return s1.Compare(s2) > 0; +} +inline bool operator>(const NPT_String& s1, const char* s2) { + return s1.Compare(s2) > 0; +} +inline bool operator>(const char* s1, const NPT_String& s2) { + return s2.Compare(s1) < 0; +} +inline bool operator<=(const NPT_String& s1, const NPT_String& s2) { + return s1.Compare(s2) <= 0; +} +inline bool operator<=(const NPT_String& s1, const char* s2) { + return s1.Compare(s2) <= 0; +} +inline bool operator<=(const char* s1, const NPT_String& s2) { + return s2.Compare(s1) >= 0; +} +inline bool operator>=(const NPT_String& s1, const NPT_String& s2) { + return s1.Compare(s2) >= 0; +} +inline bool operator>=(const NPT_String& s1, const char* s2) { + return s1.Compare(s2) >= 0; +} +inline bool operator>=(const char* s1, const NPT_String& s2) { + return s2.Compare(s1) <= 0; +} + +/*---------------------------------------------------------------------- +| hashing ++---------------------------------------------------------------------*/ +template <> +struct NPT_Hash<NPT_String> +{ + NPT_UInt32 operator()(const NPT_String& s) const { return s.GetHash32(); } +}; + + +#endif // _NPT_STRINGS_H_ diff --git a/lib/libUPnP/Neptune/Source/Core/NptSystem.cpp b/lib/libUPnP/Neptune/Source/Core/NptSystem.cpp new file mode 100644 index 0000000..0d4e9b2 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptSystem.cpp @@ -0,0 +1,37 @@ +/***************************************************************** +| +| Neptune - System +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptSystem.h" + + diff --git a/lib/libUPnP/Neptune/Source/Core/NptSystem.h b/lib/libUPnP/Neptune/Source/Core/NptSystem.h new file mode 100644 index 0000000..224a058 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptSystem.h @@ -0,0 +1,63 @@ +/***************************************************************** +| +| Neptune - System +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +#ifndef _NPT_SYSTEM_H_ +#define _NPT_SYSTEM_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptTypes.h" +#include "NptTime.h" + +/*---------------------------------------------------------------------- +| NPT_System ++---------------------------------------------------------------------*/ +class NPT_System +{ +public: + // methods + static NPT_Result GetProcessId(NPT_UInt32& id); + static NPT_Result GetMachineName(NPT_String& name); + static NPT_Result GetCurrentTimeStamp(NPT_TimeStamp& now); + static NPT_Result Sleep(const NPT_TimeInterval& duration); + static NPT_Result SleepUntil(const NPT_TimeStamp& when); + static NPT_Result SetRandomSeed(unsigned int seed); + static NPT_UInt32 GetRandomInteger(); + +protected: + // constructor + NPT_System() {} +}; + +NPT_Result NPT_GetSystemMachineName(NPT_String& name); + +#endif // _NPT_SYSTEM_H_ diff --git a/lib/libUPnP/Neptune/Source/Core/NptThreads.cpp b/lib/libUPnP/Neptune/Source/Core/NptThreads.cpp new file mode 100644 index 0000000..25a867d --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptThreads.cpp @@ -0,0 +1,161 @@ +/***************************************************************** +| +| Neptune - Threads +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptThreads.h" + +/*---------------------------------------------------------------------- +| NPT_SingletonLock ++---------------------------------------------------------------------*/ +NPT_Mutex NPT_SingletonLock::Instance; + +/*---------------------------------------------------------------------- +| NPT_ThreadCallbackSlot::NPT_ThreadCallbackSlot ++---------------------------------------------------------------------*/ +NPT_ThreadCallbackSlot::NPT_ThreadCallbackSlot() : + m_CallbackArgs(NULL), + m_Shutdown(false), + m_NotificationHelper(NULL) +{ +} + +/*---------------------------------------------------------------------- +| NPT_ThreadCallbackSlot::Shutdown ++---------------------------------------------------------------------*/ +NPT_Result +NPT_ThreadCallbackSlot::Shutdown() +{ + // protect against concurrent access + //FIXME: This will not work if another Thread has called ReceiveCallback with a timeout + NPT_AutoLock lock(m_ReadLock); + + // signal we are shut down + m_Shutdown = true; + + // clear up any pending callbacks + m_Pending.SetValue(0); + m_Ack.SetValue(1); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_ThreadCallbackSlot::SetNotificationHelper ++---------------------------------------------------------------------*/ +NPT_Result +NPT_ThreadCallbackSlot::SetNotificationHelper(NotificationHelper* helper) +{ + m_NotificationHelper = helper; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_ThreadCallbackSlot::ReceiveCallback ++---------------------------------------------------------------------*/ +NPT_Result +NPT_ThreadCallbackSlot::ReceiveCallback(NPT_ThreadCallbackReceiver& receiver, + NPT_Timeout timeout) +{ + // protect against concurrent access + //NPT_Debug("NPT_ThreadCallbackSlot::ReceiveCallback - read locking, timeout=%d\n", timeout); + NPT_AutoLock lock(m_ReadLock); + + if (timeout) { + // wait until there is a pending callback + //NPT_Debug("NPT_ThreadCallbackSlot::ReceiveCallback - waiting...\n"); + NPT_Result result = m_Pending.WaitUntilEquals(1, timeout); + if (NPT_FAILED(result)) return result; // don't log here because the result + // could be NPT_ERROR_TIMEOUT which + // is an expected normal case. + //NPT_Debug("NPT_ThreadCallbackSlot::ReceiveCallback - got it\n"); + } else { + // see if something is pending + if (m_Pending.GetValue() == 0) { + //NPT_Debug("NPT_ThreadCallbackSlot::ReceiveCallback - nothing pending\n"); + return NPT_ERROR_CALLBACK_NOTHING_PENDING; + } + } + + // check if we have been shutdown + if (m_Shutdown) return NPT_ERROR_CALLBACK_HANDLER_SHUTDOWN; + + // process the callback + //NPT_Debug("NPT_ThreadCallbackSlot::ReceiveCallback - calling back\n"); + receiver.OnCallback(const_cast<void*>(m_CallbackArgs)); + + // signal that we've processed the callback + m_Pending.SetValue(0); + m_Ack.SetValue(1); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_ThreadCallbackSlot::SendCallback ++---------------------------------------------------------------------*/ +NPT_Result +NPT_ThreadCallbackSlot::SendCallback(void* args) +{ + // protect against concurrent access + //NPT_Debug("NPT_ThreadCallbackSlot::SendCallback - write locking\n"); + NPT_AutoLock lock(m_WriteLock); + + // there should be nothing pending +#if defined(NPT_DEBUG) + NPT_ASSERT(m_Pending.GetValue() == 0); +#endif + + // check if we have been shutdown + if (m_Shutdown) return NPT_ERROR_CALLBACK_HANDLER_SHUTDOWN; + + // put the callback args + m_CallbackArgs = args; + //NPT_Debug("NPT_ThreadCallbackSlot::SendCallback - signalling\n"); + m_Pending.SetValue(1); + + // call the helper before we wait + if (m_NotificationHelper) { + m_NotificationHelper->Notify(); + } + + // wait until the callback has been process, or we've been shutdown + //NPT_Debug("NPT_ThreadCallbackSlot::SendCallback - waiting...\n"); + m_Ack.WaitUntilEquals(1); + //NPT_Debug("NPT_ThreadCallbackSlot::SendCallback - got it\n"); + + // done + m_Ack.SetValue(0); + m_CallbackArgs = NULL; + + return m_Shutdown?NPT_ERROR_CALLBACK_HANDLER_SHUTDOWN:NPT_SUCCESS; +} diff --git a/lib/libUPnP/Neptune/Source/Core/NptThreads.h b/lib/libUPnP/Neptune/Source/Core/NptThreads.h new file mode 100644 index 0000000..b14568e --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptThreads.h @@ -0,0 +1,322 @@ +/***************************************************************** +| +| Neptune - Threads +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +#ifndef _NPT_THREADS_H_ +#define _NPT_THREADS_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptTypes.h" +#include "NptConstants.h" +#include "NptInterfaces.h" + +/*---------------------------------------------------------------------- +| error codes ++---------------------------------------------------------------------*/ +const int NPT_ERROR_CALLBACK_HANDLER_SHUTDOWN = NPT_ERROR_BASE_THREADS-0; +const int NPT_ERROR_CALLBACK_NOTHING_PENDING = NPT_ERROR_BASE_THREADS-1; + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const int NPT_THREAD_PRIORITY_MIN = -15; +const int NPT_THREAD_PRIORITY_IDLE = -15; +const int NPT_THREAD_PRIORITY_LOWEST = -2; +const int NPT_THREAD_PRIORITY_BELOW_NORMAL = -1; +const int NPT_THREAD_PRIORITY_NORMAL = 0; +const int NPT_THREAD_PRIORITY_ABOVE_NORMAL = 1; +const int NPT_THREAD_PRIORITY_HIGHEST = 2; +const int NPT_THREAD_PRIORITY_TIME_CRITICAL = 15; +const int NPT_THREAD_PRIORITY_MAX = 15; + +/*---------------------------------------------------------------------- +| NPT_MutexInterface ++---------------------------------------------------------------------*/ +class NPT_MutexInterface +{ + public: + // methods + virtual ~NPT_MutexInterface() {} + virtual NPT_Result Lock() = 0; + virtual NPT_Result Unlock() = 0; +}; + +/*---------------------------------------------------------------------- +| NPT_Mutex ++---------------------------------------------------------------------*/ +class NPT_Mutex : public NPT_MutexInterface +{ + public: + // methods + NPT_Mutex(bool recursive = false); + ~NPT_Mutex() override { delete m_Delegate; } + NPT_Result Lock() override { return m_Delegate->Lock(); } + NPT_Result Unlock() override { return m_Delegate->Unlock(); } + + private: + // members + NPT_MutexInterface* m_Delegate; +}; + +/*---------------------------------------------------------------------- +| NPT_AutoLock ++---------------------------------------------------------------------*/ +class NPT_AutoLock +{ + public: + // methods + NPT_AutoLock(NPT_Mutex &mutex) : m_Mutex(mutex) { + m_Mutex.Lock(); + } + ~NPT_AutoLock() { + m_Mutex.Unlock(); + } + + private: + // members + NPT_Mutex& m_Mutex; +}; + +/*---------------------------------------------------------------------- +| NPT_Lock ++---------------------------------------------------------------------*/ +template <typename T> +class NPT_Lock : public T, + public NPT_Mutex +{ +}; + +/*---------------------------------------------------------------------- +| NPT_SingletonLock ++---------------------------------------------------------------------*/ +class NPT_SingletonLock +{ +public: + static NPT_Mutex& GetInstance() { + return Instance; + } + +private: + static NPT_Mutex Instance; +}; + +/*---------------------------------------------------------------------- +| NPT_SharedVariableInterface ++---------------------------------------------------------------------*/ +class NPT_SharedVariableInterface +{ + public: + // methods + virtual ~NPT_SharedVariableInterface() {} + virtual void SetValue(int value)= 0; + virtual int GetValue() = 0; + virtual NPT_Result WaitUntilEquals(int value, NPT_Timeout timeout = NPT_TIMEOUT_INFINITE) = 0; + virtual NPT_Result WaitWhileEquals(int value, NPT_Timeout timeout = NPT_TIMEOUT_INFINITE) = 0; +}; + +/*---------------------------------------------------------------------- +| NPT_SharedVariable ++---------------------------------------------------------------------*/ +class NPT_SharedVariable : public NPT_SharedVariableInterface +{ + public: + // methods + NPT_SharedVariable(int value = 0); + ~NPT_SharedVariable() override { delete m_Delegate; } + void SetValue(int value) override { + m_Delegate->SetValue(value); + } + int GetValue() override { + return m_Delegate->GetValue(); + } + NPT_Result WaitUntilEquals(int value, NPT_Timeout timeout = NPT_TIMEOUT_INFINITE) override { + return m_Delegate->WaitUntilEquals(value, timeout); + } + NPT_Result WaitWhileEquals(int value, NPT_Timeout timeout = NPT_TIMEOUT_INFINITE) override { + return m_Delegate->WaitWhileEquals(value, timeout); + } + + private: + // members + NPT_SharedVariableInterface* m_Delegate; +}; + +/*---------------------------------------------------------------------- +| NPT_AtomicVariableInterface ++---------------------------------------------------------------------*/ +class NPT_AtomicVariableInterface +{ + public: + // methods + virtual ~NPT_AtomicVariableInterface() {} + virtual int Increment() = 0; + virtual int Decrement() = 0; + virtual int GetValue() = 0; + virtual void SetValue(int value) = 0; +}; + +/*---------------------------------------------------------------------- +| NPT_AtomicVariable ++---------------------------------------------------------------------*/ +class NPT_AtomicVariable : public NPT_AtomicVariableInterface +{ + public: + // methods + NPT_AtomicVariable(int value = 0); + ~NPT_AtomicVariable() override { delete m_Delegate; } + int Increment() override { return m_Delegate->Increment();} + int Decrement() override { return m_Delegate->Decrement();} + void SetValue(int value) override { m_Delegate->SetValue(value); } + int GetValue() override { return m_Delegate->GetValue(); } + + private: + // members + NPT_AtomicVariableInterface* m_Delegate; +}; + +/*---------------------------------------------------------------------- +| NPT_Runnable ++---------------------------------------------------------------------*/ +class NPT_Runnable +{ +public: + virtual ~NPT_Runnable() {} + virtual void Run() = 0; +}; + +/*---------------------------------------------------------------------- +| NPT_ThreadInterface ++---------------------------------------------------------------------*/ +class NPT_ThreadInterface: public NPT_Runnable, public NPT_Interruptible +{ + public: + // methods + ~NPT_ThreadInterface() override {} + virtual NPT_Result Start() = 0; + virtual NPT_Result Wait(NPT_Timeout timeout = NPT_TIMEOUT_INFINITE) = 0; + virtual NPT_Result SetPriority(int /*priority*/) { return NPT_SUCCESS; } + virtual NPT_Result CancelBlockerSocket() = 0; + virtual NPT_Result GetPriority(int& priority) = 0; +}; + +/*---------------------------------------------------------------------- +| NPT_Thread ++---------------------------------------------------------------------*/ +class NPT_Thread : public NPT_ThreadInterface +{ + public: + // types + typedef NPT_UInt64 ThreadId; + + // class methods + static ThreadId GetCurrentThreadId(); + static NPT_Result SetCurrentThreadPriority(int priority); + static NPT_Result GetCurrentThreadPriority(int& priority); + + // methods + explicit NPT_Thread(bool detached = false); + explicit NPT_Thread(NPT_Runnable& target, bool detached = false); + ~NPT_Thread() override { delete m_Delegate; } + + // cancel any socket that this thread may be waiting for + NPT_Result CancelBlockerSocket() override { return m_Delegate->CancelBlockerSocket(); } + + // NPT_ThreadInterface methods + NPT_Result Start() override { + return m_Delegate->Start(); + } + NPT_Result Wait(NPT_Timeout timeout = NPT_TIMEOUT_INFINITE) override { + return m_Delegate->Wait(timeout); + } + NPT_Result SetPriority(int priority) override { + return m_Delegate->SetPriority(priority); + } + NPT_Result GetPriority(int& priority) override { + return m_Delegate->GetPriority(priority); + } + + // NPT_Runnable methods + void Run() override {} + + // NPT_Interruptible methods + NPT_Result Interrupt() override { return m_Delegate->Interrupt(); } + + private: + // members + NPT_ThreadInterface* m_Delegate; +}; + + +/*---------------------------------------------------------------------- +| NPT_ThreadCallbackReceiver ++---------------------------------------------------------------------*/ +class NPT_ThreadCallbackReceiver +{ +public: + virtual ~NPT_ThreadCallbackReceiver() {} + virtual void OnCallback(void* args) = 0; +}; + +/*---------------------------------------------------------------------- +| NPT_ThreadCallbackSlot ++---------------------------------------------------------------------*/ +class NPT_ThreadCallbackSlot +{ +public: + // types + class NotificationHelper { + public: + virtual ~NotificationHelper() {}; + virtual void Notify(void) = 0; + }; + + // constructor + NPT_ThreadCallbackSlot(); + + // methods + NPT_Result ReceiveCallback(NPT_ThreadCallbackReceiver& receiver, NPT_Timeout timeout = 0); + NPT_Result SendCallback(void* args); + NPT_Result SetNotificationHelper(NotificationHelper* helper); + NPT_Result Shutdown(); + +protected: + // members + volatile void* m_CallbackArgs; + volatile bool m_Shutdown; + NPT_SharedVariable m_Pending; + NPT_SharedVariable m_Ack; + NPT_Mutex m_ReadLock; + NPT_Mutex m_WriteLock; + NotificationHelper* m_NotificationHelper; +}; + +#endif // _NPT_THREADS_H_ diff --git a/lib/libUPnP/Neptune/Source/Core/NptTime.cpp b/lib/libUPnP/Neptune/Source/Core/NptTime.cpp new file mode 100755 index 0000000..d842259 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptTime.cpp @@ -0,0 +1,714 @@ +/***************************************************************** +| +| Neptune - Time +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptTime.h" +#include "NptUtils.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const char* const NPT_TIME_DAYS_SHORT[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; +const char* const NPT_TIME_DAYS_LONG[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; +const char* const NPT_TIME_MONTHS[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + +static const NPT_Int32 NPT_TIME_MONTH_DAY[] = {-1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364 }; +static const NPT_Int32 NPT_TIME_MONTH_DAY_LEAP[] = {-1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; +static const NPT_Int32 NPT_TIME_ELAPSED_DAYS_AT_MONTH[13] = { + 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 +}; + +const NPT_Int32 NPT_SECONDS_PER_DAY = (24L * 60L * 60L); +const NPT_Int32 NPT_SECONDS_PER_YEAR = (365L * NPT_SECONDS_PER_DAY); + +/*---------------------------------------------------------------------- +| macros ++---------------------------------------------------------------------*/ +#define NPT_TIME_YEAR_IS_LEAP(_y) ((((_y)%4 == 0) && ((_y)%100 != 0)) || ((_y)%400 == 0)) +#define NPT_TIME_CHECK_BOUNDS(_var, _low, _high) do { \ + if (((_var)<(_low)) || ((_var)>(_high))) { \ + return NPT_ERROR_OUT_OF_RANGE; \ + } \ +} while (0) + +/*---------------------------------------------------------------------- +| NPT_TimeStamp::NPT_TimeStamp ++---------------------------------------------------------------------*/ +NPT_TimeStamp::NPT_TimeStamp(const NPT_TimeStamp& timestamp) +{ + m_NanoSeconds = timestamp.m_NanoSeconds; +} + +/*---------------------------------------------------------------------- +| NPT_TimeStamp::NPT_TimeStamp ++---------------------------------------------------------------------*/ +NPT_TimeStamp::NPT_TimeStamp(double seconds) +{ + m_NanoSeconds = (NPT_Int64)(seconds * 1e9); +} + +/*---------------------------------------------------------------------- +| NPT_TimeStamp::operator+= ++---------------------------------------------------------------------*/ +NPT_TimeStamp& +NPT_TimeStamp::operator+=(const NPT_TimeStamp& t) +{ + m_NanoSeconds += t.m_NanoSeconds; + return *this; +} + +/*---------------------------------------------------------------------- +| NPT_TimeStamp::operator-= ++---------------------------------------------------------------------*/ +NPT_TimeStamp& +NPT_TimeStamp::operator-=(const NPT_TimeStamp& t) +{ + m_NanoSeconds -= t.m_NanoSeconds; + return *this; +} + +/*---------------------------------------------------------------------- +| MatchString ++---------------------------------------------------------------------*/ +static int +MatchString(const char* string, const char* const* list, unsigned int list_length) +{ + for (unsigned int i=0; i<list_length; i++) { + if (NPT_StringsEqual(string, list[i])) return i; + } + + return -1; +} + +/*---------------------------------------------------------------------- +| ElapsedLeapYearsSince1900 ++---------------------------------------------------------------------*/ +static NPT_UInt32 +ElapsedLeapYearsSince1900(NPT_UInt32 year) +{ + if (year < 1901) return 0; + NPT_UInt32 years_since_1900 = year-1-1900; // not including the current year + return years_since_1900/4 - + years_since_1900/100 + + (years_since_1900+300)/400; +} + +/*---------------------------------------------------------------------- +| ElapsedDaysSince1900 ++---------------------------------------------------------------------*/ +static NPT_UInt32 +ElapsedDaysSince1900(const NPT_DateTime& date) +{ + // compute the number of days elapsed in the year + NPT_UInt32 day_count = NPT_TIME_ELAPSED_DAYS_AT_MONTH[date.m_Month-1] + date.m_Day - 1; + + // adjust for leap years after february + if (NPT_TIME_YEAR_IS_LEAP(date.m_Year) && (date.m_Month > 2)) ++day_count; + + // compute the total number of elapsed days + NPT_UInt32 leap_year_count = ElapsedLeapYearsSince1900(date.m_Year); + day_count += (date.m_Year-1900)*365 + leap_year_count; + + return day_count; +} + +/*---------------------------------------------------------------------- +| NPT_DateTime::NPT_DateTime ++---------------------------------------------------------------------*/ +NPT_DateTime::NPT_DateTime() : + m_Year(1970), + m_Month(1), + m_Day(1), + m_Hours(0), + m_Minutes(0), + m_Seconds(0), + m_NanoSeconds(0), + m_TimeZone(0) +{ +} + +/*---------------------------------------------------------------------- +| NPT_DateTime::NPT_DateTime ++---------------------------------------------------------------------*/ +NPT_DateTime::NPT_DateTime(const NPT_TimeStamp& timestamp, bool local) +{ + FromTimeStamp(timestamp, local); +} + +/*---------------------------------------------------------------------- +| NPT_DateTime::ChangeTimeZone ++---------------------------------------------------------------------*/ +NPT_Result +NPT_DateTime::ChangeTimeZone(NPT_Int32 timezone) +{ + if (timezone < -12*60 || timezone > 12*60) { + return NPT_ERROR_OUT_OF_RANGE; + } + NPT_TimeStamp ts; + NPT_Result result = ToTimeStamp(ts); + if (NPT_FAILED(result)) return result; + ts.SetNanos(ts.ToNanos()+(NPT_Int64)timezone*(NPT_Int64)60*(NPT_Int64)1000000000); + + result = FromTimeStamp(ts); + m_TimeZone = timezone; + return result; +} + +/*---------------------------------------------------------------------- +| NPT_DateTime::FromTimeStamp ++---------------------------------------------------------------------*/ +NPT_Result +NPT_DateTime::FromTimeStamp(const NPT_TimeStamp& ts, bool local) +{ + // number of seconds from the epoch (positive or negative) + NPT_Int64 seconds = ts.ToSeconds(); + + // check the range (we only allow up to 31 bits of negative range for seconds + // in order to have the same lower bound as the 32-bit gmtime() function) + if (seconds < 0 && (NPT_Int32)seconds != seconds) return NPT_ERROR_OUT_OF_RANGE; + + // adjust for the timezone if necessary + NPT_Int32 timezone = 0; + if (local) { + timezone = GetLocalTimeZone(); + seconds += timezone*60; + } + + // adjust to the number of seconds since 1900 + seconds += (NPT_Int64)NPT_SECONDS_PER_YEAR*70 + + (NPT_Int64)(17*NPT_SECONDS_PER_DAY); // 17 leap year between 1900 and 1970 + + // compute the years since 1900, not adjusting for leap years + NPT_UInt32 years_since_1900 = (NPT_UInt32)(seconds/NPT_SECONDS_PER_YEAR); + + // compute the number of seconds elapsed in the current year + seconds -= (NPT_Int64)years_since_1900 * NPT_SECONDS_PER_YEAR; + + // adjust for leap years + bool is_leap_year = false; + NPT_Int64 leap_years_since_1900 = ElapsedLeapYearsSince1900(years_since_1900+1900); + if (seconds < (leap_years_since_1900 * NPT_SECONDS_PER_DAY)) { + // not enough seconds in the current year to compensate, move one year back + seconds += NPT_SECONDS_PER_YEAR; + seconds -= leap_years_since_1900 * NPT_SECONDS_PER_DAY; + --years_since_1900; + if (NPT_TIME_YEAR_IS_LEAP(years_since_1900+1900) ) { + seconds += NPT_SECONDS_PER_DAY; + is_leap_year = true; + } + } else { + seconds -= leap_years_since_1900 * NPT_SECONDS_PER_DAY; + if (NPT_TIME_YEAR_IS_LEAP(years_since_1900+1900) ) { + is_leap_year = true; + } + } + + // now we know the year + m_Year = years_since_1900+1900; + + // compute the number of days since January 1 (0 - 365) + NPT_UInt32 day_of_the_year = (NPT_UInt32)(seconds/NPT_SECONDS_PER_DAY); + + // compute the number of seconds in the current day + seconds -= day_of_the_year * NPT_SECONDS_PER_DAY; + + // compute the number of months since January (0 - 11) and the day of month (1 - 31) */ + const NPT_Int32* month_day = is_leap_year?NPT_TIME_MONTH_DAY_LEAP:NPT_TIME_MONTH_DAY; + NPT_UInt32 month; + for (month = 1; month_day[month] < (NPT_Int32)day_of_the_year ; month++) {} + + // now we know the month and day + m_Month = month; + m_Day = day_of_the_year - month_day[month-1]; + + // compute the number of hours since midnight (0 - 23), minutes after the hour + // (0 - 59), seconds after the minute (0 - 59) and nanoseconds + m_Hours = (NPT_Int32)seconds/3600; + seconds -= m_Hours * 3600L; + m_Minutes = (NPT_Int32)seconds / 60; + m_Seconds = (NPT_Int32)seconds - m_Minutes * 60; + m_NanoSeconds = (NPT_Int32)(ts.ToNanos()%1000000000); + if (local) { + m_TimeZone = timezone; + } else { + m_TimeZone = 0; + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| CheckDate ++---------------------------------------------------------------------*/ +static NPT_Result +CheckDate(const NPT_DateTime& date) +{ + NPT_TIME_CHECK_BOUNDS(date.m_Year, NPT_DATETIME_YEAR_MIN, NPT_DATETIME_YEAR_MAX); + NPT_TIME_CHECK_BOUNDS(date.m_Month, 1, 12); + NPT_TIME_CHECK_BOUNDS(date.m_Day, 1, 31); + NPT_TIME_CHECK_BOUNDS(date.m_Hours, 0, 23); + NPT_TIME_CHECK_BOUNDS(date.m_Minutes, 0, 59); + NPT_TIME_CHECK_BOUNDS(date.m_Seconds, 0, 59); + NPT_TIME_CHECK_BOUNDS(date.m_NanoSeconds, 0, 999999999); + NPT_TIME_CHECK_BOUNDS(date.m_TimeZone, -12*60, 12*60); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_DateTime::ToTimeStamp ++---------------------------------------------------------------------*/ +NPT_Result +NPT_DateTime::ToTimeStamp(NPT_TimeStamp& timestamp) const +{ + // default value + timestamp.SetNanos(0); + + // check bounds + NPT_Result result = CheckDate(*this); + if (NPT_FAILED(result)) return result; + + // compute the number of days elapsed since 1900 + NPT_UInt32 days = ElapsedDaysSince1900(*this); + + // compute the number of nanoseconds + NPT_Int64 seconds = (NPT_Int64)days * (24*60*60) + + (NPT_Int64)m_Hours * (60*60) + + (NPT_Int64)m_Minutes * (60) + + (NPT_Int64)m_Seconds; + seconds -= (NPT_Int64)m_TimeZone*60; + + // adjust to the number of seconds since 1900 + seconds -= (NPT_Int64)NPT_SECONDS_PER_YEAR*70 + + (NPT_Int64)(17*NPT_SECONDS_PER_DAY); // 17 leap year between 1900 and 1970 + + timestamp.FromNanos(seconds * 1000000000 + m_NanoSeconds); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| AppendNumber ++---------------------------------------------------------------------*/ +static void +AppendNumber(NPT_String& output, NPT_UInt32 number, unsigned int digit_count) +{ + NPT_Size new_length = output.GetLength()+digit_count; + output.SetLength(new_length); + char* dest = output.UseChars()+new_length; + while (digit_count--) { + *--dest = '0'+(number%10); + number /= 10; + } +} + +/*---------------------------------------------------------------------- +| NPT_DateTime::ToString ++---------------------------------------------------------------------*/ +NPT_String +NPT_DateTime::ToString(Format format, NPT_Flags flags) const +{ + NPT_String result; + + if (NPT_FAILED(CheckDate(*this))) return result; + + switch (format) { + case FORMAT_W3C: + AppendNumber(result, m_Year, 4); + result += '-'; + AppendNumber(result, m_Month, 2); + result += '-'; + AppendNumber(result, m_Day, 2); + result += 'T'; + AppendNumber(result, m_Hours, 2); + result += ':'; + AppendNumber(result, m_Minutes, 2); + result += ':'; + AppendNumber(result, m_Seconds, 2); + if (flags & FLAG_EMIT_FRACTION) { + result += '.'; + if (flags & FLAG_EXTENDED_PRECISION) { + // nanoseconds precision + AppendNumber(result, m_NanoSeconds, 9); + } else { + // only miliseconds precision + AppendNumber(result, m_NanoSeconds/1000000, 3); + } + } + if (m_TimeZone) { + NPT_UInt32 tz; + if (m_TimeZone > 0) { + result += '+'; + tz = m_TimeZone; + } else { + result += '-'; + tz = -m_TimeZone; + } + AppendNumber(result, tz/60, 2); + result += ':'; + AppendNumber(result, tz%60, 2); + } else { + result += 'Z'; + } + break; + + case FORMAT_ANSI: { + // compute the number of days elapsed since 1900 + NPT_UInt32 days = ElapsedDaysSince1900(*this); + + // format the result + result.SetLength(24); + NPT_FormatString(result.UseChars(), result.GetLength()+1, + "%.3s %.3s%3d %.2d:%.2d:%.2d %d", + NPT_TIME_DAYS_SHORT[(days+1)%7], + NPT_TIME_MONTHS[m_Month-1], + m_Day, + m_Hours, + m_Minutes, + m_Seconds, + m_Year); + break; + } + + case FORMAT_RFC_1036: + case FORMAT_RFC_1123: { + // compute the number of days elapsed since 1900 + NPT_UInt32 days = ElapsedDaysSince1900(*this); + + if (format == FORMAT_RFC_1036) { + result += NPT_TIME_DAYS_LONG[(days+1)%7]; + result += ", "; + AppendNumber(result, m_Day, 2); + result += '-'; + result += NPT_TIME_MONTHS[m_Month-1]; + result += '-'; + AppendNumber(result, m_Year%100, 2); + } else { + result += NPT_TIME_DAYS_SHORT[(days+1)%7]; + result += ", "; + AppendNumber(result, m_Day, 2); + result += ' '; + result += NPT_TIME_MONTHS[m_Month-1]; + result += ' '; + AppendNumber(result, m_Year, 4); + } + result += ' '; + AppendNumber(result, m_Hours, 2); + result += ':'; + AppendNumber(result, m_Minutes, 2); + result += ':'; + AppendNumber(result, m_Seconds, 2); + if (m_TimeZone) { + if (m_TimeZone > 0) { + result += " +"; + AppendNumber(result, m_TimeZone/60, 2); + AppendNumber(result, m_TimeZone%60, 2); + } else { + result += " -"; + AppendNumber(result, -m_TimeZone/60, 2); + AppendNumber(result, -m_TimeZone%60, 2); + } + } else { + result += " GMT"; + } + break; + } + } + + return result; +} + +/*---------------------------------------------------------------------- +| NPT_DateTime::FromString ++--------------------------------------------------------------------*/ +NPT_Result +NPT_DateTime::FromString(const char* date, Format format) +{ + if (date == NULL || date[0] == '\0') return NPT_ERROR_INVALID_PARAMETERS; + + // create a local copy to work with + NPT_String workspace(date); + char* input = workspace.UseChars(); + NPT_Size input_size = workspace.GetLength(); + + switch (format) { + case FORMAT_W3C: { + if (input_size < 17 && input_size != 10) return NPT_ERROR_INVALID_SYNTAX; + + // check separators + if (input[4] != '-' || + input[7] != '-') { + return NPT_ERROR_INVALID_SYNTAX; + } + + // replace separators with terminators + input[4] = input[7] = '\0'; + + bool no_seconds = true; + if (input_size > 10) { + if (input[10] != 'T' || + input[13] != ':') { + return NPT_ERROR_INVALID_SYNTAX; + } + input[10] = input[13] = '\0'; + if (input[16] == ':') { + input[16] = '\0'; + no_seconds = false; + if (input_size < 20) return NPT_ERROR_INVALID_SYNTAX; + } else { + m_Seconds = 0; + } + } + + + // parse CCYY-MM-DD fields + if (NPT_FAILED(NPT_ParseInteger(input, m_Year, false)) || + NPT_FAILED(NPT_ParseInteger(input+5, m_Month, false)) || + NPT_FAILED(NPT_ParseInteger(input+8, m_Day, false))) { + return NPT_ERROR_INVALID_SYNTAX; + } + + // parse remaining fields if any + if (input_size > 10) { + // parse the timezone part + if (input[input_size-1] == 'Z') { + m_TimeZone = 0; + input[input_size-1] = '\0'; + } else if (input[input_size-6] == '+' || input[input_size-6] == '-') { + if (input[input_size-3] != ':') return NPT_ERROR_INVALID_SYNTAX; + input[input_size-3] = '\0'; + unsigned int hh, mm; + if (NPT_FAILED(NPT_ParseInteger(input+input_size-5, hh, false)) || + NPT_FAILED(NPT_ParseInteger(input+input_size-2, mm, false))) { + return NPT_ERROR_INVALID_SYNTAX; + } + if (hh > 59 || mm > 59) return NPT_ERROR_INVALID_SYNTAX; + m_TimeZone = hh*60+mm; + if (input[input_size-6] == '-') m_TimeZone = -m_TimeZone; + input[input_size-6] = '\0'; + } + + // parse fields + if (NPT_FAILED(NPT_ParseInteger(input+11, m_Hours, false)) || + NPT_FAILED(NPT_ParseInteger(input+14, m_Minutes, false))) { + return NPT_ERROR_INVALID_SYNTAX; + } + if (!no_seconds && input[19] == '.') { + char fraction[10]; + fraction[9] = '\0'; + unsigned int fraction_size = NPT_StringLength(&input[20]); + if (fraction_size == 0) return NPT_ERROR_INVALID_SYNTAX; + for (unsigned int i=0; i<9; i++) { + if (i < fraction_size) { + fraction[i] = input[20+i]; + } else { + fraction[i] = '0'; + } + } + if (NPT_FAILED(NPT_ParseInteger(fraction, m_NanoSeconds, false))) { + return NPT_ERROR_INVALID_SYNTAX; + } + input[19] = '\0'; + } else { + m_NanoSeconds = 0; + } + if (!no_seconds) { + if (NPT_FAILED(NPT_ParseInteger(input+17, m_Seconds, false))) { + return NPT_ERROR_INVALID_SYNTAX; + } + } + } + break; + } + + case FORMAT_RFC_1036: + case FORMAT_RFC_1123: { + if (input_size < 26) return NPT_ERROR_INVALID_SYNTAX; + // look for the weekday and separtor + const char* wday = input; + while (*input && *input != ',') { + ++input; + --input_size; + } + if (*input == '\0' || *wday == ',') return NPT_ERROR_INVALID_SYNTAX; + *input++ = '\0'; + --input_size; + + // look for the timezone + char* timezone = input+input_size-1; + unsigned int timezone_size = 0; + while (input_size && *timezone != ' ') { + --timezone; + ++timezone_size; + --input_size; + } + if (input_size == 0) return NPT_ERROR_INVALID_SYNTAX; + *timezone++ = '\0'; + + // check separators + if (input_size < 20) return NPT_ERROR_INVALID_SYNTAX; + unsigned int yl = input_size-18; + if (yl != 2 && yl != 4) return NPT_ERROR_INVALID_SYNTAX; + char sep; + int wday_index; + if (format == FORMAT_RFC_1036) { + sep = '-'; + wday_index = MatchString(wday, NPT_TIME_DAYS_LONG, 7); + } else { + sep = ' '; + wday_index = MatchString(wday, NPT_TIME_DAYS_SHORT, 7); + } + if (input[0] != ' ' || + input[3] != sep || + input[7] != sep || + input[8+yl] != ' ' || + input[11+yl] != ':' || + input[14+yl] != ':') { + return NPT_ERROR_INVALID_SYNTAX; + } + input[3] = input[7] = input[8+yl] = input[11+yl] = input[14+yl] = '\0'; + + // parse fields + m_Month = 1+MatchString(input+4, NPT_TIME_MONTHS, 12); + if (NPT_FAILED(NPT_ParseInteger(input+1, m_Day, false)) || + NPT_FAILED(NPT_ParseInteger(input+8, m_Year, false)) || + NPT_FAILED(NPT_ParseInteger(input+9+yl, m_Hours, false)) || + NPT_FAILED(NPT_ParseInteger(input+12+yl, m_Minutes, false)) || + NPT_FAILED(NPT_ParseInteger(input+15+yl, m_Seconds, false))) { + return NPT_ERROR_INVALID_SYNTAX; + } + + // adjust short year lengths + if (yl == 2) m_Year += 1900; + + // parse the timezone + if (NPT_StringsEqual(timezone, "GMT") || + NPT_StringsEqual(timezone, "UT") || + NPT_StringsEqual(timezone, "Z")) { + m_TimeZone = 0; + } else if (NPT_StringsEqual(timezone, "EDT")) { + m_TimeZone = -4*60; + } else if (NPT_StringsEqual(timezone, "EST") || + NPT_StringsEqual(timezone, "CDT")) { + m_TimeZone = -5*60; + } else if (NPT_StringsEqual(timezone, "CST") || + NPT_StringsEqual(timezone, "MDT")) { + m_TimeZone = -6*60; + } else if (NPT_StringsEqual(timezone, "MST") || + NPT_StringsEqual(timezone, "PDT")) { + m_TimeZone = -7*60; + } else if (NPT_StringsEqual(timezone, "PST")) { + m_TimeZone = -8*60; + } else if (timezone_size == 1) { + if (timezone[0] >= 'A' && timezone[0] <= 'I') { + m_TimeZone = -60*(1+timezone[0]-'A'); + } else if (timezone[0] >= 'K' && timezone[0] <= 'M') { + m_TimeZone = -60*(timezone[0]-'A'); + } else if (timezone[0] >= 'N' && timezone[0] <= 'Y') { + m_TimeZone = 60*(1+timezone[0]-'N'); + } else { + return NPT_ERROR_INVALID_SYNTAX; + } + } else if (timezone_size == 5) { + int sign; + if (timezone[0] == '-') { + sign = -1; + } else if (timezone[0] == '+') { + sign = 1; + } else { + return NPT_ERROR_INVALID_SYNTAX; + } + NPT_UInt32 tz; + if (NPT_FAILED(NPT_ParseInteger(timezone+1, tz, false))) { + return NPT_ERROR_INVALID_SYNTAX; + } + unsigned int hh = (tz/100); + unsigned int mm = (tz%100); + if (hh > 59 || mm > 59) return NPT_ERROR_INVALID_SYNTAX; + m_TimeZone = sign*(hh*60+mm); + } else { + return NPT_ERROR_INVALID_SYNTAX; + } + + // compute the number of days elapsed since 1900 + NPT_UInt32 days = ElapsedDaysSince1900(*this); + if ((int)((days+1)%7) != wday_index) { + return NPT_ERROR_INVALID_PARAMETERS; + } + + m_NanoSeconds = 0; + + break; + } + + case FORMAT_ANSI: { + if (input_size != 24) return NPT_ERROR_INVALID_SYNTAX; + + // check separators + if (input[3] != ' ' || + input[7] != ' ' || + input[10] != ' ' || + input[13] != ':' || + input[16] != ':' || + input[19] != ' ') { + return NPT_ERROR_INVALID_SYNTAX; + } + input[3] = input[7] = input[10] = input[13] = input[16] = input[19] = '\0'; + if (input[8] == ' ') input[8] = '0'; + + m_Month = 1+MatchString(input+4, NPT_TIME_MONTHS, 12); + if (NPT_FAILED(NPT_ParseInteger(input+8, m_Day, false)) || + NPT_FAILED(NPT_ParseInteger(input+11, m_Hours, false)) || + NPT_FAILED(NPT_ParseInteger(input+14, m_Minutes, false)) || + NPT_FAILED(NPT_ParseInteger(input+17, m_Seconds, false)) || + NPT_FAILED(NPT_ParseInteger(input+20, m_Year, false))) { + return NPT_ERROR_INVALID_SYNTAX; + } + + // compute the number of days elapsed since 1900 + NPT_UInt32 days = ElapsedDaysSince1900(*this); + if ((int)((days+1)%7) != MatchString(input, NPT_TIME_DAYS_SHORT, 7)) { + return NPT_ERROR_INVALID_PARAMETERS; + } + + m_TimeZone = 0; + m_NanoSeconds = 0; + break; + } + + default: + return NPT_ERROR_INVALID_PARAMETERS; + } + + return CheckDate(*this); +} diff --git a/lib/libUPnP/Neptune/Source/Core/NptTime.h b/lib/libUPnP/Neptune/Source/Core/NptTime.h new file mode 100644 index 0000000..ae02a48 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptTime.h @@ -0,0 +1,156 @@ +/***************************************************************** +| +| Neptune - Time +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +#ifndef _NPT_TIME_H_ +#define _NPT_TIME_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptTypes.h" +#include "NptStrings.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +#define NPT_DATETIME_YEAR_MIN 1901 +#define NPT_DATETIME_YEAR_MAX 2262 + +/*---------------------------------------------------------------------- +| NPT_TimeStamp ++---------------------------------------------------------------------*/ +class NPT_TimeStamp +{ + public: + // methods + NPT_TimeStamp(const NPT_TimeStamp& timestamp); + NPT_TimeStamp() : m_NanoSeconds(0) {} + NPT_TimeStamp(NPT_Int64 nanoseconds) : m_NanoSeconds(nanoseconds) {} + NPT_TimeStamp(double seconds); + NPT_TimeStamp& operator+=(const NPT_TimeStamp& time_stamp); + NPT_TimeStamp& operator-=(const NPT_TimeStamp& time_stamp); + bool operator==(const NPT_TimeStamp& t) const { return m_NanoSeconds == t.m_NanoSeconds; } + bool operator!=(const NPT_TimeStamp& t) const { return m_NanoSeconds != t.m_NanoSeconds; } + bool operator> (const NPT_TimeStamp& t) const { return m_NanoSeconds > t.m_NanoSeconds; } + bool operator< (const NPT_TimeStamp& t) const { return m_NanoSeconds < t.m_NanoSeconds; } + bool operator>=(const NPT_TimeStamp& t) const { return m_NanoSeconds >= t.m_NanoSeconds; } + bool operator<=(const NPT_TimeStamp& t) const { return m_NanoSeconds <= t.m_NanoSeconds; } + + // accessors + void SetNanos(NPT_Int64 nanoseconds) { m_NanoSeconds = nanoseconds; } + void SetMicros(NPT_Int64 micros) { m_NanoSeconds = micros * 1000; } + void SetMillis(NPT_Int64 millis) { m_NanoSeconds = millis * 1000000; } + void SetSeconds(NPT_Int64 seconds) { m_NanoSeconds = seconds * 1000000000; } + + // conversion + operator double() const { return (double)m_NanoSeconds/1E9; } + void FromNanos(NPT_Int64 nanoseconds) { m_NanoSeconds = nanoseconds; } + NPT_Int64 ToNanos() const { return m_NanoSeconds; } + NPT_Int64 ToMicros() const { return m_NanoSeconds/1000; } + NPT_Int64 ToMillis() const { return m_NanoSeconds/1000000; } + NPT_Int64 ToSeconds() const { return m_NanoSeconds/1000000000; } + +private: + // members + NPT_Int64 m_NanoSeconds; +}; + +/*---------------------------------------------------------------------- +| operator+ ++---------------------------------------------------------------------*/ +inline +NPT_TimeStamp +operator+(const NPT_TimeStamp& t1, const NPT_TimeStamp& t2) +{ + NPT_TimeStamp t = t1; + return t += t2; +} + +/*---------------------------------------------------------------------- +| operator- ++---------------------------------------------------------------------*/ +inline +NPT_TimeStamp +operator-(const NPT_TimeStamp& t1, const NPT_TimeStamp& t2) +{ + NPT_TimeStamp t = t1; + return t -= t2; +} + +/*---------------------------------------------------------------------- +| NPT_TimeInterval ++---------------------------------------------------------------------*/ +typedef NPT_TimeStamp NPT_TimeInterval; + +/*---------------------------------------------------------------------- +| NPT_DateTime ++---------------------------------------------------------------------*/ +class NPT_DateTime { +public: + // types + enum Format { + FORMAT_ANSI, + FORMAT_W3C, + FORMAT_RFC_1123, // RFC 822 updated by RFC 1123 + FORMAT_RFC_1036 // RFC 850 updated by RFC 1036 + }; + + enum FormatFlags { + FLAG_EMIT_FRACTION = 1, + FLAG_EXTENDED_PRECISION = 2 + }; + + // class methods + NPT_Int32 GetLocalTimeZone(); + + // constructors + NPT_DateTime(); + NPT_DateTime(const NPT_TimeStamp& timestamp, bool local=false); + + // methods + NPT_Result ChangeTimeZone(NPT_Int32 timezone); + NPT_Result FromTimeStamp(const NPT_TimeStamp& timestamp, bool local=false); + NPT_Result ToTimeStamp(NPT_TimeStamp& timestamp) const; + NPT_Result FromString(const char* date, Format format = FORMAT_ANSI); + NPT_String ToString(Format format = FORMAT_ANSI, NPT_Flags flags=0) const; + + // members + NPT_Int32 m_Year; // year + NPT_Int32 m_Month; // month of the year (1-12) + NPT_Int32 m_Day; // day of the month (1-31) + NPT_Int32 m_Hours; // hours (0-23) + NPT_Int32 m_Minutes; // minutes (0-59) + NPT_Int32 m_Seconds; // seconds (0-59) + NPT_Int32 m_NanoSeconds; // nanoseconds (0-999999999) + NPT_Int32 m_TimeZone; // minutes offset from GMT +}; + +#endif // _NPT_TIME_H_ diff --git a/lib/libUPnP/Neptune/Source/Core/NptTls.cpp b/lib/libUPnP/Neptune/Source/Core/NptTls.cpp new file mode 100644 index 0000000..594adbd --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptTls.cpp @@ -0,0 +1,1227 @@ +/***************************************************************** +| +| Neptune - TLS/SSL Support +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptConfig.h" +#include "NptTls.h" +#include "NptLogging.h" +#include "NptUtils.h" +#include "NptSockets.h" +#include "NptSystem.h" +#include "NptDigest.h" +#include "NptAutomaticCleaner.h" + +/*---------------------------------------------------------------------- +| logging ++---------------------------------------------------------------------*/ +NPT_SET_LOCAL_LOGGER("neptune.tls") + +#if defined(NPT_CONFIG_ENABLE_TLS) +#include "ssl.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const unsigned int NPT_TLS_CONTEXT_DEFAULT_SESSION_CACHE = 16; +const unsigned int NPT_HTTP_TLS_CONNECTOR_MAX_PROXY_RESPONSE_SIZE = (16*1024); + +/*---------------------------------------------------------------------- +| types ++---------------------------------------------------------------------*/ +typedef NPT_Reference<NPT_TlsSessionImpl> NPT_TlsSessionImplReference; + +/*---------------------------------------------------------------------- +| SSL_DateTime_Before ++---------------------------------------------------------------------*/ +int +SSL_DateTime_Before(const SSL_DateTime* t1, const SSL_DateTime* t2) +{ + if (t1->year == t2->year) { + if (t1->month == t2->month) { + if (t1->day == t2->day) { + return t1->hours*3600+t1->minutes*60+t1->seconds < + t2->hours*3600+t2->minutes*60+t2->seconds ? 1 : 0; + } else { + return t1->day < t2->day ? 1 : 0; + } + } else { + return t1->month < t2->month ? 1 : 0; + } + } else { + return t1->year < t2->year ? 1 : 0; + } +} + +/*---------------------------------------------------------------------- +| SSL_DateTime_Now ++---------------------------------------------------------------------*/ +void +SSL_DateTime_Now(SSL_DateTime* now) +{ + NPT_TimeStamp ts; + NPT_System::GetCurrentTimeStamp(ts); + NPT_DateTime dt; + dt.FromTimeStamp(ts); + now->year = dt.m_Year; + now->month = dt.m_Month; + now->day = dt.m_Day; + now->hours = dt.m_Hours; + now->minutes = dt.m_Minutes; + now->seconds = dt.m_Seconds; +} + +/*---------------------------------------------------------------------- +| SSL_GetRandomSeed ++---------------------------------------------------------------------*/ +uint64_t +SSL_GetRandomSeed() +{ + NPT_TimeStamp ts; + NPT_System::GetCurrentTimeStamp(ts); + return ts.ToNanos(); +} + +/*---------------------------------------------------------------------- +| SSL_Mutex_Create ++---------------------------------------------------------------------*/ +void +SSL_Mutex_Create(NPT_Mutex** mutex) +{ + *mutex = new NPT_Mutex(); +} + +/*---------------------------------------------------------------------- +| SSL_Mutex_Destroy ++---------------------------------------------------------------------*/ +void +SSL_Mutex_Destroy(NPT_Mutex* mutex) +{ + delete mutex; +} + +/*---------------------------------------------------------------------- +| SSL_Mutex_Lock ++---------------------------------------------------------------------*/ +void +SSL_Mutex_Lock(NPT_Mutex* mutex) +{ + mutex->Lock(); +} + +/*---------------------------------------------------------------------- +| SSL_Mutex_Lock ++---------------------------------------------------------------------*/ +void +SSL_Mutex_Unlock(NPT_Mutex* mutex) +{ + mutex->Unlock(); +} + +/*---------------------------------------------------------------------- +| SSL_Sha256_ComputeDigest ++---------------------------------------------------------------------*/ +void +SSL_Sha256_ComputeDigest(const unsigned char* data, + unsigned int data_size, + unsigned char* digest_value) +{ + NPT_Digest* digest = NULL; + NPT_Digest::Create(NPT_Digest::ALGORITHM_SHA256, digest); + digest->Update(data, data_size); + NPT_DataBuffer buffer; + digest->GetDigest(buffer); + NPT_CopyMemory(digest_value, buffer.GetData(), 32); + delete digest; +} + +/*---------------------------------------------------------------------- +| NPT_Tls::MatchDnsName ++---------------------------------------------------------------------*/ +bool +NPT_Tls::MatchDnsName(const char* hostname, const char* dns_name) +{ + // NULL or empty names don't match anything + if (hostname == NULL || *hostname == '\0') return false; + if (dns_name == NULL || *dns_name == '\0') return false; + + // check for wildcards */ + if (dns_name[0] == '*') { + // wildcard match, expect '*.' at the start, we don't match '*foo.com' + if (dns_name[1] != '.') return false; + + // skip the first component of the hostname + while (hostname[0] != '\0' && hostname[0] != '.') { + ++hostname; + } + if (hostname[0] == '.') ++hostname; + + // compare the tails + return NPT_String::Compare(hostname, dns_name+2, true) == 0; + } else { + // full match + return NPT_String::Compare(hostname, dns_name, true) == 0; + } +} + +/*---------------------------------------------------------------------- +| NPT_Tls::MatchDnsNames ++---------------------------------------------------------------------*/ +bool +NPT_Tls::MatchDnsNames(const char* hostname, + const NPT_List<NPT_String>& dns_names) +{ + // NULL or empty names don't match anything + if (hostname == NULL || *hostname == '\0') return false; + + // check the dns names + for (NPT_List<NPT_String>::Iterator i = dns_names.GetFirstItem(); + i; + ++i) { + if (MatchDnsName(hostname, (*i).GetChars())) return true; + } + + // no match + return false; +} + +/*---------------------------------------------------------------------- +| NPT_Tls_MapResult ++---------------------------------------------------------------------*/ +static NPT_Result +NPT_Tls_MapResult(int err) +{ + switch (err) { + case SSL_ERROR_CONN_LOST: return NPT_ERROR_CONNECTION_ABORTED; + case SSL_ERROR_TIMEOUT: return NPT_ERROR_TIMEOUT; + case SSL_ERROR_EOS: return NPT_ERROR_EOS; + case SSL_CLOSE_NOTIFY: return NPT_ERROR_EOS; + case SSL_ERROR_NOT_SUPPORTED: return NPT_ERROR_NOT_SUPPORTED; + case SSL_ERROR_INVALID_HANDSHAKE: return NPT_ERROR_TLS_INVALID_HANDSHAKE; + case SSL_ERROR_INVALID_PROT_MSG: return NPT_ERROR_TLS_INVALID_PROTOCOL_MESSAGE; + case SSL_ERROR_INVALID_HMAC: return NPT_ERROR_TLS_INVALID_HMAC; + case SSL_ERROR_INVALID_VERSION: return NPT_ERROR_TLS_INVALID_VERSION; + case SSL_ERROR_INVALID_SESSION: return NPT_ERROR_TLS_INVALID_SESSION; + case SSL_ERROR_NO_CIPHER: return NPT_ERROR_TLS_NO_CIPHER; + case SSL_ERROR_BAD_CERTIFICATE: return NPT_ERROR_TLS_BAD_CERTIFICATE; + case SSL_ERROR_INVALID_KEY: return NPT_ERROR_TLS_INVALID_KEY; + case SSL_ERROR_FINISHED_INVALID: return NPT_ERROR_TLS_INVALID_FINISHED_MESSAGE; + case SSL_ERROR_NO_CERT_DEFINED: return NPT_ERROR_TLS_NO_CERTIFICATE_DEFINED; + case SSL_ERROR_NO_CLIENT_RENOG: return NPT_ERROR_TLS_NO_CLIENT_RENEGOTIATION; + case -SSL_ALERT_HANDSHAKE_FAILURE: return NPT_ERROR_TLS_ALERT_HANDSHAKE_FAILED; + case -SSL_ALERT_BAD_CERTIFICATE: return NPT_ERROR_TLS_ALERT_BAD_CERTIFICATE; + case -SSL_ALERT_INVALID_VERSION: return NPT_ERROR_TLS_ALERT_INVALID_VERSION; + case -SSL_ALERT_BAD_RECORD_MAC: return NPT_ERROR_TLS_ALERT_BAD_RECORD_MAC; + case -SSL_ALERT_DECODE_ERROR: return NPT_ERROR_TLS_ALERT_DECODE_ERROR; + case -SSL_ALERT_DECRYPT_ERROR: return NPT_ERROR_TLS_ALERT_DECRYPT_ERROR; + case -SSL_ALERT_ILLEGAL_PARAMETER: return NPT_ERROR_TLS_ALERT_ILLEGAL_PARAMETER; + case -SSL_ALERT_UNEXPECTED_MESSAGE: return NPT_ERROR_TLS_ALERT_UNEXPECTED_MESSAGE; + case SSL_X509_ERROR(X509_NOT_OK): return NPT_ERROR_TLS_CERTIFICATE_FAILURE; + case SSL_X509_ERROR(X509_VFY_ERROR_NO_TRUSTED_CERT): return NPT_ERROR_TLS_CERTIFICATE_NO_TRUST_ANCHOR; + case SSL_X509_ERROR(X509_VFY_ERROR_BAD_SIGNATURE): return NPT_ERROR_TLS_CERTIFICATE_BAD_SIGNATURE; + case SSL_X509_ERROR(X509_VFY_ERROR_NOT_YET_VALID): return NPT_ERROR_TLS_CERTIFICATE_NOT_YET_VALID; + case SSL_X509_ERROR(X509_VFY_ERROR_EXPIRED): return NPT_ERROR_TLS_CERTIFICATE_EXPIRED; + case SSL_X509_ERROR(X509_VFY_ERROR_SELF_SIGNED): return NPT_ERROR_TLS_CERTIFICATE_SELF_SIGNED; + case SSL_X509_ERROR(X509_VFY_ERROR_INVALID_CHAIN): return NPT_ERROR_TLS_CERTIFICATE_INVALID_CHAIN; + case SSL_X509_ERROR(X509_VFY_ERROR_UNSUPPORTED_DIGEST): return NPT_ERROR_TLS_CERTIFICATE_UNSUPPORTED_DIGEST; + case SSL_X509_ERROR(X509_INVALID_PRIV_KEY): return NPT_ERROR_TLS_CERTIFICATE_INVALID_PRIVATE_KEY; + case 0: return NPT_SUCCESS; + default: return NPT_FAILURE; + } +} + +/*---------------------------------------------------------------------- +| NPT_TlsContextImpl ++---------------------------------------------------------------------*/ +class NPT_TlsContextImpl { +public: + NPT_TlsContextImpl(NPT_Flags options) : + m_SSL_CTX(ssl_ctx_new(((options & NPT_TlsContext::OPTION_VERIFY_LATER)?SSL_SERVER_VERIFY_LATER:0) | + ((options & NPT_TlsContext::OPTION_REQUIRE_CLIENT_CERTIFICATE)?SSL_CLIENT_AUTHENTICATION:0), + (options & NPT_TlsContext::OPTION_NO_SESSION_CACHE)?0:NPT_TLS_CONTEXT_DEFAULT_SESSION_CACHE)) {} + ~NPT_TlsContextImpl() { ssl_ctx_free(m_SSL_CTX); } + + NPT_Result LoadKey(NPT_TlsKeyFormat key_format, + const unsigned char* key_data, + NPT_Size key_data_size, + const char* password); + NPT_Result SelfSignCertificate(const char* common_name, + const char* organization, + const char* organizational_name); + NPT_Result AddTrustAnchor(const unsigned char* ta_data, + NPT_Size ta_data_size); + + SSL_CTX* m_SSL_CTX; +}; + +/*---------------------------------------------------------------------- +| NPT_TlsContextImpl::LoadKey ++---------------------------------------------------------------------*/ +NPT_Result +NPT_TlsContextImpl::LoadKey(NPT_TlsKeyFormat key_format, + const unsigned char* key_data, + NPT_Size key_data_size, + const char* password) +{ + int object_type; + switch (key_format) { + case NPT_TLS_KEY_FORMAT_RSA_PRIVATE: object_type = SSL_OBJ_RSA_KEY; break; + case NPT_TLS_KEY_FORMAT_PKCS8: object_type = SSL_OBJ_PKCS8; break; + case NPT_TLS_KEY_FORMAT_PKCS12: object_type = SSL_OBJ_PKCS12; break; + default: return NPT_ERROR_INVALID_PARAMETERS; + } + + int result = ssl_obj_memory_load(m_SSL_CTX, object_type, key_data, key_data_size, password); + return NPT_Tls_MapResult(result); +} + +/*---------------------------------------------------------------------- +| NPT_TlsContextImpl::SelfSignCertificate ++---------------------------------------------------------------------*/ +NPT_Result +NPT_TlsContextImpl::SelfSignCertificate(const char* common_name, + const char* organization, + const char* organizational_name) +{ + const char* dn[3] = {common_name, organization, organizational_name}; + uint8_t* certificate = NULL; + int result = ssl_x509_create(m_SSL_CTX, 0, dn, &certificate); + if (result <= 0) { + if (certificate) { + ssl_mem_free(certificate); + } + return NPT_Tls_MapResult(result); + } + result = ssl_obj_memory_load(m_SSL_CTX, SSL_OBJ_X509_CERT, certificate, result, NULL); + ssl_mem_free(certificate); + + return NPT_Tls_MapResult(result); +} + +/*---------------------------------------------------------------------- +| NPT_TlsContextImpl::AddTrustAnchor ++---------------------------------------------------------------------*/ +NPT_Result +NPT_TlsContextImpl::AddTrustAnchor(const unsigned char* ta_data, + NPT_Size ta_data_size) +{ + int result = ssl_obj_memory_load(m_SSL_CTX, SSL_OBJ_X509_CACERT, ta_data, ta_data_size, NULL); + return NPT_Tls_MapResult(result); +} + +/*---------------------------------------------------------------------- +| NPT_TlsStreamAdapter ++---------------------------------------------------------------------*/ +struct NPT_TlsStreamAdapter +{ + static int Read(SSL_SOCKET* _self, void* buffer, unsigned int size) { + NPT_TlsStreamAdapter* self = (NPT_TlsStreamAdapter*)_self; + NPT_Size bytes_read = 0; + NPT_Result result = self->m_Input->Read(buffer, size, &bytes_read); + if (NPT_FAILED(result)) { + switch (result) { + case NPT_ERROR_EOS: return SSL_ERROR_EOS; + case NPT_ERROR_TIMEOUT: return SSL_ERROR_TIMEOUT; + default: return SSL_ERROR_CONN_LOST; + } + } + return bytes_read; + } + + static int Write(SSL_SOCKET* _self, const void* buffer, unsigned int size) { + NPT_TlsStreamAdapter* self = (NPT_TlsStreamAdapter*)_self; + NPT_Size bytes_written = 0; + NPT_Result result = self->m_Output->Write(buffer, size, &bytes_written); + if (NPT_FAILED(result)) { + switch (result) { + case NPT_ERROR_EOS: return SSL_ERROR_EOS; + case NPT_ERROR_TIMEOUT: return SSL_ERROR_TIMEOUT; + default: return SSL_ERROR_CONN_LOST; + } + } + return bytes_written; + } + + NPT_TlsStreamAdapter(NPT_InputStreamReference input, + NPT_OutputStreamReference output) : + m_Input(input), m_Output(output) { + m_Base.Read = Read; + m_Base.Write = Write; + } + + SSL_SOCKET m_Base; + NPT_InputStreamReference m_Input; + NPT_OutputStreamReference m_Output; +}; + + +/*---------------------------------------------------------------------- +| NPT_TlsSessionImpl ++---------------------------------------------------------------------*/ +class NPT_TlsSessionImpl { +public: + NPT_TlsSessionImpl(SSL_CTX* context, + NPT_InputStreamReference& input, + NPT_OutputStreamReference& output) : + m_SSL_CTX(context), + m_SSL(NULL), + m_StreamAdapter(input, output) {} + virtual ~NPT_TlsSessionImpl() { ssl_free(m_SSL); } + + // methods + virtual NPT_Result Handshake() = 0; + virtual NPT_Result GetHandshakeStatus(); + virtual NPT_Result VerifyPeerCertificate(); + virtual NPT_Result VerifyDnsNameMatch(const char* hostname); + virtual NPT_Result GetSessionId(NPT_DataBuffer& session_id); + virtual NPT_UInt32 GetCipherSuiteId(); + virtual NPT_Result GetPeerCertificateInfo(NPT_TlsCertificateInfo& cert_info, + NPT_Ordinal position); + + // members + SSL_CTX* m_SSL_CTX; + SSL* m_SSL; + NPT_TlsStreamAdapter m_StreamAdapter; +}; + +/*---------------------------------------------------------------------- +| NPT_TlsSessionImpl::GetHandshakeStatus ++---------------------------------------------------------------------*/ +NPT_Result +NPT_TlsSessionImpl::GetHandshakeStatus() +{ + int status; + if (m_SSL == NULL || (status = ssl_handshake_status(m_SSL)) == SSL_NOT_OK) { + // no handshake done + return NPT_ERROR_INVALID_STATE; + } + + return NPT_Tls_MapResult(status); +} + +/*---------------------------------------------------------------------- +| NPT_TlsSessionImpl::VerifyPeerCertificate ++---------------------------------------------------------------------*/ +NPT_Result +NPT_TlsSessionImpl::VerifyPeerCertificate() +{ + if (m_SSL == NULL || ssl_handshake_status(m_SSL) == SSL_NOT_OK) { + // no handshake done + return NPT_ERROR_INVALID_STATE; + } + + int result = ssl_verify_cert(m_SSL); + return NPT_Tls_MapResult(result); +} + +/*---------------------------------------------------------------------- +| NPT_TlsSessionImpl::VerifyDnsNameMatch ++---------------------------------------------------------------------*/ +NPT_Result +NPT_TlsSessionImpl::VerifyDnsNameMatch(const char* hostname) +{ + if (hostname == NULL) return NPT_ERROR_INVALID_PARAMETERS; + if (m_SSL == NULL || ssl_handshake_status(m_SSL) == SSL_NOT_OK) { + // no handshake done + return NPT_ERROR_INVALID_STATE; + } + + // get the peer certificate + const SSL_X509_CERT* cert = ssl_get_peer_cert(m_SSL, 0); + if (cert == NULL) return NPT_ERROR_NO_SUCH_ITEM; + + // try the common name + const char* common_name = ssl_cert_get_dn(cert, SSL_X509_CERT_COMMON_NAME); + if (common_name && NPT_Tls::MatchDnsName(hostname, common_name)) return NPT_SUCCESS; + + // try all the alt DNS names + const char* alt_name = NULL; + for (unsigned int i=0; (alt_name=ssl_cert_get_subject_alt_dnsname(cert, i)); i++) { + if (NPT_Tls::MatchDnsName(hostname, alt_name)) return NPT_SUCCESS; + } + + return NPT_FAILURE; +} + +/*---------------------------------------------------------------------- +| NPT_TlsSessionImpl::GetSessionId ++---------------------------------------------------------------------*/ +NPT_Result +NPT_TlsSessionImpl::GetSessionId(NPT_DataBuffer& session_id) +{ + if (m_SSL == NULL || ssl_handshake_status(m_SSL) == SSL_NOT_OK) { + // no handshake done + session_id.SetDataSize(0); + return NPT_ERROR_INVALID_STATE; + } + + // return the session id + session_id.SetData(ssl_get_session_id(m_SSL), + ssl_get_session_id_size(m_SSL)); + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_TlsSessionImpl::GetCipherSuiteId ++---------------------------------------------------------------------*/ +NPT_UInt32 +NPT_TlsSessionImpl::GetCipherSuiteId() +{ + if (m_SSL == NULL || ssl_handshake_status(m_SSL) == SSL_NOT_OK) { + // no handshake done + return 0; + } + + return ssl_get_cipher_id(m_SSL); +} + +/*---------------------------------------------------------------------- +| NPT_TlsSessionImpl::GetPeerCertificateInfo ++---------------------------------------------------------------------*/ +NPT_Result +NPT_TlsSessionImpl::GetPeerCertificateInfo(NPT_TlsCertificateInfo& cert_info, + NPT_Ordinal position) +{ + if (m_SSL == NULL || ssl_handshake_status(m_SSL) == SSL_NOT_OK) { + // no handshake done + return NPT_ERROR_INVALID_STATE; + } + + // find the certificate at the requested index + const SSL_X509_CERT* cert = ssl_get_peer_cert(m_SSL, position); + if (cert == NULL) return NPT_ERROR_NO_SUCH_ITEM; + + // get the certificate fields + cert_info.subject.common_name = ssl_cert_get_dn(cert, SSL_X509_CERT_COMMON_NAME); + cert_info.subject.organization = ssl_cert_get_dn(cert, SSL_X509_CERT_ORGANIZATION); + cert_info.subject.organizational_name = ssl_cert_get_dn(cert, SSL_X509_CERT_ORGANIZATIONAL_NAME); + cert_info.issuer.common_name = ssl_cert_get_dn(cert, SSL_X509_CA_CERT_COMMON_NAME); + cert_info.issuer.organization = ssl_cert_get_dn(cert, SSL_X509_CA_CERT_ORGANIZATION); + cert_info.issuer.organizational_name = ssl_cert_get_dn(cert, SSL_X509_CA_CERT_ORGANIZATIONAL_NAME); + + ssl_cert_get_fingerprints(cert, cert_info.fingerprint.md5, cert_info.fingerprint.sha1); + SSL_DateTime not_before, not_after; + ssl_cert_get_validity_dates(cert, ¬_before, ¬_after); + cert_info.issue_date.m_Year = not_before.year; + cert_info.issue_date.m_Month = not_before.month; + cert_info.issue_date.m_Day = not_before.day; + cert_info.issue_date.m_Hours = not_before.hours; + cert_info.issue_date.m_Minutes = not_before.minutes; + cert_info.issue_date.m_Seconds = not_before.seconds; + cert_info.issue_date.m_NanoSeconds = 0; + cert_info.issue_date.m_TimeZone = 0; + cert_info.expiration_date.m_Year = not_after.year; + cert_info.expiration_date.m_Month = not_after.month; + cert_info.expiration_date.m_Day = not_after.day; + cert_info.expiration_date.m_Hours = not_after.hours; + cert_info.expiration_date.m_Minutes = not_after.minutes; + cert_info.expiration_date.m_Seconds = not_after.seconds; + cert_info.expiration_date.m_NanoSeconds = 0; + cert_info.expiration_date.m_TimeZone = 0; + + // alternate names + cert_info.alternate_names.Clear(); + const char* alt_name = NULL; + for (unsigned int i=0; (alt_name=ssl_cert_get_subject_alt_dnsname(cert, i)); i++) { + cert_info.alternate_names.Add(NPT_String(alt_name)); + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_TlsClientSessionImpl ++---------------------------------------------------------------------*/ +class NPT_TlsClientSessionImpl : public NPT_TlsSessionImpl { +public: + NPT_TlsClientSessionImpl(SSL_CTX* context, + NPT_InputStreamReference& input, + NPT_OutputStreamReference& output) : + NPT_TlsSessionImpl(context, input, output) {} + + // methods + virtual NPT_Result Handshake(); +}; + +/*---------------------------------------------------------------------- +| NPT_TlsClientSessionImpl::Handshake ++---------------------------------------------------------------------*/ +NPT_Result +NPT_TlsClientSessionImpl::Handshake() +{ + if (m_SSL == NULL) { + // we have not created the client object yet + m_SSL = ssl_client_new(m_SSL_CTX, &m_StreamAdapter.m_Base, NULL, 0); + } + + int result = ssl_handshake_status(m_SSL); + return NPT_Tls_MapResult(result); +} + +/*---------------------------------------------------------------------- +| NPT_TlsServerSessionImpl ++---------------------------------------------------------------------*/ +class NPT_TlsServerSessionImpl : public NPT_TlsSessionImpl { +public: + NPT_TlsServerSessionImpl(SSL_CTX* context, + NPT_InputStreamReference& input, + NPT_OutputStreamReference& output) : + NPT_TlsSessionImpl(context, input, output) {} + + // methods + virtual NPT_Result Handshake(); +}; + +/*---------------------------------------------------------------------- +| NPT_TlsServerSessionImpl::Handshake ++---------------------------------------------------------------------*/ +NPT_Result +NPT_TlsServerSessionImpl::Handshake() +{ + if (m_SSL == NULL) { + // we have not created the server object yet + m_SSL = ssl_server_new(m_SSL_CTX, &m_StreamAdapter.m_Base); + } + + uint8_t* data = NULL; + int result; + while ((result = ssl_handshake_status(m_SSL)) == SSL_NOT_OK) { + result = ssl_read(m_SSL, &data); + if (result != SSL_OK) break; + if (data != NULL) { + NPT_LOG_WARNING("got data during handshake???"); + return NPT_ERROR_INTERNAL; + } + } + return NPT_Tls_MapResult(result); +} + +/*---------------------------------------------------------------------- +| NPT_TlsInputStream ++---------------------------------------------------------------------*/ +class NPT_TlsInputStream : public NPT_InputStream { +public: + NPT_TlsInputStream(NPT_TlsSessionImplReference& session) : + m_Session(session), + m_Position(0), + m_RecordCacheData(NULL), + m_RecordCacheSize(0) {} + + // NPT_InputStream methods + virtual NPT_Result Read(void* buffer, + NPT_Size bytes_to_read, + NPT_Size* bytes_read = NULL); + virtual NPT_Result Seek(NPT_Position) { return NPT_ERROR_NOT_SUPPORTED; } + virtual NPT_Result Tell(NPT_Position& offset) { offset = m_Position; return NPT_SUCCESS; } + virtual NPT_Result GetSize(NPT_LargeSize& size) { size=0; return NPT_ERROR_NOT_SUPPORTED; } + virtual NPT_Result GetAvailable(NPT_LargeSize& available); + +private: + NPT_TlsSessionImplReference m_Session; + NPT_Position m_Position; + uint8_t* m_RecordCacheData; + NPT_Size m_RecordCacheSize; +}; + +/*---------------------------------------------------------------------- +| NPT_TlsInputStream::Read ++---------------------------------------------------------------------*/ +NPT_Result +NPT_TlsInputStream::Read(void* buffer, + NPT_Size bytes_to_read, + NPT_Size* bytes_read) +{ + // setup default values + if (bytes_read) *bytes_read = 0; + + // quick check for edge case + if (bytes_to_read == 0) return NPT_SUCCESS; + + // read a new record if we don't have one cached + if (m_RecordCacheData == NULL) { + int ssl_result; + do { + ssl_result = ssl_read(m_Session->m_SSL, &m_RecordCacheData); + } while (ssl_result == 0); + if (ssl_result < 0) { + return NPT_Tls_MapResult(ssl_result); + } + m_RecordCacheSize = ssl_result; + } + + // we now have data in cache + if (bytes_to_read > m_RecordCacheSize) { + // read at most what's in the cache + bytes_to_read = m_RecordCacheSize; + } + NPT_CopyMemory(buffer, m_RecordCacheData, bytes_to_read); + if (bytes_read) *bytes_read = bytes_to_read; + + // update the record cache + m_RecordCacheSize -= bytes_to_read; + if (m_RecordCacheSize == 0) { + // nothing left in the cache + m_RecordCacheData = NULL; + } else { + // move the cache pointer + m_RecordCacheData += bytes_to_read; + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_TlsInputStream::GetAvailable ++---------------------------------------------------------------------*/ +NPT_Result +NPT_TlsInputStream::GetAvailable(NPT_LargeSize& /*available*/) +{ + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_TlsOutputStream ++---------------------------------------------------------------------*/ +class NPT_TlsOutputStream : public NPT_OutputStream { +public: + NPT_TlsOutputStream(NPT_TlsSessionImplReference& session) : + m_Session(session), + m_Position(0) {} + + // NPT_OutputStream methods + virtual NPT_Result Write(const void* buffer, + NPT_Size bytes_to_write, + NPT_Size* bytes_written = NULL); + virtual NPT_Result Seek(NPT_Position) { return NPT_ERROR_NOT_SUPPORTED; } + virtual NPT_Result Tell(NPT_Position& offset) { offset = m_Position; return NPT_SUCCESS; } + +private: + NPT_TlsSessionImplReference m_Session; + NPT_Position m_Position; +}; + +/*---------------------------------------------------------------------- +| NPT_TlsOutputStream::Write ++---------------------------------------------------------------------*/ +NPT_Result +NPT_TlsOutputStream::Write(const void* buffer, + NPT_Size bytes_to_write, + NPT_Size* bytes_written) +{ + // setup default values + if (bytes_written) *bytes_written = 0; + + // quick check for edge case + if (bytes_to_write == 0) return NPT_SUCCESS; + + // write some data + int ssl_result; + do { + ssl_result = ssl_write(m_Session->m_SSL, (const uint8_t*)buffer, bytes_to_write); + } while (ssl_result == 0); + if (ssl_result < 0) { + return NPT_Tls_MapResult(ssl_result); + } + m_Position += ssl_result; + if (bytes_written) *bytes_written = (NPT_Size)ssl_result; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_Tls::GetDefaultTrustAnchors ++---------------------------------------------------------------------*/ +const NPT_TlsTrustAnchorData* +NPT_Tls::GetDefaultTrustAnchors(NPT_Ordinal indx) +{ + if (indx == 0) { + return NptTlsDefaultTrustAnchorsBase; + } else if (indx == 2) { + return NptTlsDefaultTrustAnchorsExtended; + } else { + return NULL; + } +} + +/*---------------------------------------------------------------------- +| NPT_TlsContext::NPT_TlsContext ++---------------------------------------------------------------------*/ +NPT_TlsContext::NPT_TlsContext(NPT_Flags options) : + m_Impl(new NPT_TlsContextImpl(options)) +{ + if (options & OPTION_ADD_DEFAULT_TRUST_ANCHORS) { + const NPT_TlsTrustAnchorData* ta = NPT_Tls::GetDefaultTrustAnchors(0); + if (ta) { + AddTrustAnchors(ta); + } + } +} + +/*---------------------------------------------------------------------- +| NPT_TlsContext::~NPT_TlsContext ++---------------------------------------------------------------------*/ +NPT_TlsContext::~NPT_TlsContext() +{ + delete m_Impl; +} + +/*---------------------------------------------------------------------- +| NPT_TlsContext::LoadKey ++---------------------------------------------------------------------*/ +NPT_Result +NPT_TlsContext::LoadKey(NPT_TlsKeyFormat key_format, + const unsigned char* key_data, + NPT_Size key_data_size, + const char* password) +{ + return m_Impl->LoadKey(key_format, key_data, key_data_size, password); +} + +/*---------------------------------------------------------------------- +| NPT_TlsContext::SelfSignCertificate ++---------------------------------------------------------------------*/ +NPT_Result +NPT_TlsContext::SelfSignCertificate(const char* common_name, + const char* organization, + const char* organizational_name) +{ + return m_Impl->SelfSignCertificate(common_name, organization, organizational_name); +} + +/*---------------------------------------------------------------------- +| NPT_TlsContext::AddTrustAnchor ++---------------------------------------------------------------------*/ +NPT_Result +NPT_TlsContext::AddTrustAnchor(const unsigned char* ta_data, + NPT_Size ta_data_size) +{ + return m_Impl->AddTrustAnchor(ta_data, ta_data_size); +} + +/*---------------------------------------------------------------------- +| NPT_TlsContext::AddTrustAnchors ++---------------------------------------------------------------------*/ +NPT_Result +NPT_TlsContext::AddTrustAnchors(const NPT_TlsTrustAnchorData* anchors, + NPT_Cardinal anchor_count) +{ + if (anchors == NULL) return NPT_SUCCESS; + for (unsigned int i=0; + anchor_count ? + (i<anchor_count) : + (anchors[i].cert_data && anchors[i].cert_size); + i++) { + // add the trust anchor and ignore the error + m_Impl->AddTrustAnchor(anchors[i].cert_data, anchors[i].cert_size); + } + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_TlsSession::NPT_TlsSession ++---------------------------------------------------------------------*/ +NPT_TlsSession::NPT_TlsSession(NPT_TlsContext& context, + NPT_TlsSessionImpl* impl) : + m_Context(context), + m_Impl(impl), + m_InputStream(new NPT_TlsInputStream(m_Impl)), + m_OutputStream(new NPT_TlsOutputStream(m_Impl)) +{ +} + +/*---------------------------------------------------------------------- +| NPT_TlsSession::~NPT_TlsSession ++---------------------------------------------------------------------*/ +NPT_TlsSession::~NPT_TlsSession() +{ +} + +/*---------------------------------------------------------------------- +| NPT_TlsSession::Handshake ++---------------------------------------------------------------------*/ +NPT_Result +NPT_TlsSession::Handshake() +{ + return m_Impl->Handshake(); +} + +/*---------------------------------------------------------------------- +| NPT_TlsSession::GetHandshakeStatus ++---------------------------------------------------------------------*/ +NPT_Result +NPT_TlsSession::GetHandshakeStatus() +{ + return m_Impl->GetHandshakeStatus(); +} + +/*---------------------------------------------------------------------- +| NPT_TlsSession::VerifyPeerCertificate ++---------------------------------------------------------------------*/ +NPT_Result +NPT_TlsSession::VerifyPeerCertificate() +{ + return m_Impl->VerifyPeerCertificate(); +} + +/*---------------------------------------------------------------------- +| NPT_TlsSession::VerifyDnsNameMatch ++---------------------------------------------------------------------*/ +NPT_Result +NPT_TlsSession::VerifyDnsNameMatch(const char* hostname) +{ + return m_Impl->VerifyDnsNameMatch(hostname); +} + +/*---------------------------------------------------------------------- +| NPT_TlsClientSession::GetSessionId ++---------------------------------------------------------------------*/ +NPT_Result +NPT_TlsSession::GetSessionId(NPT_DataBuffer& session_id) +{ + return m_Impl->GetSessionId(session_id); +} + +/*---------------------------------------------------------------------- +| NPT_TlsSession::GetCipherSuiteId ++---------------------------------------------------------------------*/ +NPT_UInt32 +NPT_TlsSession::GetCipherSuiteId() +{ + return m_Impl->GetCipherSuiteId(); +} + +/*---------------------------------------------------------------------- +| NPT_TlsSession::GetPeerCertificateInfo ++---------------------------------------------------------------------*/ +NPT_Result +NPT_TlsSession::GetPeerCertificateInfo(NPT_TlsCertificateInfo& cert_info, + unsigned int position) +{ + return m_Impl->GetPeerCertificateInfo(cert_info, position); +} + +/*---------------------------------------------------------------------- +| NPT_TlsSession::GetInputStream ++---------------------------------------------------------------------*/ +NPT_Result +NPT_TlsSession::GetInputStream(NPT_InputStreamReference& stream) +{ + stream = m_InputStream; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_TlsSession::GetOutputStream ++---------------------------------------------------------------------*/ +NPT_Result +NPT_TlsSession::GetOutputStream(NPT_OutputStreamReference& stream) +{ + stream = m_OutputStream; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_TlsClientSession::NPT_TlsClientSession ++---------------------------------------------------------------------*/ +NPT_TlsClientSession::NPT_TlsClientSession(NPT_TlsContext& context, + NPT_InputStreamReference& input, + NPT_OutputStreamReference& output) : + NPT_TlsSession(context, new NPT_TlsClientSessionImpl(context.m_Impl->m_SSL_CTX, input, output)) +{ +} + +/*---------------------------------------------------------------------- +| NPT_TlsServerSession::NPT_TlsServerSession ++---------------------------------------------------------------------*/ +NPT_TlsServerSession::NPT_TlsServerSession(NPT_TlsContext& context, + NPT_InputStreamReference& input, + NPT_OutputStreamReference& output) : + NPT_TlsSession(context, new NPT_TlsServerSessionImpl(context.m_Impl->m_SSL_CTX, input, output)) +{ +} + +/*---------------------------------------------------------------------- +| NPT_HttpTlsConnector::DefaultTlsContext ++---------------------------------------------------------------------*/ +NPT_TlsContext* NPT_HttpTlsConnector::DefaultTlsContext = NULL; + +/*---------------------------------------------------------------------- +| NPT_HttpTlsConnector::NPT_HttpTlsConnector ++---------------------------------------------------------------------*/ +NPT_HttpTlsConnector::NPT_HttpTlsConnector(NPT_Flags options) : + m_TlsContext(GetDefaultTlsContext()), + m_Options(options) +{ +} + +/*---------------------------------------------------------------------- +| NPT_HttpTlsConnector::NPT_HttpTlsConnector ++---------------------------------------------------------------------*/ +NPT_HttpTlsConnector::NPT_HttpTlsConnector(NPT_TlsContext& tls_context, NPT_Flags options) : + m_TlsContext(tls_context), + m_Options(options) +{ +} + +/*---------------------------------------------------------------------- +| NPT_HttpTlsConnector::GetDefaultTlsContext ++---------------------------------------------------------------------*/ +NPT_TlsContext& +NPT_HttpTlsConnector::GetDefaultTlsContext() +{ + if (DefaultTlsContext == NULL) { + NPT_SingletonLock::GetInstance().Lock(); + if (DefaultTlsContext == NULL) { + DefaultTlsContext = new NPT_TlsContext(NPT_TlsContext::OPTION_VERIFY_LATER | + NPT_TlsContext::OPTION_ADD_DEFAULT_TRUST_ANCHORS); + + // Prepare for recycling + NPT_AutomaticCleaner::GetInstance()->RegisterTlsContext(DefaultTlsContext); + } + NPT_SingletonLock::GetInstance().Unlock(); + } + + return *DefaultTlsContext; +} + +/*---------------------------------------------------------------------- +| NPT_HttpTlsConnector::VerifyPeer ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpTlsConnector::VerifyPeer(NPT_TlsClientSession& session, const char* hostname) +{ + // verify the certificate + NPT_Result result = session.VerifyPeerCertificate(); + if (NPT_FAILED(result)) { + if (result == NPT_ERROR_TLS_CERTIFICATE_SELF_SIGNED) { + if (!m_Options && OPTION_ACCEPT_SELF_SIGNED_CERTS) { + // self-signed certs are not acceptable + NPT_LOG_FINE("rejecting self-signed certificate"); + return result; + } + } else { + NPT_LOG_WARNING_2("TLS certificate verification failed (%d:%s)", result, NPT_ResultText(result)); + return result; + } + } + + // chech the DNS name + if (!(m_Options & OPTION_ACCEPT_HOSTNAME_MISMATCH)) { + // check the hostname + result = session.VerifyDnsNameMatch(hostname); + if (NPT_FAILED(result)) { + NPT_LOG_WARNING_2("TLS certificate does not match DNS name (%d:%s)", result, NPT_ResultText(result)); + return NPT_ERROR_TLS_DNS_NAME_MISMATCH; + } + } + + return NPT_SUCCESS; +} + +#endif // defined(NPT_CONFIG_ENABLE_TLS) + +/*---------------------------------------------------------------------- +| NPT_HttpSimpleTlsConnection ++---------------------------------------------------------------------*/ +class NPT_HttpSimpleTlsConnection : public NPT_HttpClient::Connection +{ +public: + NPT_InputStreamReference& GetInputStream() override { + return m_InputStream; + } + NPT_OutputStreamReference& GetOutputStream() override { + return m_OutputStream; + } + + // members + NPT_InputStreamReference m_InputStream; + NPT_OutputStreamReference m_OutputStream; +}; + +/*---------------------------------------------------------------------- +| NPT_HttpTlsConnector::Connect ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HttpTlsConnector::Connect(const NPT_HttpUrl& url, + NPT_HttpClient& client, + const NPT_HttpProxyAddress* proxy, + bool reuse, + NPT_HttpClient::Connection*& connection) +{ + // default values + connection = NULL; + + // local reference holders + NPT_InputStreamReference input_stream; + NPT_OutputStreamReference output_stream; + + // decide which server we need to connect to + const char* peer_hostname = (const char*)url.GetHost(); + const char* server_hostname; + NPT_UInt16 server_port; + if (proxy) { + // the proxy is set + server_hostname = (const char*)proxy->GetHostName(); + server_port = proxy->GetPort(); + } else { + // no proxy: connect directly + server_hostname = peer_hostname; + server_port = url.GetPort(); + } + + // resolve the server address + NPT_IpAddress ip_address; + NPT_CHECK_FINE(ip_address.ResolveName(server_hostname, client.GetConfig().m_NameResolverTimeout)); + + // check if we can reuse a connection + // TODO: with this we don't yet support reusing a connection to a proxy + NPT_SocketAddress socket_address(ip_address, server_port); + NPT_HttpConnectionManager* connection_manager = NPT_HttpConnectionManager::GetInstance(); + if (!proxy && reuse) { + NPT_LOG_FINE("looking for a connection to reuse"); + connection = connection_manager->FindConnection(socket_address); + if (connection) { + NPT_LOG_FINE("reusing connection"); + // track connection immediately so we can abort it later + NPT_CHECK_FINE(Connector::TrackConnection(client, connection)); + return NPT_SUCCESS; + } + } + + // create a socket + NPT_LOG_FINE_2("TLS connector will connect to %s:%d", server_hostname, server_port); + NPT_TcpClientSocket* tcp_socket = new NPT_TcpClientSocket(NPT_SOCKET_FLAG_CANCELLABLE); + NPT_SocketReference socket(tcp_socket); + tcp_socket->SetReadTimeout(client.GetConfig().m_IoTimeout); + tcp_socket->SetWriteTimeout(client.GetConfig().m_IoTimeout); + + // create a connection object for the socket so we can abort it during connect + // even though streams are not valid yet + NPT_Reference<NPT_HttpConnectionManager::Connection> cref(new NPT_HttpConnectionManager::Connection(*connection_manager, + socket, + input_stream, + output_stream)); + // track connection immediately before connecting so we can abort immediately it if necessary + NPT_CHECK_FINE(Connector::TrackConnection(client, cref.AsPointer())); + + // connect to the server + NPT_CHECK_FINE(tcp_socket->Connect(socket_address, client.GetConfig().m_ConnectionTimeout)); + + // get the streams + NPT_InputStreamReference raw_input; + NPT_OutputStreamReference raw_output; + NPT_CHECK_FINE(tcp_socket->GetInputStream(raw_input)); + NPT_CHECK_FINE(tcp_socket->GetOutputStream(raw_output)); + + if (url.GetSchemeId() == NPT_Url::SCHEME_ID_HTTPS) { +#if defined(NPT_CONFIG_ENABLE_TLS) + if (proxy) { + // RFC 2817 CONNECT + NPT_String connect_host = url.GetHost() + ":" + NPT_String::FromInteger(url.GetPort()); + NPT_String connect = "CONNECT " + connect_host + " HTTP/1.1\r\n" + "Host: " + connect_host + "\r\n\r\n"; + NPT_Result result = raw_output->WriteFully(connect.GetChars(), connect.GetLength()); + if (NPT_FAILED(result)) return result; + NPT_String connect_response; + connect_response.Reserve(1024); + bool connect_ok = false; + for (unsigned int x=0; x<NPT_HTTP_TLS_CONNECTOR_MAX_PROXY_RESPONSE_SIZE; x++) { + connect_response.Reserve(x+1); + result = raw_input->Read(connect_response.UseChars()+x, 1); + if (NPT_FAILED(result)) return result; + if (connect_response.GetChars()[x] == '\n') { + connect_response.SetLength(x+1); + if (!connect_ok) { + // check the connection result + NPT_LOG_FINE_1("proxy response: %s", connect_response.GetChars()); + if (connect_response.GetLength() < 12) { + return NPT_ERROR_HTTP_INVALID_RESPONSE_LINE; + } + if (!connect_response.StartsWith("HTTP/1.")) { + return NPT_ERROR_HTTP_INVALID_RESPONSE_LINE; + } + if (connect_response[8] != ' ') { + return NPT_ERROR_HTTP_INVALID_RESPONSE_LINE; + } + NPT_String status_code = connect_response.SubString(9, 3); + if (status_code != "200") { + NPT_LOG_WARNING_1("proxy response is not 200 (%s)", status_code.GetChars()); + return NPT_ERROR_HTTP_INVALID_RESPONSE_LINE; + } + connect_ok = true; + } else { + if (connect_response.EndsWith("\r\n\r\n")) { + // this is the end, my friend + break; + } + } + } + } + if (!connect_ok) { + return NPT_ERROR_HTTP_INVALID_RESPONSE_LINE; + } + } + + // setup the TLS connection + NPT_TlsClientSession tls_session(m_TlsContext, raw_input, raw_output); + NPT_Result result = tls_session.Handshake(); + if (NPT_FAILED(result)) { + NPT_LOG_WARNING_2("TLS handshake failed (%d:%s)", result, NPT_ResultText(result)); + return result; + } + result = VerifyPeer(tls_session, peer_hostname); + if (NPT_FAILED(result)) { + NPT_LOG_WARNING_2("VerifyPeer failed (%d:%s)", result, NPT_ResultText(result)); + return result; + } + + // return the TLS streams + tls_session.GetInputStream(input_stream); + tls_session.GetOutputStream(output_stream); +#else + return NPT_ERROR_NOT_SUPPORTED; +#endif + } else { + input_stream = raw_input; + output_stream = raw_output; + } + + // update connection streams + cref->m_InputStream = input_stream; + cref->m_OutputStream = output_stream; + + connection = cref.AsPointer(); + cref.Detach(); // release the internal ref + + return NPT_SUCCESS; +} + diff --git a/lib/libUPnP/Neptune/Source/Core/NptTls.h b/lib/libUPnP/Neptune/Source/Core/NptTls.h new file mode 100644 index 0000000..d5459d6 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptTls.h @@ -0,0 +1,304 @@ +/***************************************************************** +| +| Neptune - TLS/SSL Support +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +#ifndef _NPT_TLS_H_ +#define _NPT_TLS_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptConfig.h" +#include "NptStreams.h" +#include "NptTime.h" +#include "NptHttp.h" + +/*---------------------------------------------------------------------- +| error codes ++---------------------------------------------------------------------*/ +const NPT_Result NPT_ERROR_INVALID_PASSWORD = (NPT_ERROR_BASE_TLS-1); +const NPT_Result NPT_ERROR_TLS_INVALID_HANDSHAKE = (NPT_ERROR_BASE_TLS-2); +const NPT_Result NPT_ERROR_TLS_INVALID_PROTOCOL_MESSAGE = (NPT_ERROR_BASE_TLS-3); +const NPT_Result NPT_ERROR_TLS_INVALID_HMAC = (NPT_ERROR_BASE_TLS-4); +const NPT_Result NPT_ERROR_TLS_INVALID_VERSION = (NPT_ERROR_BASE_TLS-5); +const NPT_Result NPT_ERROR_TLS_INVALID_SESSION = (NPT_ERROR_BASE_TLS-6); +const NPT_Result NPT_ERROR_TLS_NO_CIPHER = (NPT_ERROR_BASE_TLS-7); +const NPT_Result NPT_ERROR_TLS_BAD_CERTIFICATE = (NPT_ERROR_BASE_TLS-8); +const NPT_Result NPT_ERROR_TLS_INVALID_KEY = (NPT_ERROR_BASE_TLS-9); +const NPT_Result NPT_ERROR_TLS_NO_CLIENT_RENEGOTIATION = (NPT_ERROR_BASE_TLS-10); +const NPT_Result NPT_ERROR_TLS_INVALID_FINISHED_MESSAGE = (NPT_ERROR_BASE_TLS-11); +const NPT_Result NPT_ERROR_TLS_NO_CERTIFICATE_DEFINED = (NPT_ERROR_BASE_TLS-12); +const NPT_Result NPT_ERROR_TLS_ALERT_HANDSHAKE_FAILED = (NPT_ERROR_BASE_TLS-13); +const NPT_Result NPT_ERROR_TLS_ALERT_BAD_CERTIFICATE = (NPT_ERROR_BASE_TLS-14); +const NPT_Result NPT_ERROR_TLS_ALERT_INVALID_VERSION = (NPT_ERROR_BASE_TLS-15); +const NPT_Result NPT_ERROR_TLS_ALERT_BAD_RECORD_MAC = (NPT_ERROR_BASE_TLS-16); +const NPT_Result NPT_ERROR_TLS_ALERT_DECODE_ERROR = (NPT_ERROR_BASE_TLS-17); +const NPT_Result NPT_ERROR_TLS_ALERT_DECRYPT_ERROR = (NPT_ERROR_BASE_TLS-18); +const NPT_Result NPT_ERROR_TLS_ALERT_ILLEGAL_PARAMETER = (NPT_ERROR_BASE_TLS-19); +const NPT_Result NPT_ERROR_TLS_ALERT_UNEXPECTED_MESSAGE = (NPT_ERROR_BASE_TLS-20); +const NPT_Result NPT_ERROR_TLS_CERTIFICATE_FAILURE = (NPT_ERROR_BASE_TLS-21); +const NPT_Result NPT_ERROR_TLS_CERTIFICATE_NO_TRUST_ANCHOR = (NPT_ERROR_BASE_TLS-22); +const NPT_Result NPT_ERROR_TLS_CERTIFICATE_BAD_SIGNATURE = (NPT_ERROR_BASE_TLS-23); +const NPT_Result NPT_ERROR_TLS_CERTIFICATE_NOT_YET_VALID = (NPT_ERROR_BASE_TLS-24); +const NPT_Result NPT_ERROR_TLS_CERTIFICATE_EXPIRED = (NPT_ERROR_BASE_TLS-25); +const NPT_Result NPT_ERROR_TLS_CERTIFICATE_SELF_SIGNED = (NPT_ERROR_BASE_TLS-26); +const NPT_Result NPT_ERROR_TLS_CERTIFICATE_INVALID_CHAIN = (NPT_ERROR_BASE_TLS-27); +const NPT_Result NPT_ERROR_TLS_CERTIFICATE_UNSUPPORTED_DIGEST = (NPT_ERROR_BASE_TLS-28); +const NPT_Result NPT_ERROR_TLS_CERTIFICATE_INVALID_PRIVATE_KEY = (NPT_ERROR_BASE_TLS-29); +const NPT_Result NPT_ERROR_TLS_DNS_NAME_MISMATCH = (NPT_ERROR_BASE_TLS-30); + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const unsigned int NPT_TLS_NULL_WITH_NULL_NULL = 0x00; +const unsigned int NPT_TLS_RSA_WITH_RC4_128_MD5 = 0x04; +const unsigned int NPT_TLS_RSA_WITH_RC4_128_SHA = 0x05; +const unsigned int NPT_TLS_RSA_WITH_AES_128_CBC_SHA = 0x2F; +const unsigned int NPT_TLS_RSA_WITH_AES_256_CBC_SHA = 0x35; + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class NPT_TlsContextImpl; +class NPT_TlsSessionImpl; + +/*---------------------------------------------------------------------- +| types ++---------------------------------------------------------------------*/ +typedef enum { + NPT_TLS_KEY_FORMAT_RSA_PRIVATE, + NPT_TLS_KEY_FORMAT_PKCS8, + NPT_TLS_KEY_FORMAT_PKCS12 +} NPT_TlsKeyFormat; + +struct NPT_TlsTrustAnchorData { + const unsigned char* cert_data; + unsigned int cert_size; +}; + +/*---------------------------------------------------------------------- +| NPT_Tls ++---------------------------------------------------------------------*/ +class NPT_Tls +{ +public: + static const NPT_TlsTrustAnchorData* GetDefaultTrustAnchors(NPT_Ordinal indx=0); + static bool MatchDnsNames(const char* hostname, + const NPT_List<NPT_String>& dns_names); + static bool MatchDnsName(const char* hostname, const char* dns_name); + +private: + NPT_Tls() {}; // don't instantiate +}; + +/*---------------------------------------------------------------------- +| NPT_TlsContext ++---------------------------------------------------------------------*/ +class NPT_TlsContext : public NPT_AutomaticCleaner::Singleton +{ +public: + enum { + OPTION_VERIFY_LATER = 1, + OPTION_REQUIRE_CLIENT_CERTIFICATE = 2, + OPTION_ADD_DEFAULT_TRUST_ANCHORS = 4, + OPTION_NO_SESSION_CACHE = 8 + }; + NPT_TlsContext(NPT_Flags options=0); + ~NPT_TlsContext() override; + + // methods + NPT_Result LoadKey(NPT_TlsKeyFormat key_format, + const unsigned char* key_data, + NPT_Size key_data_size, + const char* password); + + NPT_Result SelfSignCertificate(const char* common_name, + const char* organization, + const char* organizational_name); + + /** + * Add one trust anchor + */ + NPT_Result AddTrustAnchor(const unsigned char* ta_data, + NPT_Size ta_data_size); + /** + * Add one or more trust anchors, from a list + * @param anchors Array of trust anchor data + * @param anchor_count Number of anchors in the array, or 0 if the array + * is terminated by a 'sentinel' (an anchor data with the field cert_data set + * to NULL and the field cert_size set to 0). + */ + NPT_Result AddTrustAnchors(const NPT_TlsTrustAnchorData* anchors, + NPT_Cardinal anchor_count = 0); + +protected: + NPT_TlsContextImpl* m_Impl; + + // friends + friend class NPT_TlsSession; + friend class NPT_TlsClientSession; + friend class NPT_TlsServerSession; +}; + +/*---------------------------------------------------------------------- +| NPT_TlsCertificateInfo ++---------------------------------------------------------------------*/ +struct NPT_TlsCertificateInfo +{ + struct _subject { + NPT_String common_name; + NPT_String organization; + NPT_String organizational_name; + } subject; + struct _issuer { + NPT_String common_name; + NPT_String organization; + NPT_String organizational_name; + } issuer; + struct _fingerprint { + unsigned char sha1[20]; + unsigned char md5[16]; + } fingerprint; + NPT_DateTime issue_date; + NPT_DateTime expiration_date; + NPT_List<NPT_String> alternate_names; +}; + +/*---------------------------------------------------------------------- +| NPT_TlsSession ++---------------------------------------------------------------------*/ +class NPT_TlsSession +{ +public: + virtual ~NPT_TlsSession(); + virtual NPT_Result Handshake(); + virtual NPT_Result GetHandshakeStatus(); + virtual NPT_Result GetPeerCertificateInfo(NPT_TlsCertificateInfo& info, NPT_Ordinal position=0); + virtual NPT_Result VerifyPeerCertificate(); + virtual NPT_Result VerifyDnsNameMatch(const char* hostname); + virtual NPT_Result GetSessionId(NPT_DataBuffer& session_id); + virtual NPT_UInt32 GetCipherSuiteId(); + virtual NPT_Result GetInputStream(NPT_InputStreamReference& stream); + virtual NPT_Result GetOutputStream(NPT_OutputStreamReference& stream); + +protected: + NPT_TlsSession(NPT_TlsContext& context, + NPT_TlsSessionImpl* impl); + + NPT_TlsContext& m_Context; + NPT_Reference<NPT_TlsSessionImpl> m_Impl; + NPT_InputStreamReference m_InputStream; + NPT_OutputStreamReference m_OutputStream; +}; + +/*---------------------------------------------------------------------- +| NPT_TlsClientSession ++---------------------------------------------------------------------*/ +class NPT_TlsClientSession : public NPT_TlsSession +{ +public: + NPT_TlsClientSession(NPT_TlsContext& context, + NPT_InputStreamReference& input, + NPT_OutputStreamReference& output); +}; + +/*---------------------------------------------------------------------- +| NPT_TlsServerSession ++---------------------------------------------------------------------*/ +class NPT_TlsServerSession : public NPT_TlsSession +{ +public: + NPT_TlsServerSession(NPT_TlsContext& context, + NPT_InputStreamReference& input, + NPT_OutputStreamReference& output); +}; + +/*---------------------------------------------------------------------- +| NPT_HttpTlsConnector ++---------------------------------------------------------------------*/ +#if defined(NPT_CONFIG_ENABLE_TLS) +class NPT_HttpTlsConnector : public NPT_HttpClient::Connector +{ +public: + enum { + OPTION_ACCEPT_SELF_SIGNED_CERTS = 1, + OPTION_ACCEPT_HOSTNAME_MISMATCH = 2 + }; + NPT_HttpTlsConnector(NPT_Flags options = 0); + NPT_HttpTlsConnector(NPT_TlsContext& tls_context, NPT_Flags options = 0); + virtual ~NPT_HttpTlsConnector() {} + NPT_TlsContext& GetTlsContext() { return m_TlsContext; } + virtual NPT_Result Connect(const NPT_HttpUrl& url, + NPT_HttpClient& client, + const NPT_HttpProxyAddress* proxy, + bool reuse, + NPT_HttpClient::Connection*& connection); + + virtual NPT_Result VerifyPeer(NPT_TlsClientSession& session, + const char* hostname); + +private: + // class methods + static NPT_TlsContext& GetDefaultTlsContext(); + + // class members + static NPT_TlsContext* DefaultTlsContext; + + // members + NPT_TlsContext& m_TlsContext; + NPT_Flags m_Options; +}; +#else +class NPT_HttpTlsConnector : public NPT_HttpClient::Connector +{ +public: + ~NPT_HttpTlsConnector() override {} + NPT_Result Connect(const NPT_HttpUrl& url, + NPT_HttpClient& client, + const NPT_HttpProxyAddress* proxy, + bool reuse, + NPT_HttpClient::Connection*& connection) override; +}; +#endif + +/*---------------------------------------------------------------------- +| Trust Anchors ++-----------------------------------------------------------------*/ +/** + * Arrays of trust anchors (each array element is of type NPT_TlsTrustAnchorData + * and the last element is a terminator element: the cert_data field is NULL + * and the cert_size field is 0 + */ +#if defined(NPT_CONFIG_ENABLE_TLS) +#include "NptTlsDefaultTrustAnchorsBase.h" +#include "NptTlsDefaultTrustAnchorsExtended.h" +#endif + +#endif // _NPT_TLS_H_ diff --git a/lib/libUPnP/Neptune/Source/Core/NptTlsDefaultTrustAnchorsBase.h b/lib/libUPnP/Neptune/Source/Core/NptTlsDefaultTrustAnchorsBase.h new file mode 100644 index 0000000..170cdb2 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptTlsDefaultTrustAnchorsBase.h @@ -0,0 +1,583 @@ +/***************************************************************** +| +| Neptune - Trust Anchors +| +| This file is automatically generated by a script, do not edit! +| +| Copyright (c) 2002-2010, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + + /* This file is automatically generated by GenTrustAnchorsTables.py, do not edit */ + +#include "NptTls.h" + +extern const NPT_TlsTrustAnchorData NptTlsDefaultTrustAnchorsBase[137]; + +/* Verisign/RSA Secure Server CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0000_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0000_Data[]; + +/* GTE CyberTrust Root CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0001_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0001_Data[]; + +/* GTE CyberTrust Global Root */ +extern const unsigned int NptTlsTrustAnchor_Base_0002_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0002_Data[]; + +/* Thawte Personal Basic CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0003_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0003_Data[]; + +/* Thawte Personal Premium CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0004_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0004_Data[]; + +/* Thawte Personal Freemail CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0005_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0005_Data[]; + +/* Thawte Server CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0006_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0006_Data[]; + +/* Thawte Premium Server CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0007_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0007_Data[]; + +/* Equifax Secure CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0008_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0008_Data[]; + +/* Digital Signature Trust Co. Global CA 1 */ +extern const unsigned int NptTlsTrustAnchor_Base_0009_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0009_Data[]; + +/* Digital Signature Trust Co. Global CA 3 */ +extern const unsigned int NptTlsTrustAnchor_Base_0010_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0010_Data[]; + +/* Digital Signature Trust Co. Global CA 2 */ +extern const unsigned int NptTlsTrustAnchor_Base_0011_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0011_Data[]; + +/* Digital Signature Trust Co. Global CA 4 */ +extern const unsigned int NptTlsTrustAnchor_Base_0012_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0012_Data[]; + +/* Verisign Class 1 Public Primary Certification Authority */ +extern const unsigned int NptTlsTrustAnchor_Base_0013_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0013_Data[]; + +/* Verisign Class 2 Public Primary Certification Authority */ +extern const unsigned int NptTlsTrustAnchor_Base_0014_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0014_Data[]; + +/* Verisign Class 3 Public Primary Certification Authority */ +extern const unsigned int NptTlsTrustAnchor_Base_0015_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0015_Data[]; + +/* Verisign Class 1 Public Primary Certification Authority - G2 */ +extern const unsigned int NptTlsTrustAnchor_Base_0016_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0016_Data[]; + +/* Verisign Class 2 Public Primary Certification Authority - G2 */ +extern const unsigned int NptTlsTrustAnchor_Base_0017_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0017_Data[]; + +/* Verisign Class 3 Public Primary Certification Authority - G2 */ +extern const unsigned int NptTlsTrustAnchor_Base_0018_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0018_Data[]; + +/* Verisign Class 4 Public Primary Certification Authority - G2 */ +extern const unsigned int NptTlsTrustAnchor_Base_0019_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0019_Data[]; + +/* GlobalSign Root CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0020_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0020_Data[]; + +/* GlobalSign Root CA - R2 */ +extern const unsigned int NptTlsTrustAnchor_Base_0021_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0021_Data[]; + +/* ValiCert Class 1 VA */ +extern const unsigned int NptTlsTrustAnchor_Base_0022_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0022_Data[]; + +/* ValiCert Class 2 VA */ +extern const unsigned int NptTlsTrustAnchor_Base_0023_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0023_Data[]; + +/* RSA Root Certificate 1 */ +extern const unsigned int NptTlsTrustAnchor_Base_0024_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0024_Data[]; + +/* Verisign Class 1 Public Primary Certification Authority - G3 */ +extern const unsigned int NptTlsTrustAnchor_Base_0025_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0025_Data[]; + +/* Verisign Class 2 Public Primary Certification Authority - G3 */ +extern const unsigned int NptTlsTrustAnchor_Base_0026_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0026_Data[]; + +/* Verisign Class 3 Public Primary Certification Authority - G3 */ +extern const unsigned int NptTlsTrustAnchor_Base_0027_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0027_Data[]; + +/* Verisign Class 4 Public Primary Certification Authority - G3 */ +extern const unsigned int NptTlsTrustAnchor_Base_0028_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0028_Data[]; + +/* Entrust.net Secure Server CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0029_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0029_Data[]; + +/* Entrust.net Secure Personal CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0030_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0030_Data[]; + +/* Entrust.net Premium 2048 Secure Server CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0031_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0031_Data[]; + +/* Baltimore CyberTrust Root */ +extern const unsigned int NptTlsTrustAnchor_Base_0032_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0032_Data[]; + +/* Equifax Secure Global eBusiness CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0033_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0033_Data[]; + +/* Equifax Secure eBusiness CA 1 */ +extern const unsigned int NptTlsTrustAnchor_Base_0034_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0034_Data[]; + +/* Equifax Secure eBusiness CA 2 */ +extern const unsigned int NptTlsTrustAnchor_Base_0035_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0035_Data[]; + +/* Visa International Global Root 2 */ +extern const unsigned int NptTlsTrustAnchor_Base_0036_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0036_Data[]; + +/* AddTrust Low-Value Services Root */ +extern const unsigned int NptTlsTrustAnchor_Base_0037_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0037_Data[]; + +/* AddTrust External Root */ +extern const unsigned int NptTlsTrustAnchor_Base_0038_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0038_Data[]; + +/* AddTrust Public Services Root */ +extern const unsigned int NptTlsTrustAnchor_Base_0039_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0039_Data[]; + +/* AddTrust Qualified Certificates Root */ +extern const unsigned int NptTlsTrustAnchor_Base_0040_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0040_Data[]; + +/* Verisign Time Stamping Authority CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0041_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0041_Data[]; + +/* Thawte Time Stamping CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0042_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0042_Data[]; + +/* Entrust.net Global Secure Server CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0043_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0043_Data[]; + +/* Entrust.net Global Secure Personal CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0044_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0044_Data[]; + +/* Entrust Root Certification Authority */ +extern const unsigned int NptTlsTrustAnchor_Base_0045_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0045_Data[]; + +/* AOL Time Warner Root Certification Authority 1 */ +extern const unsigned int NptTlsTrustAnchor_Base_0046_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0046_Data[]; + +/* AOL Time Warner Root Certification Authority 2 */ +extern const unsigned int NptTlsTrustAnchor_Base_0047_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0047_Data[]; + +/* beTRUSTed Root CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0048_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0048_Data[]; + +/* beTRUSTed Root CA-Baltimore Implementation */ +extern const unsigned int NptTlsTrustAnchor_Base_0049_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0049_Data[]; + +/* beTRUSTed Root CA - Entrust Implementation */ +extern const unsigned int NptTlsTrustAnchor_Base_0050_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0050_Data[]; + +/* beTRUSTed Root CA - RSA Implementation */ +extern const unsigned int NptTlsTrustAnchor_Base_0051_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0051_Data[]; + +/* RSA Security 2048 v3 */ +extern const unsigned int NptTlsTrustAnchor_Base_0052_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0052_Data[]; + +/* RSA Security 1024 v3 */ +extern const unsigned int NptTlsTrustAnchor_Base_0053_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0053_Data[]; + +/* GeoTrust Global CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0054_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0054_Data[]; + +/* GeoTrust Global CA 2 */ +extern const unsigned int NptTlsTrustAnchor_Base_0055_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0055_Data[]; + +/* GeoTrust Universal CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0056_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0056_Data[]; + +/* GeoTrust Universal CA 2 */ +extern const unsigned int NptTlsTrustAnchor_Base_0057_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0057_Data[]; + +/* UTN-USER First-Network Applications */ +extern const unsigned int NptTlsTrustAnchor_Base_0058_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0058_Data[]; + +/* America Online Root Certification Authority 1 */ +extern const unsigned int NptTlsTrustAnchor_Base_0059_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0059_Data[]; + +/* America Online Root Certification Authority 2 */ +extern const unsigned int NptTlsTrustAnchor_Base_0060_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0060_Data[]; + +/* Visa eCommerce Root */ +extern const unsigned int NptTlsTrustAnchor_Base_0061_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0061_Data[]; + +/* TC TrustCenter, Germany, Class 2 CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0062_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0062_Data[]; + +/* TC TrustCenter, Germany, Class 3 CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0063_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0063_Data[]; + +/* Certum Root CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0064_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0064_Data[]; + +/* Comodo AAA Services root */ +extern const unsigned int NptTlsTrustAnchor_Base_0065_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0065_Data[]; + +/* Comodo Secure Services root */ +extern const unsigned int NptTlsTrustAnchor_Base_0066_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0066_Data[]; + +/* Comodo Trusted Services root */ +extern const unsigned int NptTlsTrustAnchor_Base_0067_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0067_Data[]; + +/* IPS Chained CAs root */ +extern const unsigned int NptTlsTrustAnchor_Base_0068_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0068_Data[]; + +/* IPS CLASE1 root */ +extern const unsigned int NptTlsTrustAnchor_Base_0069_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0069_Data[]; + +/* IPS CLASE3 root */ +extern const unsigned int NptTlsTrustAnchor_Base_0070_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0070_Data[]; + +/* IPS CLASEA1 root */ +extern const unsigned int NptTlsTrustAnchor_Base_0071_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0071_Data[]; + +/* IPS CLASEA3 root */ +extern const unsigned int NptTlsTrustAnchor_Base_0072_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0072_Data[]; + +/* IPS Servidores root */ +extern const unsigned int NptTlsTrustAnchor_Base_0073_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0073_Data[]; + +/* IPS Timestamping root */ +extern const unsigned int NptTlsTrustAnchor_Base_0074_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0074_Data[]; + +/* QuoVadis Root CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0075_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0075_Data[]; + +/* QuoVadis Root CA 2 */ +extern const unsigned int NptTlsTrustAnchor_Base_0076_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0076_Data[]; + +/* QuoVadis Root CA 3 */ +extern const unsigned int NptTlsTrustAnchor_Base_0077_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0077_Data[]; + +/* Security Communication Root CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0078_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0078_Data[]; + +/* Sonera Class 1 Root CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0079_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0079_Data[]; + +/* Sonera Class 2 Root CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0080_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0080_Data[]; + +/* Staat der Nederlanden Root CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0081_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0081_Data[]; + +/* TDC Internet Root CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0082_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0082_Data[]; + +/* TDC OCES Root CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0083_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0083_Data[]; + +/* UTN DATACorp SGC Root CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0084_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0084_Data[]; + +/* UTN USERFirst Email Root CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0085_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0085_Data[]; + +/* UTN USERFirst Hardware Root CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0086_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0086_Data[]; + +/* UTN USERFirst Object Root CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0087_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0087_Data[]; + +/* Camerfirma Chambers of Commerce Root */ +extern const unsigned int NptTlsTrustAnchor_Base_0088_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0088_Data[]; + +/* Camerfirma Global Chambersign Root */ +extern const unsigned int NptTlsTrustAnchor_Base_0089_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0089_Data[]; + +/* NetLock Qualified (Class QA) Root */ +extern const unsigned int NptTlsTrustAnchor_Base_0090_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0090_Data[]; + +/* NetLock Notary (Class A) Root */ +extern const unsigned int NptTlsTrustAnchor_Base_0091_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0091_Data[]; + +/* NetLock Business (Class B) Root */ +extern const unsigned int NptTlsTrustAnchor_Base_0092_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0092_Data[]; + +/* NetLock Express (Class C) Root */ +extern const unsigned int NptTlsTrustAnchor_Base_0093_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0093_Data[]; + +/* XRamp Global CA Root */ +extern const unsigned int NptTlsTrustAnchor_Base_0094_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0094_Data[]; + +/* Go Daddy Class 2 CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0095_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0095_Data[]; + +/* Starfield Class 2 CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0096_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0096_Data[]; + +/* StartCom Ltd. */ +extern const unsigned int NptTlsTrustAnchor_Base_0097_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0097_Data[]; + +/* StartCom Certification Authority */ +extern const unsigned int NptTlsTrustAnchor_Base_0098_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0098_Data[]; + +/* Firmaprofesional Root CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0099_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0099_Data[]; + +/* Wells Fargo Root CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0100_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0100_Data[]; + +/* Swisscom Root CA 1 */ +extern const unsigned int NptTlsTrustAnchor_Base_0101_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0101_Data[]; + +/* DigiCert Assured ID Root CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0102_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0102_Data[]; + +/* DigiCert Global Root CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0103_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0103_Data[]; + +/* DigiCert High Assurance EV Root CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0104_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0104_Data[]; + +/* Certplus Class 2 Primary CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0105_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0105_Data[]; + +/* DST Root CA X3 */ +extern const unsigned int NptTlsTrustAnchor_Base_0106_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0106_Data[]; + +/* DST ACES CA X6 */ +extern const unsigned int NptTlsTrustAnchor_Base_0107_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0107_Data[]; + +/* SwissSign Platinum CA - G2 */ +extern const unsigned int NptTlsTrustAnchor_Base_0108_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0108_Data[]; + +/* SwissSign Gold CA - G2 */ +extern const unsigned int NptTlsTrustAnchor_Base_0109_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0109_Data[]; + +/* SwissSign Silver CA - G2 */ +extern const unsigned int NptTlsTrustAnchor_Base_0110_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0110_Data[]; + +/* GeoTrust Primary Certification Authority */ +extern const unsigned int NptTlsTrustAnchor_Base_0111_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0111_Data[]; + +/* thawte Primary Root CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0112_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0112_Data[]; + +/* VeriSign Class 3 Public Primary Certification Authority - G5 */ +extern const unsigned int NptTlsTrustAnchor_Base_0113_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0113_Data[]; + +/* SecureTrust CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0114_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0114_Data[]; + +/* Secure Global CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0115_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0115_Data[]; + +/* COMODO Certification Authority */ +extern const unsigned int NptTlsTrustAnchor_Base_0116_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0116_Data[]; + +/* DigiNotar Root CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0117_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0117_Data[]; + +/* Network Solutions Certificate Authority */ +extern const unsigned int NptTlsTrustAnchor_Base_0118_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0118_Data[]; + +/* WellsSecure Public Root Certificate Authority */ +extern const unsigned int NptTlsTrustAnchor_Base_0119_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0119_Data[]; + +/* IGC/A */ +extern const unsigned int NptTlsTrustAnchor_Base_0120_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0120_Data[]; + +/* Security Communication EV RootCA1 */ +extern const unsigned int NptTlsTrustAnchor_Base_0121_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0121_Data[]; + +/* TC TrustCenter Class 2 CA II */ +extern const unsigned int NptTlsTrustAnchor_Base_0122_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0122_Data[]; + +/* TC TrustCenter Class 3 CA II */ +extern const unsigned int NptTlsTrustAnchor_Base_0123_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0123_Data[]; + +/* TC TrustCenter Universal CA I */ +extern const unsigned int NptTlsTrustAnchor_Base_0124_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0124_Data[]; + +/* Deutsche Telekom Root CA 2 */ +extern const unsigned int NptTlsTrustAnchor_Base_0125_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0125_Data[]; + +/* ComSign CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0126_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0126_Data[]; + +/* ComSign Secured CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0127_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0127_Data[]; + +/* Cybertrust Global Root */ +extern const unsigned int NptTlsTrustAnchor_Base_0128_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0128_Data[]; + +/* Buypass Class 2 CA 1 */ +extern const unsigned int NptTlsTrustAnchor_Base_0129_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0129_Data[]; + +/* Buypass Class 3 CA 1 */ +extern const unsigned int NptTlsTrustAnchor_Base_0130_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0130_Data[]; + +/* certSIGN ROOT CA */ +extern const unsigned int NptTlsTrustAnchor_Base_0131_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0131_Data[]; + +/* ApplicationCA - Japanese Government */ +extern const unsigned int NptTlsTrustAnchor_Base_0132_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0132_Data[]; + +/* GeoTrust Primary Certification Authority - G3 */ +extern const unsigned int NptTlsTrustAnchor_Base_0133_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0133_Data[]; + +/* thawte Primary Root CA - G2 */ +extern const unsigned int NptTlsTrustAnchor_Base_0134_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0134_Data[]; + +/* GeoTrust Primary Certification Authority - G2 */ +extern const unsigned int NptTlsTrustAnchor_Base_0135_Size; +extern const unsigned char NptTlsTrustAnchor_Base_0135_Data[]; + diff --git a/lib/libUPnP/Neptune/Source/Core/NptTlsDefaultTrustAnchorsExtended.h b/lib/libUPnP/Neptune/Source/Core/NptTlsDefaultTrustAnchorsExtended.h new file mode 100644 index 0000000..005a6f0 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptTlsDefaultTrustAnchorsExtended.h @@ -0,0 +1,91 @@ +/***************************************************************** +| +| Neptune - Trust Anchors +| +| This file is automatically generated by a script, do not edit! +| +| Copyright (c) 2002-2010, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + + /* This file is automatically generated by GenTrustAnchorsTables.py, do not edit */ + +#include "NptTls.h" + +extern const NPT_TlsTrustAnchorData NptTlsDefaultTrustAnchorsExtended[14]; + +/* ABAecom (sub., Am. Bankers Assn.) Root CA */ +extern const unsigned int NptTlsTrustAnchor_Extended_0000_Size; +extern const unsigned char NptTlsTrustAnchor_Extended_0000_Data[]; + +/* Taiwan GRCA */ +extern const unsigned int NptTlsTrustAnchor_Extended_0001_Size; +extern const unsigned char NptTlsTrustAnchor_Extended_0001_Data[]; + +/* TURKTRUST Certificate Services Provider Root 1 */ +extern const unsigned int NptTlsTrustAnchor_Extended_0002_Size; +extern const unsigned char NptTlsTrustAnchor_Extended_0002_Data[]; + +/* TURKTRUST Certificate Services Provider Root 2 */ +extern const unsigned int NptTlsTrustAnchor_Extended_0003_Size; +extern const unsigned char NptTlsTrustAnchor_Extended_0003_Data[]; + +/* OISTE WISeKey Global Root GA CA */ +extern const unsigned int NptTlsTrustAnchor_Extended_0004_Size; +extern const unsigned char NptTlsTrustAnchor_Extended_0004_Data[]; + +/* S-TRUST Authentication and Encryption Root CA 2005 PN */ +extern const unsigned int NptTlsTrustAnchor_Extended_0005_Size; +extern const unsigned char NptTlsTrustAnchor_Extended_0005_Data[]; + +/* Microsec e-Szigno Root CA */ +extern const unsigned int NptTlsTrustAnchor_Extended_0006_Size; +extern const unsigned char NptTlsTrustAnchor_Extended_0006_Data[]; + +/* Certigna */ +extern const unsigned int NptTlsTrustAnchor_Extended_0007_Size; +extern const unsigned char NptTlsTrustAnchor_Extended_0007_Data[]; + +/* AC Ra\xC3\xADz Certic\xC3\xA1mara S.A. */ +extern const unsigned int NptTlsTrustAnchor_Extended_0008_Size; +extern const unsigned char NptTlsTrustAnchor_Extended_0008_Data[]; + +/* ePKI Root Certification Authority */ +extern const unsigned int NptTlsTrustAnchor_Extended_0009_Size; +extern const unsigned char NptTlsTrustAnchor_Extended_0009_Data[]; + +/* TUBITAK UEKAE Kok Sertifika Hizmet Saglayicisi - Surum 3 */ +extern const unsigned int NptTlsTrustAnchor_Extended_0010_Size; +extern const unsigned char NptTlsTrustAnchor_Extended_0010_Data[]; + +/* CNNIC ROOT */ +extern const unsigned int NptTlsTrustAnchor_Extended_0011_Size; +extern const unsigned char NptTlsTrustAnchor_Extended_0011_Data[]; + +/* EBG Elektronik Sertifika Hizmet Saglayicisi */ +extern const unsigned int NptTlsTrustAnchor_Extended_0012_Size; +extern const unsigned char NptTlsTrustAnchor_Extended_0012_Data[]; + diff --git a/lib/libUPnP/Neptune/Source/Core/NptTypes.h b/lib/libUPnP/Neptune/Source/Core/NptTypes.h new file mode 100644 index 0000000..4c82174 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptTypes.h @@ -0,0 +1,149 @@ +/***************************************************************** +| +| Neptune - Types +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +#ifndef _NPT_TYPES_H_ +#define _NPT_TYPES_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptConfig.h" + +/*---------------------------------------------------------------------- +| sized types (this assumes that ints are 32 bits) ++---------------------------------------------------------------------*/ +typedef NPT_CONFIG_INT64_TYPE NPT_Int64; +typedef unsigned NPT_CONFIG_INT64_TYPE NPT_UInt64; +typedef unsigned int NPT_UInt32; +typedef int NPT_Int32; +typedef unsigned short NPT_UInt16; +typedef short NPT_Int16; +typedef unsigned char NPT_UInt8; +typedef char NPT_Int8; +typedef float NPT_Float; + +/*---------------------------------------------------------------------- +| named types ++---------------------------------------------------------------------*/ +typedef int NPT_Result; +typedef unsigned int NPT_Cardinal; +typedef unsigned int NPT_Ordinal; +typedef NPT_UInt32 NPT_Size; +typedef NPT_UInt64 NPT_LargeSize; +typedef NPT_Int32 NPT_Offset; +typedef NPT_UInt64 NPT_Position; +typedef NPT_Int32 NPT_Timeout; +typedef void NPT_Interface; +typedef NPT_UInt8 NPT_Byte; +typedef NPT_UInt32 NPT_Flags; +typedef void* NPT_Any; +typedef const void* NPT_AnyConst; + +/*---------------------------------------------------------------------- +| limits ++---------------------------------------------------------------------*/ +#if defined(NPT_CONFIG_HAVE_LIMITS_H) +#include <limits.h> +#endif + +#if !defined(NPT_INT_MIN) +#if defined(NPT_CONFIG_HAVE_INT_MIN) +#define NPT_INT_MIN INT_MIN +#endif +#endif + +#if !defined(NPT_INT_MAX) +#if defined(NPT_CONFIG_HAVE_INT_MAX) +#define NPT_INT_MAX INT_MAX +#endif +#endif + +#if !defined(NPT_UINT_MAX) +#if defined(NPT_CONFIG_HAVE_UINT_MAX) +#define NPT_UINT_MAX UINT_MAX +#endif +#endif + +#if !defined(NPT_LONG_MIN) +#if defined(NPT_CONFIG_HAVE_LONG_MIN) +#define NPT_LONG_MIN LONG_MIN +#endif +#endif + +#if !defined(NPT_LONG_MAX) +#if defined(NPT_CONFIG_HAVE_LONG_MAX) +#define NPT_LONG_MAX LONG_MAX +#endif +#endif + +#if !defined(NPT_ULONG_MAX) +#if defined(NPT_CONFIG_HAVE_ULONG_MAX) +#define NPT_ULONG_MAX ULONG_MAX +#endif +#endif + +#if !defined(NPT_INT32_MAX) +#define NPT_INT32_MAX 0x7FFFFFFF +#endif + +#if !defined(NPT_INT32_MIN) +#define NPT_INT32_MIN (-NPT_INT32_MAX - 1) +#endif + +#if !defined(NPT_UINT32_MAX) +#define NPT_UINT32_MAX 0xFFFFFFFF +#endif + +#if !defined(NPT_INT64_MAX) +#if defined(NPT_CONFIG_HAVE_LLONG_MAX) +#define NPT_INT64_MAX LLONG_MAX +#else +#define NPT_INT64_MAX 0x7FFFFFFFFFFFFFFFLL +#endif +#endif + +#if !defined(NPT_INT64_MIN) +#if defined(NPT_CONFIG_HAVE_LLONG_MIN) +#define NPT_INT64_MIN LLONG_MIN +#else +#define NPT_INT64_MIN (-NPT_INT64_MAX - 1LL) +#endif +#endif + +#if !defined(NPT_UINT64_MAX) +#if defined(NPT_CONFIG_HAVE_ULLONG_MAX) +#define NPT_UINT64_MAX ULLONG_MAX +#else +#define NPT_UINT64_MAX 0xFFFFFFFFFFFFFFFFULL +#endif +#endif + +#endif // _NPT_TYPES_H_ diff --git a/lib/libUPnP/Neptune/Source/Core/NptUri.cpp b/lib/libUPnP/Neptune/Source/Core/NptUri.cpp new file mode 100644 index 0000000..e4a7c3b --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptUri.cpp @@ -0,0 +1,912 @@ +/***************************************************************** +| +| Neptune - URI +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ***************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptUri.h" +#include "NptUtils.h" +#include "NptResults.h" + +/*---------------------------------------------------------------------- +| NPT_Uri::ParseScheme ++---------------------------------------------------------------------*/ +NPT_Uri::SchemeId +NPT_Uri::ParseScheme(const NPT_String& scheme) +{ + if (scheme == "http") { + return SCHEME_ID_HTTP; + } else if (scheme == "https") { + return SCHEME_ID_HTTPS; + } else { + return SCHEME_ID_UNKNOWN; + } +} + +/*---------------------------------------------------------------------- +| NPT_Uri::SetScheme ++---------------------------------------------------------------------*/ +void +NPT_Uri::SetScheme(const char* scheme) +{ + m_Scheme = scheme; + m_Scheme.MakeLowercase(); + m_SchemeId = ParseScheme(m_Scheme); +} + +/*---------------------------------------------------------------------- +| NPT_Uri::SetSchemeFromUri ++---------------------------------------------------------------------*/ +NPT_Result +NPT_Uri::SetSchemeFromUri(const char* uri) +{ + const char* start = uri; + char c; + while ((c =*uri++)) { + if (c == ':') { + m_Scheme.Assign(start, (NPT_Size)(uri-start-1)); + m_Scheme.MakeLowercase(); + m_SchemeId = ParseScheme(m_Scheme); + return NPT_SUCCESS; + } else if ((c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') || + (c == '+') || + (c == '.') || + (c == '-')) { + continue; + } else { + break; + } + } + return NPT_ERROR_INVALID_SYNTAX; +} + +/*---------------------------------------------------------------------- +Appendix A. Collected ABNF for URI + + URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] + + hier-part = "//" authority path-abempty + / path-absolute + / path-rootless + / path-empty + + URI-reference = URI / relative-ref + + absolute-URI = scheme ":" hier-part [ "?" query ] + + relative-ref = relative-part [ "?" query ] [ "#" fragment ] + + relative-part = "//" authority path-abempty + / path-absolute + / path-noscheme + / path-empty + + scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) + + authority = [ userinfo "@" ] host [ ":" port ] + userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) + host = IP-literal / IPv4address / reg-name + port = *DIGIT + + IP-literal = "[" ( IPv6address / IPvFuture ) "]" + + IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" ) + + IPv6address = 6( h16 ":" ) ls32 + / "::" 5( h16 ":" ) ls32 + / [ h16 ] "::" 4( h16 ":" ) ls32 + / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32 + / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32 + / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32 + / [ *4( h16 ":" ) h16 ] "::" ls32 + / [ *5( h16 ":" ) h16 ] "::" h16 + / [ *6( h16 ":" ) h16 ] "::" + + h16 = 1*4HEXDIG + ls32 = ( h16 ":" h16 ) / IPv4address + IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet + dec-octet = DIGIT ; 0-9 + / %x31-39 DIGIT ; 10-99 + / "1" 2DIGIT ; 100-199 + / "2" %x30-34 DIGIT ; 200-249 + / "25" %x30-35 ; 250-255 + + reg-name = *( unreserved / pct-encoded / sub-delims ) + + path = path-abempty ; begins with "/" or is empty + / path-absolute ; begins with "/" but not "//" + / path-noscheme ; begins with a non-colon segment + / path-rootless ; begins with a segment + / path-empty ; zero characters + + path-abempty = *( "/" segment ) + path-absolute = "/" [ segment-nz *( "/" segment ) ] + path-noscheme = segment-nz-nc *( "/" segment ) + path-rootless = segment-nz *( "/" segment ) + path-empty = 0<pchar> + + segment = *pchar + segment-nz = 1*pchar + segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" ) + ; non-zero-length segment without any colon ":" + + pchar = unreserved / pct-encoded / sub-delims / ":" / "@" + + query = *( pchar / "/" / "?" ) + + fragment = *( pchar / "/" / "?" ) + + pct-encoded = "%" HEXDIG HEXDIG + + unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" + reserved = gen-delims / sub-delims + gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" + sub-delims = "!" / "$" / "&" / "'" / "(" / ")" + / "*" / "+" / "," / ";" / "=" + +---------------------------------------------------------------------*/ + +#define NPT_URI_ALWAYS_ENCODE " !\"<>\\^`{|}" + +/*---------------------------------------------------------------------- +| NPT_Uri::PathCharsToEncode ++---------------------------------------------------------------------*/ +const char* const +NPT_Uri::PathCharsToEncode = NPT_URI_ALWAYS_ENCODE "?#[]"; + +/*---------------------------------------------------------------------- +| NPT_Uri::QueryCharsToEncode ++---------------------------------------------------------------------*/ +const char* const +NPT_Uri::QueryCharsToEncode = NPT_URI_ALWAYS_ENCODE "#[]"; + +/*---------------------------------------------------------------------- +| NPT_Uri::FragmentCharsToEncode ++---------------------------------------------------------------------*/ +const char* const +NPT_Uri::FragmentCharsToEncode = NPT_URI_ALWAYS_ENCODE "[]"; + +/*---------------------------------------------------------------------- +| NPT_Uri::UnsafeCharsToEncode ++---------------------------------------------------------------------*/ +const char* const +NPT_Uri::UnsafeCharsToEncode = NPT_URI_ALWAYS_ENCODE; + +/*---------------------------------------------------------------------- +| NPT_Uri::PercentEncode ++---------------------------------------------------------------------*/ +NPT_String +NPT_Uri::PercentEncode(const char* str, const char* chars, bool encode_percents) +{ + NPT_String encoded; + + // check args + if (str == NULL) return encoded; + + // reserve at least the size of the current uri + encoded.Reserve(NPT_StringLength(str)); + + // process each character + char escaped[3]; + escaped[0] = '%'; + while (unsigned char c = *str++) { + bool encode = false; + if (encode_percents && c == '%') { + encode = true; + } else if (c < ' ' || c > '~') { + encode = true; + } else { + const char* match = chars; + while (*match) { + if (c == *match) { + encode = true; + break; + } + ++match; + } + } + if (encode) { + // encode + NPT_ByteToHex(c, &escaped[1], true); + encoded.Append(escaped, 3); + } else { + // no encoding required + encoded += c; + } + } + + return encoded; +} + +/*---------------------------------------------------------------------- +| NPT_Uri::PercentDecode ++---------------------------------------------------------------------*/ +NPT_String +NPT_Uri::PercentDecode(const char* str) +{ + NPT_String decoded; + + // check args + if (str == NULL) return decoded; + + // reserve at least the size of the current uri + decoded.Reserve(NPT_StringLength(str)); + + // process each character + while (unsigned char c = *str++) { + if (c == '%') { + // needs to be unescaped + unsigned char unescaped; + if (NPT_SUCCEEDED(NPT_HexToByte(str, unescaped))) { + decoded += unescaped; + str += 2; + } else { + // not a valid escape sequence, just keep the % + decoded += c; + } + } else { + // no unescaping required + decoded += c; + } + } + + return decoded; +} + +/*---------------------------------------------------------------------- +| NPT_UrlQuery::NPT_UrlQuery ++---------------------------------------------------------------------*/ +NPT_UrlQuery::NPT_UrlQuery(const char* query) +{ + Parse(query); +} + +/*---------------------------------------------------------------------- +| NPT_UrlQuery::UrlEncode ++---------------------------------------------------------------------*/ +NPT_String +NPT_UrlQuery::UrlEncode(const char* str, bool encode_percents) +{ + NPT_String encoded = NPT_Uri::PercentEncode( + str, + ";/?:@&=+$," /* reserved as defined in RFC 2396 */ + "\"#<>\\^`{|}", /* other unsafe chars */ + encode_percents); + encoded.Replace(' ','+'); + + return encoded; +} + +/*---------------------------------------------------------------------- +| NPT_UrlQuery::UrlDecode ++---------------------------------------------------------------------*/ +NPT_String +NPT_UrlQuery::UrlDecode(const char* str) +{ + NPT_String decoded(str); + decoded.Replace('+', ' '); + return NPT_Uri::PercentDecode(decoded); +} + +/*---------------------------------------------------------------------- +| NPT_UrlQuery::Field::Field ++---------------------------------------------------------------------*/ +NPT_UrlQuery::Field::Field(const char* name, const char* value, bool encoded) +{ + if (encoded) { + m_Name = name; + m_Value = value; + } else { + m_Name = UrlEncode(name); + m_Value = UrlEncode(value); + } +} + +/*---------------------------------------------------------------------- +| NPT_UrlQuery::ToString ++---------------------------------------------------------------------*/ +NPT_String +NPT_UrlQuery::ToString() +{ + NPT_String encoded; + bool separator = false; + for (NPT_List<Field>::Iterator it = m_Fields.GetFirstItem(); + it; + ++it) { + Field& field = *it; + if (separator) encoded += "&"; + separator = true; + encoded += field.m_Name; + encoded += "="; + encoded += field.m_Value; + } + + return encoded; +} + +/*---------------------------------------------------------------------- +| NPT_UrlQuery::Parse ++---------------------------------------------------------------------*/ +NPT_Result +NPT_UrlQuery::Parse(const char* query) +{ + const char* cursor = query; + NPT_String name; + NPT_String value; + bool in_name = true; + do { + if (*cursor == '\0' || *cursor == '&') { + AddField(name, value, true); + name.SetLength(0); + value.SetLength(0); + in_name = true; + } else if (*cursor == '=' && in_name) { + in_name = false; + } else { + if (in_name) { + name += *cursor; + } else { + value += *cursor; + } + } + } while (*cursor++); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_UrlQuery::AddField ++---------------------------------------------------------------------*/ +NPT_Result +NPT_UrlQuery::AddField(const char* name, const char* value, bool encoded) +{ + return m_Fields.Add(Field(name, value, encoded)); +} + +/*---------------------------------------------------------------------- +| NPT_UrlQuery::SetField ++---------------------------------------------------------------------*/ +NPT_Result +NPT_UrlQuery::SetField(const char* name, const char* value, bool encoded) +{ + NPT_String ename; + if (encoded) { + ename = name; + } else { + ename = UrlEncode(name); + } + for (NPT_List<Field>::Iterator it = m_Fields.GetFirstItem(); + it; + ++it) { + Field& field = *it; + if (field.m_Name == ename) { + if (encoded) { + field.m_Value = value; + } else { + field.m_Value = UrlEncode(value); + } + return NPT_SUCCESS; + } + } + + // field not found, add it + return AddField(name, value, encoded); +} + +/*---------------------------------------------------------------------- +| NPT_UrlQuery::GetField ++---------------------------------------------------------------------*/ +const char* +NPT_UrlQuery::GetField(const char* name) +{ + NPT_String ename = UrlEncode(name); + for (NPT_List<Field>::Iterator it = m_Fields.GetFirstItem(); + it; + ++it) { + Field& field = *it; + if (field.m_Name == ename) return field.m_Value; + } + + // field not found + return NULL; +} + +/*---------------------------------------------------------------------- +| types ++---------------------------------------------------------------------*/ +typedef enum { + NPT_URL_PARSER_STATE_START, + NPT_URL_PARSER_STATE_SCHEME, + NPT_URL_PARSER_STATE_LEADING_SLASH, + NPT_URL_PARSER_STATE_HOST, + NPT_URL_PARSER_STATE_HOST_IPV6_ADDR, + NPT_URL_PARSER_STATE_PORT, + NPT_URL_PARSER_STATE_PATH, + NPT_URL_PARSER_STATE_QUERY +} NPT_UrlParserState; + +/*---------------------------------------------------------------------- +| NPT_Url::NPT_Url ++---------------------------------------------------------------------*/ +NPT_Url::NPT_Url() : + m_HostIsIpv6Address(false), + m_Port(NPT_URL_INVALID_PORT), + m_Path("/"), + m_HasQuery(false), + m_HasFragment(false) +{ +} + +/*---------------------------------------------------------------------- +| NPT_Url::NPT_Url ++---------------------------------------------------------------------*/ +NPT_Url::NPT_Url(const char* url, NPT_UInt16 default_port) : + m_HostIsIpv6Address(false), + m_Port(NPT_URL_INVALID_PORT), + m_HasQuery(false), + m_HasFragment(false) +{ + // try to parse + if (NPT_FAILED(Parse(url, default_port))) { + Reset(); + } +} + +/*---------------------------------------------------------------------- +| NPT_Url::Parse ++---------------------------------------------------------------------*/ +NPT_Result +NPT_Url::Parse(const char* url, NPT_UInt16 default_port) +{ + // check parameters + if (url == NULL) return NPT_ERROR_INVALID_PARAMETERS; + + // set the uri scheme + NPT_Result result = SetSchemeFromUri(url); + if (NPT_FAILED(result)) return result; + + // set the default port + if (default_port) { + m_Port = default_port; + } else { + switch (m_SchemeId) { + case SCHEME_ID_HTTP: m_Port = NPT_URL_DEFAULT_HTTP_PORT; break; + case SCHEME_ID_HTTPS: m_Port = NPT_URL_DEFAULT_HTTPS_PORT; break; + default: break; + } + } + + // move to the scheme-specific part + url += m_Scheme.GetLength()+1; + + // intialize the parser + NPT_UrlParserState state = NPT_URL_PARSER_STATE_START; + const char* mark = url; + + // parse the URL + char c; + do { + c = *url++; + switch (state) { + case NPT_URL_PARSER_STATE_START: + if (c == '/') { + state = NPT_URL_PARSER_STATE_LEADING_SLASH; + } else { + return NPT_ERROR_INVALID_SYNTAX; + } + break; + + case NPT_URL_PARSER_STATE_LEADING_SLASH: + if (c == '/') { + state = NPT_URL_PARSER_STATE_HOST; + mark = url; + } else { + return NPT_ERROR_INVALID_SYNTAX; + } + break; + + case NPT_URL_PARSER_STATE_HOST_IPV6_ADDR: + if (c == ']') { + state = NPT_URL_PARSER_STATE_HOST; + } + break; + + case NPT_URL_PARSER_STATE_HOST: + if (c == '[' && url == mark+1) { + // start of an IPv6 address + state = NPT_URL_PARSER_STATE_HOST_IPV6_ADDR; + } else if (c == ':' || c == '/' || c == '\0' || c == '?' || c == '#') { + NPT_Size host_length = (NPT_Size)(url-1-mark); + if (host_length > 2 && mark[0] == '[' && mark[host_length-1] == ']') { + m_Host.Assign(mark+1, host_length-2); + m_HostIsIpv6Address = true; + } else { + m_Host.Assign(mark, host_length); + m_HostIsIpv6Address = false; + } + if (c == ':') { + mark = url; + m_Port = 0; + state = NPT_URL_PARSER_STATE_PORT; + } else { + mark = url-1; + state = NPT_URL_PARSER_STATE_PATH; + } + } + break; + + case NPT_URL_PARSER_STATE_PORT: + if (c >= '0' && c <= '9') { + unsigned int val = m_Port*10+(c-'0'); + if (val > 65535) { + m_Port = NPT_URL_INVALID_PORT; + return NPT_ERROR_INVALID_SYNTAX; + } + m_Port = val; + } else if (c == '/' || c == '\0') { + mark = url-1; + state = NPT_URL_PARSER_STATE_PATH; + } else { + // invalid character + m_Port = NPT_URL_INVALID_PORT; + return NPT_ERROR_INVALID_SYNTAX; + } + break; + + case NPT_URL_PARSER_STATE_PATH: + if (*mark) { + return ParsePathPlus(mark); + } + break; + + default: + break; + } + } while (c); + + // if we get here, the path is implicit + m_Path = "/"; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_Url::NPT_Url ++---------------------------------------------------------------------*/ +NPT_Url::NPT_Url(const char* scheme, + const char* host, + NPT_UInt16 port, + const char* path, + const char* query, + const char* fragment) : + m_Host(host), + m_HostIsIpv6Address(false), + m_Port(port), + m_Path(path), + m_HasQuery(query != NULL), + m_Query(query), + m_HasFragment(fragment != NULL), + m_Fragment(fragment) +{ + SetScheme(scheme); + + // deal with IPv6 addresses + if (m_Host.StartsWith("[") && m_Host.EndsWith("]")) { + m_HostIsIpv6Address = true; + m_Host = m_Host.SubString(1, m_Host.GetLength()-2); + } +} + +/*---------------------------------------------------------------------- +| NPT_Url::Reset ++---------------------------------------------------------------------*/ +void +NPT_Url::Reset() +{ + m_Host.SetLength(0); + m_HostIsIpv6Address = false; + m_Port = 0; + m_Path.SetLength(0); + m_HasQuery = false; + m_Query.SetLength(0); + m_HasFragment = false; + m_Fragment.SetLength(0); +} + +/*---------------------------------------------------------------------- +| NPT_Url::IsValid ++---------------------------------------------------------------------*/ +bool +NPT_Url::IsValid() const +{ + switch (m_SchemeId) { + case SCHEME_ID_HTTP: + case SCHEME_ID_HTTPS: + return m_Port != NPT_URL_INVALID_PORT && !m_Host.IsEmpty(); + break; + + default: + return !m_Scheme.IsEmpty(); + } +} + +/*---------------------------------------------------------------------- +| NPT_Url::SetHost ++---------------------------------------------------------------------*/ +NPT_Result +NPT_Url::SetHost(const char* host) +{ + const char* port; + if (*host == '[') { + const char* host_end = host+1; + while (*host_end && *host_end != ']') ++host_end; + if (*host_end != ']') { + return NPT_ERROR_INVALID_SYNTAX; + } + port = host_end+1; + if (*port && *port != ':') { + return NPT_ERROR_INVALID_SYNTAX; + } + m_Host.Assign(host+1, (NPT_Size)(host_end-host-1)); + m_HostIsIpv6Address = true; + } else { + port = host; + while (*port && *port != ':') port++; + m_Host.Assign(host, (NPT_Size)(port-host)); + m_HostIsIpv6Address = false; + } + + if (*port) { + unsigned int port_number; + // parse the port number but ignore errors (be lenient) + if (NPT_SUCCEEDED(NPT_ParseInteger(port+1, port_number, false))) { + if (port_number > 65535) { + return NPT_ERROR_OUT_OF_RANGE; + } + m_Port = (NPT_UInt16)port_number; + } else { + return NPT_ERROR_INVALID_SYNTAX; + } + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_Url::SetPort ++---------------------------------------------------------------------*/ +NPT_Result +NPT_Url::SetPort(NPT_UInt16 port) +{ + m_Port = port; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_Url::SetPath ++---------------------------------------------------------------------*/ +NPT_Result +NPT_Url::SetPath(const char* path, bool encoded) +{ + if (encoded) { + m_Path = path; + } else { + m_Path = PercentEncode(path, PathCharsToEncode); + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_Url::ParsePathPlus ++---------------------------------------------------------------------*/ +NPT_Result +NPT_Url::ParsePathPlus(const char* path_plus) +{ + // check parameters + if (path_plus == NULL) return NPT_ERROR_INVALID_PARAMETERS; + + // reset any existing values + m_Path.SetLength(0); + m_Query.SetLength(0); + m_Fragment.SetLength(0); + m_HasQuery = false; + m_HasFragment = false; + +#ifdef _WIN32 + // Skip the leading '/' if there is an absolute path starting with + // a drive letter on Windows. + if (path_plus[0] == '/' && + ((path_plus[1] >= 'a' && path_plus[1] <= 'z') || + (path_plus[1] >= 'A' && path_plus[1] <= 'Z')) && + path_plus[2] == ':') + { + ++path_plus; + } +#endif + + // intialize the parser + NPT_UrlParserState state = NPT_URL_PARSER_STATE_PATH; + const char* mark = path_plus; + + // parse the path+ + char c; + do { + c = *path_plus++; + switch (state) { + case NPT_URL_PARSER_STATE_PATH: + if (c == '\0' || c == '?' || c == '#') { + if (path_plus-1 > mark) { + m_Path.Append(mark, (NPT_Size)(path_plus-1-mark)); + } + if (c == '?') { + m_HasQuery = true; + state = NPT_URL_PARSER_STATE_QUERY; + mark = path_plus; + } else if (c == '#') { + m_HasFragment = true; + m_Fragment = path_plus; + return NPT_SUCCESS; + } + } + break; + + case NPT_URL_PARSER_STATE_QUERY: + if (c == '\0' || c == '#') { + m_Query.Assign(mark, (NPT_Size)(path_plus-1-mark)); + if (c == '#') { + m_HasFragment = true; + m_Fragment = path_plus; + } + return NPT_SUCCESS; + } + break; + + default: + break; + } + } while (c); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_Url::SetQuery ++---------------------------------------------------------------------*/ +NPT_Result +NPT_Url::SetQuery(const char* query, bool encoded) +{ + if (encoded) { + m_Query = query; + } else { + m_Query = PercentEncode(query, QueryCharsToEncode); + } + m_HasQuery = query!=NULL && NPT_StringLength(query)>0; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_Url::SetFragment ++---------------------------------------------------------------------*/ +NPT_Result +NPT_Url::SetFragment(const char* fragment, bool encoded) +{ + if (encoded) { + m_Fragment = fragment; + } else { + m_Fragment = PercentEncode(fragment, FragmentCharsToEncode); + } + m_HasFragment = fragment!=NULL; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_Url::ToRequestString ++---------------------------------------------------------------------*/ +NPT_String +NPT_Url::ToRequestString(bool with_fragment) const +{ + NPT_String result; + NPT_Size length = m_Path.GetLength()+1; + if (m_HasQuery) length += 1+m_Query.GetLength(); + if (with_fragment) length += 1+m_Fragment.GetLength(); + result.Reserve(length); + + if (m_Path.IsEmpty()) { + result += "/"; + } else { +#if defined(_WIN32) + // prepend a '/' if the path starts with the drive letter on Windows + if (((m_Path[0] >= 'a' && m_Path[0] <= 'z') || + (m_Path[0] >= 'A' && m_Path[0] <= 'Z')) && + m_Path[1] == ':') + { + result += "/"; + } +#endif + result += m_Path; + } + if (m_HasQuery) { + result += "?"; + result += m_Query; + } + if (with_fragment && m_HasFragment) { + result += "#"; + result += m_Fragment; + } + return result; +} + +/*---------------------------------------------------------------------- +| NPT_Url::ToStringWithDefaultPort ++---------------------------------------------------------------------*/ +NPT_String +NPT_Url::ToStringWithDefaultPort(NPT_UInt16 default_port, bool with_fragment) const +{ + NPT_String result; + NPT_String request = ToRequestString(with_fragment); + NPT_Size length = m_Scheme.GetLength()+3+m_Host.GetLength()+6+request.GetLength(); + + if (m_HostIsIpv6Address) { + length += 2; + } + + result.Reserve(length); + result += m_Scheme; + result += "://"; + if (m_HostIsIpv6Address) { + result += "["; + } + result += m_Host; + if (m_HostIsIpv6Address) { + result += "]"; + } + if (m_Port != default_port) { + NPT_String port = NPT_String::FromInteger(m_Port); + result += ":"; + result += port; + } + result += request; + return result; +} + +/*---------------------------------------------------------------------- +| NPT_Url::ToString ++---------------------------------------------------------------------*/ +NPT_String +NPT_Url::ToString(bool with_fragment) const +{ + return ToStringWithDefaultPort(0, with_fragment); +} diff --git a/lib/libUPnP/Neptune/Source/Core/NptUri.h b/lib/libUPnP/Neptune/Source/Core/NptUri.h new file mode 100644 index 0000000..f3661c0 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptUri.h @@ -0,0 +1,322 @@ +/***************************************************************** +| +| Neptune - URI +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +#ifndef _NPT_URI_H_ +#define _NPT_URI_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptStrings.h" +#include "NptList.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const NPT_UInt16 NPT_URL_INVALID_PORT = 0; +const NPT_UInt16 NPT_URL_DEFAULT_HTTP_PORT = 80; +const NPT_UInt16 NPT_URL_DEFAULT_HTTPS_PORT = 443; + +/*---------------------------------------------------------------------- +| NPT_Uri ++---------------------------------------------------------------------*/ +class NPT_Uri { +public: + // types + typedef enum { + SCHEME_ID_UNKNOWN, + SCHEME_ID_HTTP, + SCHEME_ID_HTTPS + } SchemeId; + + // constants. use as a parameter to Encode() + static const char* const PathCharsToEncode; + static const char* const QueryCharsToEncode; + static const char* const FragmentCharsToEncode; + static const char* const UnsafeCharsToEncode; + + // class methods + static NPT_String PercentEncode(const char* str, const char* chars, bool encode_percents=true); + static NPT_String PercentDecode(const char* str); + static SchemeId ParseScheme(const NPT_String& scheme); + + // methods + NPT_Uri() : m_SchemeId(SCHEME_ID_UNKNOWN) {} + virtual ~NPT_Uri() {} + const NPT_String& GetScheme() const { + return m_Scheme; + } + void SetScheme(const char* scheme); + NPT_Result SetSchemeFromUri(const char* uri); + SchemeId GetSchemeId() const { + return m_SchemeId; + } + +protected: + // members + NPT_String m_Scheme; + SchemeId m_SchemeId; +}; + +/*---------------------------------------------------------------------- +| NPT_UrlQuery ++---------------------------------------------------------------------*/ +class NPT_UrlQuery +{ +public: + // class methods + static NPT_String UrlEncode(const char* str, bool encode_percents=true); + static NPT_String UrlDecode(const char* str); + + // types + struct Field { + Field(const char* name, const char* value, bool encoded); + NPT_String m_Name; + NPT_String m_Value; + }; + + // constructor + NPT_UrlQuery() {} + NPT_UrlQuery(const char* query); + + // accessors + NPT_List<Field>& GetFields() { return m_Fields; } + + // methods + NPT_Result Parse(const char* query); + NPT_Result SetField(const char* name, const char* value, bool encoded=false); + NPT_Result AddField(const char* name, const char* value, bool encoded=false); + const char* GetField(const char* name); + NPT_String ToString(); + +private: + // members + NPT_List<Field> m_Fields; +}; + +/*---------------------------------------------------------------------- +| NPT_Url ++---------------------------------------------------------------------*/ +class NPT_Url : public NPT_Uri { +public: + /** + * Default constructor. This does not construct a valid URL, but an + * uninitialized one that can later be initialized to a valid URL by + * parsing or setting some of its fields. + */ + NPT_Url(); + + /** + * Construct a URL by parsing an input string in its fully encoded form. + * If an error occurs during parsing (such as an invalid syntax), the + * URL will be in an invalid state (a call to IsValid() will return false). + * + * @param url The URL string in its encoded form + * @param default_port The default port number, or 0 if not specified + */ + NPT_Url(const char* url, NPT_UInt16 default_port = 0); + + /** + * Construct a URL from its components. When constructing a URL from + * components, the components are assumed to be passed in their non-encoded + * form, and will thus be encoded automatically. + * + * @param scheme The URL scheme + * @param host The host name (enclose with [ and ] for IPv6 addresses) + * @param port The port number + * @param path The path + * @param query The query, if any, or NULL + * @param fragment The fragment, if any, or NULL + */ + NPT_Url(const char* scheme, + const char* host, + NPT_UInt16 port, + const char* path, + const char* query = NULL, + const char* fragment = NULL); + + /** + * Parse a URL from its fully encoded form. + * + * @param url The URL string in its encoded form + * @param default port The defautl port number, or 0 if not specified + */ + NPT_Result Parse(const char* url, NPT_UInt16 default_port = 0); + + /** + * Parse just the path plus optional query and fragment from a fully encoded form. + * + * @param path_plus The URL path plus optional query and fragment + */ + NPT_Result ParsePathPlus(const char* path_plus); + + /** + * Returns the host part of the URL, in its encoded form + */ + const NPT_String& GetHost() const { return m_Host; } + + /** + * Returns the port number of the URL. + */ + NPT_UInt16 GetPort() const { return m_Port; } + + /** + * Returns the path part of the URL, in its encoded form + */ + const NPT_String& GetPath() const { return m_Path; } + + /** + * Returns the path part of the URL, in its encoded or decoded form + */ + NPT_String GetPath(bool decoded) const { return decoded?NPT_Uri::PercentDecode(m_Path):m_Path;} + + /** + * Returns the query part of the URL, in its encoded form + */ + const NPT_String& GetQuery() const { return m_Query; } + + /** + * Returns the fragment part of the URL, in its encoded form + */ + const NPT_String& GetFragment() const { return m_Fragment; } + + /** + * Returns whether the URL is valid or not. Invalid URLs are uninitialized or + * not fully initialized URLs. + * + * @return true if the URL is valid, false if it is not. + */ + virtual bool IsValid() const; + + /** + * Resets a URL to an uninitialized state. + */ + void Reset(); + + /** + * Returns whether the URL has a query part or not. + * + * @return true if the URL has a query part, false if it does not. + */ + bool HasQuery() const { return m_HasQuery; } + + /** + * Returns whether the URL has a fragment part or not. + * + * @return true if the URL has a fragment part, false if it does not. + */ + bool HasFragment() const { return m_HasFragment; } + + /** + * Sets the host part of the URL. + * + * @param host The host part of the URL (enclose with [ and ] for IPv6 addresses) + */ + NPT_Result SetHost(const char* host); + + /** + * Sets the port number of the URL. + * + * @param port The port number of the URL + */ + NPT_Result SetPort(NPT_UInt16 port); + + /** + * Sets the path part of the URL. + * + * @param path The path part of the URL + * @param encoded Boolean flag indicating whether the path parameter is + * already encoded or not. If it is not already encoded, it will be + * automatically encoded. + */ + NPT_Result SetPath(const char* path, bool encoded=false); + + /** + * Sets the query part of the URL. + * + * @param query The query part of the URL + * @param encoded Boolean flag indicating whether the query parameter is + * already encoded or not. If it is not already encoded, it will be + * automatically encoded. + */ + NPT_Result SetQuery(const char* query, bool encoded=false); + + /** + * Sets the fragment part of the URL. + * + * @param query The fragment part of the URL + * @param encoded Boolean flag indicating whether the fragment parameter is + * already encoded or not. If it is not already encoded, it will be + * automatically encoded. + */ + NPT_Result SetFragment(const char* fragment, bool encoded=false); + + /** + * Return the string representation of the URL in a way that can be used in + * an HTTP request (i.e just the portion of the URL starting with the path) + * + * @param with_fragment Boolean flag specifiying whether the fragment part of + * the URL should be included in the returned string or not. + */ + virtual NPT_String ToRequestString(bool with_fragment = false) const; + + /** + * Return the string representation of the URL. + * + * @param default_port default port number for the scheme. If the port number of + * the URL is not equal to the default port, then port number is explicitely + * included in the string representation of the URL. + * @param with_fragment Boolean flag specifiying whether the fragment part of + * the URL should be included in the returned string or not. + */ + virtual NPT_String ToStringWithDefaultPort(NPT_UInt16 default_port, bool with_fragment = true) const; + + /** + * Return the string representation of the URL. + * + * @param with_fragment Boolean flag specifiying whether the fragment part of + * the URL should be included in the returned string or not. + */ + virtual NPT_String ToString(bool with_fragment = true) const; + +protected: + // members + NPT_String m_Host; + bool m_HostIsIpv6Address; + NPT_UInt16 m_Port; + NPT_String m_Path; + bool m_HasQuery; + NPT_String m_Query; + bool m_HasFragment; + NPT_String m_Fragment; +}; + +#endif // _NPT_URI_H_ diff --git a/lib/libUPnP/Neptune/Source/Core/NptUtils.cpp b/lib/libUPnP/Neptune/Source/Core/NptUtils.cpp new file mode 100644 index 0000000..f427f8b --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptUtils.cpp @@ -0,0 +1,957 @@ +/***************************************************************** +| +| Neptune - Utils +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include <math.h> + +#include "NptConfig.h" +#include "NptTypes.h" +#include "NptDebug.h" +#include "NptUtils.h" +#include "NptResults.h" + +#if defined(NPT_CONFIG_HAVE_LIMITS_H) +#include <limits.h> +#endif + +#ifdef TARGET_WINDOWS_STORE +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 +#endif +#include <windows.h> +#endif +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const unsigned int NPT_FORMAT_LOCAL_BUFFER_SIZE = 1024; +const unsigned int NPT_FORMAT_BUFFER_INCREMENT = 4096; +const unsigned int NPT_FORMAT_BUFFER_MAX_SIZE = 65536; + +/*---------------------------------------------------------------------- +| NPT_BytesToInt64Be ++---------------------------------------------------------------------*/ +NPT_UInt64 +NPT_BytesToInt64Be(const unsigned char* bytes) +{ + return + ( ((NPT_UInt64)bytes[0])<<56 ) | + ( ((NPT_UInt64)bytes[1])<<48 ) | + ( ((NPT_UInt64)bytes[2])<<40 ) | + ( ((NPT_UInt64)bytes[3])<<32 ) | + ( ((NPT_UInt64)bytes[4])<<24 ) | + ( ((NPT_UInt64)bytes[5])<<16 ) | + ( ((NPT_UInt64)bytes[6])<<8 ) | + ( ((NPT_UInt64)bytes[7]) ); +} + +/*---------------------------------------------------------------------- +| NPT_BytesToInt32Be ++---------------------------------------------------------------------*/ +NPT_UInt32 +NPT_BytesToInt32Be(const unsigned char* bytes) +{ + return + ( ((NPT_UInt32)bytes[0])<<24 ) | + ( ((NPT_UInt32)bytes[1])<<16 ) | + ( ((NPT_UInt32)bytes[2])<<8 ) | + ( ((NPT_UInt32)bytes[3]) ); +} + +/*---------------------------------------------------------------------- +| NPT_BytesToInt24Be ++---------------------------------------------------------------------*/ +NPT_UInt32 +NPT_BytesToInt24Be(const unsigned char* bytes) +{ + return + ( ((NPT_UInt32)bytes[0])<<16 ) | + ( ((NPT_UInt32)bytes[1])<<8 ) | + ( ((NPT_UInt32)bytes[2]) ); +} + +/*---------------------------------------------------------------------- +| NPT_BytesToInt16Be ++---------------------------------------------------------------------*/ +NPT_UInt16 +NPT_BytesToInt16Be(const unsigned char* bytes) +{ + return + ( ((NPT_UInt16)bytes[0])<<8 ) | + ( ((NPT_UInt16)bytes[1]) ); +} + +/*---------------------------------------------------------------------- +| NPT_BytesToInt64Le ++---------------------------------------------------------------------*/ +NPT_UInt64 +NPT_BytesToInt64Le(const unsigned char* bytes) +{ + return + ( ((NPT_UInt64)bytes[7])<<56 ) | + ( ((NPT_UInt64)bytes[6])<<48 ) | + ( ((NPT_UInt64)bytes[5])<<40 ) | + ( ((NPT_UInt64)bytes[4])<<32 ) | + ( ((NPT_UInt64)bytes[3])<<24 ) | + ( ((NPT_UInt64)bytes[2])<<16 ) | + ( ((NPT_UInt64)bytes[1])<<8 ) | + ( ((NPT_UInt64)bytes[0]) ); +} + +/*---------------------------------------------------------------------- +| NPT_BytesToInt32Le ++---------------------------------------------------------------------*/ +NPT_UInt32 +NPT_BytesToInt32Le(const unsigned char* bytes) +{ + return + ( ((NPT_UInt32)bytes[3])<<24 ) | + ( ((NPT_UInt32)bytes[2])<<16 ) | + ( ((NPT_UInt32)bytes[1])<<8 ) | + ( ((NPT_UInt32)bytes[0]) ); +} + +/*---------------------------------------------------------------------- +| NPT_BytesToInt24Le ++---------------------------------------------------------------------*/ +NPT_UInt32 +NPT_BytesToInt24Le(const unsigned char* bytes) +{ + return + ( ((NPT_UInt32)bytes[2])<<16 ) | + ( ((NPT_UInt32)bytes[1])<<8 ) | + ( ((NPT_UInt32)bytes[0]) ); +} + +/*---------------------------------------------------------------------- +| NPT_BytesToInt16Le ++---------------------------------------------------------------------*/ +NPT_UInt16 +NPT_BytesToInt16Le(const unsigned char* bytes) +{ + return + ( ((NPT_UInt16)bytes[1])<<8 ) | + ( ((NPT_UInt16)bytes[0]) ); +} + +/*---------------------------------------------------------------------- +| NPT_BytesFromInt64Be ++---------------------------------------------------------------------*/ +void +NPT_BytesFromInt64Be(unsigned char* buffer, NPT_UInt64 value) +{ + buffer[0] = (unsigned char)(value>>56) & 0xFF; + buffer[1] = (unsigned char)(value>>48) & 0xFF; + buffer[2] = (unsigned char)(value>>40) & 0xFF; + buffer[3] = (unsigned char)(value>>32) & 0xFF; + buffer[4] = (unsigned char)(value>>24) & 0xFF; + buffer[5] = (unsigned char)(value>>16) & 0xFF; + buffer[6] = (unsigned char)(value>> 8) & 0xFF; + buffer[7] = (unsigned char)(value ) & 0xFF; +} + +/*---------------------------------------------------------------------- +| NPT_BytesFromInt32Be ++---------------------------------------------------------------------*/ +void +NPT_BytesFromInt32Be(unsigned char* buffer, NPT_UInt32 value) +{ + buffer[0] = (unsigned char)(value>>24) & 0xFF; + buffer[1] = (unsigned char)(value>>16) & 0xFF; + buffer[2] = (unsigned char)(value>> 8) & 0xFF; + buffer[3] = (unsigned char)(value ) & 0xFF; +} + +/*---------------------------------------------------------------------- +| NPT_BytesFromInt24Be ++---------------------------------------------------------------------*/ +void +NPT_BytesFromInt24Be(unsigned char* buffer, NPT_UInt32 value) +{ + buffer[0] = (unsigned char)(value>>16) & 0xFF; + buffer[1] = (unsigned char)(value>> 8) & 0xFF; + buffer[2] = (unsigned char)(value ) & 0xFF; +} + +/*---------------------------------------------------------------------- +| NPT_BytesFromInt16Be ++---------------------------------------------------------------------*/ +void +NPT_BytesFromInt16Be(unsigned char* buffer, NPT_UInt16 value) +{ + buffer[0] = (unsigned char)((value>> 8) & 0xFF); + buffer[1] = (unsigned char)((value ) & 0xFF); +} + +/*---------------------------------------------------------------------- +| NPT_BytesFromInt64Le ++---------------------------------------------------------------------*/ +void +NPT_BytesFromInt64Le(unsigned char* buffer, NPT_UInt64 value) +{ + buffer[7] = (unsigned char)(value>>56) & 0xFF; + buffer[6] = (unsigned char)(value>>48) & 0xFF; + buffer[5] = (unsigned char)(value>>40) & 0xFF; + buffer[4] = (unsigned char)(value>>32) & 0xFF; + buffer[3] = (unsigned char)(value>>24) & 0xFF; + buffer[2] = (unsigned char)(value>>16) & 0xFF; + buffer[1] = (unsigned char)(value>> 8) & 0xFF; + buffer[0] = (unsigned char)(value ) & 0xFF; +} + +/*---------------------------------------------------------------------- +| NPT_BytesFromInt32Le ++---------------------------------------------------------------------*/ +void +NPT_BytesFromInt32Le(unsigned char* buffer, NPT_UInt32 value) +{ + buffer[3] = (unsigned char)(value>>24) & 0xFF; + buffer[2] = (unsigned char)(value>>16) & 0xFF; + buffer[1] = (unsigned char)(value>> 8) & 0xFF; + buffer[0] = (unsigned char)(value ) & 0xFF; +} + +/*---------------------------------------------------------------------- +| NPT_BytesFromInt24Le ++---------------------------------------------------------------------*/ +void +NPT_BytesFromInt24Le(unsigned char* buffer, NPT_UInt32 value) +{ + buffer[2] = (unsigned char)(value>>16) & 0xFF; + buffer[1] = (unsigned char)(value>> 8) & 0xFF; + buffer[0] = (unsigned char)(value ) & 0xFF; +} + +/*---------------------------------------------------------------------- +| NPT_BytesFromInt16Le ++---------------------------------------------------------------------*/ +void +NPT_BytesFromInt16Le(unsigned char* buffer, NPT_UInt16 value) +{ + buffer[1] = (unsigned char)((value>> 8) & 0xFF); + buffer[0] = (unsigned char)((value ) & 0xFF); +} + +#if !defined(NPT_CONFIG_HAVE_SNPRINTF) +/*---------------------------------------------------------------------- +| NPT_FormatString ++---------------------------------------------------------------------*/ +int +NPT_FormatString(char* /*str*/, NPT_Size /*size*/, const char* /*format*/, ...) +{ + NPT_ASSERT(0); // not implemented yet + return 0; +} +#endif // NPT_CONFIG_HAVE_SNPRINTF + +/*---------------------------------------------------------------------- +| NPT_NibbleToHex ++---------------------------------------------------------------------*/ +char +NPT_NibbleToHex(unsigned int nibble, bool uppercase /* = true */) +{ + NPT_ASSERT(nibble < 16); + if (uppercase) { + return (nibble < 10) ? ('0' + nibble) : ('A' + (nibble-10)); + } else { + return (nibble < 10) ? ('0' + nibble) : ('a' + (nibble-10)); + } +} + +/*---------------------------------------------------------------------- +| NPT_HexToNibble ++---------------------------------------------------------------------*/ +int +NPT_HexToNibble(char hex) +{ + if (hex >= 'a' && hex <= 'f') { + return ((hex - 'a') + 10); + } else if (hex >= 'A' && hex <= 'F') { + return ((hex - 'A') + 10); + } else if (hex >= '0' && hex <= '9') { + return (hex - '0'); + } else { + return -1; + } +} + +/*---------------------------------------------------------------------- +| NPT_ByteToHex ++---------------------------------------------------------------------*/ +void +NPT_ByteToHex(NPT_Byte b, char* buffer, bool uppercase) +{ + buffer[0] = NPT_NibbleToHex((b>>4) & 0x0F, uppercase); + buffer[1] = NPT_NibbleToHex(b & 0x0F, uppercase); +} + +/*---------------------------------------------------------------------- +| NPT_HexToByte ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HexToByte(const char* buffer, NPT_Byte& b) +{ + int nibble_0 = NPT_HexToNibble(buffer[0]); + if (nibble_0 < 0) return NPT_ERROR_INVALID_SYNTAX; + + int nibble_1 = NPT_HexToNibble(buffer[1]); + if (nibble_1 < 0) return NPT_ERROR_INVALID_SYNTAX; + + b = (nibble_0 << 4) | nibble_1; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HexToBytes ++---------------------------------------------------------------------*/ +NPT_Result +NPT_HexToBytes(const char* hex, + NPT_DataBuffer& bytes) +{ + // check the size + NPT_Size len = NPT_StringLength(hex); + if ((len%2) != 0) return NPT_ERROR_INVALID_PARAMETERS; + NPT_Size bytes_size = len / 2; + NPT_Result result = bytes.SetDataSize(bytes_size); + if (NPT_FAILED(result)) return result; + + // decode + for (NPT_Ordinal i=0; i<bytes_size; i++) { + result = NPT_HexToByte(hex+(i*2), *(bytes.UseData()+i)); + if (NPT_FAILED(result)) return result; + } + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_HexString ++---------------------------------------------------------------------*/ +NPT_String +NPT_HexString(const unsigned char* data, + NPT_Size data_size, + const char* separator, + bool uppercase) +{ + NPT_String result; + + // quick check + if (data == NULL || data_size == 0) return result; + + // set the result size + NPT_Size separator_length = separator?NPT_StringLength(separator):0; + result.SetLength(data_size*2+(data_size-1)*separator_length); + + // build the string + const unsigned char* src = data; + char* dst = result.UseChars(); + while (data_size--) { + NPT_ByteToHex(*src++, dst, uppercase); + dst += 2; + if (data_size) { + NPT_CopyMemory(dst, separator, separator_length); + dst += separator_length; + } + } + + return result; +} + +/*---------------------------------------------------------------------- +| NPT_ParseFloat ++---------------------------------------------------------------------*/ +NPT_Result +NPT_ParseFloat(const char* str, float& result, bool relaxed) +{ + // safe default value + result = 0.0f; + + // check params + if (str == NULL || *str == '\0') { + return NPT_ERROR_INVALID_PARAMETERS; + } + + // ignore leading whitespace + if (relaxed) { + while (*str == ' ' || *str == '\t') { + str++; + } + } + if (*str == '\0') { + return NPT_ERROR_INVALID_PARAMETERS; + } + + // check for sign + bool negative = false; + if (*str == '-') { + // negative number + negative = true; + str++; + } else if (*str == '+') { + // skip the + sign + str++; + } + + // parse the digits + bool after_radix = false; + bool empty = true; + float value = 0.0f; + float decimal = 10.0f; + char c; + while ((c = *str++)) { + if (c == '.') { + if (after_radix || (*str < '0' || *str > '9')) { + return NPT_ERROR_INVALID_PARAMETERS; + } else { + after_radix = true; + } + } else if (c >= '0' && c <= '9') { + empty = false; + if (after_radix) { + value += (float)(c-'0')/decimal; + decimal *= 10.0f; + } else { + value = 10.0f*value + (float)(c-'0'); + } + } else if (c == 'e' || c == 'E') { + // exponent + if (*str == '+' || *str == '-' || (*str >= '0' && *str <= '9')) { + int exponent = 0; + if (NPT_SUCCEEDED(NPT_ParseInteger(str, exponent, relaxed))) { + value *= (float)pow(10.0f, (float)exponent); + break; + } else { + return NPT_ERROR_INVALID_PARAMETERS; + } + } else { + return NPT_ERROR_INVALID_PARAMETERS; + } + } else { + if (relaxed) { + break; + } else { + return NPT_ERROR_INVALID_PARAMETERS; + } + } + } + + // check that the value was non empty + if (empty) { + return NPT_ERROR_INVALID_PARAMETERS; + } + + // return the result + result = negative ? -value : value; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_ParseInteger64 ++---------------------------------------------------------------------*/ +NPT_Result +NPT_ParseInteger64(const char* str, NPT_Int64& result, bool relaxed, NPT_Cardinal* chars_used) +{ + // safe default value + result = 0; + if (chars_used) *chars_used = 0; + + if (str == NULL) { + return NPT_ERROR_INVALID_PARAMETERS; + } + + // ignore leading whitespace + if (relaxed) { + while (*str == ' ' || *str == '\t') { + str++; + if (chars_used) (*chars_used)++; + } + } + if (*str == '\0') { + return NPT_ERROR_INVALID_PARAMETERS; + } + + // check for sign + bool negative = false; + if (*str == '-') { + // negative number + negative = true; + str++; + if (chars_used) (*chars_used)++; + } else if (*str == '+') { + // skip the + sign + str++; + if (chars_used) (*chars_used)++; + } + + // check for overflows + NPT_Int64 max = NPT_INT64_MAX/10; + + // adjust the max for overflows when the value is negative + if (negative && ((NPT_INT64_MAX%10) == /* DISABLES CODE */ (9))) ++max; + + // parse the digits + bool empty = true; + NPT_Int64 value = 0; + char c; + while ((c = *str++)) { + if (c >= '0' && c <= '9') { + if (value < 0 || value > max) return NPT_ERROR_OVERFLOW; + value = 10*value + (c-'0'); + if (value < 0 && (!negative || value != NPT_INT64_MIN)) return NPT_ERROR_OVERFLOW; + empty = false; + if (chars_used) (*chars_used)++; + } else { + if (relaxed) { + break; + } else { + return NPT_ERROR_INVALID_PARAMETERS; + } + } + } + + // check that the value was non empty + if (empty) { + return NPT_ERROR_INVALID_PARAMETERS; + } + + // return the result + result = negative ? -value : value; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_ParseInteger64 ++---------------------------------------------------------------------*/ +NPT_Result +NPT_ParseInteger64(const char* str, NPT_UInt64& result, bool relaxed, NPT_Cardinal* chars_used) +{ + // safe default value + result = 0; + if (chars_used) *chars_used = 0; + + if (str == NULL) { + return NPT_ERROR_INVALID_PARAMETERS; + } + + // ignore leading whitespace + if (relaxed) { + while (*str == ' ' || *str == '\t') { + str++; + if (chars_used) (*chars_used)++; + } + } + if (*str == '\0') { + return NPT_ERROR_INVALID_PARAMETERS; + } + + // parse the digits + bool empty = true; + NPT_UInt64 value = 0; + char c; + while ((c = *str++)) { + if (c >= '0' && c <= '9') { + NPT_UInt64 new_value; + if (value > NPT_UINT64_MAX/10) return NPT_ERROR_OVERFLOW; + new_value = 10*value + (c-'0'); + if (new_value < value) return NPT_ERROR_OVERFLOW; + value = new_value; + empty = false; + if (chars_used) (*chars_used)++; + } else { + if (relaxed) { + break; + } else { + return NPT_ERROR_INVALID_PARAMETERS; + } + } + } + + // check that the value was non empty + if (empty) { + return NPT_ERROR_INVALID_PARAMETERS; + } + + // return the result + result = value; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_ParseInteger32 ++---------------------------------------------------------------------*/ +NPT_Result +NPT_ParseInteger32(const char* str, NPT_Int32& value, bool relaxed, NPT_Cardinal* chars_used) +{ + NPT_Int64 value_64; + NPT_Result result = NPT_ParseInteger64(str, value_64, relaxed, chars_used); + value = 0; + if (NPT_SUCCEEDED(result)) { + if (value_64 < NPT_INT32_MIN || value_64 > NPT_INT32_MAX) { + return NPT_ERROR_OVERFLOW; + } + value = (NPT_Int32)value_64; + } + return result; +} + +/*---------------------------------------------------------------------- +| NPT_ParseInteger32 ++---------------------------------------------------------------------*/ +NPT_Result +NPT_ParseInteger32(const char* str, NPT_UInt32& value, bool relaxed, NPT_Cardinal* chars_used) +{ + NPT_UInt64 value_64; + NPT_Result result = NPT_ParseInteger64(str, value_64, relaxed, chars_used); + value = 0; + if (NPT_SUCCEEDED(result)) { + if (value_64 > (NPT_UInt64)NPT_UINT32_MAX) return NPT_ERROR_OVERFLOW; + value = (NPT_UInt32)value_64; + } + return result; +} + +/*---------------------------------------------------------------------- +| NPT_ParseInteger ++---------------------------------------------------------------------*/ +NPT_Result +NPT_ParseInteger(const char* str, long& value, bool relaxed, NPT_Cardinal* chars_used) +{ + NPT_Int64 value_64; + NPT_Result result = NPT_ParseInteger64(str, value_64, relaxed, chars_used); + value = 0; + if (NPT_SUCCEEDED(result)) { +#if NPT_ULONG_MAX != NPT_UINT64_MAX + if (value_64 < NPT_LONG_MIN || value_64 > NPT_LONG_MAX) { + return NPT_ERROR_OVERFLOW; + } +#endif + value = (long)value_64; + } + return result; +} + +/*---------------------------------------------------------------------- +| NPT_ParseInteger ++---------------------------------------------------------------------*/ +NPT_Result +NPT_ParseInteger(const char* str, unsigned long& value, bool relaxed, NPT_Cardinal* chars_used) +{ + NPT_UInt64 value_64; + NPT_Result result = NPT_ParseInteger64(str, value_64, relaxed, chars_used); + value = 0; + if (NPT_SUCCEEDED(result)) { +#if NPT_ULONG_MAX != NPT_UINT64_MAX + if (value_64 > NPT_ULONG_MAX) { + return NPT_ERROR_OVERFLOW; + } +#endif + value = (unsigned long)value_64; + } + return result; +} + +/*---------------------------------------------------------------------- +| NPT_ParseInteger ++---------------------------------------------------------------------*/ +NPT_Result +NPT_ParseInteger(const char* str, int& value, bool relaxed, NPT_Cardinal* chars_used) +{ + NPT_Int64 value_64; + NPT_Result result = NPT_ParseInteger64(str, value_64, relaxed, chars_used); + value = 0; + if (NPT_SUCCEEDED(result)) { + if (value_64 < NPT_INT_MIN || value_64 > NPT_INT_MAX) { + return NPT_ERROR_OVERFLOW; + } + value = (int)value_64; + } + return result; +} + +/*---------------------------------------------------------------------- +| NPT_ParseInteger ++---------------------------------------------------------------------*/ +NPT_Result +NPT_ParseInteger(const char* str, unsigned int& value, bool relaxed, NPT_Cardinal* chars_used) +{ + NPT_UInt64 value_64; + NPT_Result result = NPT_ParseInteger64(str, value_64, relaxed, chars_used); + value = 0; + if (NPT_SUCCEEDED(result)) { + if (value_64 > NPT_UINT_MAX) { + return NPT_ERROR_OVERFLOW; + } + value = (unsigned int)value_64; + } + return result; +} + +#if !defined(NPT_CONFIG_HAVE_STRCPY) +/*---------------------------------------------------------------------- +| NPT_CopyString ++---------------------------------------------------------------------*/ +void +NPT_CopyString(char* dst, const char* src) +{ + while(*dst++ = *src++); +} +#endif + +/*---------------------------------------------------------------------- +| NPT_FormatOutput ++---------------------------------------------------------------------*/ +void +NPT_FormatOutput(void (*function)(void* parameter, const char* message), + void* function_parameter, + const char* format, + va_list args) +{ + char local_buffer[NPT_FORMAT_LOCAL_BUFFER_SIZE]; + unsigned int buffer_size = NPT_FORMAT_LOCAL_BUFFER_SIZE; + char* buffer = local_buffer; + + for(;;) { + int result; + + /* try to format the message (it might not fit) */ + result = NPT_FormatStringVN(buffer, buffer_size-1, format, args); + buffer[buffer_size-1] = 0; /* force a NULL termination */ + if (result >= 0) break; + + /* the buffer was too small, try something bigger */ + buffer_size = (buffer_size+NPT_FORMAT_BUFFER_INCREMENT)*2; + if (buffer_size > NPT_FORMAT_BUFFER_MAX_SIZE) break; + if (buffer != local_buffer) delete[] buffer; + buffer = new char[buffer_size]; + if (buffer == NULL) return; + } + + (*function)(function_parameter, buffer); + if (buffer != local_buffer) delete[] buffer; +} + +/*---------------------------------------------------------------------- +| local types ++---------------------------------------------------------------------*/ +typedef enum { + NPT_MIME_PARAMETER_PARSER_STATE_NEED_NAME, + NPT_MIME_PARAMETER_PARSER_STATE_IN_NAME, + NPT_MIME_PARAMETER_PARSER_STATE_NEED_EQUALS, + NPT_MIME_PARAMETER_PARSER_STATE_NEED_VALUE, + NPT_MIME_PARAMETER_PARSER_STATE_IN_VALUE, + NPT_MIME_PARAMETER_PARSER_STATE_IN_QUOTED_VALUE, + NPT_MIME_PARAMETER_PARSER_STATE_NEED_SEPARATOR +} NPT_MimeParameterParserState; + +/*---------------------------------------------------------------------- +| NPT_ParseMimeParameters +| +| From RFC 822 and RFC 2045 +| +| ; ( Octal, Decimal.) +| CHAR = <any ASCII character> ; ( 0-177, 0.-127.) +| ALPHA = <any ASCII alphabetic character> +| ; (101-132, 65.- 90.) +| ; (141-172, 97.-122.) +| DIGIT = <any ASCII decimal digit> ; ( 60- 71, 48.- 57.) +| CTL = <any ASCII control ; ( 0- 37, 0.- 31.) +| character and DEL> ; ( 177, 127.) +| CR = <ASCII CR, carriage return> ; ( 15, 13.) +| LF = <ASCII LF, linefeed> ; ( 12, 10.) +| SPACE = <ASCII SP, space> ; ( 40, 32.) +| HTAB = <ASCII HT, horizontal-tab> ; ( 11, 9.) +| <"> = <ASCII quote mark> ; ( 42, 34.) +| CRLF = CR LF +| +| LWSP-char = SPACE / HTAB ; semantics = SPACE +| +| linear-white-space = 1*([CRLF] LWSP-char) ; semantics = SPACE +| ; CRLF => folding +| +| parameter := attribute "=" value +| +| attribute := token +| ; Matching of attributes +| ; is ALWAYS case-insensitive. +| +| value := token / quoted-string +| +| token := 1*<any (US-ASCII) CHAR except SPACE, CTLs, or tspecials> +| +| tspecials := "(" / ")" / "<" / ">" / "@" / +| "," / ";" / ":" / "\" / <"> +| "/" / "[" / "]" / "?" / "=" +| +| quoted-string = <"> *(qtext/quoted-pair) <">; Regular qtext or +| ; quoted chars. +| +| qtext = <any CHAR excepting <">, ; => may be folded +| "\" & CR, and including +| linear-white-space> +| +| quoted-pair = "\" CHAR ; may quote any char +| ++---------------------------------------------------------------------*/ +NPT_Result +NPT_ParseMimeParameters(const char* encoded, + NPT_Map<NPT_String, NPT_String>& parameters) +{ + // check parameters + if (encoded == NULL) return NPT_ERROR_INVALID_PARAMETERS; + + // reserve some space + NPT_String param_name; + NPT_String param_value; + param_name.Reserve(64); + param_value.Reserve(64); + + NPT_MimeParameterParserState state = NPT_MIME_PARAMETER_PARSER_STATE_NEED_NAME; + bool quoted_char = false; + for (;;) { + char c = *encoded++; + if (!quoted_char && (c == 0x0A || c == 0x0D)) continue; // ignore EOL chars + switch (state) { + case NPT_MIME_PARAMETER_PARSER_STATE_NEED_NAME: + if (c == '\0') break; // END + if (c == ' ' || c == '\t') continue; // ignore leading whitespace + if (c < ' ') return NPT_ERROR_INVALID_SYNTAX; // CTLs are invalid + param_name += c; // we're not strict: accept all other chars + state = NPT_MIME_PARAMETER_PARSER_STATE_IN_NAME; + break; + + case NPT_MIME_PARAMETER_PARSER_STATE_IN_NAME: + if (c < ' ') return NPT_ERROR_INVALID_SYNTAX; // END or CTLs are invalid + if (c == ' ') { + state = NPT_MIME_PARAMETER_PARSER_STATE_NEED_EQUALS; + } else if (c == '=') { + state = NPT_MIME_PARAMETER_PARSER_STATE_NEED_VALUE; + } else { + param_name += c; // we're not strict: accept all other chars + } + break; + + case NPT_MIME_PARAMETER_PARSER_STATE_NEED_EQUALS: + if (c < ' ') return NPT_ERROR_INVALID_SYNTAX; // END or CTLs are invalid + if (c == ' ' || c == '\t') continue; // ignore leading whitespace + if (c != '=') return NPT_ERROR_INVALID_SYNTAX; + state = NPT_MIME_PARAMETER_PARSER_STATE_NEED_VALUE; + break; + + case NPT_MIME_PARAMETER_PARSER_STATE_NEED_VALUE: + if (c < ' ') return NPT_ERROR_INVALID_SYNTAX; // END or CTLs are invalid + if (c == ' ' || c == '\t') continue; // ignore leading whitespace + if (c == '"') { + state = NPT_MIME_PARAMETER_PARSER_STATE_IN_QUOTED_VALUE; + } else { + param_value += c; // we're not strict: accept all other chars + state = NPT_MIME_PARAMETER_PARSER_STATE_IN_VALUE; + } + break; + + case NPT_MIME_PARAMETER_PARSER_STATE_IN_QUOTED_VALUE: + if (quoted_char) { + quoted_char = false; + if (c == '\0') return NPT_ERROR_INVALID_SYNTAX; + param_value += c; // accept all chars + break; + } else if (c == '\\') { + quoted_char = true; + break; + } else if (c == '"') { + // add the parameter to the map + param_name.TrimRight(); + param_value.TrimRight(); + parameters[param_name] = param_value; + param_name.SetLength(0); + param_value.SetLength(0); + state = NPT_MIME_PARAMETER_PARSER_STATE_NEED_SEPARATOR; + } else if (c < ' ') { + return NPT_ERROR_INVALID_SYNTAX; // END or CTLs are invalid + } else { + param_value += c; // we're not strict: accept all other chars + } + break; + + case NPT_MIME_PARAMETER_PARSER_STATE_IN_VALUE: + if (c == '\0' || c == ';') { + // add the parameter to the map + param_name.TrimRight(); + param_value.TrimRight(); + parameters[param_name] = param_value; + param_name.SetLength(0); + param_value.SetLength(0); + state = NPT_MIME_PARAMETER_PARSER_STATE_NEED_NAME; + } else if (c < ' ') { + // CTLs are invalid + return NPT_ERROR_INVALID_SYNTAX; + } else { + param_value += c; // we're not strict: accept all other chars + } + break; + + case NPT_MIME_PARAMETER_PARSER_STATE_NEED_SEPARATOR: + if (c == '\0') break; + if (c < ' ') return NPT_ERROR_INVALID_SYNTAX; // CTLs are invalid + if (c == ' ' || c == '\t') continue; // ignore whitespace + if (c != ';') return NPT_ERROR_INVALID_SYNTAX; + state = NPT_MIME_PARAMETER_PARSER_STATE_NEED_NAME; + break; + } + if (c == '\0') break; // end of buffer + } + + return NPT_SUCCESS; +} + +#ifdef TARGET_WINDOWS_STORE +std::wstring win32ConvertUtf8ToW(const std::string &text) +{ + if (text.empty()) + { + return L""; + } + + int bufSize = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, text.c_str(), -1, NULL, 0); + if (bufSize == 0) + return L""; + wchar_t *converted = new wchar_t[bufSize]; + if (MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, text.c_str(), -1, converted, bufSize) != bufSize) + { + delete[] converted; + return L""; + } + + std::wstring Wret(converted); + delete[] converted; + + return Wret; +} +#endif diff --git a/lib/libUPnP/Neptune/Source/Core/NptUtils.h b/lib/libUPnP/Neptune/Source/Core/NptUtils.h new file mode 100644 index 0000000..89b2e29 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptUtils.h @@ -0,0 +1,235 @@ +/***************************************************************** +| +| Neptune Utils +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +#ifndef _NPT_UTILS_H_ +#define _NPT_UTILS_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptConfig.h" +#include "NptTypes.h" +#include "NptStrings.h" +#include "NptMap.h" +#include "NptDataBuffer.h" +#include "NptHash.h" + +#if defined (NPT_CONFIG_HAVE_STDIO_H) +#include <stdio.h> +#endif + +#if defined (NPT_CONFIG_HAVE_STRING_H) +#include <string.h> +#endif + +#if defined(NPT_CONFIG_HAVE_STDARG_H) +#include <stdarg.h> +#endif + +#if defined(TARGET_WINDOWS_STORE) +#include <string> +#endif +/*---------------------------------------------------------------------- +| macros ++---------------------------------------------------------------------*/ +#define NPT_ARRAY_SIZE(_a) (sizeof(_a)/sizeof((_a)[0])) + +/*---------------------------------------------------------------------- +| byte I/O ++---------------------------------------------------------------------*/ +extern void NPT_BytesFromInt64Be(unsigned char* buffer, NPT_UInt64 value); +extern void NPT_BytesFromInt32Be(unsigned char* buffer, NPT_UInt32 value); +extern void NPT_BytesFromInt24Be(unsigned char* buffer, NPT_UInt32 value); +extern void NPT_BytesFromInt16Be(unsigned char* buffer, NPT_UInt16 value); +extern NPT_UInt64 NPT_BytesToInt64Be(const unsigned char* buffer); +extern NPT_UInt32 NPT_BytesToInt32Be(const unsigned char* buffer); +extern NPT_UInt32 NPT_BytesToInt24Be(const unsigned char* buffer); +extern NPT_UInt16 NPT_BytesToInt16Be(const unsigned char* buffer); + +extern void NPT_BytesFromInt64Le(unsigned char* buffer, NPT_UInt64 value); +extern void NPT_BytesFromInt32Le(unsigned char* buffer, NPT_UInt32 value); +extern void NPT_BytesFromInt24Le(unsigned char* buffer, NPT_UInt32 value); +extern void NPT_BytesFromInt16Le(unsigned char* buffer, NPT_UInt16 value); +extern NPT_UInt64 NPT_BytesToInt64Le(const unsigned char* buffer); +extern NPT_UInt32 NPT_BytesToInt32Le(const unsigned char* buffer); +extern NPT_UInt32 NPT_BytesToInt24Le(const unsigned char* buffer); +extern NPT_UInt16 NPT_BytesToInt16Le(const unsigned char* buffer); + +/*---------------------------------------------------------------------- +| conversion utilities ++---------------------------------------------------------------------*/ +extern NPT_Result +NPT_ParseFloat(const char* str, float& result, bool relaxed = true); + +extern NPT_Result +NPT_ParseInteger(const char* str, long& result, bool relaxed = true, NPT_Cardinal* chars_used = 0); + +extern NPT_Result +NPT_ParseInteger(const char* str, unsigned long& result, bool relaxed = true, NPT_Cardinal* chars_used = 0); + +extern NPT_Result +NPT_ParseInteger(const char* str, int& result, bool relaxed = true, NPT_Cardinal* chars_used = 0); + +extern NPT_Result +NPT_ParseInteger(const char* str, unsigned int& result, bool relaxed = true, NPT_Cardinal* chars_used = 0); + +extern NPT_Result +NPT_ParseInteger32(const char* str, NPT_Int32& result, bool relaxed = true, NPT_Cardinal* chars_used = 0); + +extern NPT_Result +NPT_ParseInteger32(const char* str, NPT_UInt32& result, bool relaxed = true, NPT_Cardinal* chars_used = 0); + +extern NPT_Result +NPT_ParseInteger64(const char* str, NPT_Int64& result, bool relaxed = true, NPT_Cardinal* chars_used = 0); + +extern NPT_Result +NPT_ParseInteger64(const char* str, NPT_UInt64& result, bool relaxed = true, NPT_Cardinal* chars_used = 0); + +/*---------------------------------------------------------------------- +| formatting ++---------------------------------------------------------------------*/ +void +NPT_FormatOutput(void (*function)(void* parameter, const char* message), + void* function_parameter, + const char* format, + va_list args); + +void NPT_ByteToHex(NPT_Byte b, char* buffer, bool uppercase=false); +NPT_Result NPT_HexToByte(const char* buffer, NPT_Byte& b); +NPT_Result NPT_HexToBytes(const char* hex, NPT_DataBuffer& bytes); +NPT_String NPT_HexString(const unsigned char* data, + NPT_Size data_size, + const char* separator = NULL, + bool uppercase=false); +char NPT_NibbleToHex(unsigned int nibble, bool uppercase = true); +int NPT_HexToNibble(char hex); + +/*---------------------------------------------------------------------- +| parsing ++---------------------------------------------------------------------*/ +NPT_Result +NPT_ParseMimeParameters(const char* encoded, + NPT_Map<NPT_String, NPT_String>& parameters); + +/*---------------------------------------------------------------------- +| environment variables ++---------------------------------------------------------------------*/ +class NPT_Environment { +public: + static NPT_Result Get(const char* name, NPT_String& value); + static NPT_Result Set(const char* name, const char* value); +}; +// compat for older APIs +#define NPT_GetEnvironment(_x,_y) NPT_Environment::Get(_x,_y) + +/*---------------------------------------------------------------------- +| string utils ++---------------------------------------------------------------------*/ +#if defined (NPT_CONFIG_HAVE_STDIO_H) +#include <stdio.h> +#endif + +#if defined (NPT_CONFIG_HAVE_STRING_H) +#include <string.h> +#endif + +#if defined (NPT_CONFIG_HAVE_SNPRINTF) +#define NPT_FormatString NPT_snprintf +#else +int NPT_FormatString(char* str, NPT_Size size, const char* format, ...); +#endif + +#if defined(NPT_CONFIG_HAVE_VSNPRINTF) +#define NPT_FormatStringVN(s,c,f,a) NPT_vsnprintf(s,c,f,a) +#else +extern int NPT_FormatStringVN(char *buffer, size_t count, const char *format, va_list argptr); +#endif + +#if defined(NPT_CONFIG_HAVE_MEMCPY) +#define NPT_CopyMemory memcpy +#else +extern void NPT_CopyMemory(void* dest, void* src, NPT_Size size); +#endif + +#if defined(NPT_CONFIG_HAVE_STRCMP) +#define NPT_StringsEqual(s1, s2) (strcmp((s1), (s2)) == 0) +#else +extern int NPT_StringsEqual(const char* s1, const char* s2); +#endif + +#if defined(NPT_CONFIG_HAVE_STRNCMP) +#define NPT_StringsEqualN(s1, s2, n) (strncmp((s1), (s2), (n)) == 0) +#else +extern int NPT_StringsEqualN(const char* s1, const char* s2, unsigned long size); +#endif + +#if defined(NPT_CONFIG_HAVE_STRLEN) +#define NPT_StringLength(s) (NPT_Size)(strlen(s)) +#else +extern unsigned long NPT_StringLength(const char* s); +#endif + +#if defined(NPT_CONFIG_HAVE_STRCPY) +#define NPT_CopyString(dst, src) ((void)NPT_strcpy((dst), (src))) +#else +extern void NPT_CopyString(char* dst, const char* src); +#endif + +/** + * Copy up to n characters from src to dst. + * The destination buffer will be null-terminated, so it must + * have enough space for n+1 characters (n from the source plus + * the null terminator). + */ +#if defined(NPT_CONFIG_HAVE_STRNCPY) +#define NPT_CopyStringN(dst, src, n) \ +do { ((void)NPT_strncpy((dst), (src), n)); (dst)[(n)] = '\0'; } while(0) +#else +extern int NPT_CopyStringN(char* dst, const char* src, unsigned long n); +#endif + +#if defined(NPT_CONFIG_HAVE_MEMSET) +#define NPT_SetMemory memset +#else +extern void NPT_SetMemory(void* dest, int c, NPT_Size size); +#endif + +#if defined(NPT_CONFIG_HAVE_MEMCMP) +#define NPT_MemoryEqual(s1, s2, n) (memcmp((s1), (s2), (n)) == 0) +#else +extern int NPT_MemoryEqual(const void* s1, const void* s2, unsigned long n); +#endif + +#if defined(TARGET_WINDOWS_STORE) +std::wstring win32ConvertUtf8ToW(const std::string &text); +#endif + +#endif // _NPT_UTILS_H_ diff --git a/lib/libUPnP/Neptune/Source/Core/NptVersion.h b/lib/libUPnP/Neptune/Source/Core/NptVersion.h new file mode 100644 index 0000000..ad34d90 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptVersion.h @@ -0,0 +1,41 @@ +/***************************************************************** +| +| Neptune - Version Info +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +#ifndef _NPT_VERSION_H_ +#define _NPT_VERSION_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#define NPT_NEPTUNE_VERSION 0x01010300 +#define NPT_NEPTUNE_VERSION_STRING "1.1.3" + +#endif // _NPT_VERSION_H_ diff --git a/lib/libUPnP/Neptune/Source/Core/NptXml.cpp b/lib/libUPnP/Neptune/Source/Core/NptXml.cpp new file mode 100644 index 0000000..d6b95ca --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptXml.cpp @@ -0,0 +1,2611 @@ +/***************************************************************** +| +| Neptune - Xml Support +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptConfig.h" +#include "NptTypes.h" +#include "NptXml.h" +#include "NptUtils.h" +#include "NptMap.h" +#include "NptDebug.h" + +/*---------------------------------------------------------------------- +| local compilation flags ++---------------------------------------------------------------------*/ +//#define NPT_XML_PARSER_DEBUG +#ifdef NPT_XML_PARSER_DEBUG +#define NPT_XML_Debug_0(s) NPT_Debug(s) +#define NPT_XML_Debug_1(s,x0) NPT_Debug(s,x0) +#define NPT_XML_Debug_2(s,x0,x1) NPT_Debug(s,x0,x1) +#define NPT_XML_Debug_3(s,x0,x1,x2) NPT_Debug(s,x0,x1,x2) +#define NPT_XML_Debug_4(s,x0,x1,x2,x3) NPT_Debug(s,x0,x1,x2,x3) +#else +#define NPT_XML_Debug_0(s) +#define NPT_XML_Debug_1(s,x0) +#define NPT_XML_Debug_2(s,x0,x1) +#define NPT_XML_Debug_3(s,x0,x1,x2) +#define NPT_XML_Debug_4(s,x0,x1,x2,x3) +#endif + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +static const NPT_String +NPT_XmlNamespaceUri_Xml("http://www.w3.org/XML/1998/namespace"); + +/*---------------------------------------------------------------------- +| NPT_XmlAttributeFinder ++---------------------------------------------------------------------*/ +class NPT_XmlAttributeFinder +{ +public: + // if 'namespc' is NULL, we're looking for ANY namespace + // if 'namespc' is '\0', we're looking for NO namespace + // if 'namespc' is non-empty, look for that SPECIFIC namespace + NPT_XmlAttributeFinder(const NPT_XmlElementNode& element, + const char* name, + const char* namespc) : + m_Element(element), m_Name(name), m_Namespace(namespc) {} + + bool operator()(const NPT_XmlAttribute* const & attribute) const { + if (attribute->m_Name == m_Name) { + if (m_Namespace) { + const NPT_String& prefix = attribute->GetPrefix(); + if (m_Namespace[0] == '\0') { + // match if the attribute has NO namespace + return prefix.IsEmpty(); + } else { + // match if the attribute has the SPECIFIC namespace + // we're looking for + if (prefix.IsEmpty()) { + // attributes without a prefix don't have a namespace + return false; + } else { + const NPT_String* namespc = m_Element.GetNamespaceUri(prefix); + return namespc && *namespc == m_Namespace; + } + } + } else { + // ANY namespace will match + return true; + } + } else { + return false; + } + } + +private: + const NPT_XmlElementNode& m_Element; + const char* m_Name; + const char* m_Namespace; +}; + +/*---------------------------------------------------------------------- +| NPT_XmlAttributeFinderWithPrefix ++---------------------------------------------------------------------*/ +class NPT_XmlAttributeFinderWithPrefix +{ +public: + NPT_XmlAttributeFinderWithPrefix(const char* prefix, const char* name) : + m_Prefix(prefix?prefix:""), m_Name(name) {} + + bool operator()(const NPT_XmlAttribute* const & attribute) const { + return attribute->m_Prefix == m_Prefix && attribute->m_Name == m_Name; + } + +private: + const char* m_Prefix; + const char* m_Name; +}; + +/*---------------------------------------------------------------------- +| NPT_XmlTagFinder ++---------------------------------------------------------------------*/ +class NPT_XmlTagFinder +{ +public: + // if 'namespc' is NULL, we're looking for ANY namespace + // if 'namespc' is '\0', we're looking for NO namespace + // if 'namespc' is non-empty, look for that SPECIFIC namespace + NPT_XmlTagFinder(const char* tag, const char* namespc) : + m_Tag(tag), m_Namespace(namespc) {} + + bool operator()(const NPT_XmlNode* const & node) const { + const NPT_XmlElementNode* element = node->AsElementNode(); + if (element && element->m_Tag == m_Tag) { + if (m_Namespace) { + // look for a SPECIFIC namespace or NO namespace + const NPT_String* namespc = element->GetNamespace(); + if (namespc) { + // the element has a namespace, match if it is equal to + // what we're looking for + return *namespc == m_Namespace; + } else { + // the element does not have a namespace, match if we're + // looking for NO namespace + return m_Namespace[0] == '\0'; + } + } else { + // ANY namespace will match + return true; + } + } else { + return false; + } + } + +private: + const char* m_Tag; + const char* m_Namespace; +}; + +/*---------------------------------------------------------------------- +| NPT_XmlTextFinder ++---------------------------------------------------------------------*/ +class NPT_XmlTextFinder +{ +public: + bool operator()(const NPT_XmlNode* const & node) const { + return node->AsTextNode() != NULL; + } +}; + +/*---------------------------------------------------------------------- +| NPT_XmlNamespaceCollapser ++---------------------------------------------------------------------*/ +class NPT_XmlNamespaceCollapser +{ +public: + NPT_XmlNamespaceCollapser(NPT_XmlElementNode* element) : + m_Root(element) {} + + void operator()(NPT_XmlNode*& node) const { + NPT_XmlElementNode* element = node->AsElementNode(); + if (element == NULL) return; + + // collapse the namespace for this element + CollapseNamespace(element, element->GetPrefix()); + + // collapse the namespaces for the attributes + NPT_List<NPT_XmlAttribute*>::Iterator item = element->GetAttributes().GetFirstItem(); + while (item) { + NPT_XmlAttribute* attribute = *item; + CollapseNamespace(element, attribute->GetPrefix()); + ++item; + } + + // recurse to the children + element->GetChildren().Apply(*this); + } + +private: + // methods + void CollapseNamespace(NPT_XmlElementNode* element, const NPT_String& prefix) const; + + // members + NPT_XmlElementNode* m_Root; +}; + +/*---------------------------------------------------------------------- +| NPT_XmlNamespaceCollapser::CollapseNamespace ++---------------------------------------------------------------------*/ +void +NPT_XmlNamespaceCollapser::CollapseNamespace(NPT_XmlElementNode* element, + const NPT_String& prefix) const +{ + if (m_Root->m_NamespaceMap == NULL || + (m_Root->m_NamespaceMap->GetNamespaceUri(prefix) == NULL && prefix != "xml")) { + // the root element does not have that prefix in the map + const NPT_String* uri = element->GetNamespaceUri(prefix); + if (uri) m_Root->SetNamespaceUri(prefix, uri->GetChars()); + } +} + +/*---------------------------------------------------------------------- +| NPT_XmlAttribute::NPT_XmlAttribute ++---------------------------------------------------------------------*/ +NPT_XmlAttribute::NPT_XmlAttribute(const char* name, const char* value) : + m_Value(value) +{ + const char* cursor = name; + while (char c = *cursor++) { + if (c == ':') { + unsigned int prefix_length = (unsigned int)(cursor-name)-1; + m_Prefix.Assign(name, prefix_length); + name = cursor; + break; + } + } + m_Name = name; +} + +/*---------------------------------------------------------------------- +| NPT_XmlElementNode::NPT_XmlElementNode ++---------------------------------------------------------------------*/ +NPT_XmlElementNode::NPT_XmlElementNode(const char* prefix, const char* tag) : + NPT_XmlNode(ELEMENT), + m_Prefix(prefix), + m_Tag(tag), + m_NamespaceMap(NULL), + m_NamespaceParent(NULL) +{ +} + +/*---------------------------------------------------------------------- +| NPT_XmlElementNode::NPT_XmlElementNode ++---------------------------------------------------------------------*/ +NPT_XmlElementNode::NPT_XmlElementNode(const char* tag) : + NPT_XmlNode(ELEMENT), + m_NamespaceMap(NULL), + m_NamespaceParent(NULL) +{ + const char* cursor = tag; + while (char c = *cursor++) { + if (c == ':') { + unsigned int prefix_length = (unsigned int)(cursor-tag)-1; + m_Prefix.Assign(tag, prefix_length); + tag = cursor; + break; + } + } + m_Tag = tag; +} + +/*---------------------------------------------------------------------- +| NPT_XmlElementNode::~NPT_XmlElementNode ++---------------------------------------------------------------------*/ +NPT_XmlElementNode::~NPT_XmlElementNode() +{ + m_Children.Apply(NPT_ObjectDeleter<NPT_XmlNode>()); + m_Attributes.Apply(NPT_ObjectDeleter<NPT_XmlAttribute>()); + delete m_NamespaceMap; +} + +/*---------------------------------------------------------------------- +| NPT_XmlElementNode::SetParent ++---------------------------------------------------------------------*/ +void +NPT_XmlElementNode::SetParent(NPT_XmlNode* parent) +{ + // update our parent + m_Parent = parent; + + // update out namespace linkage + NPT_XmlElementNode* parent_element = + parent?parent->AsElementNode():NULL; + NPT_XmlElementNode* namespace_parent; + if (parent_element) { + namespace_parent = + parent_element->m_NamespaceMap ? + parent_element: + parent_element->m_NamespaceParent; + } else { + namespace_parent = NULL; + } + if (namespace_parent != m_NamespaceParent) { + m_NamespaceParent = namespace_parent; + RelinkNamespaceMaps(); + } +} + +/*---------------------------------------------------------------------- +| NPT_XmlElementNode::AddChild ++---------------------------------------------------------------------*/ +NPT_Result +NPT_XmlElementNode::AddChild(NPT_XmlNode* child) +{ + if (child == NULL) return NPT_ERROR_INVALID_PARAMETERS; + child->SetParent(this); + return m_Children.Add(child); +} + +/*---------------------------------------------------------------------- +| NPT_XmlElementNode::GetChild ++---------------------------------------------------------------------*/ +NPT_XmlElementNode* +NPT_XmlElementNode::GetChild(const char* tag, const char* namespc, NPT_Ordinal n) const +{ + // remap the requested namespace to match the semantics of the finder + // and allow for "" to also mean NO namespace + if (namespc == NULL || namespc[0] == '\0') { + namespc = ""; // for the finder, empty string means NO namespace + } else if (namespc[0] == '*' && namespc[1] == '\0') { + namespc = NULL; // for the finder, NULL means ANY namespace + } + + // find the child + NPT_List<NPT_XmlNode*>::Iterator item; + item = m_Children.Find(NPT_XmlTagFinder(tag, namespc), n); + return item?(*item)->AsElementNode():NULL; +} + +/*---------------------------------------------------------------------- +| NPT_XmlElementNode::AddAttribute ++---------------------------------------------------------------------*/ +NPT_Result +NPT_XmlElementNode::AddAttribute(const char* name, + const char* value) +{ + if (name == NULL || value == NULL) return NPT_ERROR_INVALID_PARAMETERS; + return m_Attributes.Add(new NPT_XmlAttribute(name, value)); +} + +/*---------------------------------------------------------------------- +| NPT_XmlElementNode::SetAttribute ++---------------------------------------------------------------------*/ +NPT_Result +NPT_XmlElementNode::SetAttribute(const char* prefix, + const char* name, + const char* value) +{ + if (name == NULL || value == NULL) return NPT_ERROR_INVALID_PARAMETERS; + + /* see if this attribute is already set */ + NPT_List<NPT_XmlAttribute*>::Iterator attribute; + attribute = m_Attributes.Find(NPT_XmlAttributeFinderWithPrefix(prefix, name)); + if (attribute) { + // an attribute with this name and prefix already exists, + // change its value + (*attribute)->SetValue(value); + return NPT_SUCCESS; + } + return m_Attributes.Add(new NPT_XmlAttribute(prefix, name, value)); +} + +/*---------------------------------------------------------------------- +| NPT_XmlElementNode::SetAttribute ++---------------------------------------------------------------------*/ +NPT_Result +NPT_XmlElementNode::SetAttribute(const char* name, const char* value) +{ + return SetAttribute(NULL, name, value); +} + +/*---------------------------------------------------------------------- +| NPT_XmlElementNode::GetAttribute ++---------------------------------------------------------------------*/ +const NPT_String* +NPT_XmlElementNode::GetAttribute(const char* name, const char* namespc) const +{ + // remap the requested namespace to match the semantics of the finder + // and allow for "" to also mean NO namespace + if (namespc == NULL || namespc[0] == '\0') { + namespc = ""; // for the finder, empty string means NO namespace + } else if (namespc[0] == '*' && namespc[1] == '\0') { + namespc = NULL; // for the finder, NULL means ANY namespace + } + + // find the attribute + NPT_List<NPT_XmlAttribute*>::Iterator attribute; + attribute = m_Attributes.Find(NPT_XmlAttributeFinder(*this, name, namespc)); + if (attribute) { + return &(*attribute)->GetValue(); + } else { + return NULL; + } +} + +/*---------------------------------------------------------------------- +| NPT_XmlElementNode::AddText ++---------------------------------------------------------------------*/ +NPT_Result +NPT_XmlElementNode::AddText(const char* text) +{ + return AddChild(new NPT_XmlTextNode(NPT_XmlTextNode::CHARACTER_DATA, text)); +} + +/*---------------------------------------------------------------------- +| NPT_XmlElementNode::GetText ++---------------------------------------------------------------------*/ +const NPT_String* +NPT_XmlElementNode::GetText(NPT_Ordinal n) const +{ + NPT_List<NPT_XmlNode*>::Iterator node; + node = m_Children.Find(NPT_XmlTextFinder(), n); + return node?&(*node)->AsTextNode()->GetString():NULL; +} + +/*---------------------------------------------------------------------- +| NPT_XmlElementNode::MakeStandalone ++---------------------------------------------------------------------*/ +NPT_Result +NPT_XmlElementNode::MakeStandalone() +{ + NPT_XmlNamespaceCollapser collapser(this); + NPT_XmlNode* node_pointer = this; + collapser(node_pointer); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_XmlElementNode::RelinkNamespaceMaps ++---------------------------------------------------------------------*/ +void +NPT_XmlElementNode::RelinkNamespaceMaps() +{ + // update our children so that they can inherit the right + // namespace map + NPT_List<NPT_XmlNode*>::Iterator item = m_Children.GetFirstItem(); + while (item) { + NPT_XmlElementNode* element = (*item)->AsElementNode(); + if (element) { + if (m_NamespaceMap) { + // we have a map, so our children point to us + element->SetNamespaceParent(this); + } else { + // we don't have a map, so our children point to + // where we also point + element->SetNamespaceParent(m_NamespaceParent); + } + } + ++item; + } +} + +/*---------------------------------------------------------------------- +| NPT_XmlElementNode::SetNamespaceParent ++---------------------------------------------------------------------*/ +void +NPT_XmlElementNode::SetNamespaceParent(NPT_XmlElementNode* parent) +{ + m_NamespaceParent = parent; + RelinkNamespaceMaps(); +} + +/*---------------------------------------------------------------------- +| NPT_XmlElementNode::SetNamespaceUri ++---------------------------------------------------------------------*/ +NPT_Result +NPT_XmlElementNode::SetNamespaceUri(const char* prefix, const char* uri) +{ + // ensure that we have a namespace map + if (m_NamespaceMap == NULL) { + m_NamespaceMap = new NPT_XmlNamespaceMap(); + RelinkNamespaceMaps(); + } + + return m_NamespaceMap->SetNamespaceUri(prefix, uri); +} + +/*---------------------------------------------------------------------- +| NPT_XmlElementNode::GetNamespaceUri ++---------------------------------------------------------------------*/ +const NPT_String* +NPT_XmlElementNode::GetNamespaceUri(const char* prefix) const +{ + if (m_NamespaceMap) { + // look in our namespace map first + const NPT_String* namespc = m_NamespaceMap->GetNamespaceUri(prefix); + if (namespc) { + if (namespc->IsEmpty()) { + return NULL; + } else { + return namespc; + } + } + } + + // look into our parent's namespace map + if (m_NamespaceParent) { + return m_NamespaceParent->GetNamespaceUri(prefix); + } else { + // check if this is a well-known namespace + if (prefix[0] == 'x' && + prefix[1] == 'm' && + prefix[2] == 'l' && + prefix[3] == '\0') { + return &NPT_XmlNamespaceUri_Xml; + } + + // not found + return NULL; + } +} + +/*---------------------------------------------------------------------- +| NPT_XmlElementNode::GetNamespace ++---------------------------------------------------------------------*/ +const NPT_String* +NPT_XmlElementNode::GetNamespace() const +{ + return GetNamespaceUri(m_Prefix); +} + +/*---------------------------------------------------------------------- +| NPT_XmlElementNode::GetNamespacePrefix ++---------------------------------------------------------------------*/ +const NPT_String* +NPT_XmlElementNode::GetNamespacePrefix(const char* uri) const +{ + NPT_XmlNamespaceMap* namespace_map = + m_NamespaceMap? + m_NamespaceMap: + (m_NamespaceParent? + m_NamespaceParent->m_NamespaceMap: + NULL); + + if (namespace_map) { + return namespace_map->GetNamespacePrefix(uri); + } else { + return NULL; + } +} + +/*---------------------------------------------------------------------- +| NPT_XmlTextNode::NPT_XmlTextNode ++---------------------------------------------------------------------*/ +NPT_XmlTextNode::NPT_XmlTextNode(TokenType token_type, const char* text) : + NPT_XmlNode(TEXT), + m_TokenType(token_type), + m_Text(text) +{ +} + +/*---------------------------------------------------------------------- +| NPT_XmlAccumulator ++---------------------------------------------------------------------*/ +class NPT_XmlAccumulator { +public: + NPT_XmlAccumulator(); + ~NPT_XmlAccumulator(); + void Append(char c); + void Append(const char* s); + void AppendUTF8(unsigned int c); + void Reset() { m_Valid = 0; } + const char* GetString(); + NPT_Size GetSize() const { return m_Valid; } + const unsigned char* GetBuffer() const { return m_Buffer; } + +private: + // methods + void Allocate(NPT_Size size); + + // members + unsigned char* m_Buffer; + NPT_Size m_Allocated; + NPT_Size m_Valid; +}; + +/*---------------------------------------------------------------------- +| NPT_XmlAccumulator::NPT_XmlAccumulator ++---------------------------------------------------------------------*/ +NPT_XmlAccumulator::NPT_XmlAccumulator() : + m_Buffer(NULL), + m_Allocated(0), + m_Valid(0) +{ +} + +/*---------------------------------------------------------------------- +| NPT_XmlAccumulator::~NPT_XmlAccumulator ++---------------------------------------------------------------------*/ +NPT_XmlAccumulator::~NPT_XmlAccumulator() +{ + delete[] m_Buffer; +} + +/*---------------------------------------------------------------------- +| NPT_XmlAccumulator::Allocate ++---------------------------------------------------------------------*/ +void +NPT_XmlAccumulator::Allocate(NPT_Size size) +{ + // check if we have enough + if (m_Allocated >= size) return; + + // compute new size + do { + m_Allocated = m_Allocated ? m_Allocated * 2 : 32; + } while (m_Allocated < size); + + // reallocate + unsigned char* new_buffer = new unsigned char[m_Allocated]; + NPT_CopyMemory(new_buffer, m_Buffer, m_Valid); + delete[] m_Buffer; + m_Buffer = new_buffer; +} + +/*---------------------------------------------------------------------- +| NPT_XmlAccumulator::Append ++---------------------------------------------------------------------*/ +inline void +NPT_XmlAccumulator::Append(char c) +{ + NPT_Size needed = m_Valid+1; + if (needed > m_Allocated) Allocate(needed); + m_Buffer[m_Valid++] = c; +} + +/*---------------------------------------------------------------------- +| NPT_XmlAccumulator::Append ++---------------------------------------------------------------------*/ +void +NPT_XmlAccumulator::Append(const char* s) +{ + char c; + while ((c = *s++)) Append(c); +} + +/*---------------------------------------------------------------------- +| NPT_XmlAccumulator::AppendUTF8 ++---------------------------------------------------------------------*/ +inline void +NPT_XmlAccumulator::AppendUTF8(unsigned int c) +{ + NPT_Size needed = m_Valid+4; // allocate 4 more chars + if (needed > m_Allocated) Allocate(needed); + + if (c <= 0x7F) { + // 000000-00007F -> 1 char = 0xxxxxxx + m_Buffer[m_Valid++] = (char)c; + } else if (c <= 0x7FF) { + // 000080-0007FF -> 2 chars = 110zzzzx 10xxxxxx + m_Buffer[m_Valid++] = 0xC0|(c>>6 ); + m_Buffer[m_Valid++] = 0x80|(c&0x3F); + } else if (c <= 0xFFFF) { + // 000800-00FFFF -> 3 chars = 1110zzzz 10zxxxxx 10xxxxxx + m_Buffer[m_Valid++] = 0xE0| (c>>12 ); + m_Buffer[m_Valid++] = 0x80|((c&0xFC0)>>6); + m_Buffer[m_Valid++] = 0x80| (c&0x3F ); + } else if (c <= 0x10FFFF) { + // 010000-10FFFF -> 4 chars = 11110zzz 10zzxxxx 10xxxxxx 10xxxxxx + m_Buffer[m_Valid++] = 0xF0| (c>>18 ); + m_Buffer[m_Valid++] = 0x80|((c&0x3F000)>>12); + m_Buffer[m_Valid++] = 0x80|((c&0xFC0 )>> 6); + m_Buffer[m_Valid++] = 0x80| (c&0x3F ); + } +} + +/*---------------------------------------------------------------------- +| NPT_XmlAccumulator::GetString ++---------------------------------------------------------------------*/ +inline const char* +NPT_XmlAccumulator::GetString() +{ + // ensure that the buffer is NULL terminated + Allocate(m_Valid+1); + m_Buffer[m_Valid] = '\0'; + return (const char*)m_Buffer; +} + +/*---------------------------------------------------------------------- +| NPT_XmlNamespaceMap::~NPT_XmlNamespaceMap ++---------------------------------------------------------------------*/ +NPT_XmlNamespaceMap::~NPT_XmlNamespaceMap() +{ + m_Entries.Apply(NPT_ObjectDeleter<Entry>()); +} + +/*---------------------------------------------------------------------- +| NPT_XmlNamespaceMap::SetNamespaceUri ++---------------------------------------------------------------------*/ +NPT_Result +NPT_XmlNamespaceMap::SetNamespaceUri(const char* prefix, const char* uri) +{ + NPT_List<Entry*>::Iterator item = m_Entries.GetFirstItem(); + while (item) { + if ((*item)->m_Prefix == prefix) { + // the prefix is already in the map, update the value + (*item)->m_Uri = uri; + return NPT_SUCCESS; + } + ++item; + } + + // the prefix is not in the map, add it + return m_Entries.Add(new Entry(prefix, uri)); +} + +/*---------------------------------------------------------------------- +| NPT_XmlNamespaceMap::GetNamespaceUri ++---------------------------------------------------------------------*/ +const NPT_String* +NPT_XmlNamespaceMap::GetNamespaceUri(const char* prefix) +{ + NPT_List<Entry*>::Iterator item = m_Entries.GetFirstItem(); + while (item) { + if ((*item)->m_Prefix == prefix) { + // match + return &(*item)->m_Uri; + } + ++item; + } + + // the prefix is not in the map + return NULL; +} + +/*---------------------------------------------------------------------- +| NPT_XmlNamespaceMap::GetNamespacePrefix ++---------------------------------------------------------------------*/ +const NPT_String* +NPT_XmlNamespaceMap::GetNamespacePrefix(const char* uri) +{ + NPT_List<Entry*>::Iterator item = m_Entries.GetFirstItem(); + while (item) { + if ((*item)->m_Uri == uri) { + // match + return &(*item)->m_Prefix; + } + ++item; + } + + // the uri is not in the map + return NULL; +} + +/*---------------------------------------------------------------------- +| character map +| +| flags: +| 1 --> any char +| 2 --> whitespace +| 4 --> name +| 8 --> content +| 16 --> value ++---------------------------------------------------------------------*/ +#define NPT_XML_USE_CHAR_MAP +#if defined(NPT_XML_USE_CHAR_MAP) +// NOTE: this table is generated by the ruby script 'XmlCharMap.rb' +static const unsigned char NPT_XmlCharMap[256] = { + 0, // 0 0x00 + 0, // 1 0x01 + 0, // 2 0x02 + 0, // 3 0x03 + 0, // 4 0x04 + 0, // 5 0x05 + 0, // 6 0x06 + 0, // 7 0x07 + 0, // 8 0x08 + 1|2|8|16, // 9 0x09 + 1|2|8|16, // 10 0x0a + 0, // 11 0x0b + 0, // 12 0x0c + 1|2|8|16, // 13 0x0d + 0, // 14 0x0e + 0, // 15 0x0f + 0, // 16 0x10 + 0, // 17 0x11 + 0, // 18 0x12 + 0, // 19 0x13 + 0, // 20 0x14 + 0, // 21 0x15 + 0, // 22 0x16 + 0, // 23 0x17 + 0, // 24 0x18 + 0, // 25 0x19 + 0, // 26 0x1a + 0, // 27 0x1b + 0, // 28 0x1c + 0, // 29 0x1d + 0, // 30 0x1e + 0, // 31 0x1f + 1|2|8|16, // 32 0x20 ' ' + 1|8|16, // 33 0x21 '!' + 1|8|16, // 34 0x22 '"' + 1|8|16, // 35 0x23 '#' + 1|8|16, // 36 0x24 '$' + 1|8|16, // 37 0x25 '%' + 1, // 38 0x26 '&' + 1|8|16, // 39 0x27 ''' + 1|8|16, // 40 0x28 '(' + 1|8|16, // 41 0x29 ')' + 1|8|16, // 42 0x2a '*' + 1|8|16, // 43 0x2b '+' + 1|8|16, // 44 0x2c ',' + 1|4|8|16, // 45 0x2d '-' + 1|4|8|16, // 46 0x2e '.' + 1|8|16, // 47 0x2f '/' + 1|4|8|16, // 48 0x30 '0' + 1|4|8|16, // 49 0x31 '1' + 1|4|8|16, // 50 0x32 '2' + 1|4|8|16, // 51 0x33 '3' + 1|4|8|16, // 52 0x34 '4' + 1|4|8|16, // 53 0x35 '5' + 1|4|8|16, // 54 0x36 '6' + 1|4|8|16, // 55 0x37 '7' + 1|4|8|16, // 56 0x38 '8' + 1|4|8|16, // 57 0x39 '9' + 1|4|8|16, // 58 0x3a ':' + 1|8|16, // 59 0x3b ';' + 1, // 60 0x3c '<' + 1|8|16, // 61 0x3d '=' + 1|8|16, // 62 0x3e '>' + 1|8|16, // 63 0x3f '?' + 1|8|16, // 64 0x40 '@' + 1|4|8|16, // 65 0x41 'A' + 1|4|8|16, // 66 0x42 'B' + 1|4|8|16, // 67 0x43 'C' + 1|4|8|16, // 68 0x44 'D' + 1|4|8|16, // 69 0x45 'E' + 1|4|8|16, // 70 0x46 'F' + 1|4|8|16, // 71 0x47 'G' + 1|4|8|16, // 72 0x48 'H' + 1|4|8|16, // 73 0x49 'I' + 1|4|8|16, // 74 0x4a 'J' + 1|4|8|16, // 75 0x4b 'K' + 1|4|8|16, // 76 0x4c 'L' + 1|4|8|16, // 77 0x4d 'M' + 1|4|8|16, // 78 0x4e 'N' + 1|4|8|16, // 79 0x4f 'O' + 1|4|8|16, // 80 0x50 'P' + 1|4|8|16, // 81 0x51 'Q' + 1|4|8|16, // 82 0x52 'R' + 1|4|8|16, // 83 0x53 'S' + 1|4|8|16, // 84 0x54 'T' + 1|4|8|16, // 85 0x55 'U' + 1|4|8|16, // 86 0x56 'V' + 1|4|8|16, // 87 0x57 'W' + 1|4|8|16, // 88 0x58 'X' + 1|4|8|16, // 89 0x59 'Y' + 1|4|8|16, // 90 0x5a 'Z' + 1|8|16, // 91 0x5b '[' + 1|8|16, // 92 0x5c '\' + 1|8|16, // 93 0x5d ']' + 1|8|16, // 94 0x5e '^' + 1|4|8|16, // 95 0x5f '_' + 1|8|16, // 96 0x60 '`' + 1|4|8|16, // 97 0x61 'a' + 1|4|8|16, // 98 0x62 'b' + 1|4|8|16, // 99 0x63 'c' + 1|4|8|16, // 100 0x64 'd' + 1|4|8|16, // 101 0x65 'e' + 1|4|8|16, // 102 0x66 'f' + 1|4|8|16, // 103 0x67 'g' + 1|4|8|16, // 104 0x68 'h' + 1|4|8|16, // 105 0x69 'i' + 1|4|8|16, // 106 0x6a 'j' + 1|4|8|16, // 107 0x6b 'k' + 1|4|8|16, // 108 0x6c 'l' + 1|4|8|16, // 109 0x6d 'm' + 1|4|8|16, // 110 0x6e 'n' + 1|4|8|16, // 111 0x6f 'o' + 1|4|8|16, // 112 0x70 'p' + 1|4|8|16, // 113 0x71 'q' + 1|4|8|16, // 114 0x72 'r' + 1|4|8|16, // 115 0x73 's' + 1|4|8|16, // 116 0x74 't' + 1|4|8|16, // 117 0x75 'u' + 1|4|8|16, // 118 0x76 'v' + 1|4|8|16, // 119 0x77 'w' + 1|4|8|16, // 120 0x78 'x' + 1|4|8|16, // 121 0x79 'y' + 1|4|8|16, // 122 0x7a 'z' + 1|8|16, // 123 0x7b '{' + 1|8|16, // 124 0x7c '|' + 1|8|16, // 125 0x7d '}' + 1|8|16, // 126 0x7e '~' + 1|8|16, // 127 0x7f + 1|8|16, // 128 0x80 + 1|8|16, // 129 0x81 + 1|8|16, // 130 0x82 + 1|8|16, // 131 0x83 + 1|8|16, // 132 0x84 + 1|8|16, // 133 0x85 + 1|8|16, // 134 0x86 + 1|8|16, // 135 0x87 + 1|8|16, // 136 0x88 + 1|8|16, // 137 0x89 + 1|8|16, // 138 0x8a + 1|8|16, // 139 0x8b + 1|8|16, // 140 0x8c + 1|8|16, // 141 0x8d + 1|8|16, // 142 0x8e + 1|8|16, // 143 0x8f + 1|8|16, // 144 0x90 + 1|8|16, // 145 0x91 + 1|8|16, // 146 0x92 + 1|8|16, // 147 0x93 + 1|8|16, // 148 0x94 + 1|8|16, // 149 0x95 + 1|8|16, // 150 0x96 + 1|8|16, // 151 0x97 + 1|8|16, // 152 0x98 + 1|8|16, // 153 0x99 + 1|8|16, // 154 0x9a + 1|8|16, // 155 0x9b + 1|8|16, // 156 0x9c + 1|8|16, // 157 0x9d + 1|8|16, // 158 0x9e + 1|8|16, // 159 0x9f + 1|8|16, // 160 0xa0 + 1|8|16, // 161 0xa1 + 1|8|16, // 162 0xa2 + 1|8|16, // 163 0xa3 + 1|8|16, // 164 0xa4 + 1|8|16, // 165 0xa5 + 1|8|16, // 166 0xa6 + 1|8|16, // 167 0xa7 + 1|8|16, // 168 0xa8 + 1|8|16, // 169 0xa9 + 1|8|16, // 170 0xaa + 1|8|16, // 171 0xab + 1|8|16, // 172 0xac + 1|8|16, // 173 0xad + 1|8|16, // 174 0xae + 1|8|16, // 175 0xaf + 1|8|16, // 176 0xb0 + 1|8|16, // 177 0xb1 + 1|8|16, // 178 0xb2 + 1|8|16, // 179 0xb3 + 1|8|16, // 180 0xb4 + 1|8|16, // 181 0xb5 + 1|8|16, // 182 0xb6 + 1|8|16, // 183 0xb7 + 1|8|16, // 184 0xb8 + 1|8|16, // 185 0xb9 + 1|8|16, // 186 0xba + 1|8|16, // 187 0xbb + 1|8|16, // 188 0xbc + 1|8|16, // 189 0xbd + 1|8|16, // 190 0xbe + 1|8|16, // 191 0xbf + 1|4|8|16, // 192 0xc0 + 1|4|8|16, // 193 0xc1 + 1|4|8|16, // 194 0xc2 + 1|4|8|16, // 195 0xc3 + 1|4|8|16, // 196 0xc4 + 1|4|8|16, // 197 0xc5 + 1|4|8|16, // 198 0xc6 + 1|4|8|16, // 199 0xc7 + 1|4|8|16, // 200 0xc8 + 1|4|8|16, // 201 0xc9 + 1|4|8|16, // 202 0xca + 1|4|8|16, // 203 0xcb + 1|4|8|16, // 204 0xcc + 1|4|8|16, // 205 0xcd + 1|4|8|16, // 206 0xce + 1|4|8|16, // 207 0xcf + 1|4|8|16, // 208 0xd0 + 1|4|8|16, // 209 0xd1 + 1|4|8|16, // 210 0xd2 + 1|4|8|16, // 211 0xd3 + 1|4|8|16, // 212 0xd4 + 1|4|8|16, // 213 0xd5 + 1|4|8|16, // 214 0xd6 + 1|8|16, // 215 0xd7 + 1|4|8|16, // 216 0xd8 + 1|4|8|16, // 217 0xd9 + 1|4|8|16, // 218 0xda + 1|4|8|16, // 219 0xdb + 1|4|8|16, // 220 0xdc + 1|4|8|16, // 221 0xdd + 1|4|8|16, // 222 0xde + 1|4|8|16, // 223 0xdf + 1|4|8|16, // 224 0xe0 + 1|4|8|16, // 225 0xe1 + 1|4|8|16, // 226 0xe2 + 1|4|8|16, // 227 0xe3 + 1|4|8|16, // 228 0xe4 + 1|4|8|16, // 229 0xe5 + 1|4|8|16, // 230 0xe6 + 1|4|8|16, // 231 0xe7 + 1|4|8|16, // 232 0xe8 + 1|4|8|16, // 233 0xe9 + 1|4|8|16, // 234 0xea + 1|4|8|16, // 235 0xeb + 1|4|8|16, // 236 0xec + 1|4|8|16, // 237 0xed + 1|4|8|16, // 238 0xee + 1|4|8|16, // 239 0xef + 1|4|8|16, // 240 0xf0 + 1|4|8|16, // 241 0xf1 + 1|4|8|16, // 242 0xf2 + 1|4|8|16, // 243 0xf3 + 1|4|8|16, // 244 0xf4 + 1|4|8|16, // 245 0xf5 + 1|4|8|16, // 246 0xf6 + 1|8|16, // 247 0xf7 + 1|4|8|16, // 248 0xf8 + 1|4|8|16, // 249 0xf9 + 1|4|8|16, // 250 0xfa + 1|4|8|16, // 251 0xfb + 1|4|8|16, // 252 0xfc + 1|4|8|16, // 253 0xfd + 1|4|8|16, // 254 0xfe + 1|4|8|16 // 255 0xff +}; +#endif // defined(NPT_XML_USE_CHAR_MAP) + +/*---------------------------------------------------------------------- +| macros ++---------------------------------------------------------------------*/ +#if defined (NPT_XML_USE_CHAR_MAP) +#define NPT_XML_CHAR_IS_ANY_CHAR(c) (NPT_XmlCharMap[c] & 1) +#define NPT_XML_CHAR_IS_WHITESPACE(c) (NPT_XmlCharMap[c] & 2) +#define NPT_XML_CHAR_IS_NAME_CHAR(c) (NPT_XmlCharMap[c] & 4) +#define NPT_XML_CHAR_IS_ENTITY_REF_CHAR(c) (NPT_XML_CHAR_IS_NAME_CHAR((c)) || ((c) == '#')) +#define NPT_XML_CHAR_IS_CONTENT_CHAR(c) (NPT_XmlCharMap[c] & 8) +#define NPT_XML_CHAR_IS_VALUE_CHAR(c) (NPT_XmlCharMap[c] & 16) +#else +#define NPT_XML_CHAR_IS_WHITESPACE(c) \ +((c) == ' ' || (c) == '\t' || (c) == 0x0D || (c) == 0x0A) + +#define NPT_XML_CHAR_IS_ANY_CHAR(c) \ +(NPT_XML_CHAR_IS_WHITESPACE((c)) || ((c) >= 0x20)) + +#define NPT_XML_CHAR_IS_DIGIT(c) \ +((c) >= '0' && (c) <= '9') + +#define NPT_XML_CHAR_IS_LETTER(c) \ +(((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z') || ((c) >= 0xC0 && (c) <= 0xD6) || ((c) >= 0xD8 && (c) <= 0xF6) || ((c) >= 0xF8)) + +#define NPT_XML_CHAR_IS_NAME_CHAR(c) \ +(NPT_XML_CHAR_IS_DIGIT((c)) || NPT_XML_CHAR_IS_LETTER((c)) || (c) == '.' || (c) == '-' || (c) == '_' || (c) == ':') + +#define NPT_XML_CHAR_IS_ENTITY_REF_CHAR(c) \ +(NPT_XML_CHAR_IS_NAME_CHAR((c)) || ((c) == '#')) + +#define NPT_XML_CHAR_IS_CONTENT_CHAR(c) \ +(NPT_XML_CHAR_IS_ANY_CHAR((c)) && ((c) != '&') && ((c) != '<')) + +#define NPT_XML_CHAR_IS_VALUE_CHAR(c) \ +(NPT_XML_CHAR_IS_ANY_CHAR((c)) && ((c) != '&') && ((c) != '<')) + +#endif // defined(NPT_XML_USE_CHAR_MAP) + +/*---------------------------------------------------------------------- +| NPT_XmlStringIsWhitespace ++---------------------------------------------------------------------*/ +static bool +NPT_XmlStringIsWhitespace(const char* s, NPT_Size size) +{ + for (NPT_Size x=0; x<size; x++) { + if (!NPT_XML_CHAR_IS_WHITESPACE((int)s[x])) { + return false; + } + } + + return true; +} + +/*---------------------------------------------------------------------- +| NPT_XmlProcessor class ++---------------------------------------------------------------------*/ +class NPT_XmlProcessor { +public: + // constructor and destructor + NPT_XmlProcessor(NPT_XmlParser* parser); + + // methods + NPT_Result ProcessBuffer(const char* buffer, NPT_Size size); + void Reset(); + +private: + // types + typedef enum { + CONTEXT_NONE, + CONTEXT_OPEN_TAG, + CONTEXT_CLOSE_TAG, + CONTEXT_ATTRIBUTE, + CONTEXT_VALUE_SINGLE_QUOTE, + CONTEXT_VALUE_DOUBLE_QUOTE + } Context; + + typedef enum { + STATE_IN_INIT, + STATE_IN_BOM_EF, + STATE_IN_BOM_BB, + STATE_IN_WHITESPACE, + STATE_IN_NAME, + STATE_IN_NAME_SPECIAL, + STATE_IN_VALUE_START, + STATE_IN_VALUE, + STATE_IN_TAG_START, + STATE_IN_EMPTY_TAG_END, + STATE_IN_CONTENT, + STATE_IN_PROCESSING_INSTRUCTION_START, + STATE_IN_PROCESSING_INSTRUCTION, + STATE_IN_PROCESSING_INSTRUCTION_END, + STATE_IN_COMMENT, + STATE_IN_COMMENT_END_1, + STATE_IN_COMMENT_END_2, + STATE_IN_DTD, + STATE_IN_DTD_MARKUP_DECL, + STATE_IN_DTD_MARKUP_DECL_END, + STATE_IN_CDATA, + STATE_IN_CDATA_END_1, + STATE_IN_CDATA_END_2, + STATE_IN_SPECIAL, + STATE_IN_ENTITY_REF + } State; + + // members + NPT_XmlParser* m_Parser; + State m_State; + Context m_Context; + bool m_SkipNewline; + NPT_XmlAccumulator m_Name; + NPT_XmlAccumulator m_Value; + NPT_XmlAccumulator m_Text; + NPT_XmlAccumulator m_Entity; + + // methods +#ifdef NPT_XML_PARSER_DEBUG + const char* StateName(State state) { + switch (state) { + case STATE_IN_INIT: return "IN_INIT"; + case STATE_IN_BOM_EF: return "IN_BOM_EF"; + case STATE_IN_BOM_BB: return "IN_BOM_BB"; + case STATE_IN_WHITESPACE: return "IN_WHITESPACE"; + case STATE_IN_NAME: return "IN_NAME"; + case STATE_IN_NAME_SPECIAL: return "IN_NAME_SPECIAL"; + case STATE_IN_VALUE_START: return "IN_VALUE_START"; + case STATE_IN_VALUE: return "IN_VALUE"; + case STATE_IN_TAG_START: return "IN_TAG_START"; + case STATE_IN_EMPTY_TAG_END: return "IN_EMPTY_TAG_END"; + case STATE_IN_CONTENT: return "IN_CONTENT"; + case STATE_IN_PROCESSING_INSTRUCTION_START: return "IN_PROCESSING_INSTRUCTION_START"; + case STATE_IN_PROCESSING_INSTRUCTION: return "IN_PROCESSING_INSTRUCTION"; + case STATE_IN_PROCESSING_INSTRUCTION_END: return "IN_PROCESSING_INSTRUCTION_END"; + case STATE_IN_COMMENT: return "IN_COMMENT"; + case STATE_IN_COMMENT_END_1: return "IN_COMMENT_END_1"; + case STATE_IN_COMMENT_END_2: return "IN_COMMENT_END_2"; + case STATE_IN_DTD: return "IN_DTD"; + case STATE_IN_DTD_MARKUP_DECL: return "IN_DTD_MARKUP_DECL"; + case STATE_IN_DTD_MARKUP_DECL_END: return "IN_DTD_MARKUP_DECL_END"; + case STATE_IN_CDATA: return "IN_CDATA"; + case STATE_IN_CDATA_END_1: return "IN_CDATA_END_1"; + case STATE_IN_CDATA_END_2: return "IN_CDATA_END_2"; + case STATE_IN_SPECIAL: return "IN_SPECIAL"; + case STATE_IN_ENTITY_REF: return "IN_ENTITY_REF"; + } + return "UNKNOWN"; + } + + const char* ContextName(Context context) { + switch (context) { + case CONTEXT_NONE: return "NONE"; + case CONTEXT_OPEN_TAG: return "OPEN_TAG"; + case CONTEXT_CLOSE_TAG: return "CLOSE_TAG"; + case CONTEXT_ATTRIBUTE: return "ATTRIBUTE"; + case CONTEXT_VALUE_SINGLE_QUOTE: return "VALUE_SINGLE_QUOTE"; + case CONTEXT_VALUE_DOUBLE_QUOTE: return "VALUE_DOUBLE_QUOTE"; + } + return "UNKNOWN"; + } +#endif /* NPT_XML_PARSER_DEBUG */ + + inline void SetState(State state) { + NPT_XML_Debug_3("\nstate transition: %s to %s [ctx=%s]\n", + StateName(m_State), + StateName(state), + ContextName(m_Context)); + m_State = state; + } + + inline void SetState(State state, Context context) { + NPT_XML_Debug_4("\nstate transition: %s [ctx=%s] to %s [ctx=%s]\n", + StateName(m_State), + ContextName(m_Context), + StateName(state), + ContextName(context)); + m_State = state; + m_Context = context; + } + + NPT_Result ResolveEntity(NPT_XmlAccumulator& source, + NPT_XmlAccumulator& destination); + NPT_Result FlushPendingText(); +}; + +/*---------------------------------------------------------------------- +| NPT_XmlProcessor::NPT_XmlProcessor ++---------------------------------------------------------------------*/ +NPT_XmlProcessor::NPT_XmlProcessor(NPT_XmlParser* parser) : + m_Parser(parser), + m_State(STATE_IN_INIT), + m_Context(CONTEXT_NONE), + m_SkipNewline(false) +{ +} + +/*---------------------------------------------------------------------- +| NPT_XmlProcessor::Reset ++---------------------------------------------------------------------*/ +void +NPT_XmlProcessor::Reset() +{ + m_State = STATE_IN_INIT; + m_Context = CONTEXT_NONE; + m_SkipNewline = false; +} + +/*---------------------------------------------------------------------- +| NPT_XmlProcessor::ResolveEntity ++---------------------------------------------------------------------*/ +NPT_Result +NPT_XmlProcessor::ResolveEntity(NPT_XmlAccumulator& source, + NPT_XmlAccumulator& destination) +{ + const char* entity = (const char*)source.GetString(); + + if (NPT_StringsEqual(entity, "lt")) { + destination.Append('<'); + } else if (NPT_StringsEqual(entity, "gt")) { + destination.Append('>'); + } else if (NPT_StringsEqual(entity, "amp")) { + destination.Append('&'); + } else if (NPT_StringsEqual(entity, "quot")) { + destination.Append('"'); + } else if (NPT_StringsEqual(entity, "apos")) { + destination.Append('\''); + } else if (entity[0] == '#') { + int i=1; + int base = 10; + if (entity[1] == 'x') { + i++; + base = 16; + } + int parsed = 0; + while (char c = entity[i++]) { + int digit = -1; + if (c>='0' && c<='9') { + digit = c-'0'; + } else if (base == 16) { + if (c >= 'a' && c <= 'f') { + digit = 10+c-'a'; + } else if (c >= 'A' && c <= 'F') { + digit = 10+c-'A'; + } + } + if (digit == -1) { + // invalid char, leave the entity unparsed + destination.Append(source.GetString()); + return NPT_ERROR_INVALID_SYNTAX; + } + parsed = base*parsed+digit; + } + destination.AppendUTF8(parsed); + } else { + // unknown entity, leave as-is + destination.Append(source.GetString()); + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_XmlProcessor::FlushPendingText ++---------------------------------------------------------------------*/ +NPT_Result +NPT_XmlProcessor::FlushPendingText() +{ + if (m_Text.GetSize() > 0) { + NPT_CHECK(m_Parser->OnCharacterData(m_Text.GetString(), + m_Text.GetSize())); + m_Text.Reset(); + } + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_XmlProcessor::ProcessBuffer ++---------------------------------------------------------------------*/ +NPT_Result +NPT_XmlProcessor::ProcessBuffer(const char* buffer, NPT_Size size) +{ + unsigned char c; + + while (size-- && (c = *buffer++)) { + NPT_XML_Debug_1("[%c]", (c == '\n' || c == '\r') ? '#' : c); + + // normalize line ends + if (m_SkipNewline) { + m_SkipNewline = false; + if (c == '\n') continue; + } + if (c == '\r') { + m_SkipNewline = true; + c = '\n'; + } + + // process the character + switch (m_State) { + case STATE_IN_INIT: + if (NPT_XML_CHAR_IS_WHITESPACE(c)) { + SetState(STATE_IN_WHITESPACE); + break; + } else if (c == '<') { + SetState(STATE_IN_TAG_START); + break; + } else if (c == 0xEF) { + SetState(STATE_IN_BOM_EF); + break; + } + return NPT_ERROR_INVALID_SYNTAX; + + case STATE_IN_BOM_EF: + if (c == 0xBB) { + SetState(STATE_IN_BOM_BB); + break; + } + return NPT_ERROR_INVALID_SYNTAX; + + case STATE_IN_BOM_BB: + if (c == 0xBF) { + SetState(STATE_IN_WHITESPACE); + break; + } + return NPT_ERROR_INVALID_SYNTAX; + + case STATE_IN_WHITESPACE: + if (NPT_XML_CHAR_IS_WHITESPACE(c)) break; + switch (m_Context) { + case CONTEXT_NONE: + if (c == '<') { + SetState(STATE_IN_TAG_START); + } else { + return NPT_ERROR_INVALID_SYNTAX; + } + break; + + case CONTEXT_ATTRIBUTE: + if (c == '/') { + SetState(STATE_IN_EMPTY_TAG_END, CONTEXT_NONE); + } else if (c == '>') { + SetState(STATE_IN_CONTENT, CONTEXT_NONE); + } else if (NPT_XML_CHAR_IS_NAME_CHAR(c)) { + m_Name.Reset(); + m_Name.Append(c); + SetState(STATE_IN_NAME); + } else { + return NPT_ERROR_INVALID_SYNTAX; + } + break; + + case CONTEXT_CLOSE_TAG: + if (c == '>') { + NPT_CHECK(FlushPendingText()); + NPT_CHECK(m_Parser->OnEndElement(m_Name.GetString())); + SetState(STATE_IN_CONTENT, CONTEXT_NONE); + } else { + return NPT_ERROR_INVALID_SYNTAX; + } + break; + + default: + return NPT_ERROR_INVALID_SYNTAX; + } + break; + + case STATE_IN_NAME: + if (NPT_XML_CHAR_IS_NAME_CHAR(c)) { + m_Name.Append(c); + break; + } + switch (m_Context) { + case CONTEXT_ATTRIBUTE: + if (c == '=') { + m_Value.Reset(); + SetState(STATE_IN_VALUE_START); + } else if (!NPT_XML_CHAR_IS_WHITESPACE(c)) { + return NPT_ERROR_INVALID_SYNTAX; + } + break; + + case CONTEXT_OPEN_TAG: + if (c == '>' || c == '/' || NPT_XML_CHAR_IS_WHITESPACE(c)) { + NPT_CHECK(FlushPendingText()); + NPT_CHECK(m_Parser->OnStartElement(m_Name.GetString())); + m_Name.Reset(); + if (c == '>') { + SetState(STATE_IN_CONTENT, CONTEXT_NONE); + } else if (c == '/') { + SetState(STATE_IN_EMPTY_TAG_END); + } else { + SetState(STATE_IN_WHITESPACE, CONTEXT_ATTRIBUTE); + } + } else { + return NPT_ERROR_INVALID_SYNTAX; + } + break; + + case CONTEXT_CLOSE_TAG: + if (c == '>') { + NPT_CHECK(FlushPendingText()); + NPT_CHECK(m_Parser->OnEndElement(m_Name.GetString())); + SetState(STATE_IN_CONTENT, CONTEXT_NONE); + } else if (NPT_XML_CHAR_IS_WHITESPACE(c)) { + SetState(STATE_IN_WHITESPACE); + } else { + return NPT_ERROR_INVALID_SYNTAX; + } + break; + + default: + return NPT_ERROR_INVALID_SYNTAX; + } + break; + + case STATE_IN_NAME_SPECIAL: + if (NPT_XML_CHAR_IS_NAME_CHAR(c) || (c == '[')) { + m_Name.Append(c); + + const unsigned char* nb = m_Name.GetBuffer(); + if (m_Name.GetSize() == 2) { + if (nb[0] == '-' && + nb[1] == '-') { + m_Name.Reset(); + SetState(STATE_IN_COMMENT, CONTEXT_NONE); + break; + } + } else if (m_Name.GetSize() == 7) { + if (nb[0] == '[' && + nb[1] == 'C' && + nb[2] == 'D' && + nb[3] == 'A' && + nb[4] == 'T' && + nb[5] == 'A' && + nb[6] == '[') { + m_Name.Reset(); + SetState(STATE_IN_CDATA, CONTEXT_NONE); + break; + } + } + break; + } + if (NPT_XML_CHAR_IS_WHITESPACE(c)) { + const char* special = m_Name.GetString(); + if (special && NPT_StringsEqual(special, "DOCTYPE")) { + SetState(STATE_IN_DTD, CONTEXT_NONE); + } else { + SetState(STATE_IN_SPECIAL, CONTEXT_NONE); + } + m_Name.Reset(); + } else { + return NPT_ERROR_INVALID_SYNTAX; + } + break; + + case STATE_IN_VALUE_START: + if (NPT_XML_CHAR_IS_WHITESPACE(c)) break; + if (c == '"') { + m_Value.Reset(); + SetState(STATE_IN_VALUE, CONTEXT_VALUE_DOUBLE_QUOTE); + } else if (c == '\'') { + m_Value.Reset(); + SetState(STATE_IN_VALUE, CONTEXT_VALUE_SINGLE_QUOTE); + } else { + return NPT_ERROR_INVALID_SYNTAX; + } + break; + + case STATE_IN_VALUE: + if ((c == '"' && m_Context == CONTEXT_VALUE_DOUBLE_QUOTE) || + (c == '\'' && m_Context == CONTEXT_VALUE_SINGLE_QUOTE)) { + NPT_CHECK(m_Parser->OnElementAttribute(m_Name.GetString(), + m_Value.GetString())); + SetState(STATE_IN_WHITESPACE, CONTEXT_ATTRIBUTE); + } else if (c == '&') { + m_Entity.Reset(); + SetState(STATE_IN_ENTITY_REF); + } else if (NPT_XML_CHAR_IS_WHITESPACE(c)) { + m_Value.Append(' '); + } else if (NPT_XML_CHAR_IS_VALUE_CHAR(c)) { + m_Value.Append(c); + } else { + return NPT_ERROR_INVALID_SYNTAX; + } + break; + + case STATE_IN_TAG_START: + m_Name.Reset(); + if (c == '!') { + SetState(STATE_IN_NAME_SPECIAL, CONTEXT_NONE); + } else if (c == '?') { + SetState(STATE_IN_PROCESSING_INSTRUCTION, CONTEXT_NONE); + } else if (c == '/') { + SetState(STATE_IN_NAME, CONTEXT_CLOSE_TAG); + } else if (NPT_XML_CHAR_IS_NAME_CHAR(c)) { + m_Name.Append(c); + SetState(STATE_IN_NAME, CONTEXT_OPEN_TAG); + } else { + return NPT_ERROR_INVALID_SYNTAX; + } + break; + + case STATE_IN_EMPTY_TAG_END: + if (c == '>') { + NPT_CHECK(FlushPendingText()); + NPT_CHECK(m_Parser->OnEndElement(NULL)); + SetState(STATE_IN_CONTENT, CONTEXT_NONE); + } else { + return NPT_ERROR_INVALID_SYNTAX; + } + break; + + case STATE_IN_ENTITY_REF: + switch (m_Context) { + case CONTEXT_VALUE_SINGLE_QUOTE: + case CONTEXT_VALUE_DOUBLE_QUOTE: + if (c == ';') { + NPT_CHECK(ResolveEntity(m_Entity, m_Value)); + SetState(STATE_IN_VALUE); + } else if (NPT_XML_CHAR_IS_ENTITY_REF_CHAR(c)) { + m_Entity.Append(c); + } else { + return NPT_ERROR_INVALID_SYNTAX; + } + break; + + case CONTEXT_NONE: + if (c == ';') { + NPT_CHECK(ResolveEntity(m_Entity, m_Text)); + SetState(STATE_IN_CONTENT); + } else if (NPT_XML_CHAR_IS_ENTITY_REF_CHAR(c)) { + m_Entity.Append(c); + } else { + return NPT_ERROR_INVALID_SYNTAX; + } + break; + + default: + return NPT_ERROR_INVALID_SYNTAX; + } + break; + + case STATE_IN_COMMENT: + if (c == '-') { + SetState(STATE_IN_COMMENT_END_1); + } else if (!NPT_XML_CHAR_IS_ANY_CHAR(c)) { + return NPT_ERROR_INVALID_SYNTAX; + } + break; + + case STATE_IN_COMMENT_END_1: + if (c == '-') { + SetState(STATE_IN_COMMENT_END_2); + } else if (NPT_XML_CHAR_IS_ANY_CHAR(c)) { + SetState(STATE_IN_COMMENT); + } else { + return NPT_ERROR_INVALID_SYNTAX; + } + break; + + case STATE_IN_COMMENT_END_2: + if (c == '>') { + SetState(STATE_IN_CONTENT, CONTEXT_NONE); + } else { + return NPT_ERROR_INVALID_SYNTAX; + } + break; + + case STATE_IN_CONTENT: + if (c == '<') { + SetState(STATE_IN_TAG_START, CONTEXT_NONE); + } else if (c == '&') { + m_Entity.Reset(); + SetState(STATE_IN_ENTITY_REF); + } else { + m_Text.Append(c); + } + break; + + case STATE_IN_PROCESSING_INSTRUCTION_START: + break; + + case STATE_IN_PROCESSING_INSTRUCTION_END: + if (c == '>') { + SetState(STATE_IN_WHITESPACE, CONTEXT_NONE); + } else { + return NPT_ERROR_INVALID_SYNTAX; + } + break; + + case STATE_IN_PROCESSING_INSTRUCTION: + if (c == '?') { + SetState(STATE_IN_PROCESSING_INSTRUCTION_END); + } + break; + + case STATE_IN_DTD: + if (NPT_XML_CHAR_IS_WHITESPACE(c)) break; + if (c == '[') { + SetState(STATE_IN_DTD_MARKUP_DECL); + } else if (c == '>') { + SetState(STATE_IN_WHITESPACE, CONTEXT_NONE); + } + break; + + case STATE_IN_DTD_MARKUP_DECL: + if (c == ']') { + SetState(STATE_IN_DTD_MARKUP_DECL_END); + } + break; + + case STATE_IN_DTD_MARKUP_DECL_END: + if (c == '>') { + SetState(STATE_IN_WHITESPACE, CONTEXT_NONE); + } else if (!NPT_XML_CHAR_IS_WHITESPACE(c)) { + return NPT_ERROR_INVALID_SYNTAX; + } + break; + + case STATE_IN_CDATA: + if (c == ']') { + SetState(STATE_IN_CDATA_END_1); + } else { + m_Text.Append(c); + } + break; + + case STATE_IN_CDATA_END_1: + if (c == ']') { + SetState(STATE_IN_CDATA_END_2); + } else { + m_Text.Append(']'); + m_Text.Append(c); + SetState(STATE_IN_CDATA); + } + break; + + case STATE_IN_CDATA_END_2: + if (c == '>') { + SetState(STATE_IN_CONTENT, CONTEXT_NONE); + } else { + m_Text.Append("]]"); + m_Text.Append(c); + SetState(STATE_IN_CDATA); + } + break; + + case STATE_IN_SPECIAL: + if (c == '>') { + SetState(STATE_IN_WHITESPACE, CONTEXT_NONE); + } + break; + } + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_XmlParser::NPT_XmlParser ++---------------------------------------------------------------------*/ +NPT_XmlParser::NPT_XmlParser(bool keep_whitespace /* = false */) : + m_Root(NULL), + m_CurrentElement(NULL), + m_KeepWhitespace(keep_whitespace) +{ + m_Processor = new NPT_XmlProcessor(this); +} + +/*---------------------------------------------------------------------- +| NPT_XmlParser::~NPT_XmlParser ++---------------------------------------------------------------------*/ +NPT_XmlParser::~NPT_XmlParser() +{ + Reset(); + delete m_CurrentElement; + delete m_Processor; +} + +/*---------------------------------------------------------------------- +| NPT_XmlParser::Reset ++---------------------------------------------------------------------*/ +void +NPT_XmlParser::Reset() +{ + // delete anything that has been created + NPT_XmlNode* walker = m_CurrentElement; + while (walker && walker->GetParent()) { + walker = walker->GetParent(); + } + delete walker; + m_CurrentElement = NULL; + + m_Processor->Reset(); + + m_Root = NULL; +} + +/*---------------------------------------------------------------------- +| NPT_XmlParser::Parse ++---------------------------------------------------------------------*/ +NPT_Result +NPT_XmlParser::Parse(NPT_InputStream& stream, + NPT_Size& size, + NPT_XmlNode*& node, + bool incremental /* = false */) +{ + NPT_Result result; + + // start with a known state + m_Root = NULL; + node = NULL; + if (!incremental) { + Reset(); + } + + // use a buffer on the stack + char buffer[1024]; + + // read a buffer and parse it until the end of the stream + NPT_Size max_bytes_to_read = size; + size = 0; + do { + NPT_Size bytes_read; + NPT_Size bytes_to_read = sizeof(buffer); + if (max_bytes_to_read != 0 && + size+bytes_to_read > max_bytes_to_read) { + bytes_to_read = max_bytes_to_read-size; + } + result = stream.Read(buffer, bytes_to_read, &bytes_read); + if (NPT_SUCCEEDED(result)) { + // update the counter + size += bytes_read; + + // parse the buffer + result = m_Processor->ProcessBuffer(buffer, bytes_read); + if (NPT_FAILED(result)) break; + } else { + break; + } + } while(NPT_SUCCEEDED(result) && + (max_bytes_to_read == 0 || size < max_bytes_to_read)); + + // return a tree if we have one + node = m_Root; + if (incremental) { + return result; + } else { + if (NPT_FAILED(result) && result != NPT_ERROR_EOS) { + delete m_Root; + m_Root = NULL; + node = NULL; + return result; + } else { + return m_Root?NPT_SUCCESS:NPT_ERROR_XML_NO_ROOT; + } + } +} + +/*---------------------------------------------------------------------- +| NPT_XmlParser::Parse ++---------------------------------------------------------------------*/ +NPT_Result +NPT_XmlParser::Parse(NPT_InputStream& stream, + NPT_XmlNode*& node, + bool incremental /* = false */) +{ + NPT_Size max_read = 0; // no limit + return Parse(stream, max_read, node, incremental); +} + +/*---------------------------------------------------------------------- +| NPT_XmlParser::Parse ++---------------------------------------------------------------------*/ +NPT_Result +NPT_XmlParser::Parse(const char* xml, + NPT_XmlNode*& node, + bool incremental /* = false */) +{ + NPT_Size size = NPT_StringLength(xml); + + return Parse(xml, size, node, incremental); +} + +/*---------------------------------------------------------------------- +| NPT_XmlParser::Parse ++---------------------------------------------------------------------*/ +NPT_Result +NPT_XmlParser::Parse(const char* xml, + NPT_Size size, + NPT_XmlNode*& node, + bool incremental /* = false */) +{ + // start with a known state + m_Root = NULL; + node = NULL; + if (!incremental) { + Reset(); + } + + // parse the buffer + NPT_Result result = m_Processor->ProcessBuffer(xml, size); + + // return a tree if we have one + node = m_Root; + if (incremental) { + return result; + } else { + if (NPT_FAILED(result)) { + delete m_Root; + m_Root = NULL; + node = NULL; + return result; + } else { + return m_Root?NPT_SUCCESS:NPT_ERROR_XML_NO_ROOT; + } + } +} + +/*---------------------------------------------------------------------- +| NPT_XmlParser::OnStartElement ++---------------------------------------------------------------------*/ +NPT_Result +NPT_XmlParser::OnStartElement(const char* name) +{ + NPT_XML_Debug_1("\nNPT_XmlParser::OnStartElement: %s\n", name); + + // we cannot start an element if we already have a root + if (m_Root) { + return NPT_ERROR_XML_MULTIPLE_ROOTS; + } + + // create new node + NPT_XmlElementNode* node = new NPT_XmlElementNode(name); + + // add node to tree + if (m_CurrentElement) { + // add the new node + m_CurrentElement->AddChild(node); + } + m_CurrentElement = node; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_XmlParser::OnElementAttribute ++---------------------------------------------------------------------*/ +NPT_Result +NPT_XmlParser::OnElementAttribute(const char* name, const char* value) +{ + NPT_XML_Debug_2("\nNPT_XmlParser::OnElementAttribute: name=%s, value='%s'\n", + name, value); + + if (m_CurrentElement == NULL) { + return NPT_ERROR_INVALID_SYNTAX; + } + + // check if this is a namespace attribute + if (name[0] == 'x' && + name[1] == 'm' && + name[2] == 'l' && + name[3] == 'n' && + name[4] == 's' && + (name[5] == '\0' || name[5] == ':')) { + // namespace definition + m_CurrentElement->SetNamespaceUri((name[5] == ':')?name+6:"", value); + } else { + m_CurrentElement->AddAttribute(name, value); + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_XmlParser::OnEndElement ++---------------------------------------------------------------------*/ +NPT_Result +NPT_XmlParser::OnEndElement(const char* name) +{ + NPT_XML_Debug_1("\nNPT_XmlParser::OnEndElement: %s\n", name ? name : "NULL"); + + if (m_CurrentElement == NULL) return NPT_ERROR_XML_TAG_MISMATCH; + + // check that the name matches (if there is a name) + if (name) { + const char* prefix = name; + unsigned int prefix_length = 0; + const char* tag = name; + const char* cursor = name; + while (char c = *cursor++) { + if (c == ':') { + prefix_length = (unsigned int)(cursor-name)-1; + tag = cursor; + } + } + // check that the name and prefix length match + if (m_CurrentElement->GetTag() != tag || + m_CurrentElement->GetPrefix().GetLength() != prefix_length) { + return NPT_ERROR_XML_TAG_MISMATCH; + } + + // check the prefix + const char* current_prefix = m_CurrentElement->GetPrefix().GetChars(); + for (unsigned int i=0; i<prefix_length; i++) { + if (current_prefix[i] != prefix[i]) { + return NPT_ERROR_XML_TAG_MISMATCH; + } + } + } + + // pop up the stack + NPT_XmlNode* parent = m_CurrentElement->GetParent(); + if (parent) { + m_CurrentElement = parent->AsElementNode(); + } else { + if (m_Root) { + // this should never happen + delete m_CurrentElement; + m_CurrentElement = NULL; + return NPT_ERROR_XML_MULTIPLE_ROOTS; + } else { + m_Root = m_CurrentElement; + m_CurrentElement = NULL; + } + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_XmlParser::OnCharacterData ++---------------------------------------------------------------------*/ +NPT_Result +NPT_XmlParser::OnCharacterData(const char* data, NPT_Size size) +{ + NPT_XML_Debug_1("\nNPT_XmlParser::OnCharacterData: %s\n", data); + + // check that we have a current element + if (m_CurrentElement == NULL) { + // we do not allow non-whitespace outside an element content + if (!NPT_XmlStringIsWhitespace(data, size)) { + return NPT_ERROR_XML_INVALID_NESTING; + } + + // ignore whitespace + return NPT_SUCCESS; + } + + // ignore whitespace if applicable + if (m_KeepWhitespace || !NPT_XmlStringIsWhitespace(data, size)) { + // add the text to the current element + m_CurrentElement->AddText(data); + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_XmlAttributeWriter ++---------------------------------------------------------------------*/ +class NPT_XmlAttributeWriter +{ +public: + NPT_XmlAttributeWriter(NPT_XmlSerializer& serializer) : m_Serializer(serializer) {} + void operator()(NPT_XmlAttribute*& attribute) const { + m_Serializer.Attribute(attribute->GetPrefix(), + attribute->GetName(), + attribute->GetValue()); + } + +private: + // members + NPT_XmlSerializer& m_Serializer; +}; + +/*---------------------------------------------------------------------- +| NPT_XmlNodeWriter ++---------------------------------------------------------------------*/ +class NPT_XmlNodeWriter +{ +public: + NPT_XmlNodeWriter(NPT_XmlSerializer& serializer) : + m_Serializer(serializer), m_AttributeWriter(serializer) { + m_Serializer.StartDocument(); + } + void operator()(NPT_XmlNode*& node) const { + if (NPT_XmlElementNode* element = node->AsElementNode()) { + const NPT_String& prefix = element->GetPrefix(); + const NPT_String& tag = element->GetTag(); + m_Serializer.StartElement(prefix, tag); + element->GetAttributes().Apply(m_AttributeWriter); + + // emit namespace attributes + if (element->m_NamespaceMap) { + NPT_List<NPT_XmlNamespaceMap::Entry*>::Iterator item = + element->m_NamespaceMap->m_Entries.GetFirstItem(); + while (item) { + if ((*item)->m_Prefix.IsEmpty()) { + // default namespace + m_Serializer.Attribute(NULL, "xmlns", (*item)->m_Uri); + } else { + // namespace with prefix + m_Serializer.Attribute("xmlns", (*item)->m_Prefix, (*item)->m_Uri); + } + ++item; + } + } + + element->GetChildren().Apply(*this); + m_Serializer.EndElement(prefix, tag); + } else if (NPT_XmlTextNode* text = node->AsTextNode()) { + m_Serializer.Text(text->GetString()); + } + } + +private: + // members + NPT_XmlSerializer& m_Serializer; + NPT_XmlAttributeWriter m_AttributeWriter; +}; + +/*---------------------------------------------------------------------- +| NPT_XmlNodeCanonicalWriter ++---------------------------------------------------------------------*/ +class NPT_XmlNodeCanonicalWriter +{ +public: + // types + struct MapChainLink { + MapChainLink(MapChainLink* parent) : m_Parent(parent) {} + MapChainLink* m_Parent; + NPT_Map<NPT_String, NPT_String> m_RenderedNamespaces; + }; + + // constructor + NPT_XmlNodeCanonicalWriter(NPT_XmlSerializer& serializer, + MapChainLink* map_chain = NULL) : + m_MapChain(map_chain), + m_Serializer(serializer) { + m_Serializer.StartDocument(); + } + void operator()(NPT_XmlNode*& node) const; + +private: + // types + struct SortedAttributeList { + // types + struct Entry { + const NPT_String* m_NamespaceUri; + const NPT_XmlAttribute* m_Attribute; + }; + + // methods + void Add(const NPT_String* namespace_uri, + const NPT_XmlAttribute* attribute); + void Emit(NPT_XmlSerializer& serializer); + + // members + NPT_List<Entry> m_Entries; + }; + + struct SortedNamespaceList { + // types + struct Entry { + const NPT_String* m_NamespacePrefix; + const NPT_String* m_NamespaceUri; + }; + + // methods + void Add(const NPT_String* prefix, const NPT_String* uri); + void Emit(NPT_XmlSerializer& serializer); + + // members + NPT_List<Entry> m_Entries; + }; + + // methods + const NPT_String* GetNamespaceRenderedForPrefix(const NPT_String& prefix) const; + + // members + MapChainLink* m_MapChain; + NPT_XmlSerializer& m_Serializer; +}; + +/*---------------------------------------------------------------------- +| NPT_XmlNodeCanonicalWriter::SortedAttributeList::Add ++---------------------------------------------------------------------*/ +void +NPT_XmlNodeCanonicalWriter::SortedAttributeList::Add( + const NPT_String* namespace_uri, + const NPT_XmlAttribute* attribute) +{ + // transform empty strings into NULL pointers + if (namespace_uri && namespace_uri->IsEmpty()) namespace_uri = NULL; + + // find the namespace insertion position + NPT_List<Entry>::Iterator entry = m_Entries.GetFirstItem(); + for (; entry; ++entry) { + // decide if we insert now or move on + const NPT_String* other_namespace_uri = entry->m_NamespaceUri; + if (namespace_uri && + (other_namespace_uri == NULL || *namespace_uri > *other_namespace_uri)) { + // this namespace uri is greater than the other, skip + continue; + } else if ((namespace_uri == NULL && other_namespace_uri == NULL) || + (namespace_uri && other_namespace_uri && + *namespace_uri == *other_namespace_uri)) { + // namespace uris match, compare the names + const NPT_XmlAttribute* other_attribute = entry->m_Attribute; + if (attribute->GetName() > other_attribute->GetName()) continue; + } + break; + } + + Entry new_entry = {namespace_uri, attribute}; + m_Entries.Insert(entry, new_entry); +} + +/*---------------------------------------------------------------------- +| NPT_XmlNodeCanonicalWriter::SortedAttributeList::Emit ++---------------------------------------------------------------------*/ +void +NPT_XmlNodeCanonicalWriter::SortedAttributeList::Emit(NPT_XmlSerializer& serializer) +{ + for (NPT_List<Entry>::Iterator i = m_Entries.GetFirstItem(); i; ++i) { + serializer.Attribute(i->m_Attribute->GetPrefix(), + i->m_Attribute->GetName(), + i->m_Attribute->GetValue()); + } +} + +/*---------------------------------------------------------------------- +| NPT_XmlNodeCanonicalWriter::SortedNamespaceList::Add ++---------------------------------------------------------------------*/ +void +NPT_XmlNodeCanonicalWriter::SortedNamespaceList::Add(const NPT_String* prefix, + const NPT_String* uri) +{ + // find the namespace insertion position + NPT_List<Entry>::Iterator entry = m_Entries.GetFirstItem(); + if (prefix && !prefix->IsEmpty()) { + for (; entry; ++entry) { + // decide if we insert now or move on + if (entry->m_NamespacePrefix && *prefix <= *entry->m_NamespacePrefix) { + break; + } + } + } else { + prefix = NULL; + } + + Entry new_entry = {prefix, uri}; + m_Entries.Insert(entry, new_entry); +} + +/*---------------------------------------------------------------------- +| NPT_XmlNodeCanonicalWriter::SortedNamespaceList::Emit ++---------------------------------------------------------------------*/ +void +NPT_XmlNodeCanonicalWriter::SortedNamespaceList::Emit(NPT_XmlSerializer& serializer) +{ + for (NPT_List<Entry>::Iterator i = m_Entries.GetFirstItem(); i; ++i) { + const NPT_String* key = i->m_NamespacePrefix; + const NPT_String* value = i->m_NamespaceUri; + if (key == NULL) { + serializer.Attribute(NULL, "xmlns", *value); + } else if (*key != "xml" || *value != NPT_XmlNamespaceUri_Xml) { + serializer.Attribute("xmlns", *key, *value); + } + } +} + +/*---------------------------------------------------------------------- +| NPT_XmlNodeCanonicalWriter::GetNamespaceRenderedForPrefix ++---------------------------------------------------------------------*/ +const NPT_String* +NPT_XmlNodeCanonicalWriter::GetNamespaceRenderedForPrefix(const NPT_String& prefix) const +{ + for (MapChainLink* link = m_MapChain; + link; + link = link->m_Parent) { + NPT_String* uri; + if (NPT_SUCCEEDED(link->m_RenderedNamespaces.Get(prefix, uri))) { + return uri; + } + } + + return NULL; +} + +/*---------------------------------------------------------------------- +| NPT_XmlNodeCanonicalWriter::operator() ++---------------------------------------------------------------------*/ +void +NPT_XmlNodeCanonicalWriter::operator()(NPT_XmlNode*& node) const +{ + MapChainLink map_link(m_MapChain); + + if (NPT_XmlElementNode* element = node->AsElementNode()) { + const NPT_String& prefix = element->GetPrefix(); + const NPT_String& tag = element->GetTag(); + + // process namespaces + const NPT_String* namespace_uri = element->GetNamespace(); + const NPT_String* rendered = GetNamespaceRenderedForPrefix(prefix); + if (namespace_uri && namespace_uri->IsEmpty()) namespace_uri = NULL; + if (prefix.IsEmpty()) { + // default namespace + if (rendered == NULL) { + // default namespace not rendered + if (namespace_uri) { + map_link.m_RenderedNamespaces.Put("", *namespace_uri); + } + } else { + // default namespace already rendered + const char* compare; + if (namespace_uri) { + compare = namespace_uri->GetChars(); + } else { + compare = ""; + } + if (*rendered != compare) { + // the rendered default namespace had a different uri + map_link.m_RenderedNamespaces.Put("", compare); + } + } + } else { + // explicit namespace + // NOTE: namespace_uri should not be an empty string, but we test just + // in case the XML document is not compliant + if (namespace_uri && (rendered == NULL || *rendered != *namespace_uri)) { + // namespace prefix not rendered or rendered with a different value + map_link.m_RenderedNamespaces.Put(prefix, *namespace_uri); + } + } + + // process attributes + SortedAttributeList prefixed_attributes; + SortedAttributeList naked_attributes; + for (NPT_List<NPT_XmlAttribute*>::Iterator attribute = element->GetAttributes().GetFirstItem(); + attribute; + ++attribute) { + const NPT_String& a_prefix = (*attribute)->GetPrefix(); + if (a_prefix.IsEmpty()) { + // naked attribute + naked_attributes.Add(NULL, *attribute); + } else { + // decide if we need to render this namespace declaration + namespace_uri = element->GetNamespaceUri(a_prefix); + if (namespace_uri) { + rendered = GetNamespaceRenderedForPrefix(a_prefix);; + if (rendered == NULL || *rendered != *namespace_uri) { + // namespace not rendered or rendered with a different value + map_link.m_RenderedNamespaces.Put(a_prefix, *namespace_uri); + } + prefixed_attributes.Add(namespace_uri, *attribute); + } + } + } + + // start of element + m_Serializer.StartElement(prefix, tag); + + // namespace declarations + if (map_link.m_RenderedNamespaces.GetEntryCount()) { + SortedNamespaceList namespaces; + NPT_List<NPT_Map<NPT_String, NPT_String>::Entry*>::Iterator entry = + map_link.m_RenderedNamespaces.GetEntries().GetFirstItem(); + while (entry) { + const NPT_String& key = (*entry)->GetKey(); + const NPT_String& value = (*entry)->GetValue(); + namespaces.Add(&key, &value); + ++entry; + } + namespaces.Emit(m_Serializer); + } + + // attributes + naked_attributes.Emit(m_Serializer); + prefixed_attributes.Emit(m_Serializer); + + // children + MapChainLink* chain; + if (map_link.m_RenderedNamespaces.GetEntryCount()) { + chain = &map_link; + } else { + chain = m_MapChain; + } + element->GetChildren().Apply(NPT_XmlNodeCanonicalWriter(m_Serializer, chain)); + + // end of element + m_Serializer.EndElement(prefix, tag); + } else if (NPT_XmlTextNode* text = node->AsTextNode()) { + m_Serializer.Text(text->GetString()); + } +} + +/*---------------------------------------------------------------------- +| NPT_XmlSerializer::NPT_XmlSerializer ++---------------------------------------------------------------------*/ +NPT_XmlSerializer::NPT_XmlSerializer(NPT_OutputStream* output, + NPT_Cardinal indentation, + bool shrink_empty_elements, + bool add_xml_decl) : + m_Output(output), + m_ElementPending(false), + m_Depth(0), + m_Indentation(indentation), + m_ElementHasText(false), + m_ShrinkEmptyElements(shrink_empty_elements), + m_AddXmlDecl(add_xml_decl) +{ +} + +/*---------------------------------------------------------------------- +| NPT_XmlSerializer::~NPT_XmlSerializer ++---------------------------------------------------------------------*/ +NPT_XmlSerializer::~NPT_XmlSerializer() +{ +} + +/*---------------------------------------------------------------------- +| NPT_XmlSerializer::StartDocument ++---------------------------------------------------------------------*/ +NPT_Result +NPT_XmlSerializer::StartDocument() +{ + if (!m_AddXmlDecl) return NPT_SUCCESS; + + return m_Output->WriteString("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"); +} + +/*---------------------------------------------------------------------- +| NPT_XmlSerializer::EndDocument ++---------------------------------------------------------------------*/ +NPT_Result +NPT_XmlSerializer::EndDocument() +{ + return m_ElementPending?NPT_ERROR_INVALID_STATE:NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_XmlSerializer::EscapeChar ++---------------------------------------------------------------------*/ +void +NPT_XmlSerializer::EscapeChar(unsigned char c, char* text) +{ + *text++ = '&'; + *text++ = '#'; + *text++ = 'x'; + int c0 = c>>4; + int c1 = c&0xF; + if (c0) { + *text++ = c0 >= 10 ? 'A'+(c0-10) : '0'+c0; + } + *text++ = c1 >= 10 ? 'A'+(c1-10) : '0'+c1; + *text++ = ';'; + *text = '\0'; +} + +/*---------------------------------------------------------------------- +| NPT_XmlSerializer::ProcessPending ++---------------------------------------------------------------------*/ +NPT_Result +NPT_XmlSerializer::ProcessPending() +{ + if (!m_ElementPending) return NPT_SUCCESS; + m_ElementPending = false; + return m_Output->Write(">", 1); +} + +/*---------------------------------------------------------------------- +| NPT_XmlSerializer::OutputEscapedString ++---------------------------------------------------------------------*/ +NPT_Result +NPT_XmlSerializer::OutputEscapedString(const char* text, bool attribute) +{ + const char* start = text; + char escaped[7]; + while (char c = *text) { + const char* insert = NULL; + switch (c) { + case '\r': { + EscapeChar(c, escaped); + insert = escaped; + break; + } + case '\n': + case '\t': + if (attribute) { + EscapeChar(c, escaped); + insert = escaped; + } + break; + + case '&' : insert = "&"; break; + case '<' : insert = "<"; break; + case '>' : if (!attribute) insert = ">"; break; + case '"' : if (attribute) insert = """; break; + default : + break; + } + if (insert) { + // output pending chars + if (start != text) m_Output->WriteFully(start, (NPT_Size)(text-start)); + m_Output->WriteString(insert); + start = ++text; + } else { + ++text; + } + } + if (start != text) { + m_Output->WriteFully(start, (NPT_Size)(text-start)); + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_XmlSerializer::OutputIndentation ++---------------------------------------------------------------------*/ +void +NPT_XmlSerializer::OutputIndentation(bool start) +{ + if (m_Depth || !start) m_Output->Write("\r\n", 2); + + // ensure we have enough chars in the prefix string + unsigned int prefix_length = m_Indentation*m_Depth; + if (m_IndentationPrefix.GetLength() < prefix_length) { + unsigned int needed = prefix_length-m_IndentationPrefix.GetLength(); + for (unsigned int i=0; i<needed; i+=16) { + m_IndentationPrefix.Append(" ", 16); + } + } + + // print the indentation prefix + m_Output->WriteFully(m_IndentationPrefix.GetChars(), prefix_length); +} + +/*---------------------------------------------------------------------- +| NPT_XmlSerializer::StartElement ++---------------------------------------------------------------------*/ +NPT_Result +NPT_XmlSerializer::StartElement(const char* prefix, const char* name) +{ + ProcessPending(); + if (m_Indentation) OutputIndentation(true); + m_ElementPending = true; + m_ElementHasText = false; + m_Depth++; + m_Output->Write("<", 1); + if (prefix && prefix[0]) { + m_Output->WriteString(prefix); + m_Output->Write(":", 1); + } + return m_Output->WriteString(name); +} + +/*---------------------------------------------------------------------- +| NPT_XmlSerializer::EndElement ++---------------------------------------------------------------------*/ +NPT_Result +NPT_XmlSerializer::EndElement(const char* prefix, const char* name) +{ + m_Depth--; + + if (m_ElementPending) { + // this element has no children + m_ElementPending = false; + if (m_ShrinkEmptyElements) { + return m_Output->WriteFully("/>", 2); + } else { + m_Output->Write(">",1); + } + } + + if (m_Indentation && !m_ElementHasText) OutputIndentation(false); + m_ElementHasText = false; + m_Output->WriteFully("</", 2); + if (prefix && prefix[0]) { + m_Output->WriteString(prefix); + m_Output->Write(":", 1); + } + m_Output->WriteString(name); + return m_Output->Write(">", 1); +} + +/*---------------------------------------------------------------------- +| NPT_XmlSerializer::Attribute ++---------------------------------------------------------------------*/ +NPT_Result +NPT_XmlSerializer::Attribute(const char* prefix, const char* name, const char* value) +{ + m_Output->Write(" ", 1); + if (prefix && prefix[0]) { + m_Output->WriteString(prefix); + m_Output->Write(":", 1); + } + m_Output->WriteString(name); + m_Output->WriteFully("=\"", 2); + OutputEscapedString(value, true); + return m_Output->Write("\"", 1); +} + +/*---------------------------------------------------------------------- +| NPT_XmlSerializer::Text ++---------------------------------------------------------------------*/ +NPT_Result +NPT_XmlSerializer::Text(const char* text) +{ + ProcessPending(); + m_ElementHasText = true; + return OutputEscapedString(text, false); +} + +/*---------------------------------------------------------------------- +| NPT_XmlSerializer::CdataSection ++---------------------------------------------------------------------*/ +NPT_Result +NPT_XmlSerializer::CdataSection(const char* data) +{ + ProcessPending(); + m_ElementHasText = true; + m_Output->WriteFully("<![CDATA[", 9); + m_Output->WriteString(data); + return m_Output->WriteFully("]]>", 3); +} + +/*---------------------------------------------------------------------- +| NPT_XmlSerializer::Comment ++---------------------------------------------------------------------*/ +NPT_Result +NPT_XmlSerializer::Comment(const char* comment) +{ + ProcessPending(); + m_Output->WriteFully("<!--", 4); + m_Output->WriteString(comment); + return m_Output->WriteFully("-->", 3); +} + +/*---------------------------------------------------------------------- +| NPT_XmlWriter::Serialize ++---------------------------------------------------------------------*/ +NPT_Result +NPT_XmlWriter::Serialize(NPT_XmlNode& node, + NPT_OutputStream& output, + bool add_xml_decl) +{ + NPT_XmlSerializer serializer(&output, m_Indentation, true, add_xml_decl); + NPT_XmlNodeWriter node_writer(serializer); + NPT_XmlNode* node_pointer = &node; + node_writer(node_pointer); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_XmlCanonicalizer::Serialize ++---------------------------------------------------------------------*/ +NPT_Result +NPT_XmlCanonicalizer::Serialize(NPT_XmlNode& node, + NPT_OutputStream& output, + bool add_xml_decl) +{ + // create a serializer with no indentation and no shrinking of empty elements + NPT_XmlSerializer serializer(&output, 0, false, add_xml_decl); + + // serialize the node + NPT_XmlNodeCanonicalWriter node_writer(serializer); + NPT_XmlNode* node_pointer = &node; + node_writer(node_pointer); + + return NPT_SUCCESS; +} diff --git a/lib/libUPnP/Neptune/Source/Core/NptXml.h b/lib/libUPnP/Neptune/Source/Core/NptXml.h new file mode 100644 index 0000000..cd06a88 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptXml.h @@ -0,0 +1,391 @@ +/***************************************************************** +| +| Neptune - Xml Support +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +#ifndef _NPT_XML_H_ +#define _NPT_XML_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptTypes.h" +#include "NptList.h" +#include "NptStrings.h" +#include "NptStreams.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const int NPT_ERROR_XML_INVALID_NESTING = NPT_ERROR_BASE_XML - 0; +const int NPT_ERROR_XML_TAG_MISMATCH = NPT_ERROR_BASE_XML - 1; +const int NPT_ERROR_XML_NO_ROOT = NPT_ERROR_BASE_XML - 2; +const int NPT_ERROR_XML_MULTIPLE_ROOTS = NPT_ERROR_BASE_XML - 3; + +#define NPT_XML_ANY_NAMESPACE "*" +#define NPT_XML_NO_NAMESPACE NULL + +/*---------------------------------------------------------------------- +| forward declarations ++---------------------------------------------------------------------*/ +class NPT_XmlProcessor; + +/*---------------------------------------------------------------------- +| NPT_XmlAttribute ++---------------------------------------------------------------------*/ +class NPT_XmlAttribute +{ + public: + // methods + NPT_XmlAttribute(const char* name, const char* value); + NPT_XmlAttribute(const char* prefix, const char* name, const char* value) : + m_Prefix(prefix), m_Name(name), m_Value(value) {} + const NPT_String& GetPrefix() const { return m_Prefix; } + const NPT_String& GetName() const { return m_Name; } + const NPT_String& GetValue() const { return m_Value; } + void SetValue(const char* value) { m_Value = value; } + + private: + // members + NPT_String m_Prefix; + NPT_String m_Name; + NPT_String m_Value; + + NPT_XmlAttribute(const NPT_XmlAttribute& attribute) : + m_Prefix(attribute.m_Prefix), + m_Name(attribute.m_Name), + m_Value(attribute.m_Value) {} + NPT_XmlAttribute& operator=(const NPT_XmlAttribute& a); + + // friends + friend class NPT_XmlAttributeFinder; + friend class NPT_XmlAttributeFinderWithPrefix; +}; + +/*---------------------------------------------------------------------- +| NPT_XmlNamespaceMap ++---------------------------------------------------------------------*/ +class NPT_XmlNamespaceMap +{ +public: + // destructor + ~NPT_XmlNamespaceMap(); + + // methods + NPT_Result SetNamespaceUri(const char* prefix, const char* uri); + const NPT_String* GetNamespaceUri(const char* prefix); + const NPT_String* GetNamespacePrefix(const char* uri); + +private: + // types + class Entry { + public: + // constructor + Entry(const char* prefix, const char* uri) : + m_Prefix(prefix), m_Uri(uri) {} + + // members + NPT_String m_Prefix; + NPT_String m_Uri; + }; + + // members + NPT_List<Entry*> m_Entries; + + // friends + friend class NPT_XmlWriter; + friend class NPT_XmlNodeWriter; + friend class NPT_XmlNodeCanonicalWriter; +}; + +/*---------------------------------------------------------------------- +| NPT_XmlNode ++---------------------------------------------------------------------*/ +class NPT_XmlElementNode; +class NPT_XmlTextNode; +class NPT_XmlNode +{ + public: + // types + typedef enum { + DOCUMENT, + ELEMENT, + TEXT + } Type; + + // methods + NPT_XmlNode(Type type) : m_Type(type), m_Parent(NULL) {} + virtual ~NPT_XmlNode() {} + Type GetType() const { return m_Type; } + NPT_XmlNode* GetParent() const { return m_Parent; } + + // type casting + virtual NPT_XmlElementNode* AsElementNode() { return NULL; } + virtual const NPT_XmlElementNode* AsElementNode() const { return NULL; } + virtual NPT_XmlTextNode* AsTextNode() { return NULL; } + virtual const NPT_XmlTextNode* AsTextNode() const { return NULL; } + + protected: + // methods + virtual void SetParent(NPT_XmlNode* parent) { m_Parent = parent; } + + // members + Type m_Type; + NPT_XmlNode* m_Parent; + + // friends + friend class NPT_XmlNodeFinder; + friend class NPT_XmlSerializer; + friend class NPT_XmlWriter; + friend class NPT_XmlElementNode; // to allow access to SetParent() +}; + +/*---------------------------------------------------------------------- +| NPT_XmlElementNode ++---------------------------------------------------------------------*/ +class NPT_XmlElementNode : public NPT_XmlNode +{ + public: + // methods + NPT_XmlElementNode(const char* tag); + NPT_XmlElementNode(const char* prefix, const char* tag); + ~NPT_XmlElementNode() override; + NPT_List<NPT_XmlNode*>& GetChildren() { return m_Children; } + const NPT_List<NPT_XmlNode*>& + GetChildren() const { return m_Children; } + NPT_XmlElementNode* GetChild(const char* tag, + const char* namespc = NPT_XML_NO_NAMESPACE, + NPT_Ordinal n=0) const; + NPT_Result AddChild(NPT_XmlNode* child); + NPT_Result SetAttribute(const char* prefix, + const char* name, + const char* value); + NPT_Result SetAttribute(const char* name, + const char* value); + NPT_Result AddText(const char* text); + NPT_List<NPT_XmlAttribute*>& + GetAttributes() { return m_Attributes; } + const NPT_List<NPT_XmlAttribute*>& + GetAttributes() const { return m_Attributes; } + const NPT_String* GetAttribute(const char* name, + const char* namespc = NPT_XML_NO_NAMESPACE) const; + const NPT_String& GetPrefix() const { return m_Prefix; } + const NPT_String& GetTag() const { return m_Tag; } + const NPT_String* GetText(NPT_Ordinal n=0) const; + + // bring all the namespace definitions used in this element of one of its descendants + // into the namespace map of this element so that it may be serialized as a + // standalone element without any prefixes with undefined namespace uris + NPT_Result MakeStandalone(); + + // namespace methods + const NPT_String* GetNamespace() const; + NPT_Result SetNamespaceUri(const char* prefix, const char* uri); + const NPT_String* GetNamespaceUri(const char* prefix) const; + const NPT_String* GetNamespacePrefix(const char* uri) const; + + // type casting + NPT_XmlElementNode* AsElementNode() override { return this; } + const NPT_XmlElementNode* AsElementNode() const override { return this; } + +protected: + // methods + void SetParent(NPT_XmlNode* parent) override; + void SetNamespaceParent(NPT_XmlElementNode* parent); + void RelinkNamespaceMaps(); + + NPT_Result AddAttribute(const char* name, const char* value); + + // members + NPT_String m_Prefix; + NPT_String m_Tag; + NPT_List<NPT_XmlNode*> m_Children; + NPT_List<NPT_XmlAttribute*> m_Attributes; + NPT_XmlNamespaceMap* m_NamespaceMap; + NPT_XmlElementNode* m_NamespaceParent; + + // friends + friend class NPT_XmlTagFinder; + friend class NPT_XmlSerializer; + friend class NPT_XmlWriter; + friend class NPT_XmlNodeWriter; + friend class NPT_XmlNodeCanonicalWriter; + friend class NPT_XmlParser; + friend class NPT_XmlProcessor; + friend class NPT_XmlNamespaceCollapser; +}; + +/*---------------------------------------------------------------------- +| NPT_XmlTextNode ++---------------------------------------------------------------------*/ +class NPT_XmlTextNode : public NPT_XmlNode +{ + public: + // types + typedef enum { + CHARACTER_DATA, + IGNORABLE_WHITESPACE, + CDATA_SECTION, + ENTITY_REFERENCE, + COMMENT + } TokenType; + + // constructor + NPT_XmlTextNode(TokenType token_type, const char* text); + + // methods + const NPT_String& GetString() const { return m_Text; } + TokenType GetTokenType() const { return m_TokenType; } + + // type casting + NPT_XmlTextNode* AsTextNode() override { return this; } + const NPT_XmlTextNode* AsTextNode() const override { return this; } + + private: + // members + TokenType m_TokenType; + NPT_String m_Text; +}; + +/*---------------------------------------------------------------------- +| NPT_XmlParser ++---------------------------------------------------------------------*/ +class NPT_XmlParser +{ + public: + // methods + NPT_XmlParser(bool keep_whitespace = true); + virtual ~NPT_XmlParser(); + virtual NPT_Result Parse(const char* xml, + NPT_XmlNode*& tree, + bool incremental=false); + virtual NPT_Result Parse(const char* xml, + NPT_Size size, + NPT_XmlNode*& tree, + bool incremental=false); + virtual NPT_Result Parse(NPT_InputStream& stream, + NPT_XmlNode*& tree, + bool incremental=false); + virtual NPT_Result Parse(NPT_InputStream& stream, + NPT_Size& size, + NPT_XmlNode*& tree, + bool incremental=false); + + protected: + // NPT_XmlHandler methods + NPT_Result OnStartElement(const char* name); + NPT_Result OnElementAttribute(const char* name, const char* value); + NPT_Result OnEndElement(const char* name); + NPT_Result OnCharacterData(const char* data, NPT_Size size); + void RemoveIgnorableWhitespace(); + + // members + NPT_XmlProcessor* m_Processor; + NPT_XmlElementNode* m_Root; + NPT_XmlElementNode* m_CurrentElement; + bool m_KeepWhitespace; + +private: + void Reset(); + + // friends + friend class NPT_XmlProcessor; +}; + +/*---------------------------------------------------------------------- +| NPT_XmlSerializer ++---------------------------------------------------------------------*/ +class NPT_XmlSerializer +{ +public: + // methods + NPT_XmlSerializer(NPT_OutputStream* output, + NPT_Cardinal indentation = 0, + bool shrink_empty_elements = true, + bool add_xml_decl = false); + virtual ~NPT_XmlSerializer(); + virtual NPT_Result StartDocument(); + virtual NPT_Result EndDocument(); + virtual NPT_Result StartElement(const char* prefix, const char* name); + virtual NPT_Result EndElement(const char* prefix, const char* name); + virtual NPT_Result Attribute(const char* prefix, const char* name, const char* value); + virtual NPT_Result Text(const char* text); + virtual NPT_Result CdataSection(const char* data); + virtual NPT_Result Comment(const char* comment); + +protected: + // methods + void EscapeChar(unsigned char c, char* text); + NPT_Result ProcessPending(); + NPT_Result OutputEscapedString(const char* text, bool attribute); + void OutputIndentation(bool start); + + // members + NPT_OutputStream* m_Output; + bool m_ElementPending; + NPT_Cardinal m_Depth; + NPT_Cardinal m_Indentation; + NPT_String m_IndentationPrefix; + bool m_ElementHasText; + bool m_ShrinkEmptyElements; + bool m_AddXmlDecl; +}; + +/*---------------------------------------------------------------------- +| NPT_XmlWriter ++---------------------------------------------------------------------*/ +class NPT_XmlWriter +{ +public: + // constructor + explicit NPT_XmlWriter(NPT_Cardinal indentation = 0) : m_Indentation(indentation) {} + + // methods + NPT_Result Serialize(NPT_XmlNode& node, + NPT_OutputStream& stream, + bool add_xml_decl = false); + +private: + // members + NPT_Cardinal m_Indentation; +}; + +/*---------------------------------------------------------------------- +| NPT_XmlCanonicalizer ++---------------------------------------------------------------------*/ +class NPT_XmlCanonicalizer +{ +public: + // methods + NPT_Result Serialize(NPT_XmlNode& node, + NPT_OutputStream& stream, + bool add_xml_decl = false); +}; + +#endif // _NPT_XML_H_ diff --git a/lib/libUPnP/Neptune/Source/Core/NptZip.cpp b/lib/libUPnP/Neptune/Source/Core/NptZip.cpp new file mode 100644 index 0000000..0ee50fd --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptZip.cpp @@ -0,0 +1,886 @@ +/***************************************************************** +| +| Neptune - Zip Support +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptConfig.h" +#include "NptZip.h" +#include "NptLogging.h" +#include "NptUtils.h" + +#if defined(NPT_CONFIG_ENABLE_ZIP) +#include "zlib.h" +#endif + +/*---------------------------------------------------------------------- +| logging ++---------------------------------------------------------------------*/ +NPT_SET_LOCAL_LOGGER("neptune.zip") + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +static const NPT_UInt32 NPT_ZIP_END_OF_CENTRAL_DIRECTORY_SIGNATURE = 0x06054b50; +static const NPT_UInt32 NPT_ZIP64_END_OF_CENTRAL_DIRECTORY_SIGNATURE = 0x06064b50; +static const NPT_UInt32 NPT_ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIGNATURE = 0x07064b50; +static const NPT_UInt32 NPT_ZIP_CENTRAL_FILE_HEADER_SIGNATURE = 0x02014b50; +//static const NPT_UInt32 NPT_ZIP_LOCAL_FILE_HEADER_SIGNATURE = 0x04034b50; +static const NPT_UInt16 NPT_ZIP_EXT_DATA_TYPE_ZIP64 = 0x0001; + +static const NPT_UInt32 NPT_ZIP_MAX_DIRECTORY_SIZE = 0x1000000; // 16 MB +static const NPT_UInt32 NPT_ZIP_MAX_ENTRY_COUNT = 0x100000; // 1M entries + +/*---------------------------------------------------------------------- +| NPT_ZipFile::NPT_ZipFile ++---------------------------------------------------------------------*/ +NPT_ZipFile::NPT_ZipFile() +{ +} + +/*---------------------------------------------------------------------- +| NPT_ZipFile::Parse ++---------------------------------------------------------------------*/ +NPT_Result +NPT_ZipFile::Parse(NPT_InputStream& stream, NPT_ZipFile*& file) +{ + // defautl return value + file = NULL; + + // check that we know the size of the stream + NPT_LargeSize stream_size = 0; + NPT_Result result = stream.GetSize(stream_size); + if (NPT_FAILED(result)) { + NPT_LOG_WARNING_1("cannot get stream size (%d)", result); + return result; + } + if (stream_size < 22) { + NPT_LOG_WARNING("input stream too short"); + return NPT_ERROR_INVALID_FORMAT; + } + + // seek to the most likely start of the end of central directory record + unsigned int max_eocdr_size = 22+65536; + if (max_eocdr_size > stream_size) { + max_eocdr_size = (unsigned int)stream_size; + } + unsigned char eocdr[22]; + bool record_found = false; + NPT_Position position = 0; + for (unsigned int i=0; i<max_eocdr_size; i++) { + position = stream_size-22-i; + result = stream.Seek(position); + if (NPT_FAILED(result)) { + NPT_LOG_WARNING_1("seek failed (%d)", result); + return result; + } + result = stream.ReadFully(eocdr, 22); + if (NPT_FAILED(result)) { + NPT_LOG_WARNING_1("read failed (%d)", result); + return result; + } + NPT_UInt32 signature = NPT_BytesToInt32Le(eocdr); + if (signature == NPT_ZIP_END_OF_CENTRAL_DIRECTORY_SIGNATURE) { + record_found = true; + break; + } + } + if (!record_found) { + NPT_LOG_WARNING("eocd record not found at end of stream"); + return NPT_ERROR_INVALID_FORMAT; + } + + // parse the eocdr + NPT_UInt32 this_disk = NPT_BytesToInt16Le(&eocdr[ 4]); + NPT_UInt32 start_disk = NPT_BytesToInt16Le(&eocdr[ 6]); + NPT_UInt64 this_disk_entry_count = NPT_BytesToInt16Le(&eocdr[ 8]); + NPT_UInt64 total_entry_count = NPT_BytesToInt16Le(&eocdr[10]); + NPT_UInt64 central_directory_size = NPT_BytesToInt32Le(&eocdr[12]); + NPT_Position central_directory_offset = NPT_BytesToInt32Le(&eocdr[16]); + + // format check + if (this_disk != 0 || start_disk != 0) { + return NPT_ERROR_NOT_SUPPORTED; + } + if (this_disk_entry_count != total_entry_count) { + return NPT_ERROR_NOT_SUPPORTED; + } + + // check if this is a zip64 file + if (central_directory_offset == 0xFFFFFFFF) { + unsigned char zip64_locator[20]; + result = stream.Seek(position-20); + if (NPT_FAILED(result)) { + NPT_LOG_WARNING_1("seek failed (%d)", result); + return result; + } + result = stream.ReadFully(zip64_locator, 20); + if (NPT_FAILED(result)) { + NPT_LOG_WARNING_1("read failed (%d)", result); + return result; + } + + NPT_UInt32 signature = NPT_BytesToInt32Le(&zip64_locator[0]); + if (signature != NPT_ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIGNATURE) { + NPT_LOG_WARNING("zip64 directory locator signature not found"); + return NPT_ERROR_INVALID_FORMAT; + } + NPT_UInt32 zip64_disk_start = NPT_BytesToInt32Le(&zip64_locator[ 4]); + NPT_UInt64 zip64_directory_offset = NPT_BytesToInt64Le(&zip64_locator[ 8]); + NPT_UInt32 zip64_disk_count = NPT_BytesToInt32Le(&zip64_locator[16]); + + // format check + if (zip64_disk_start != 0 || zip64_disk_count != 1) { + return NPT_ERROR_NOT_SUPPORTED; + } + + // size check + if (zip64_directory_offset > stream_size) { + NPT_LOG_WARNING("zip64 directory offset too large"); + return NPT_ERROR_INVALID_FORMAT; + } + + // load and parse the eocdr64 + unsigned char eocdr64[56]; + result = stream.Seek(zip64_directory_offset); + if (NPT_FAILED(result)) { + NPT_LOG_WARNING_1("seek failed (%d)", result); + return result; + } + result = stream.ReadFully(eocdr64, 56); + if (NPT_FAILED(result)) { + NPT_LOG_WARNING_1("read failed (%d)", result); + return result; + } + + signature = NPT_BytesToInt32Le(&eocdr64[0]); + if (signature != NPT_ZIP64_END_OF_CENTRAL_DIRECTORY_SIGNATURE) { + NPT_LOG_WARNING("zip64 directory signature not found"); + return NPT_ERROR_INVALID_FORMAT; + } + + this_disk = NPT_BytesToInt32Le(&eocdr64[16]); + start_disk = NPT_BytesToInt32Le(&eocdr64[20]); + this_disk_entry_count = NPT_BytesToInt64Le(&eocdr64[24]); + total_entry_count = NPT_BytesToInt64Le(&eocdr64[32]); + central_directory_size = NPT_BytesToInt64Le(&eocdr64[40]); + central_directory_offset = NPT_BytesToInt64Le(&eocdr64[48]); + } + + // format check + if (this_disk != 0 || start_disk != 0) { + return NPT_ERROR_NOT_SUPPORTED; + } + if (this_disk_entry_count != total_entry_count) { + return NPT_ERROR_NOT_SUPPORTED; + } + + // check that the size looks reasonable + if (central_directory_size > NPT_ZIP_MAX_DIRECTORY_SIZE) { + NPT_LOG_WARNING("central directory larger than max supported"); + return NPT_ERROR_OUT_OF_RANGE; + } + if (total_entry_count > NPT_ZIP_MAX_ENTRY_COUNT) { + NPT_LOG_WARNING("central directory larger than max supported"); + return NPT_ERROR_OUT_OF_RANGE; + } + + // read the central directory + NPT_DataBuffer central_directory_buffer; + result = central_directory_buffer.SetDataSize((NPT_Size)central_directory_size); + if (NPT_FAILED(result)) { + NPT_LOG_WARNING_1("central directory too large (%lld)", central_directory_size); + return result; + } + result = stream.Seek(central_directory_offset); + if (NPT_FAILED(result)) { + NPT_LOG_WARNING_1("seek failed (%d)", result); + return result; + } + result = stream.ReadFully(central_directory_buffer.UseData(), (NPT_Size)central_directory_size); + if (NPT_FAILED(result)) { + NPT_LOG_WARNING_1("failed to read central directory (%d)", result); + return result; + } + + // create a new file object + file = new NPT_ZipFile(); + file->m_Entries.Reserve((NPT_Cardinal)total_entry_count); + + // parse all entries + const unsigned char* buffer = (const unsigned char*)central_directory_buffer.GetData(); + NPT_Size buffer_size = central_directory_buffer.GetDataSize(); + for (unsigned int i=0; i<total_entry_count; i++) { + if (buffer_size < 4) break; + NPT_UInt32 signature = NPT_BytesToInt32Le(buffer); + if (signature != NPT_ZIP_CENTRAL_FILE_HEADER_SIGNATURE) { + NPT_LOG_WARNING("unexpected signature in central directory"); + break; + } + + NPT_ZipFile::Entry entry(buffer, buffer_size); + if (entry.m_DirectoryEntrySize == 0) { + NPT_LOG_WARNING("invalid entry data"); + break; + } + if (entry.m_DirectoryEntrySize > central_directory_size || + entry.m_DirectoryEntrySize > buffer_size) { + NPT_LOG_WARNING_1("entry size too large (%d)", entry.m_DirectoryEntrySize); + break; + } + + file->GetEntries().Add(entry); + + central_directory_size -= entry.m_DirectoryEntrySize; + buffer += entry.m_DirectoryEntrySize; + buffer_size -= entry.m_DirectoryEntrySize; + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_ZipFile::GetInputStream ++---------------------------------------------------------------------*/ +NPT_Result +NPT_ZipFile::GetInputStream(Entry& entry, NPT_InputStreamReference& zip_stream, NPT_InputStream*& file_stream) +{ + // default return value + file_stream = NULL; + + // we don't support encrypted files + if (entry.m_Flags & NPT_ZIP_FILE_FLAG_ENCRYPTED) { + return NPT_ERROR_NOT_SUPPORTED; + } + + // check that we support the compression method +#if NPT_CONFIG_ENABLE_ZIP + if (entry.m_CompressionMethod != NPT_ZIP_FILE_COMPRESSION_METHOD_NONE && + entry.m_CompressionMethod != NPT_ZIP_FILE_COMPRESSION_METHOD_DEFLATE) { + return NPT_ERROR_NOT_SUPPORTED; + } +#else + if (entry.m_CompressionMethod != NPT_ZIP_FILE_COMPRESSION_METHOD_NONE) { + return NPT_ERROR_NOT_SUPPORTED; + } +#endif + + // seek to the start of the file entry + NPT_Result result = zip_stream->Seek(entry.m_RelativeOffset); + if (NPT_FAILED(result)) { + NPT_LOG_WARNING_1("seek failed (%d)", result); + return result; + } + + // read the fixed part of the header + unsigned char header[30]; + result = zip_stream->ReadFully(header, 30); + if (NPT_FAILED(result)) { + NPT_LOG_WARNING_1("read failed (%d)", result); + return result; + } + + NPT_UInt16 file_name_length = NPT_BytesToInt16Le(&header[26]); + NPT_UInt16 extra_field_length = NPT_BytesToInt16Le(&header[28]); + + unsigned int header_size = 30+file_name_length+extra_field_length; + NPT_LargeSize zip_stream_size = 0; + zip_stream->GetSize(zip_stream_size); + if (entry.m_RelativeOffset+header_size+entry.m_CompressedSize > zip_stream_size) { + // something's wrong here + return NPT_ERROR_INVALID_FORMAT; + } + + file_stream = new NPT_SubInputStream(zip_stream, entry.m_RelativeOffset+header_size, entry.m_CompressedSize); + +#if NPT_CONFIG_ENABLE_ZIP + if (entry.m_CompressionMethod == NPT_ZIP_FILE_COMPRESSION_METHOD_DEFLATE) { + NPT_InputStreamReference file_stream_ref(file_stream); + file_stream = new NPT_ZipInflatingInputStream(file_stream_ref, true); + } +#endif + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_ZipFile::Entry::Entry ++---------------------------------------------------------------------*/ +NPT_ZipFile::Entry::Entry(const unsigned char* data, NPT_Size data_available) : + m_Flags(0), + m_CompressionMethod(0), + m_Crc32(0), + m_CompressedSize(0), + m_UncompressedSize(0), + m_DiskNumber(0), + m_InternalFileAttributes(0), + m_ExternalFileAttributes(0), + m_RelativeOffset(0), + m_DirectoryEntrySize(0) +{ + if (data_available < 46) return; + + m_Flags = NPT_BytesToInt16Le(data+ 8); + m_CompressionMethod = NPT_BytesToInt16Le(data+10); + m_Crc32 = NPT_BytesToInt32Le(data+16); + m_CompressedSize = NPT_BytesToInt32Le(data+20); + m_UncompressedSize = NPT_BytesToInt32Le(data+24); + m_DiskNumber = NPT_BytesToInt16Le(data+34); + m_InternalFileAttributes = NPT_BytesToInt32Le(data+36); + m_ExternalFileAttributes = NPT_BytesToInt32Le(data+38); + m_RelativeOffset = NPT_BytesToInt32Le(data+42); + + NPT_UInt16 file_name_length = NPT_BytesToInt16Le(data+28); + NPT_UInt16 extra_field_length = NPT_BytesToInt16Le(data+30); + NPT_UInt16 file_comment_length = NPT_BytesToInt16Le(data+32); + + m_DirectoryEntrySize = 46+file_name_length+extra_field_length+file_comment_length; + if (m_DirectoryEntrySize > data_available) { + m_DirectoryEntrySize = 0; + return; + } + + // extract the file name + m_Name.Assign((const char*)data+46, file_name_length); + + // check for a zip64 extension + const unsigned char* ext_data = data+46+file_name_length; + unsigned int ext_data_size = extra_field_length; + while (ext_data_size >= 4) { + unsigned int ext_id = NPT_BytesToInt16Le(ext_data); + unsigned int ext_size = NPT_BytesToInt16Le(ext_data+2); + + if (ext_id == NPT_ZIP_EXT_DATA_TYPE_ZIP64) { + const unsigned char* local_data = ext_data+4; + if (m_UncompressedSize == 0xFFFFFFFF) { + m_UncompressedSize = NPT_BytesToInt64Le(local_data); + local_data += 8; + } + if (m_CompressedSize == 0xFFFFFFFF) { + m_CompressedSize = NPT_BytesToInt64Le(local_data); + local_data += 8; + } + if (m_RelativeOffset == 0xFFFFFFFF) { + m_RelativeOffset = NPT_BytesToInt64Le(local_data); + local_data += 8; + } + if (m_DiskNumber == 0xFFFF) { + m_DiskNumber = NPT_BytesToInt32Le(local_data); + local_data += 4; + } + } + + ext_data += 4+ext_size; + if (ext_data_size >= 4+ext_size) { + ext_data_size -= 4+ext_size; + } else { + ext_data_size = 0; + } + } +} + +#if defined(NPT_CONFIG_ENABLE_ZIP) + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const unsigned int NPT_ZIP_DEFAULT_BUFFER_SIZE = 4096; + +/*---------------------------------------------------------------------- +| NPT_Zip::MapError ++---------------------------------------------------------------------*/ +NPT_Result +NPT_Zip::MapError(int err) +{ + switch (err) { + case Z_OK: return NPT_SUCCESS; + case Z_STREAM_END: return NPT_ERROR_EOS; + case Z_DATA_ERROR: + case Z_STREAM_ERROR: return NPT_ERROR_INVALID_FORMAT; + case Z_MEM_ERROR: return NPT_ERROR_OUT_OF_MEMORY; + case Z_VERSION_ERROR: return NPT_ERROR_INTERNAL; + case Z_NEED_DICT: return NPT_ERROR_NOT_SUPPORTED; + default: return NPT_FAILURE; + } +} + +/*---------------------------------------------------------------------- +| NPT_ZipInflateState ++---------------------------------------------------------------------*/ +class NPT_ZipInflateState { +public: + NPT_ZipInflateState(bool raw = false); + ~NPT_ZipInflateState(); + z_stream m_Stream; +}; + +/*---------------------------------------------------------------------- +| NPT_ZipInflateState::NPT_ZipInflateState ++---------------------------------------------------------------------*/ +NPT_ZipInflateState::NPT_ZipInflateState(bool raw) +{ + // initialize the state + NPT_SetMemory(&m_Stream, 0, sizeof(m_Stream)); + + // initialize the decompressor + inflateInit2(&m_Stream, raw?-15:15+32); // 15 = default window bits, +32 = automatic header +} + +/*---------------------------------------------------------------------- +| NPT_ZipInflateState::~NPT_ZipInflateState ++---------------------------------------------------------------------*/ +NPT_ZipInflateState::~NPT_ZipInflateState() +{ + inflateEnd(&m_Stream); +} + +/*---------------------------------------------------------------------- +| NPT_ZipDeflateState ++---------------------------------------------------------------------*/ +class NPT_ZipDeflateState { +public: + NPT_ZipDeflateState(int compression_level, + NPT_Zip::Format format); + ~NPT_ZipDeflateState(); + z_stream m_Stream; +}; + +/*---------------------------------------------------------------------- +| NPT_ZipDeflateState::NPT_ZipDeflateState ++---------------------------------------------------------------------*/ +NPT_ZipDeflateState::NPT_ZipDeflateState(int compression_level, + NPT_Zip::Format format) +{ + // check parameters + if (compression_level < NPT_ZIP_COMPRESSION_LEVEL_DEFAULT || + compression_level > NPT_ZIP_COMPRESSION_LEVEL_MAX) { + compression_level = NPT_ZIP_COMPRESSION_LEVEL_DEFAULT; + } + + // initialize the state + NPT_SetMemory(&m_Stream, 0, sizeof(m_Stream)); + + // initialize the compressor + deflateInit2(&m_Stream, + compression_level, + Z_DEFLATED, + 15 + (format == NPT_Zip::GZIP ? 16 : 0), + 8, + Z_DEFAULT_STRATEGY); +} + +/*---------------------------------------------------------------------- +| NPT_ZipDeflateState::~NPT_ZipDeflateState ++---------------------------------------------------------------------*/ +NPT_ZipDeflateState::~NPT_ZipDeflateState() +{ + deflateEnd(&m_Stream); +} + +/*---------------------------------------------------------------------- +| NPT_ZipInflatingInputStream::NPT_ZipInflatingInputStream ++---------------------------------------------------------------------*/ +NPT_ZipInflatingInputStream::NPT_ZipInflatingInputStream(NPT_InputStreamReference& source, bool raw) : + m_Source(source), + m_Position(0), + m_State(new NPT_ZipInflateState(raw)), + m_Buffer(NPT_ZIP_DEFAULT_BUFFER_SIZE) +{ +} + +/*---------------------------------------------------------------------- +| NPT_ZipInflatingInputStream::~NPT_ZipInflatingInputStream ++---------------------------------------------------------------------*/ +NPT_ZipInflatingInputStream::~NPT_ZipInflatingInputStream() +{ + delete m_State; +} + +/*---------------------------------------------------------------------- +| NPT_ZipInflatingInputStream::Read ++---------------------------------------------------------------------*/ +NPT_Result +NPT_ZipInflatingInputStream::Read(void* buffer, + NPT_Size bytes_to_read, + NPT_Size* bytes_read) +{ + // check state and parameters + if (m_State == NULL) return NPT_ERROR_INVALID_STATE; + if (buffer == NULL) return NPT_ERROR_INVALID_PARAMETERS; + if (bytes_to_read == 0) return NPT_SUCCESS; + + // default values + if (bytes_read) *bytes_read = 0; + + // setup the output buffer + m_State->m_Stream.next_out = (Bytef*)buffer; + m_State->m_Stream.avail_out = (uInt)bytes_to_read; + + while (m_State->m_Stream.avail_out) { + // decompress what we can + int err = inflate(&m_State->m_Stream, Z_NO_FLUSH); + + if (err == Z_STREAM_END) { + // we decompressed everything + break; + } else if (err == Z_OK) { + // we got something + continue; + } else if (err == Z_BUF_ERROR) { + // we need more input data + NPT_Size input_bytes_read = 0; + NPT_Result result = m_Source->Read(m_Buffer.UseData(), m_Buffer.GetBufferSize(), &input_bytes_read); + if (NPT_FAILED(result)) return result; + + // setup the input buffer + m_Buffer.SetDataSize(input_bytes_read); + m_State->m_Stream.next_in = m_Buffer.UseData(); + m_State->m_Stream.avail_in = m_Buffer.GetDataSize(); + + } else { + return NPT_Zip::MapError(err); + } + } + + // report how much we could decompress + NPT_Size progress = bytes_to_read - m_State->m_Stream.avail_out; + if (bytes_read) { + *bytes_read = progress; + } + m_Position += progress; + + return progress == 0 ? NPT_ERROR_EOS:NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_ZipInflatingInputStream::Seek ++---------------------------------------------------------------------*/ +NPT_Result +NPT_ZipInflatingInputStream::Seek(NPT_Position /* offset */) +{ + // we can't seek + return NPT_ERROR_NOT_SUPPORTED; +} + +/*---------------------------------------------------------------------- +| NPT_ZipInflatingInputStream::Tell ++---------------------------------------------------------------------*/ +NPT_Result +NPT_ZipInflatingInputStream::Tell(NPT_Position& offset) +{ + offset = m_Position; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_ZipInflatingInputStream::GetSize ++---------------------------------------------------------------------*/ +NPT_Result +NPT_ZipInflatingInputStream::GetSize(NPT_LargeSize& size) +{ + // the size is not predictable + size = 0; + return NPT_ERROR_NOT_SUPPORTED; +} + +/*---------------------------------------------------------------------- +| NPT_ZipInflatingInputStream::GetAvailable ++---------------------------------------------------------------------*/ +NPT_Result +NPT_ZipInflatingInputStream::GetAvailable(NPT_LargeSize& available) +{ + // we don't know + available = 0; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_ZipDeflatingInputStream::NPT_ZipDeflatingInputStream ++---------------------------------------------------------------------*/ +NPT_ZipDeflatingInputStream::NPT_ZipDeflatingInputStream( + NPT_InputStreamReference& source, + int compression_level, + NPT_Zip::Format format) : + m_Source(source), + m_Position(0), + m_Eos(false), + m_State(new NPT_ZipDeflateState(compression_level, format)), + m_Buffer(NPT_ZIP_DEFAULT_BUFFER_SIZE) +{ +} + +/*---------------------------------------------------------------------- +| NPT_ZipDeflatingInputStream::~NPT_ZipDeflatingInputStream ++---------------------------------------------------------------------*/ +NPT_ZipDeflatingInputStream::~NPT_ZipDeflatingInputStream() +{ + delete m_State; +} + +/*---------------------------------------------------------------------- +| NPT_ZipDeflatingInputStream::Read ++---------------------------------------------------------------------*/ +NPT_Result +NPT_ZipDeflatingInputStream::Read(void* buffer, + NPT_Size bytes_to_read, + NPT_Size* bytes_read) +{ + // check state and parameters + if (m_State == NULL) return NPT_ERROR_INVALID_STATE; + if (buffer == NULL) return NPT_ERROR_INVALID_PARAMETERS; + if (bytes_to_read == 0) return NPT_SUCCESS; + + // default values + if (bytes_read) *bytes_read = 0; + + // setup the output buffer + m_State->m_Stream.next_out = (Bytef*)buffer; + m_State->m_Stream.avail_out = (uInt)bytes_to_read; + + while (m_State->m_Stream.avail_out) { + // compress what we can + int err = deflate(&m_State->m_Stream, m_Eos?Z_FINISH:Z_NO_FLUSH); + + if (err == Z_STREAM_END) { + // we compressed everything + break; + } else if (err == Z_OK) { + // we got something + continue; + } else if (err == Z_BUF_ERROR) { + // we need more input data + NPT_Size input_bytes_read = 0; + NPT_Result result = m_Source->Read(m_Buffer.UseData(), m_Buffer.GetBufferSize(), &input_bytes_read); + if (result == NPT_ERROR_EOS) { + m_Eos = true; + } else { + if (NPT_FAILED(result)) return result; + } + + // setup the input buffer + m_Buffer.SetDataSize(input_bytes_read); + m_State->m_Stream.next_in = m_Buffer.UseData(); + m_State->m_Stream.avail_in = m_Buffer.GetDataSize(); + + } else { + return NPT_Zip::MapError(err); + } + } + + // report how much we could compress + NPT_Size progress = bytes_to_read - m_State->m_Stream.avail_out; + if (bytes_read) { + *bytes_read = progress; + } + m_Position += progress; + + return progress == 0 ? NPT_ERROR_EOS:NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_ZipDeflatingInputStream::Seek ++---------------------------------------------------------------------*/ +NPT_Result +NPT_ZipDeflatingInputStream::Seek(NPT_Position /* offset */) +{ + // we can't seek + return NPT_ERROR_NOT_SUPPORTED; +} + +/*---------------------------------------------------------------------- +| NPT_ZipDeflatingInputStream::Tell ++---------------------------------------------------------------------*/ +NPT_Result +NPT_ZipDeflatingInputStream::Tell(NPT_Position& offset) +{ + offset = m_Position; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_ZipDeflatingInputStream::GetSize ++---------------------------------------------------------------------*/ +NPT_Result +NPT_ZipDeflatingInputStream::GetSize(NPT_LargeSize& size) +{ + // the size is not predictable + size = 0; + return NPT_ERROR_NOT_SUPPORTED; +} + +/*---------------------------------------------------------------------- +| NPT_ZipDeflatingInputStream::GetAvailable ++---------------------------------------------------------------------*/ +NPT_Result +NPT_ZipDeflatingInputStream::GetAvailable(NPT_LargeSize& available) +{ + // we don't know + available = 0; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_Zip::Deflate ++---------------------------------------------------------------------*/ +NPT_Result +NPT_Zip::Deflate(const NPT_DataBuffer& in, + NPT_DataBuffer& out, + int compression_level, + Format format /* = ZLIB */) +{ + // default return state + out.SetDataSize(0); + + // check parameters + if (compression_level < NPT_ZIP_COMPRESSION_LEVEL_DEFAULT || + compression_level > NPT_ZIP_COMPRESSION_LEVEL_MAX) { + return NPT_ERROR_INVALID_PARAMETERS; + } + + // setup the stream + z_stream stream; + NPT_SetMemory(&stream, 0, sizeof(stream)); + stream.next_in = (Bytef*)in.GetData(); + stream.avail_in = (uInt)in.GetDataSize(); + + // setup the memory functions + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + // initialize the compressor + int err = deflateInit2(&stream, + compression_level, + Z_DEFLATED, + 15 + (format == GZIP ? 16 : 0), + 8, + Z_DEFAULT_STRATEGY); + if (err != Z_OK) return MapError(err); + + // reserve an output buffer known to be large enough + out.Reserve((NPT_Size)deflateBound(&stream, stream.avail_in) + (format==GZIP?10:0)); + stream.next_out = out.UseData(); + stream.avail_out = out.GetBufferSize(); + + // decompress + err = deflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + deflateEnd(&stream); + return MapError(err); + } + + // update the output size + out.SetDataSize((NPT_Size)stream.total_out); + + // cleanup + err = deflateEnd(&stream); + return MapError(err); +} + +/*---------------------------------------------------------------------- +| NPT_Zip::Inflate ++---------------------------------------------------------------------*/ +NPT_Result +NPT_Zip::Inflate(const NPT_DataBuffer& in, + NPT_DataBuffer& out, + bool raw) +{ + // assume an output buffer twice the size of the input plus a bit + NPT_CHECK_WARNING(out.Reserve(32+2*in.GetDataSize())); + + // setup the stream + z_stream stream; + stream.next_in = (Bytef*)in.GetData(); + stream.avail_in = (uInt)in.GetDataSize(); + stream.next_out = out.UseData(); + stream.avail_out = (uInt)out.GetBufferSize(); + + // setup the memory functions + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + // initialize the decompressor + int err = inflateInit2(&stream, raw?-15:15+32); // 15 = default window bits, +32 = automatic header + if (err != Z_OK) return MapError(err); + + // decompress until the end + do { + err = inflate(&stream, Z_SYNC_FLUSH); + if (err == Z_STREAM_END || err == Z_OK || err == Z_BUF_ERROR) { + out.SetDataSize((NPT_Size)stream.total_out); + if ((err == Z_OK && stream.avail_out == 0) || err == Z_BUF_ERROR) { + // grow the output buffer + out.Reserve(out.GetBufferSize()*2); + stream.next_out = out.UseData()+stream.total_out; + stream.avail_out = out.GetBufferSize()-(NPT_Size)stream.total_out; + } + } + } while (err == Z_OK); + + // check for errors + if (err != Z_STREAM_END) { + inflateEnd(&stream); + return MapError(err); + } + + // cleanup + err = inflateEnd(&stream); + return MapError(err); +} + + +/*---------------------------------------------------------------------- +| NPT_Zip::Deflate ++---------------------------------------------------------------------*/ +NPT_Result +NPT_Zip::Deflate(NPT_File& in, + NPT_File& out, + int compression_level, + Format format /* = ZLIB */) +{ + // check parameters + if (compression_level < NPT_ZIP_COMPRESSION_LEVEL_DEFAULT || + compression_level > NPT_ZIP_COMPRESSION_LEVEL_MAX) { + return NPT_ERROR_INVALID_PARAMETERS; + } + + NPT_InputStreamReference input; + NPT_CHECK(in.GetInputStream(input)); + NPT_OutputStreamReference output; + NPT_CHECK(out.GetOutputStream(output)); + + NPT_ZipDeflatingInputStream deflating_stream(input, compression_level, format); + return NPT_StreamToStreamCopy(deflating_stream, *output.AsPointer()); +} + +#endif // NPT_CONFIG_ENABLE_ZIP diff --git a/lib/libUPnP/Neptune/Source/Core/NptZip.h b/lib/libUPnP/Neptune/Source/Core/NptZip.h new file mode 100644 index 0000000..fbbebcb --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptZip.h @@ -0,0 +1,220 @@ +/***************************************************************** +| +| Neptune - Zip Support +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +#ifndef _NPT_ZIP_H_ +#define _NPT_ZIP_H_ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptConfig.h" +#include "NptStreams.h" +#include "NptArray.h" +#include "NptFile.h" + +/*---------------------------------------------------------------------- +| class references ++---------------------------------------------------------------------*/ +class NPT_ZipInflateState; +class NPT_ZipDeflateState; + +/*---------------------------------------------------------------------- +| NPT_ZipFile ++---------------------------------------------------------------------*/ +const unsigned int NPT_ZIP_FILE_FLAG_ENCRYPTED = 0x01; +const unsigned int NPT_ZIP_FILE_COMPRESSION_METHOD_NONE = 0x00; +const unsigned int NPT_ZIP_FILE_COMPRESSION_METHOD_DEFLATE = 0x08; + +class NPT_ZipFile +{ +public: + // types + class Entry { + public: + Entry(const unsigned char* data, NPT_Size data_available); + NPT_String m_Name; + NPT_UInt16 m_Flags; + NPT_UInt16 m_CompressionMethod; + NPT_UInt32 m_Crc32; + NPT_LargeSize m_CompressedSize; + NPT_LargeSize m_UncompressedSize; + NPT_UInt16 m_DiskNumber; + NPT_UInt16 m_InternalFileAttributes; + NPT_UInt32 m_ExternalFileAttributes; + NPT_Position m_RelativeOffset; + NPT_UInt32 m_DirectoryEntrySize; + }; + + // class methods + static NPT_Result Parse(NPT_InputStream& stream, NPT_ZipFile*& file); + static NPT_Result GetInputStream(Entry& entry, NPT_InputStreamReference& zip_stream, NPT_InputStream*& file_stream); + + // accessors + NPT_Array<Entry>& GetEntries() { return m_Entries; } + +private: + // constructor + NPT_ZipFile(); + + // members + NPT_Array<Entry> m_Entries; +}; + +/*---------------------------------------------------------------------- +| NPT_Zip ++---------------------------------------------------------------------*/ +const int NPT_ZIP_COMPRESSION_LEVEL_DEFAULT = -1; +const int NPT_ZIP_COMPRESSION_LEVEL_MIN = 0; +const int NPT_ZIP_COMPRESSION_LEVEL_MAX = 9; +const int NPT_ZIP_COMPRESSION_LEVEL_NONE = 0; +class NPT_Zip +{ +public: + // class methods + static NPT_Result MapError(int err); + + /** + * Compressed data format + */ + typedef enum { + ZLIB, + GZIP + } Format; + + /** + * Deflate (i.e compress) a buffer + */ + static NPT_Result Deflate(const NPT_DataBuffer& in, + NPT_DataBuffer& out, + int compression_level = NPT_ZIP_COMPRESSION_LEVEL_DEFAULT, + Format format = ZLIB); + + /** + * Inflate (i.e decompress) a buffer + */ + static NPT_Result Inflate(const NPT_DataBuffer& in, + NPT_DataBuffer& out, + bool raw = false); + + /** + * Deflate (i.e compress) a file + */ + static NPT_Result Deflate(NPT_File& in, + NPT_File& out, + int compression_level = NPT_ZIP_COMPRESSION_LEVEL_DEFAULT, + Format format = GZIP); + +}; + +/*---------------------------------------------------------------------- +| NPT_ZipInflatingInputStream ++---------------------------------------------------------------------*/ +class NPT_ZipInflatingInputStream : public NPT_InputStream +{ +public: + NPT_ZipInflatingInputStream(NPT_InputStreamReference& source, bool raw = false); + ~NPT_ZipInflatingInputStream() override; + + // NPT_InputStream methods + NPT_Result Read(void* buffer, + NPT_Size bytes_to_read, + NPT_Size* bytes_read = NULL) override; + NPT_Result Seek(NPT_Position offset) override; + NPT_Result Tell(NPT_Position& offset) override; + NPT_Result GetSize(NPT_LargeSize& size) override; + NPT_Result GetAvailable(NPT_LargeSize& available) override; + +private: + NPT_InputStreamReference m_Source; + NPT_Position m_Position; + NPT_ZipInflateState* m_State; + NPT_DataBuffer m_Buffer; +}; + +/*---------------------------------------------------------------------- +| NPT_ZipInflatingOutputStream ++---------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------- +| NPT_ZipDeflatingInputStream ++---------------------------------------------------------------------*/ +class NPT_ZipDeflatingInputStream : public NPT_InputStream +{ +public: + NPT_ZipDeflatingInputStream(NPT_InputStreamReference& source, + int compression_level = NPT_ZIP_COMPRESSION_LEVEL_DEFAULT, + NPT_Zip::Format format = NPT_Zip::ZLIB); + ~NPT_ZipDeflatingInputStream() override; + + // NPT_InputStream methods + NPT_Result Read(void* buffer, + NPT_Size bytes_to_read, + NPT_Size* bytes_read = NULL) override; + NPT_Result Seek(NPT_Position offset) override; + NPT_Result Tell(NPT_Position& offset) override; + NPT_Result GetSize(NPT_LargeSize& size) override; + NPT_Result GetAvailable(NPT_LargeSize& available) override; + +private: + NPT_InputStreamReference m_Source; + NPT_Position m_Position; + bool m_Eos; + NPT_ZipDeflateState* m_State; + NPT_DataBuffer m_Buffer; +}; + +/*---------------------------------------------------------------------- +| NPT_ZipDeflatingOutputStream ++---------------------------------------------------------------------*/ +/*class NPT_ZipDeflatingOutputStream : public NPT_OutputStream +{ +public: + NPT_ZipDeflatingOutputStream(NPT_OutputStreamReference& source, + int compression_level = NPT_ZIP_COMPRESSION_LEVEL_DEFAULT, + NPT_Zip::Format format = NPT_Zip::ZLIB); + NPT_ZipDeflatingOutputStream(); + + // NPT_OutputStream methods + virtual NPT_Result Write(void* buffer, + NPT_Size bytes_to_write, + NPT_Size* bytes_written = NULL); + virtual NPT_Result Seek(NPT_Position offset); + virtual NPT_Result Tell(NPT_Position& offset); + +private: + NPT_OutputStreamReference m_Output; + NPT_Position m_Position; + bool m_Eos; + NPT_ZipDeflateState* m_State; + NPT_DataBuffer m_Buffer; +}; */ + +#endif // _NPT_ZIP_H_ |